diff --git a/refs/pull/405/merge/.buildinfo b/refs/pull/405/merge/.buildinfo new file mode 100644 index 00000000..1dd263c9 --- /dev/null +++ b/refs/pull/405/merge/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 012007e1214812f57fe9bda99df4d3ab +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/refs/pull/405/merge/_images/boot.cast b/refs/pull/405/merge/_images/boot.cast new file mode 100644 index 00000000..e69de29b diff --git a/refs/pull/405/merge/_images/buffers-scheme.png b/refs/pull/405/merge/_images/buffers-scheme.png new file mode 100644 index 00000000..aa70c0ed Binary files /dev/null and b/refs/pull/405/merge/_images/buffers-scheme.png differ diff --git a/refs/pull/405/merge/_images/context_switch.cast b/refs/pull/405/merge/_images/context_switch.cast new file mode 100644 index 00000000..d59458dc --- /dev/null +++ b/refs/pull/405/merge/_images/context_switch.cast @@ -0,0 +1,1055 @@ +{"version": 2, "width": 80, "height": 24, "timestamp": 1615893527, "idle_time_limit": 1.0, "env": {"SHELL": null, "TERM": "xterm"}} +[0.002326, "o", "$ "] +[1.9175, "o", "m"] +[1.959726, "o", "a"] +[2.032681, "o", "k"] +[2.164502, "o", "e"] +[2.232149, "o", " "] +[2.488152, "o", "g"] +[2.596492, "o", "d"] +[2.677323, "o", "b"] +[5.648402, "o", "\r\n"] +[5.657328, "o", "gdb -ex \"target remote localhost:1234\" /linux/vmlinux\r\n"] +[5.69046, "o", "\u001b[35;1m\u001b[35;1mGNU gdb \u001b[m\u001b[35;1m(Ubuntu 9.2-0ubuntu1~20.04) \u001b[m\u001b[35;1m9.2\u001b[m\u001b[35;1m\r\n\u001b[m\u001b[mCopyright (C) 2020 Free Software Foundation, Inc.\r\nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\r\nThis is free software: you are free to change and redistribute it.\r\nThere is NO WARRANTY, to the extent permitted by law.\r\nType \"show copying\" and \"show warranty\" for details.\r\nThis GDB was configured as \"x86_64-linux-gnu\".\r\nType \"show configuration\" for configuration details.\r\nFor bug reporting instructions, please see:\r\n<http://www.gnu.org/software/gdb/bugs/>.\r\nFind the GDB manual and other documentation resources online at:\r\n <http://www.gnu.org/software/gdb/documentation/>.\r\n\r\nFor help, type \"help\".\r\nType \"apropos word\" to search for commands related to \"word\"...\r\n"] +[5.690654, "o", "Reading symbols from \u001b[32m/linux/vmlinux\u001b[m...\r\n"] +[6.256082, "o", "Remote debugging using localhost:1234\r\n"] +[6.268525, "o", "\u001b[33mdefault_idle\u001b[m () at \u001b[32march/x86/kernel/process.c\u001b[m:689\r\n689\t}\r\n"] +[6.269022, "o", "(gdb) "] +[8.116975, "o", "b"] +[8.192267, "o", "r"] +[8.249065, "o", "e"] +[8.289452, "o", "a"] +[8.360076, "o", "k"] +[8.473813, "o", " "] +[8.832714, "o", "_"] +[9.629251, "o", "_"] +[9.941666, "o", "s"] +[10.104279, "o", "w"] +[10.221431, "o", "i"] +[10.309944, "o", "t"] +[10.509059, "o", "c"] +[10.557026, "o", "h"] +[10.849393, "o", "_"] +[11.068795, "o", "t"] +[11.110265, "o", "o"] +[11.352371, "o", "_"] +[14.021585, "o", "a"] +[14.117609, "o", "s"] +[14.213449, "o", "m"] +[14.888578, "o", "\r\n"] +[14.9167, "o", "Breakpoint 1 at \u001b[34m0xc10018e8\u001b[m: file \u001b[32march/x86/entry/entry_32.S\u001b[m, line 765.\r\n(gdb) "] +[16.968107, "o", "c"] +[18.104467, "o", "\r\nContinuing.\r\n"] +[18.156456, "o", "\r\n"] +[18.156634, "o", "Breakpoint 1, \u001b[33m__switch_to_asm\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:765\r\n765\t\tpushl\t%ebp\r\n(gdb) "] +[21.008556, "o", "#"] +[21.237238, "o", " "] +[21.396102, "o", "l"] +[21.51189, "o", "e"] +[21.76495, "o", "t"] +[22.05648, "o", "s"] +[22.357544, "o", " "] +[24.804429, "o", "i"] +[25.30049, "o", "n"] +[25.476535, "o", "s"] +[25.664918, "o", "p"] +[25.773304, "o", "e"] +[25.860811, "o", "c"] +[26.128876, "o", "t"] +[26.278527, "o", " "] +[26.396147, "o", "t"] +[26.648694, "o", "h"] +[27.311874, "o", "e"] +[27.496339, "o", " "] +[31.342091, "o", "p"] +[31.483434, "o", "r"] +[31.554903, "o", "e"] +[31.796618, "o", "v"] +[32.029108, "o", " "] +[33.628667, "o", "t"] +[34.296017, "o", "\b\u001b[K"] +[34.841223, "o", "("] +[36.838321, "o", "\b\u001b[K"] +[40.880455, "o", "t"] +[40.999641, "o", "a"] +[41.19229, "o", "s"] +[41.299116, "o", "k"] +[42.109647, "o", " "] +[42.583652, "o", "("] +[43.015787, "o", "\b\u001b[K"] +[43.181496, "o", "-"] +[43.312415, "o", " "] +[43.501299, "o", "t"] +[43.544044, "o", "h"] +[43.673582, "o", "e"] +[43.728303, "o", " "] +[43.912104, "o", "t"] +[44.079964, "o", "a"] +[44.136162, "o", "s"] +[44.225298, "o", "k"] +[44.297573, "o", " "] +[44.424163, "o", "w"] +[44.539926, "o", "e"] +[44.701627, "o", " "] +[44.845224, "o", "a"] +[45.013358, "o", "r"] +[45.058936, "o", "e"] +[45.143809, "o", " "] +[45.243002, "o", "s"] +[45.400578, "o", "w"] +[45.479309, "o", "i"] +[45.607647, "o", "t"] +[45.838044, "o", "c"] +[45.888549, "o", "h"] +[45.951578, "o", "i"] +[46.061361, "o", "n"] +[46.116627, "o", "g"] +[46.260458, "o", " "] +[46.312755, "o", "a"] +[46.62442, "o", "w"] +[46.717299, "o", "a"] +[46.870336, "o", "y"] +[46.975698, "o", " "] +[47.14446, "o", "f"] +[47.209771, "o", "r"] +[47.259233, "o", "o"] +[47.311775, "o", "m"] +[47.840572, "o", "\r\n(gdb) "] +[50.231971, "o", "l"] +[50.440366, "o", "i"] +[50.495315, "o", "s"] +[50.719925, "o", "t"] +[50.82848, "o", " "] +[51.933215, "o", "7"] +[54.782257, "o", "6"] +[56.895922, "o", "0"] +[57.559601, "o", "\r\n"] +[57.561485, "o", "755\t/*\r\n756\t * %eax: prev task\r\n757\t * %edx: next task\r\n758\t */\r\n759\t.pushsection .text, \"ax\"\r\n760\tSYM_CODE_START(__switch_to_asm)\r\n761\t\t/*\r\n762\t\t * Save callee-saved registers\r\n763\t\t * This must match the order in struct inactive_task_frame\r\n764\t\t */\r\n(gdb) "] +[60.462285, "o", "p"] +[60.804466, "o", "r"] +[60.880276, "o", "i"] +[60.952589, "o", "n"] +[61.048481, "o", "t"] +[61.144253, "o", " "] +[61.567815, "o", "("] +[62.084353, "o", "("] +[62.340434, "o", "s"] +[62.521336, "o", "t"] +[62.584033, "o", "r"] +[62.681088, "o", "u"] +[62.808595, "o", "c"] +[63.020327, "o", "t"] +[63.157429, "o", " "] +[63.280568, "o", "t"] +[63.377159, "o", "a"] +[63.533418, "o", "s"] +[63.622482, "o", "k"] +[63.875748, "o", "_"] +[64.146633, "o", "s"] +[64.482186, "o", "t"] +[64.511947, "o", "r"] +[64.637404, "o", "u"] +[64.777177, "o", "c"] +[64.97617, "o", "t"] +[65.695387, "o", "*"] +[66.288011, "o", ")"] +[67.279895, "o", "$"] +[71.141799, "o", "e"] +[71.240296, "o", "a"] +[71.636944, "o", "x"] +[72.43762, "o", ")"] +[72.839998, "o", "-"] +[73.182685, "o", ">"] +[73.437056, "o", "c"] +[73.58784, "o", "o"] +[73.7922, "o", "m"] +[73.916696, "o", "m"] +[74.544734, "o", "\r\n"] +[74.575314, "o", "$1 = \"swapper/0\\000\\000\\000\\000\\000\\000\"\r\n(gdb) "] +[78.960006, "o", "#"] +[79.380986, "o", " "] +[80.31777, "o", "a"] +[80.439599, "o", "n"] +[80.535856, "o", "d"] +[80.628399, "o", " "] +[80.759967, "o", "l"] +[80.807871, "o", "e"] +[80.984042, "o", "t"] +[81.197923, "o", "s"] +[81.316977, "o", " "] +[81.439785, "o", "s"] +[81.749919, "o", "e"] +[81.884422, "o", "e"] +[82.073889, "o", " "] +[83.576034, "o", "t"] +[83.693926, "o", "h"] +[83.808938, "o", "e"] +[83.973244, "o", " "] +[84.221634, "o", "s"] +[85.29237, "o", "\b\u001b[K"] +[85.445562, "o", "\b\u001b[K"] +[85.567927, "o", "\b\u001b[K"] +[85.701674, "o", "\b\u001b[K"] +[85.824798, "o", "\b\u001b[K"] +[86.004056, "o", "t"] +[86.079743, "o", "o"] +[86.237188, "o", " "] +[86.652315, "o", "w"] +[86.749408, "o", "h"] +[86.808631, "o", "i"] +[86.917022, "o", "c"] +[86.98438, "o", "h"] +[87.06647, "o", " "] +[87.260113, "o", "t"] +[87.388902, "o", "a"] +[87.551541, "o", "s"] +[87.712082, "o", "k"] +[88.144914, "o", " "] +[88.411207, "o", "w"] +[88.511967, "o", "e"] +[88.6247, "o", " "] +[88.808452, "o", "a"] +[88.973655, "o", "r"] +[89.044472, "o", "e"] +[89.128021, "o", " "] +[89.293244, "o", "s"] +[89.485572, "o", "w"] +[89.59152, "o", "i"] +[90.069057, "o", "t"] +[90.356352, "o", "c"] +[90.426188, "o", "h"] +[90.524199, "o", "i"] +[90.623739, "o", "n"] +[90.712003, "o", "g"] +[90.831687, "o", " "] +[90.996124, "o", "t"] +[91.064549, "o", "o"] +[91.608395, "o", "\r\n"] +[91.608597, "o", "(gdb) "] +[92.768673, "o", "# and lets see to which task we are switching to"] +[93.125736, "o", "\b"] +[93.506024, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[9Pprint ((struct task_struct*)$eax)->comm"] +[93.752135, "o", "\b"] +[94.255802, "o", "\b"] +[94.2866, "o", "\b"] +[94.33478, "o", "\b"] +[94.36526, "o", "\b"] +[94.397811, "o", "\b"] +[94.428704, "o", "\b"] +[94.460327, "o", "\b"] +[94.495522, "o", "\b"] +[94.523042, "o", "\b"] +[94.554005, "o", "\b"] +[94.815994, "o", "\u001b[C"] +[94.981232, "o", "\u001b[C"] +[95.133933, "o", "\u001b[C"] +[97.174123, "o", "\b\u001b[1Px)->comm\b\b\b\b\b\b\b\b"] +[97.320654, "o", "dx)->comm\b\b\b\b\b\b\b\b"] +[98.368145, "o", "\r\n"] +[98.386055, "o", "$2 = \"kworker/0:1\\000\\000\\000\\000\"\r\n(gdb) "] +[109.290011, "o", "c"] +[110.600274, "o", "\r\nContinuing.\r\n"] +[110.611283, "o", "\r\n"] +[110.611546, "o", "Breakpoint 1, \u001b[33m__switch_to_asm\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:765\r\n765\t\tpushl\t%ebp\r\n(gdb) "] +[111.72507, "o", "c"] +[111.887716, "o", "\bprint ((struct task_struct*)$edx)->comm"] +[113.100353, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C# and lets see to which task we are switching to"] +[114.228918, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[9Pprint ((struct task_struct*)$edx)->comm"] +[115.280062, "o", "\r\n"] +[115.296922, "o", "$3 = \"swapper/0\\000\\000\\000\\000\\000\\000\"\r\n(gdb) "] +[116.415272, "o", "c"] +[116.912694, "o", "\r\n"] +[116.912781, "o", "Continuing.\r\n"] +[117.312405, "o", "\r\n"] +[117.313149, "o", "Breakpoint 1, \u001b[33m__switch_to_asm\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:765\r\n765\t\tpushl\t%ebp\r\n"] +[117.313648, "o", "(gdb) "] +[117.933355, "o", "c"] +[118.080051, "o", "\bprint ((struct task_struct*)$edx)->comm"] +[119.912687, "o", "\r\n"] +[119.92993, "o", "$4 = \"init\\000er/0\\000\\000\\000\\000\\000\\000\"\r\n(gdb) "] +[123.256997, "o", "print ((struct task_struct*)$edx)->comm"] +[123.876701, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[K"] +[124.45439, "o", "print ((struct task_struct*)$edx)->comm"] +[124.647655, "o", "\b"] +[124.80468, "o", "\b"] +[124.952888, "o", "\b"] +[125.110239, "o", "\b"] +[125.248208, "o", "\b"] +[125.396351, "o", "\b"] +[125.549064, "o", "\b"] +[125.688114, "o", "\b"] +[126.095543, "o", "\b\u001b[1Px)->comm\b\b\b\b\b\b\b\b"] +[126.191882, "o", "ax)->comm\b\b\b\b\b\b\b\b"] +[126.719944, "o", "\r\n"] +[126.736207, "o", "$5 = \"swapper/0\\000\\000\\000\\000\\000\\000\"\r\n(gdb) "] +[133.316754, "o", "#"] +[133.484351, "o", " "] +[133.66117, "o", "l"] +[133.824069, "o", "o"] +[133.949648, "o", "o"] +[134.022861, "o", "k"] +[134.17215, "o", "s"] +[134.223574, "o", " "] +[134.331832, "o", "l"] +[134.49252, "o", "i"] +[134.639694, "o", "k"] +[134.688238, "o", "e"] +[134.775713, "o", " "] +[134.879648, "o", "w"] +[134.951696, "o", "e"] +[135.033237, "o", " "] +[135.163839, "o", "a"] +[135.264608, "o", "r"] +[135.320082, "o", "e"] +[135.40093, "o", " "] +[135.535122, "o", "s"] +[135.725486, "o", "w"] +[135.816051, "o", "i"] +[135.927456, "o", "t"] +[136.131156, "o", "c"] +[136.202658, "o", "h"] +[136.256422, "o", "i"] +[136.396776, "o", "n"] +[136.460338, "o", "g"] +[136.580257, "o", " "] +[136.687682, "o", "f"] +[136.77995, "o", "r"] +[136.832341, "o", "o"] +[136.887861, "o", "m"] +[137.036266, "o", " "] +[137.135292, "o", "t"] +[137.247438, "o", "h"] +[137.356536, "o", "e"] +[137.439224, "o", " "] +[137.678756, "o", "s"] +[137.871289, "o", "w"] +[137.999837, "o", "a"] +[138.119198, "o", "p"] +[138.257533, "o", "p"] +[138.350743, "o", "e"] +[138.433485, "o", "r"] +[138.749519, "o", " "] +[139.888082, "o", "t"] +[140.087705, "o", "a"] +[140.119863, "o", "s"] +[140.276783, "o", "k"] +[140.435722, "o", " "] +[140.592133, "o", "t"] +[140.691411, "o", "o"] +[140.78898, "o", " "] +[140.873948, "o", "t"] +[141.005069, "o", "h"] +[141.055666, "o", "e"] +[141.191609, "o", " "] +[141.493029, "o", "i"] +[141.5594, "o", "n"] +[141.639238, "o", "i"] +[141.744796, "o", "t"] +[141.82812, "o", " "] +[141.927392, "o", "t"] +[142.103712, "o", "a"] +[142.179748, "o", "s"] +[142.452147, "o", "k"] +[143.168201, "o", "\r\n(gdb) "] +[146.056263, "o", "b"] +[146.12877, "o", "t"] +[148.33612, "o", "\r\n"] +[148.35078, "o", "#0 \u001b[33m__switch_to_asm\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:765\r\n"] +[148.351576, "o", "#1 \u001b[34m0xc15d8277\u001b[m in \u001b[33mcontext_switch\u001b[m (\u001b[36mrf\u001b[m=0xc17c9f04, \u001b[36mnext\u001b[m=<optimized out>, \u001b[m\r\n"] +[148.351914, "o", " \u001b[m\u001b[36mprev\u001b[m=0xc17d02c0 <init_task>, \u001b[36mrq\u001b[m=0xcfdcb700) at \u001b[32mkernel/sched/core.c\u001b[m:3779\r\n"] +[148.352077, "o", "#2 \u001b[33m__schedule\u001b[m (\u001b[36mpreempt\u001b[m=<optimized out>, \u001b[36mpreempt@entry\u001b[m=false)\u001b[m\r\n"] +[148.352169, "o", " \u001b[m at \u001b[32mkernel/sched/core.c\u001b[m:4528\r\n#3 \u001b[34m0xc15d8a37\u001b[m in \u001b[33mschedule_idle\u001b[m () at \u001b[32mkernel/sched/core.c\u001b[m:4634\r\n"] +[148.358451, "o", "#4 \u001b[34m0xc108d8a5\u001b[m in \u001b[33mdo_idle\u001b[m () at \u001b[32mkernel/sched/idle.c\u001b[m:327\r\n"] +[148.365129, "o", "#5 \u001b[34m0xc108dbd5\u001b[m in \u001b[33mcpu_startup_entry\u001b[m (\u001b[36mstate=state@entry\u001b[m=CPUHP_ONLINE)\u001b[m\r\n \u001b[m at \u001b[32mkernel/sched/idle.c\u001b[m:395\r\n#6 \u001b[34m0xc15d6100\u001b[m in \u001b[33mrest_init\u001b[m () at \u001b[32minit/main.c\u001b[m:721\r\n#7 \u001b[34m0xc18c77de\u001b[m in \u001b[33march_call_rest_init\u001b[m () at \u001b[32minit/main.c\u001b[m:845\r\n"] +[148.36552, "o", "#8 \u001b[34m0xc18c7c30\u001b[m in \u001b[33mstart_kernel\u001b[m () at \u001b[32minit/main.c\u001b[m:1061\r\n"] +[148.367951, "o", "#9 \u001b[34m0xc18c7218\u001b[m in \u001b[33mi386_start_kernel\u001b[m () at \u001b[32march/x86/kernel/head32.c\u001b[m:56\r\n"] +[148.368485, "o", "#10 \u001b[34m0xc10001db\u001b[m in \u001b[33mstartup_32_smp\u001b[m () at \u001b[32march/x86/kernel/head_32.S\u001b[m:327\r\n"] +[148.36957, "o", "#11 \u001b[34m0x00000000\u001b[m in \u001b[33m??\u001b[m ()\r\n"] +[148.369972, "o", "(gdb) "] +[151.00407, "o", "#"] +[151.19242, "o", " "] +[151.460669, "o", "y"] +[151.535715, "o", "e"] +[151.62446, "o", "s"] +[151.759619, "o", ","] +[151.847569, "o", " "] +[152.111536, "o", "t"] +[152.207294, "o", "h"] +[152.251822, "o", "i"] +[152.375566, "o", "s"] +[152.468326, "o", " "] +[152.651638, "o", "l"] +[152.815662, "o", "o"] +[152.959592, "o", "o"] +[153.076986, "o", "k"] +[153.231758, "o", "s"] +[153.335568, "o", " "] +[153.503403, "o", "l"] +[153.639799, "o", "i"] +[153.814824, "o", "k"] +[153.892142, "o", "e"] +[154.011029, "o", " "] +[154.136079, "o", "t"] +[154.191539, "o", "h"] +[154.287617, "o", "e"] +[154.367043, "o", " "] +[154.535718, "o", "s"] +[154.719646, "o", "w"] +[154.838308, "o", "a"] +[155.020956, "o", "p"] +[155.404904, "o", "p"] +[155.536173, "o", "e"] +[155.653023, "o", "r"] +[155.768249, "o", " "] +[156.056207, "o", "t"] +[156.143169, "o", "a"] +[156.291919, "o", "s"] +[156.440453, "o", "k"] +[158.224694, "o", "\r\n(gdb) "] +[162.551586, "o", "s"] +[163.114829, "o", "t"] +[163.205076, "o", "e"] +[163.340616, "o", "p"] +[163.643258, "o", "i"] +[167.327688, "o", "\b\u001b[K"] +[167.839044, "o", "\b\u001b[K"] +[167.965402, "o", "\b\u001b[K"] +[168.113034, "o", "\b\u001b[K"] +[168.239474, "o", "\b\u001b[K"] +[168.484145, "o", "#"] +[168.703431, "o", " "] +[169.027423, "o", "l"] +[169.112353, "o", "e"] +[169.28797, "o", "t"] +[169.524584, "o", "s"] +[169.735299, "o", " "] +[171.135828, "o", "s"] +[171.4075, "o", "t"] +[171.464843, "o", "e"] +[171.808964, "o", "p"] +[172.115755, "o", " "] +[172.317145, "o", "a"] +[172.47342, "o", "n"] +[172.596959, "o", "d"] +[172.735489, "o", " "] +[172.927669, "o", "o"] +[173.042781, "o", "v"] +[173.108033, "o", "e"] +[173.907894, "o", "\b\u001b[K"] +[174.127765, "o", "b"] +[174.815899, "o", "\b\u001b[K"] +[174.939745, "o", "\b\u001b[K"] +[175.15, "o", "b"] +[175.428235, "o", "s"] +[175.59581, "o", "e"] +[175.723777, "o", "r"] +[175.97285, "o", "v"] +[176.055296, "o", "e"] +[176.248513, "o", " "] +[176.51233, "o", "t"] +[177.968133, "o", "h"] +[179.192669, "o", "e"] +[182.952071, "o", "\b\u001b[K"] +[183.087972, "o", "\b\u001b[K"] +[183.214224, "o", "\b\u001b[K"] +[183.448903, "o", "h"] +[183.488214, "o", "o"] +[183.551638, "o", "w"] +[183.707961, "o", " "] +[183.951723, "o", "t"] +[184.027742, "o", "h"] +[184.119558, "o", "e"] +[184.227577, "o", " "] +[184.428877, "o", "c"] +[184.515292, "o", "o"] +[184.599136, "o", "n"] +[184.695565, "o", "t"] +[184.751404, "o", "e"] +[184.975304, "o", "x"] +[185.18823, "o", "t"] +[185.287641, "o", " "] +[185.383712, "o", "s"] +[185.581109, "o", "w"] +[185.704285, "o", "i"] +[185.783127, "o", "t"] +[186.016302, "o", "c"] +[186.102309, "o", "h"] +[187.085348, "o", " "] +[187.500213, "o", "u"] +[187.57576, "o", "n"] +[187.815524, "o", "f"] +[188.02442, "o", "o"] +[188.199542, "o", "l"] +[188.533385, "o", "d"] +[188.621774, "o", "s"] +[189.632444, "o", "\r\n(gdb) "] +[190.303457, "o", "s"] +[190.479487, "o", "t"] +[190.544727, "o", "e"] +[190.591511, "o", "p"] +[190.703644, "o", "i"] +[191.007796, "o", "\r\n"] +[191.010816, "o", "766\t\tpushl\t%ebx\r\n(gdb) "] +[191.912524, "o", "\r\n"] +[191.915059, "o", "767\t\tpushl\t%edi\r\n(gdb) "] +[192.743936, "o", "\r\n"] +[192.746308, "o", "768\t\tpushl\t%esi\r\n(gdb) "] +[193.511536, "o", "\r\n"] +[193.514218, "o", "774\t\tpushfl\r\n(gdb) "] +[194.415367, "o", "\r\n"] +[194.41946, "o", "\u001b[33m__switch_to_asm\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:777\r\n777\t\tmovl\t%esp, TASK_threadsp(%eax)\r\n"] +[194.419691, "o", "(gdb) "] +[195.220364, "o", "#"] +[195.520461, "o", " "] +[195.799342, "o", "w"] +[195.935095, "o", "e"] +[196.088054, "o", " "] +[196.252345, "o", "s"] +[196.373061, "o", "a"] +[196.59163, "o", "v"] +[196.623491, "o", "e"] +[196.823595, "o", "d"] +[197.018563, "o", " "] +[197.143737, "o", "t"] +[197.274616, "o", "h"] +[197.332048, "o", "e"] +[197.472049, "o", " "] +[197.783684, "o", "r"] +[197.831704, "o", "e"] +[198.02048, "o", "g"] +[198.141339, "o", "i"] +[198.192092, "o", "s"] +[198.339912, "o", "t"] +[198.402788, "o", "e"] +[198.520477, "o", "r"] +[198.688044, "o", "s"] +[198.84898, "o", " "] +[199.00533, "o", "s"] +[199.107804, "o", "o"] +[199.279942, "o", " "] +[199.508566, "o", "f"] +[199.671398, "o", "a"] +[199.887722, "o", "r"] +[200.351521, "o", ","] +[200.463301, "o", " "] +[200.655968, "o", "n"] +[200.687803, "o", "e"] +[200.772872, "o", "x"] +[201.05564, "o", "t"] +[201.240283, "o", " "] +[201.524903, "o", "w"] +[201.61563, "o", "e"] +[201.751344, "o", " "] +[202.125757, "o", "s"] +[202.523685, "o", "\b\u001b[K"] +[202.64147, "o", "w"] +[202.727705, "o", "i"] +[202.903547, "o", "l"] +[203.045364, "o", "l"] +[203.156751, "o", " "] +[203.413128, "o", "s"] +[203.596934, "o", "w"] +[203.719746, "o", "i"] +[203.832585, "o", "t"] +[204.068109, "o", "c"] +[204.14267, "o", "h"] +[204.271578, "o", " "] +[204.320065, "o", "t"] +[204.455512, "o", "h"] +[204.523486, "o", "e"] +[204.657363, "o", " "] +[204.759158, "o", "t"] +[205.586833, "o", "\b\u001b[K"] +[205.648223, "o", "s"] +[205.768517, "o", "t"] +[205.840198, "o", "a"] +[206.035781, "o", "c"] +[206.047227, "o", "k"] +[206.687714, "o", "\r\n"] +[206.687766, "o", "(gdb) "] +[207.179955, "o", "s"] +[207.355887, "o", "t"] +[207.428741, "o", "e"] +[207.457028, "o", "p"] +[207.612888, "o", "i"] +[208.064286, "o", "\r\n"] +[208.067075, "o", "778\t\tmovl\tTASK_threadsp(%edx), %esp\r\n(gdb) "] +[209.407591, "o", "\r\n"] +[209.411316, "o", "\u001b[33m__switch_to_asm\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:781\r\n781\t\tmovl\tTASK_stack_canary(%edx), %ebx\r\n"] +[209.411612, "o", "(gdb) "] +[212.902993, "o", "#"] +[213.186849, "o", " "] +[213.319001, "o", "w"] +[213.390944, "o", "e"] +[213.535507, "o", " "] +[213.663195, "o", "a"] +[213.799039, "o", "r"] +[213.879251, "o", "e"] +[213.967477, "o", " "] +[214.079533, "o", "d"] +[214.155535, "o", "o"] +[214.332766, "o", "n"] +[214.399683, "o", "e"] +[214.55702, "o", " "] +[214.7656, "o", "s"] +[215.047766, "o", "w"] +[215.228474, "o", "i"] +[215.304639, "o", "t"] +[215.519221, "o", "c"] +[215.604247, "o", "h"] +[215.733286, "o", "i"] +[215.813391, "o", "n"] +[215.8956, "o", "g"] +[216.004892, "o", " "] +[216.079528, "o", "t"] +[216.183413, "o", "h"] +[216.267953, "o", "e"] +[216.399454, "o", " "] +[216.623103, "o", "s"] +[216.821001, "o", "t"] +[216.863454, "o", "a"] +[217.111792, "o", "c"] +[217.195888, "o", "k"] +[217.707786, "o", ","] +[217.787686, "o", " "] +[217.949878, "o", "l"] +[218.023149, "o", "e"] +[218.167388, "o", "t"] +[218.375101, "o", "s"] +[218.503646, "o", " "] +[218.671911, "o", "t"] +[218.735588, "o", "a"] +[218.871225, "o", "k"] +[218.982322, "o", "e"] +[219.068728, "o", " "] +[219.175086, "o", "a"] +[219.296026, "o", " "] +[219.596276, "o", "l"] +[219.771622, "o", "o"] +[219.901863, "o", "o"] +[219.967878, "o", "k"] +[220.087157, "o", " "] +[220.17509, "o", "a"] +[220.347339, "o", "t"] +[220.403464, "o", " "] +[220.519087, "o", "t"] +[220.612148, "o", "h"] +[220.67667, "o", "e"] +[220.772254, "o", " "] +[220.943396, "o", "b"] +[221.031202, "o", "r"] +[221.038285, "o", "a"] +[221.298946, "o", "c"] +[221.420949, "o", "k"] +[221.741402, "o", "\b\u001b[K"] +[221.876722, "o", "\b\u001b[K"] +[221.999662, "o", "\b\u001b[K"] +[222.119543, "o", "\b\u001b[K"] +[222.151268, "o", "a"] +[222.263857, "o", "c"] +[222.343319, "o", "k"] +[222.566421, "o", "t"] +[222.731723, "o", "r"] +[222.806406, "o", "a"] +[222.983386, "o", "c"] +[223.076776, "o", "e"] +[223.447917, "o", "\r\n(gdb) "] +[224.002251, "o", "b"] +[224.055592, "o", "t"] +[224.271867, "o", "\r\n"] +[224.272024, "o", "#0 \u001b[33m__switch_to_asm\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:781\r\n"] +[224.27223, "o", "#1 \u001b[34m0xc253ba58\u001b[m in \u001b[33m??\u001b[m ()\r\nBacktrace stopped: previous frame inner to this frame (corrupt stack?)\r\n(gdb) "] +[226.94333, "o", "#"] +[227.288215, "o", " "] +[227.551148, "o", "o"] +[227.683628, "o", "o"] +[227.839199, "o", "p"] +[228.980471, "o", "s"] +[229.095151, "o", ","] +[229.197165, "o", " "] +[229.364899, "o", "t"] +[229.447006, "o", "h"] +[229.543446, "o", "e"] +[229.643847, "o", " "] +[229.764396, "o", "d"] +[229.823982, "o", "e"] +[229.922185, "o", "b"] +[229.959231, "o", "u"] +[230.103636, "o", "g"] +[230.50335, "o", "g"] +[230.628726, "o", "e"] +[230.732769, "o", "r"] +[230.877045, "o", " "] +[230.996275, "o", "i"] +[231.107576, "o", "s"] +[231.210359, "o", " "] +[231.399261, "o", "c"] +[231.487397, "o", "o"] +[231.599424, "o", "n"] +[232.09977, "o", "f"] +[232.287115, "o", "u"] +[232.485493, "o", "s"] +[232.676843, "o", "e"] +[232.771224, "o", "d"] +[233.251928, "o", ","] +[233.424736, "o", " "] +[240.103124, "o", "w"] +[240.182868, "o", "e"] +[240.327268, "o", " "] +[240.486874, "o", "a"] +[240.66716, "o", "r"] +[240.729259, "o", "e"] +[240.868472, "o", " "] +[241.096347, "o", "m"] +[241.18101, "o", "i"] +[241.327393, "o", "s"] +[241.485639, "o", "s"] +[241.574748, "o", "i"] +[241.661021, "o", "n"] +[241.743456, "o", "g"] +[241.906569, "o", " "] +[242.12363, "o", "t"] +[242.244647, "o", "h"] +[242.335037, "o", "e"] +[242.496621, "o", " "] +[245.351862, "o", "\b\u001b[K"] +[245.476547, "o", "\b\u001b[K"] +[245.600162, "o", "\b\u001b[K"] +[245.733041, "o", "\b\u001b[K"] +[245.927573, "o", "p"] +[246.013118, "o", "a"] +[246.119622, "o", "r"] +[246.279117, "o", "t"] +[246.484973, "o", "s"] +[246.583587, "o", " "] +[246.695127, "o", "o"] +[246.770543, "o", "f"] +[246.911599, "o", " "] +[246.959314, "o", "t"] +[247.101026, "o", "h"] +[247.164598, "o", "e"] +[247.299367, "o", " "] +[248.091601, "o", "s"] +[248.319596, "o", "t"] +[248.391035, "o", "a"] +[248.991394, "o", "c"] +[249.100166, "o", "k"] +[250.031636, "o", " "] +[250.096947, "o", "f"] +[250.283625, "o", "r"] +[250.351461, "o", "a"] +[250.432813, "o", "m"] +[250.535577, "o", "e"] +[251.560407, "o", "\r\n(gdb) "] +[252.27138, "o", "#"] +[252.743479, "o", " "] +[254.959991, "o", "l"] +[254.983878, "o", "e"] +[255.167102, "o", "t"] +[255.355618, "o", "s"] +[255.519673, "o", " "] +[255.657043, "o", "c"] +[255.783342, "o", "o"] +[255.911076, "o", "n"] +[256.091637, "o", "t"] +[256.167365, "o", "i"] +[256.267678, "o", "n"] +[256.373344, "o", "u"] +[256.645139, "o", "e"] +[256.802641, "o", " "] +[256.975427, "o", "u"] +[257.06117, "o", "n"] +[257.231687, "o", "t"] +[257.423098, "o", "i"] +[257.528178, "o", "l"] +[257.874938, "o", " "] +[257.998964, "o", "w"] +[258.090668, "o", "e"] +[258.204414, "o", " "] +[258.39651, "o", "r"] +[258.444584, "o", "e"] +[258.566703, "o", "a"] +[258.759543, "o", "c"] +[258.862693, "o", "h"] +[259.109149, "o", " "] +[269.467858, "o", "a"] +[269.639412, "o", " "] +[269.847362, "o", "p"] +[270.032414, "o", "r"] +[270.096595, "o", "o"] +[270.245178, "o", "p"] +[270.383526, "o", "e"] +[270.448348, "o", "r"] +[270.579818, "o", " "] +[270.691356, "o", "f"] +[270.863693, "o", "u"] +[270.894962, "o", "n"] +[271.019515, "o", "c"] +[271.23123, "o", "t"] +[271.287233, "o", "i"] +[271.343717, "o", "o"] +[271.739795, "o", "n"] +[272.06029, "o", " "] +[272.580422, "o", "\b\u001b[K"] +[272.831445, "o", ","] +[272.951811, "o", " "] +[273.831788, "o", "e"] +[274.015133, "o", "."] +[274.207026, "o", "g"] +[274.284353, "o", "."] +[274.39683, "o", " "] +[275.196925, "o", "_"] +[275.339729, "o", "_"] +[275.831025, "o", "s"] +[276.015813, "o", "w"] +[276.180803, "o", "i"] +[276.331724, "o", "t"] +[276.534941, "o", "c"] +[276.566947, "o", "h"] +[276.864471, "o", "_"] +[277.055747, "o", "t"] +[277.103744, "o", "o"] +[277.879557, "o", "\r\n(gdb) "] +[278.37271, "o", "b"] +[278.477418, "o", "r"] +[278.524454, "o", "e"] +[278.590659, "o", "a"] +[278.684679, "o", "k"] +[278.775286, "o", " "] +[279.271091, "o", "_"] +[279.387961, "o", "_"] +[279.591305, "o", "s"] +[279.782144, "o", "w"] +[279.863553, "o", "i"] +[279.975196, "o", "t"] +[280.157072, "o", "c"] +[280.207462, "o", "h"] +[280.498546, "o", "_"] +[280.716367, "o", "t"] +[280.780306, "o", "o"] +[281.903272, "o", "\r\n"] +[281.920624, "o", "Breakpoint 2 at \u001b[34m0xc1020050\u001b[m: file \u001b[32march/x86/kernel/process_32.c\u001b[m, line 159.\r\n(gdb) "] +[285.580302, "o", "c"] +[287.023431, "o", "\r\nContinuing.\r\n"] +[287.025661, "o", "\r\n"] +[287.026259, "o", "Breakpoint 2, \u001b[33m__switch_to\u001b[m (\u001b[36mprev_p\u001b[m=0xc17d02c0 <init_task>, \u001b[36mnext_p\u001b[m=0xc2530040)\u001b[m\r\n \u001b[m at \u001b[32march/x86/kernel/process_32.c\u001b[m:159\r\n159\t{\r\n"] +[287.026396, "o", "(gdb) "] +[289.067669, "o", "#"] +[289.21566, "o", " "] +[289.407583, "o", "n"] +[289.463508, "o", "o"] +[289.543951, "o", "w"] +[289.72241, "o", " "] +[289.894812, "o", "l"] +[290.019586, "o", "e"] +[290.175723, "o", "t"] +[290.42348, "o", "s"] +[290.636596, "o", " "] +[291.733293, "o", "t"] +[291.80722, "o", "a"] +[291.931757, "o", "k"] +[292.036902, "o", "e"] +[292.123167, "o", " "] +[292.211687, "o", "a"] +[292.316232, "o", " "] +[292.480027, "o", "l"] +[292.660474, "o", "o"] +[292.811518, "o", "o"] +[292.919126, "o", "k"] +[293.143171, "o", " "] +[293.27092, "o", "a"] +[293.503276, "o", "t"] +[293.610102, "o", " "] +[293.723124, "o", "t"] +[293.867511, "o", "h"] +[293.950794, "o", "e"] +[294.092621, "o", " "] +[294.354438, "o", "b"] +[294.80766, "o", "a"] +[294.983003, "o", "c"] +[295.43947, "o", "k"] +[295.612526, "o", "t"] +[295.771893, "o", "r"] +[295.860273, "o", "a"] +[296.024455, "o", "c"] +[296.080174, "o", "e"] +[296.207233, "o", " "] +[296.260988, "o", "a"] +[296.491858, "o", "g"] +[296.557449, "o", "a"] +[296.659441, "o", "i"] +[296.727329, "o", "n"] +[297.063689, "o", "\r\n(gdb) "] +[297.45931, "o", "b"] +[297.535189, "o", "t"] +[297.919758, "o", "\r\n"] +[297.920155, "o", "#0 \u001b[33m__switch_to\u001b[m (\u001b[36mprev_p\u001b[m=0xc17d02c0 <init_task>, \u001b[36mnext_p\u001b[m=0xc2530040)\u001b[m\r\n \u001b[m at \u001b[32march/x86/kernel/process_32.c\u001b[m:159\r\n"] +[297.920545, "o", "#1 \u001b[34m0xc15d8277\u001b[m in \u001b[33mcontext_switch\u001b[m (\u001b[36mrf\u001b[m=0xc253ba3c, \u001b[36mnext\u001b[m=<optimized out>, \u001b[m\r\n"] +[297.920652, "o", " \u001b[m\u001b[36mprev\u001b[m=0xc2530040, \u001b[36mrq\u001b[m=0xcfdcb700) at \u001b[32mkernel/sched/core.c\u001b[m:3779\r\n"] +[297.920965, "o", "#2 \u001b[33m__schedule\u001b[m (\u001b[36mpreempt\u001b[m=<optimized out>, \u001b[36mpreempt@entry\u001b[m=false)\u001b[m\r\n \u001b[m at \u001b[32mkernel/sched/core.c\u001b[m:4528\r\n#3 \u001b[34m0xc15d86ce\u001b[m in \u001b[33mschedule\u001b[m () at \u001b[32mkernel/sched/core.c\u001b[m:4606\r\n"] +[297.927061, "o", "#4 \u001b[34m0xc15ddb66\u001b[m in \u001b[33mschedule_hrtimeout_range_clock\u001b[m (\u001b[36mexpires\u001b[m=<optimized out>, \u001b[m\r\n"] +[297.927149, "o", " \u001b[m\u001b[36mdelta\u001b[m=<optimized out>, \u001b[36mmode\u001b[m=HRTIMER_MODE_ABS, \u001b[36mclock_id\u001b[m=1)\u001b[m\r\n \u001b[m at \u001b[32mkernel/time/hrtimer.c\u001b[m:2139\r\n"] +[297.935662, "o", "#5 \u001b[34m0xc15ddc3b\u001b[m in \u001b[33mschedule_hrtimeout_range\u001b[m (\u001b[36mexpires=expires@entry\u001b[m=0xc253bb7c, \u001b[m\r\n \u001b[m\u001b[36mdelta\u001b[m=<optimized out>, \u001b[36mmode=mode@entry\u001b[m=HRTIMER_MODE_ABS)\u001b[m\r\n \u001b[m at \u001b[32mkernel/time/hrtimer.c\u001b[m:2184\r\n"] +[297.936228, "o", "#6 \u001b[34m0xc11c037f\u001b[m in \u001b[33mpoll_schedule_timeout\u001b[m (\u001b[36mpwq=pwq@entry\u001b[m=0xc253bb84, \u001b[m\r\n"] +[297.936671, "o", " \u001b[m\u001b[36mexpires=expires@entry\u001b[m=0xc253bb7c, \u001b[36mslack=slack@entry\u001b[m=4999986, \u001b[36mstate\u001b[m=1)\u001b[m\r\n"] +[297.936825, "o", " \u001b[m at \u001b[32mfs/select.c\u001b[m:243\r\n"] +[297.937767, "o", "#7 \u001b[34m0xc11c0baf\u001b[m in \u001b[33mdo_select\u001b[m (\u001b[36mn\u001b[m=<optimized out>, \u001b[36mn@entry\u001b[m=11, \u001b[m\r\n"] +[297.938173, "o", " \u001b[m\u001b[36mfds=fds@entry\u001b[m=0xc253be20, \u001b[36mend_time=end_time@entry\u001b[m=0xc253bf70)\u001b[m\r\n \u001b[m at \u001b[32mfs/select.c\u001b[m:603\r\n"] +[297.938674, "o", "#8 \u001b[34m0xc11c1985\u001b[m in \u001b[33mcore_sys_select\u001b[m (\u001b[36mn\u001b[m=<optimized out>, \u001b[36mn@entry\u001b[m=11, \u001b[m\r\n"] +[297.939277, "o", " \u001b[m\u001b[36minp=inp@entry\u001b[m=0xbf984f00, \u001b[36moutp=outp@entry\u001b[m=0x0, \u001b[36mexp\u001b[m=<optimized out>, \u001b[m\r\n"] +[297.939469, "o", " \u001b[m\u001b[36mexp@entry\u001b[m=0x0, \u001b[36mend_time\u001b[m=<optimized out>) at \u001b[32mfs/select.c\u001b[m:677\r\n"] +[297.940066, "o", "#9 \u001b[34m0xc11c1f64\u001b[m in \u001b[33mkern_select\u001b[m (\u001b[36mn\u001b[m=11, \u001b[36minp\u001b[m=0xbf984f00, \u001b[36moutp\u001b[m=0x0, \u001b[m\r\n"] +[297.94015, "o", "\u001b[m--Type <RET> for more, q to quit, c to continue without paging--"] +[299.775688, "o", "\r\n"] +[299.776122, "o", " \u001b[m\u001b[36mexp=exp@entry\u001b[m=0x0, \u001b[36mtvp\u001b[m=0xbf984df0) at \u001b[32mfs/select.c\u001b[m:718\r\n#10 \u001b[34m0xc11c1fe1\u001b[m in \u001b[33m__do_sys_select\u001b[m (\u001b[36mtvp\u001b[m=<optimized out>, \u001b[36mexp\u001b[m=<optimized out>, \u001b[m\r\n \u001b[m\u001b[36moutp\u001b[m=<optimized out>, \u001b[36minp\u001b[m=<optimized out>, \u001b[36mn\u001b[m=<optimized out>)\u001b[m\r\n \u001b[m at \u001b[32mfs/select.c\u001b[m:725\r\n"] +[299.77624, "o", "#11 \u001b[33m__se_sys_select\u001b[m (\u001b[36mtvp\u001b[m=<optimized out>, \u001b[36mexp\u001b[m=<optimized out>, \u001b[m\r\n \u001b[m\u001b[36moutp\u001b[m=<optimized out>, \u001b[36minp\u001b[m=<optimized out>, \u001b[36mn\u001b[m=<optimized out>)\u001b[m\r\n \u001b[m at \u001b[32mfs/select.c\u001b[m:722\r\n"] +[299.780969, "o", "#12 \u001b[33m__ia32_sys_select\u001b[m (\u001b[36mregs\u001b[m=<optimized out>) at \u001b[32mfs/select.c\u001b[m:722\r\n"] +[299.781337, "o", "#13 \u001b[34m0xc15d29cc\u001b[m in \u001b[33mdo_syscall_32_irqs_on\u001b[m (\u001b[36mnr\u001b[m=<optimized out>, \u001b[36mregs\u001b[m=0xc253bfb4)\u001b[m\r\n \u001b[m at \u001b[32march/x86/entry/common.c\u001b[m:77\r\n"] +[299.782024, "o", "#14 \u001b[33mdo_int80_syscall_32\u001b[m (\u001b[36mregs\u001b[m=0xc253bfb4) at \u001b[32march/x86/entry/common.c\u001b[m:94\r\n#15 \u001b[34m0xc15dfaeb\u001b[m in \u001b[33mentry_INT80_32\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:1059\r\n"] +[299.782699, "o", "#16 \u001b[34m0x0000000b\u001b[m in \u001b[33m??\u001b[m ()\r\n"] +[299.783203, "o", "#17 \u001b[34m0xbf984f00\u001b[m in \u001b[33m??\u001b[m ()\r\nBacktrace stopped: previous frame inner to this frame (corrupt stack?)\r\n(gdb) "] +[303.942905, "o", "#"] +[304.103437, "o", " "] +[304.274144, "o", "o"] +[304.358619, "o", "k"] +[304.659941, "o", ","] +[304.766807, "o", " "] +[305.28809, "o", "t"] +[305.375297, "o", "h"] +[305.431933, "o", "i"] +[305.540524, "o", "s"] +[305.655296, "o", " "] +[305.901221, "o", "l"] +[306.115461, "o", "o"] +[306.246553, "o", "o"] +[306.32009, "o", "k"] +[306.460058, "o", "s"] +[306.542589, "o", " "] +[306.694869, "o", "l"] +[306.907465, "o", "i"] +[307.075817, "o", "k"] +[307.179414, "o", "e"] +[307.295136, "o", " "] +[307.54844, "o", "t"] +[307.663017, "o", "h"] +[307.815168, "o", "e"] +[308.156909, "o", " "] +[308.39174, "o", "i"] +[308.532433, "o", "n"] +[308.595757, "o", "i"] +[310.686866, "o", "t"] +[310.8524, "o", " "] +[310.953083, "o", "t"] +[311.220312, "o", "h"] +[311.340814, "o", "r"] +[311.470856, "o", "e"] +[311.548828, "o", "a"] +[311.734896, "o", "d"] +[313.767614, "o", "\r\n"] +[313.767976, "o", "(gdb) "] +[316.999241, "o", "#"] +[317.296435, "o", " "] +[317.548667, "o", "s"] +[317.607326, "o", "o"] +[317.763134, "o", " "] +[317.887136, "o", "t"] +[317.999336, "o", "h"] +[318.095442, "o", "e"] +[318.188349, "o", " "] +[318.387557, "o", "c"] +[318.475079, "o", "o"] +[318.700291, "o", "n"] +[318.776111, "o", "t"] +[318.855308, "o", "e"] +[319.046835, "o", "x"] +[319.271115, "o", "t"] +[319.381068, "o", " "] +[319.461433, "o", "s"] +[319.631028, "o", "w"] +[319.748625, "o", "i"] +[319.846916, "o", "t"] +[320.079731, "o", "c"] +[320.134923, "o", "h"] +[320.268, "o", " "] +[320.830957, "o", "h"] +[320.99934, "o", "a"] +[321.10033, "o", "s"] +[322.903464, "o", "\b\u001b[K"] +[323.407499, "o", "\b\u001b[K"] +[323.451112, "o", "\b\u001b[K"] +[323.482209, "o", "\b\u001b[K"] +[323.513329, "o", "\b\u001b[K"] +[326.052876, "o", "h"] +[326.718835, "o", " "] +[326.942968, "o", "0"] +[327.283417, "o", " "] +[327.524209, "o", "\b\u001b[K"] +[327.654149, "o", "\b\u001b[K"] +[328.142643, "o", "-"] +[328.332367, "o", " "] +[330.483798, "o", "o"] +[330.650327, "o", "r"] +[330.732245, "o", " "] +[330.873854, "o", "p"] +[330.918697, "o", "a"] +[331.030843, "o", "r"] +[331.223103, "o", "t"] +[331.335218, "o", " "] +[331.471149, "o", "o"] +[331.56318, "o", "f"] +[331.699593, "o", " "] +[332.264753, "o", "i"] +[332.407088, "o", "t"] +[332.812649, "o", ","] +[332.97567, "o", " "] +[333.070572, "o", "t"] +[333.252959, "o", "h"] +[333.375206, "o", "a"] +[333.596096, "o", "t"] +[333.942887, "o", " "] +[334.676468, "o", "k"] +[334.807218, "o", "e"] +[334.839089, "o", "r"] +[335.599008, "o", "\b\u001b[K"] +[336.056624, "o", "\b\u001b[K"] +[336.200204, "o", "\b\u001b[K"] +[337.431057, "o", "k"] +[337.554329, "o", "e"] +[337.579172, "o", "r"] +[337.725617, "o", "n"] +[338.559416, "o", "e"] +[338.622963, "o", "l"] +[338.726658, "o", " "] +[338.868311, "o", "s"] +[339.014698, "o", "t"] +[339.079695, "o", "a"] +[339.31094, "o", "c"] +[339.413228, "o", "k"] +[339.526949, "o", " "] +[340.127059, "o", "s"] +[340.291598, "o", "w"] +[340.402142, "o", "i"] +[340.49965, "o", "t"] +[340.729408, "o", "c"] +[340.783126, "o", "h"] +[341.207083, "o", ","] +[341.469127, "o", " "] +[342.923481, "o", "\b\u001b[K"] +[343.071348, "o", "\b\u001b[K"] +[343.39639, "o", " "] +[344.339672, "o", "i"] +[344.620158, "o", "s"] +[344.74322, "o", " "] +[344.874119, "o", "d"] +[344.950506, "o", "o"] +[345.047877, "o", "n"] +[345.113522, "o", "e"] +[345.694122, "o", "\r\n"] +[345.694186, "o", "(gdb) "] +[349.573599, "o", "quit\r\n"] +[349.574221, "o", "A debugging session is active.\r\n\r\n\tInferior 1 [process 1] will be detached.\r\n\r\nQuit anyway? (y or n) "] +[350.532606, "o", "y"] +[350.638505, "o", "\r\nDetaching from program: /linux/vmlinux, process 1\r\n"] +[350.639382, "o", "Ending remote debugging.\r\n[Inferior 1 (process 1) detached]\r\n"] +[350.646756, "o", "$ "] +[352.121258, "o", "\r\n"] diff --git a/refs/pull/405/merge/_images/ditaa-019489e686a2f60f1594e37458cfcb10320eae0f.ditaa b/refs/pull/405/merge/_images/ditaa-019489e686a2f60f1594e37458cfcb10320eae0f.ditaa new file mode 100644 index 00000000..30800dd9 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-019489e686a2f60f1594e37458cfcb10320eae0f.ditaa @@ -0,0 +1,17 @@ + CPU0 + +------------+ task_struct + | ... | +--------> +-----------------------+ + +------------- | | Thread Group ID (PID) | ++--| FS | | +-----------------------+ +| +------------- | | Thread ID (TID) | +| | ... | | +-----------------------+ +| +------------+ | | ... | +| | +-----------------------+ +| Per CPU variables | | Opened files | ++->+-----------------------+ | +-----------------------+ + | ... | | | Address Space | + +-----------------------+ | +-----------------------+ + | current_task |------+ | ... | + +-----------------------+ +-----------------------+ + | ... | + +-----------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-019489e686a2f60f1594e37458cfcb10320eae0f.png b/refs/pull/405/merge/_images/ditaa-019489e686a2f60f1594e37458cfcb10320eae0f.png new file mode 100644 index 00000000..a85660c4 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-019489e686a2f60f1594e37458cfcb10320eae0f.png differ diff --git a/refs/pull/405/merge/_images/ditaa-08aff771b3ff7a5525df7b0c090e28c836502788.ditaa b/refs/pull/405/merge/_images/ditaa-08aff771b3ff7a5525df7b0c090e28c836502788.ditaa new file mode 100644 index 00000000..30f65b31 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-08aff771b3ff7a5525df7b0c090e28c836502788.ditaa @@ -0,0 +1,24 @@ + +-----------+ + | | + +------------------->| Memory |<------------------+ + | | | | + | +-----------+ | + | ^ | + | | | + v v v ++---------------+ +---------------+ +---------------+ +| | | | | | +| Processor A | | Processor B | | Processor C | +| | | | | | +| +-----------+ | | +-----------+ | | +-----------+ | +| | Process 1 | | | | Process 1 | | | | Process 1 | | +| +-----------+ | | +-----------+ | | +-----------+ | +| | | | | | +| +-----------+ | | +-----------+ | | +-----------+ | +| | Process 2 | | | | Process 2 | | | | Process 2 | | +| +-----------+ | | +-----------+ | | +-----------+ | +| | | | | | +| +-----------+ | | +-----------+ | | +-----------+ | +| | kernel | | | | kernel | | | | kernel | | +| +-----------+ | | +-----------+ | | +-----------+ | ++---------------+ +---------------+ +---------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-08aff771b3ff7a5525df7b0c090e28c836502788.png b/refs/pull/405/merge/_images/ditaa-08aff771b3ff7a5525df7b0c090e28c836502788.png new file mode 100644 index 00000000..3e8d5ccb Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-08aff771b3ff7a5525df7b0c090e28c836502788.png differ diff --git a/refs/pull/405/merge/_images/ditaa-0a96997f269a7a9cd0cdc9c9125f6e62e549be94.ditaa b/refs/pull/405/merge/_images/ditaa-0a96997f269a7a9cd0cdc9c9125f6e62e549be94.ditaa new file mode 100644 index 00000000..8be6db27 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-0a96997f269a7a9cd0cdc9c9125f6e62e549be94.ditaa @@ -0,0 +1,28 @@ ++---------------------------------+ +| Virtual Filesystem Switch | ++---------------------------------+ + ^ + | + v ++---------------------------------+ +| Device Mapper | ++---------------------------------+ + ^ + | + v ++---------------------------------+ +| Generic Block Layer | ++---------------------------------+ + ^ + | + v ++--------------------------------+ +| I/O scheduler | ++--------------------------------+ + ^ ^ + | | + v v ++--------------+ +--------------+ +| Block device | | Block device | +| driver | | driver | ++--------------+ +--------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-0a96997f269a7a9cd0cdc9c9125f6e62e549be94.png b/refs/pull/405/merge/_images/ditaa-0a96997f269a7a9cd0cdc9c9125f6e62e549be94.png new file mode 100644 index 00000000..c5d34dff Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-0a96997f269a7a9cd0cdc9c9125f6e62e549be94.png differ diff --git a/refs/pull/405/merge/_images/ditaa-0b8cde2be9bbd195ac9dcaeac978a8bbe0d3b805.ditaa b/refs/pull/405/merge/_images/ditaa-0b8cde2be9bbd195ac9dcaeac978a8bbe0d3b805.ditaa new file mode 100644 index 00000000..e0954cde --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-0b8cde2be9bbd195ac9dcaeac978a8bbe0d3b805.ditaa @@ -0,0 +1,27 @@ + preemption + +------------------------------+ + | | + V | + +------------+ +--------------+ +-------------+ + clone() | | schedule() | | exit() | | +-----------> | TASK_READY |-------------->| TASK_RUNNING |---------------->| TASK_DEAD | + | | | |--------+ | TASK_ZOMBIE | + +------------+ +--------------+ | | | + ^ | +-------------+ + | | + | | + | | + | signal +----------------------+ | + +-----------| | | + | | | wait_event() | + | wake_up() | TASK_INTERRUPTIBLE |<--------------+ + +-----------| | | + | | | | + | +----------------------+ | + | | + | | + | +----------------------+ | + | | | wait_event() | + | wake_up() | TASK_UNINTERRUPTIBLE |<--------------+ + +-----------| | + +----------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-0b8cde2be9bbd195ac9dcaeac978a8bbe0d3b805.png b/refs/pull/405/merge/_images/ditaa-0b8cde2be9bbd195ac9dcaeac978a8bbe0d3b805.png new file mode 100644 index 00000000..72a6d96d Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-0b8cde2be9bbd195ac9dcaeac978a8bbe0d3b805.png differ diff --git a/refs/pull/405/merge/_images/ditaa-0eda95a3f39dfac448fd07589656b123d3548328.ditaa b/refs/pull/405/merge/_images/ditaa-0eda95a3f39dfac448fd07589656b123d3548328.ditaa new file mode 100644 index 00000000..3c096d7f --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-0eda95a3f39dfac448fd07589656b123d3548328.ditaa @@ -0,0 +1,28 @@ + +------------------+ +------------+ + | Address space | | |-------------->+------------+ + | descriptor | +------------+ | | + +------------------+ | | Page +------------+ + | +------------+ tables | | + +------------------+--------------+ | ... | +------------+ + | | +------------+ | ... | + v v | |-------+ +------------+ + +------------+ +------------+ +------------+ | | | + | Area | | Area | | +------------+ + | descriptor | | descriptor | | + +------------+ +------------+ | + | | + +-------------+------------------+ +------>+------------+ + | | | | + v v +------------+ + +------------+ +------------+ | | + | Area | | Area | +------------+ + | descriptor | | descriptor | | ... | + +------------+ +------------+ +------------+ + | | | + +-----------+-----------+ +------------+ + | | + v v + +------------+ +------------+ + | Area | | Area | + | descriptor | | descriptor | + +------------+ +------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-0eda95a3f39dfac448fd07589656b123d3548328.png b/refs/pull/405/merge/_images/ditaa-0eda95a3f39dfac448fd07589656b123d3548328.png new file mode 100644 index 00000000..0405e091 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-0eda95a3f39dfac448fd07589656b123d3548328.png differ diff --git a/refs/pull/405/merge/_images/ditaa-29f54aaa1a85b819ff29cb7d101a4d646b3b0b06.ditaa b/refs/pull/405/merge/_images/ditaa-29f54aaa1a85b819ff29cb7d101a4d646b3b0b06.ditaa new file mode 100644 index 00000000..3188faa7 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-29f54aaa1a85b819ff29cb7d101a4d646b3b0b06.ditaa @@ -0,0 +1,23 @@ + file + descriptor + table + +------------+ +--------+ +--------+ +---------+ + | |------+--->| FILE |------->| dentry |------->| inode | + +------------+ | +--------+ +--------+ ^ +---------+ + +-> | |------+ dup | | type | + | +------------+ hard link | | perm | + | | ... | | | .... | + | +------------+ +--------+ +--------+ | +---------+ + | | |---------->| FILE |------->| dentry |---+ | + | +------------+ +--------+ +--------+ | + fd | + | + +------+ <-------------------+ + | data | + +------+ + +------+ +------+ + | data | | data | + +------+ +------+ + +------+ + | data | + +------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-29f54aaa1a85b819ff29cb7d101a4d646b3b0b06.png b/refs/pull/405/merge/_images/ditaa-29f54aaa1a85b819ff29cb7d101a4d646b3b0b06.png new file mode 100644 index 00000000..db471127 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-29f54aaa1a85b819ff29cb7d101a4d646b3b0b06.png differ diff --git a/refs/pull/405/merge/_images/ditaa-2cb0eb0056bb775d1446843d62241fd660662c96.ditaa b/refs/pull/405/merge/_images/ditaa-2cb0eb0056bb775d1446843d62241fd660662c96.ditaa new file mode 100644 index 00000000..2caaba65 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-2cb0eb0056bb775d1446843d62241fd660662c96.ditaa @@ -0,0 +1,24 @@ ++---------------------+ +---------------------+ +---------------------+ +| Guest OS | | Guest OS | | Guest OS | +| +---------------+ | | +---------------+ | | +---------------+ | +| | Guest Driver | | | | Guest Driver | | | | Guest Driver | | +| +---------------+ | | +---------------+ | | +---------------+ | +| | ^ | | | ^ | | | ^ | +| | | | | | | | | | | | ++----+-----------+----+ +----+-----------+----+ +----+-----------+----+ + | traped | | mapped | | mapped | interrupt + | access | | access | | access | posting + +---+-----------+----+ +---+-----------+-----+ +---+-----------+-----+ + | | VMM | | | | VMM | | | | VMM | | + | v | | | | | | | | | | + | +----------------+ | | | +---------+ | | | | | + | | Virtual Device | | | | | IRQ | | | | | | + | +----------------+ | | | | Mapping | | | | | | + | | ^ | | | +---------+ | | | | | + | | | | | | | | | | | | + +--+------------+----+ +---+-----------+-----+ +---+-----------+-----+ + | | | | | | + v | v | v | + +-----------------+ +-----------------+ +-----------------+ + | Physical Device | | Physical Device | | Physical Device | + +-----------------+ +-----------------+ +-----------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-2cb0eb0056bb775d1446843d62241fd660662c96.png b/refs/pull/405/merge/_images/ditaa-2cb0eb0056bb775d1446843d62241fd660662c96.png new file mode 100644 index 00000000..71a91ff0 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-2cb0eb0056bb775d1446843d62241fd660662c96.png differ diff --git a/refs/pull/405/merge/_images/ditaa-2e49ca6ac606dab4b2b53231cfbe85ff06312d36.ditaa b/refs/pull/405/merge/_images/ditaa-2e49ca6ac606dab4b2b53231cfbe85ff06312d36.ditaa new file mode 100644 index 00000000..9f22ad05 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-2e49ca6ac606dab4b2b53231cfbe85ff06312d36.ditaa @@ -0,0 +1,12 @@ + + ^ + ^ + | | | | + | Syscall | IRQi| | + User Mode | Exception (e.g. page fault) | | | + | | | | + +------------------------------------+-----+-----------------+ + | iret| | iret^ IRQj| iret| + | | | | | | +Kernel Mode v-------+ ^-------+ ^------+ v-----+ v-----+ + | | | | + IRQi| iret| IRQj| iret| + v------+ v------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-2e49ca6ac606dab4b2b53231cfbe85ff06312d36.png b/refs/pull/405/merge/_images/ditaa-2e49ca6ac606dab4b2b53231cfbe85ff06312d36.png new file mode 100644 index 00000000..896f09b9 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-2e49ca6ac606dab4b2b53231cfbe85ff06312d36.png differ diff --git a/refs/pull/405/merge/_images/ditaa-35f7597b35b83bb0025ac2a5f158c9eae23050c8.ditaa b/refs/pull/405/merge/_images/ditaa-35f7597b35b83bb0025ac2a5f158c9eae23050c8.ditaa new file mode 100644 index 00000000..a217d3f7 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-35f7597b35b83bb0025ac2a5f158c9eae23050c8.ditaa @@ -0,0 +1,31 @@ + counter is 2 + + Thread A Thread B + + * + | + | + +---------------------+ + | dec counter | counter is 1 + | cEEE | + +---------------------+ + | + | B preempts A + +-----------------------------------------------+ + | + v + +----------------------+ + counter is 0 | dec counter | + | if (!counter) | + resource is freed | free_resource(); | + | cEEE | + +----------------------+ + B finishes, A continues | + +-----------------------------------------------+ + | + v ++----------------------+ +| if (!counter) | +| free_resource(); | resource is freed +| cEEE | ++----------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-35f7597b35b83bb0025ac2a5f158c9eae23050c8.png b/refs/pull/405/merge/_images/ditaa-35f7597b35b83bb0025ac2a5f158c9eae23050c8.png new file mode 100644 index 00000000..81caa372 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-35f7597b35b83bb0025ac2a5f158c9eae23050c8.png differ diff --git a/refs/pull/405/merge/_images/ditaa-3901edd823cdc7a6f429ebc37cbc541e650abc96.ditaa b/refs/pull/405/merge/_images/ditaa-3901edd823cdc7a6f429ebc37cbc541e650abc96.ditaa new file mode 100644 index 00000000..1e6bbfb9 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-3901edd823cdc7a6f429ebc37cbc541e650abc96.ditaa @@ -0,0 +1,24 @@ ++---------------------+ +---------------------+ +| Guest OS | | Guest OS | +| +---------------+ | | +---------------+ | +| | Guest Driver | | | | Guest Driver | | +| +---------------+ | | +---------------+ | +| | ^ | | | ^ | +| | | | | | | | ++----+-----------+----+ +----+-----------+----+ + | traped | | mapped | + | access | | access | + +---+-----------+----+ +---+-----------+-----+ But how do we deal with DMA? + | | VMM | | | | VMM | | + | v | | | | | | + | +----------------+ | | | +---------+ | + | | Virtual Device | | | | | IRQ | | + | +----------------+ | | | | Mapping | | + | | ^ | | | +---------+ | + | | | | | | | | + +--+------------+----+ +---+-----------+-----+ + | | | | + v | v | + +-----------------+ +-----------------+ + | Physical Device | | Physical Device | + +-----------------+ +-----------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-3901edd823cdc7a6f429ebc37cbc541e650abc96.png b/refs/pull/405/merge/_images/ditaa-3901edd823cdc7a6f429ebc37cbc541e650abc96.png new file mode 100644 index 00000000..12b043a0 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-3901edd823cdc7a6f429ebc37cbc541e650abc96.png differ diff --git a/refs/pull/405/merge/_images/ditaa-3985c420def8f30934a72ea8c738a00ed629c298.ditaa b/refs/pull/405/merge/_images/ditaa-3985c420def8f30934a72ea8c738a00ed629c298.ditaa new file mode 100644 index 00000000..08d3fc02 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-3985c420def8f30934a72ea8c738a00ed629c298.ditaa @@ -0,0 +1,21 @@ +: : : : +| User space | Lowmem | Highmem | +| arbitrary mapping | linear mapping | arbitrary mapping | +| | | | ++----+----+--------------------+----+------+----+----+---------------+----+----+-----+----+----+ Virtual +|cEEE|cGRE|cEEE |cRED|cEEE |cAAA|cGRE| cAAA |cEEE|cGRE|cEEE |cRED|cEEE| memory +| | | | | | | | | | | | | | ++----+----+--------------------+----+------+----+----+---------------+----+----+-----+----+----+ + | | 3G | 3.896G | | 4G + | +-------+ | | | + | | | | | + |<----------------------------------+------+<-------------------------+ | + | | | + | |<-------------------------------------------+ + | | + v V ++----+----+---------------+--------------+----+------------------------------------------------+ Physical +|cAAA|cGRE| cAAA | cEEE |cRED| cEEE | memory +| | | | | | | ++----+----+---------------+--------------+----+------------------------------------------------+ + 896MB \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-3985c420def8f30934a72ea8c738a00ed629c298.png b/refs/pull/405/merge/_images/ditaa-3985c420def8f30934a72ea8c738a00ed629c298.png new file mode 100644 index 00000000..30196205 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-3985c420def8f30934a72ea8c738a00ed629c298.png differ diff --git a/refs/pull/405/merge/_images/ditaa-3dc899167df5e16a230c434cf5d6964cb5868482.ditaa b/refs/pull/405/merge/_images/ditaa-3dc899167df5e16a230c434cf5d6964cb5868482.ditaa new file mode 100644 index 00000000..8ad85a85 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-3dc899167df5e16a230c434cf5d6964cb5868482.ditaa @@ -0,0 +1,31 @@ ++-----+ +-----+ +-----+ +| App | | App | | App | ++-----+ +-----+ +-----+ + | | | User +=--|-------=--------|--------=-------|-------------------=- + | | | Kernel + v v v ++--------------------------------------------------------+ +| System Call Interface | ++--------------------------------------------------------+ + | | + v v + +-----+ +-----+ + | |<---------------------------->| | Kernel + | |<---+ +------->| | functions + +--+--+ | | +-----+ + | | | ^ + | | +-----+ | | + |+------+---->| |<---+ | + || | +-----+ | + || | | + vv | v + +--++-+ | +-----+ + | | +------------------------>| | Device + | |<---------------------------->| | Drivers + +--+--+ +--+--+ + | | + v v ++--------------------------------------------------------+ +| Hardware | ++--------------------------------------------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-3dc899167df5e16a230c434cf5d6964cb5868482.png b/refs/pull/405/merge/_images/ditaa-3dc899167df5e16a230c434cf5d6964cb5868482.png new file mode 100644 index 00000000..313367d3 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-3dc899167df5e16a230c434cf5d6964cb5868482.png differ diff --git a/refs/pull/405/merge/_images/ditaa-48374873962ca32ada36c14ab9a83b60f112a1e0.ditaa b/refs/pull/405/merge/_images/ditaa-48374873962ca32ada36c14ab9a83b60f112a1e0.ditaa new file mode 100644 index 00000000..fdbf04f5 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-48374873962ca32ada36c14ab9a83b60f112a1e0.ditaa @@ -0,0 +1,18 @@ ++---------------+ +--------------+ +---------------+ -\ +| Application 1 | | Application2 | ... | Application n | | ++---------------+ +--------------+ +---------------+ |> User space + | | | | + v v v -/ ++--------------------------------------------------------+ -\ +| System Call Interface | | ++--------------------------------------------------------+ | + | | | | + v v v |> Kernel space ++--------------------------------------------------------+ | +| Kernel | | ++--------------------------------------------------------+ | +| Device drivers | | ++--------------------------------------------------------+ -/ + | | | -\ + v v v |> Hardware + -/ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-48374873962ca32ada36c14ab9a83b60f112a1e0.png b/refs/pull/405/merge/_images/ditaa-48374873962ca32ada36c14ab9a83b60f112a1e0.png new file mode 100644 index 00000000..1dd08db8 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-48374873962ca32ada36c14ab9a83b60f112a1e0.png differ diff --git a/refs/pull/405/merge/_images/ditaa-4b5c1874d3924d9716f26d4893a3e4f313bf1c43.ditaa b/refs/pull/405/merge/_images/ditaa-4b5c1874d3924d9716f26d4893a3e4f313bf1c43.ditaa new file mode 100644 index 00000000..36a4bbe5 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-4b5c1874d3924d9716f26d4893a3e4f313bf1c43.ditaa @@ -0,0 +1,29 @@ + EPROCESS + +------------------+ ++->| KPROCESS | +| +------------------+ +| | Process ID (PID) | +| +------------------+ +| | ... | +| +------------------+ +| | Thread list |--------------+------------------------------------+ +| +------------------+ | | +| | Opened files | ETHREAD V ETHREAD V +| | +--------------+ | +| | | FILE | | +| | +--------------+ | +| | | ... | | +| | +--------------+ | +| +------------------+ +-----------------------+ +-----------------------+ +| | Address Space | | KTHREAD | | KTHREAD | +| + +--------------+ | +-----------------------+ +-----------------------+ +| | | ... | | | Thread ID (TID) | | Thread ID (TID) | +| | +--------------+ | +-----------------------+ +-----------------------+ +| +------------------+ | Thread Start Address | | Thread Start Address | +| +-----------------------+ +-----------------------+ +| | ... | ... | ... | +| +-----------------------+ +-----------------------+ +| | Process | | Process | +| +-----------------------+ +-----------------------+ +| | | ++---------------------------------------+------------------------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-4b5c1874d3924d9716f26d4893a3e4f313bf1c43.png b/refs/pull/405/merge/_images/ditaa-4b5c1874d3924d9716f26d4893a3e4f313bf1c43.png new file mode 100644 index 00000000..ff901ecf Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-4b5c1874d3924d9716f26d4893a3e4f313bf1c43.png differ diff --git a/refs/pull/405/merge/_images/ditaa-4d63c157487ff8291f2a6e93fe680ec38c1a3212.ditaa b/refs/pull/405/merge/_images/ditaa-4d63c157487ff8291f2a6e93fe680ec38c1a3212.ditaa new file mode 100644 index 00000000..028864ea --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-4d63c157487ff8291f2a6e93fe680ec38c1a3212.ditaa @@ -0,0 +1,15 @@ + +-------+ +-------+ + | CPU 0 | | CPU 1 | + +-------+ +-------+ + cache cache + +-------+ +-------+ +A | 1 | | 1 | A + +-------+ +-------+ +B | 2 | | 2 | B + +-------+ +-------+ + memory + +-----------------------------+ +A | 1 | + +-----------------------------+ +B | 2 | + +-----------------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-4d63c157487ff8291f2a6e93fe680ec38c1a3212.png b/refs/pull/405/merge/_images/ditaa-4d63c157487ff8291f2a6e93fe680ec38c1a3212.png new file mode 100644 index 00000000..965e1135 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-4d63c157487ff8291f2a6e93fe680ec38c1a3212.png differ diff --git a/refs/pull/405/merge/_images/ditaa-4e1f9758808dba9e61bc0e48faf4365d377f9d32.ditaa b/refs/pull/405/merge/_images/ditaa-4e1f9758808dba9e61bc0e48faf4365d377f9d32.ditaa new file mode 100644 index 00000000..c7527976 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-4e1f9758808dba9e61bc0e48faf4365d377f9d32.ditaa @@ -0,0 +1,33 @@ + + + Kernel space | User space + | + | ++-------------+ +-------------+ +---------------+ | +--------+ +| | | | | | | | | +| my_device | | my_driver | | my_bus_type | | | udev | +| | | | | | | | | ++-----+-------+ +------+------+ +-------+-------+ | +---+----+ + | | | | | + : : : | : + | | 1.my_register_driver() | 2.call_usermodehelper() | + | +-+------------------------->+-+------------------------->+-+ + | | | | | | | | + | | | | | | | | + | | | | | | | | + | 3.my_uevent() | | | | 4.call_usermodehelper() | | + +++-------------------------| |--------------------------> +------------------------->| | + | | | | | | | | | + | | | | 6.my_probe() | | 5.my_match() | | + | | | |<=------------------------| |<=------------------------| | + | | | | | | | | | + | | | | | | | | | + | | | | | | | | | + | | 7.my_remove() | | 8.my_uevent() | | 9.call_usermodehelper() | | +---------------------------+ + +-+------------------------>| |------------------------->| |------------------------->| | | | + | | | | | | | | | 1 - 2 -> add driver | + | | | | | | | | | 3 - 6 -> add device | + | | | | | | | | | 7 - 9 -> remove device | + | | | 10.my_unregister_driver()| | 11.call_usermodehelper() | | | 10 - 11 -> remove driver | + | +-+------------------------->+-+------------------------->+-+ | | + | | | | | +---------------------------+ + : : : | : \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-4e1f9758808dba9e61bc0e48faf4365d377f9d32.png b/refs/pull/405/merge/_images/ditaa-4e1f9758808dba9e61bc0e48faf4365d377f9d32.png new file mode 100644 index 00000000..9654c21a Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-4e1f9758808dba9e61bc0e48faf4365d377f9d32.png differ diff --git a/refs/pull/405/merge/_images/ditaa-5193a924360bebc83d2f81188cd0b0093ec01e6a.ditaa b/refs/pull/405/merge/_images/ditaa-5193a924360bebc83d2f81188cd0b0093ec01e6a.ditaa new file mode 100644 index 00000000..7336998f --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-5193a924360bebc83d2f81188cd0b0093ec01e6a.ditaa @@ -0,0 +1,25 @@ + (1) List Traversal (2) Removal + +-----------+ ++-----+ +-----+ +-----+ +-----+ | +-----+ | +-----+ +| | | | | | | | | | | | | | +| A |---->| B |---->| C | | A |--+ | B |--+->| C | +| | | | | | | | | | | | ++-----+ +-----+ +-----+ +-----+ +-----+ +-----+ + ^ ^ ^ ^ ^ ^ + | | | | | | + + + + + + + + (3) Quiescent cycle over (4) Reclamation + +-----------+ ++-----+ | +-----+ | +-----+ +-----+ +-----+ +| | | | | | | | | | | | +| A |--+ | B | +->| C | | A |---------------->| C | +| | | | | | | | | | ++-----+ +-----+ +-----+ +-----+ +-----+ + ^ ^ ^ ^ + | | | | \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-5193a924360bebc83d2f81188cd0b0093ec01e6a.png b/refs/pull/405/merge/_images/ditaa-5193a924360bebc83d2f81188cd0b0093ec01e6a.png new file mode 100644 index 00000000..bc2710ed Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-5193a924360bebc83d2f81188cd0b0093ec01e6a.png differ diff --git a/refs/pull/405/merge/_images/ditaa-528948c80a3fd78b89fb6f7bd69503a58b93a4ae.ditaa b/refs/pull/405/merge/_images/ditaa-528948c80a3fd78b89fb6f7bd69503a58b93a4ae.ditaa new file mode 100644 index 00000000..50611ba8 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-528948c80a3fd78b89fb6f7bd69503a58b93a4ae.ditaa @@ -0,0 +1,33 @@ ++----------------------+ +----------------------+ +| Application | | Application | ++----------------------+ +----------------------+ + | ^ | ^ + | send() | recv() | send() | recv() + V | V | ++----------------------+ +----------------------+ +| Socket | | Socket | ++----------------------+ +----------------------+ + | ^ | ^ + | | | | + v | v | ++---------------------------------------------------------+ +| Transport layer | ++---------------------------------------------------------+ + | ^ | ^ + | | | | + v | v | ++---------------------------------------------------------+ +| Network layer | ++---------------------------------------------------------+ + | ^ + | | + v | +/---------------------------------------------------------\ +| Routing | ----> Drop packet +\---------------------------------------------------------/ + ^ | ^ | + | RX | TX | RX | TX + | v | v ++-----------------------+ +-----------------------+ +| Network Device Driver | | Network Device Driver | ++-----------------------+ +-----------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-528948c80a3fd78b89fb6f7bd69503a58b93a4ae.png b/refs/pull/405/merge/_images/ditaa-528948c80a3fd78b89fb6f7bd69503a58b93a4ae.png new file mode 100644 index 00000000..d5d9422a Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-528948c80a3fd78b89fb6f7bd69503a58b93a4ae.png differ diff --git a/refs/pull/405/merge/_images/ditaa-58545831034f050660727be99cede213bc4a53c7.ditaa b/refs/pull/405/merge/_images/ditaa-58545831034f050660727be99cede213bc4a53c7.ditaa new file mode 100644 index 00000000..56396ba2 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-58545831034f050660727be99cede213bc4a53c7.ditaa @@ -0,0 +1,14 @@ ++-------------------------------------------+ +| Queued Spin Lock cEEE | +| | +| +---+ +---+ +---+ +---+ | +| | |----->| |----->| |----->| | | +| +---+ +---+ +---+ +---+ | +| ^ ^ ^ ^ | +| | | | | | ++-------------------------------------------+ + | | | | + CPU10 CPU17 CPU99 CPU0 + owns the spins on spins on spins on + lock private private private + lock lock lock \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-58545831034f050660727be99cede213bc4a53c7.png b/refs/pull/405/merge/_images/ditaa-58545831034f050660727be99cede213bc4a53c7.png new file mode 100644 index 00000000..af82ca04 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-58545831034f050660727be99cede213bc4a53c7.png differ diff --git a/refs/pull/405/merge/_images/ditaa-5b3c93f6e612d0cc0e4d4837d92a443627405262.ditaa b/refs/pull/405/merge/_images/ditaa-5b3c93f6e612d0cc0e4d4837d92a443627405262.ditaa new file mode 100644 index 00000000..59691093 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-5b3c93f6e612d0cc0e4d4837d92a443627405262.ditaa @@ -0,0 +1,28 @@ +arch/x86/include/asm/irq_vectors.h + +------+ + | 0 | 0..31, system traps and exceptions + +------+ + | 1 | + +------+ + | | + +------+ + | | + | | + | | + +------+ + | 32 | 32..127, device interrupts + +------+ + | | + | | + | | + +------+ + | 128 | int80 syscall interface + +------+ + | 129 | 129..255, other interrupts + +------+ + | | + | | + | | + +------+ + | 255 | + +------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-5b3c93f6e612d0cc0e4d4837d92a443627405262.png b/refs/pull/405/merge/_images/ditaa-5b3c93f6e612d0cc0e4d4837d92a443627405262.png new file mode 100644 index 00000000..d16255d3 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-5b3c93f6e612d0cc0e4d4837d92a443627405262.png differ diff --git a/refs/pull/405/merge/_images/ditaa-5cd4a8fa1ad97cff4bb1f64da13ce9ebfcfc4562.ditaa b/refs/pull/405/merge/_images/ditaa-5cd4a8fa1ad97cff4bb1f64da13ce9ebfcfc4562.ditaa new file mode 100644 index 00000000..f7c65c78 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-5cd4a8fa1ad97cff4bb1f64da13ce9ebfcfc4562.ditaa @@ -0,0 +1,11 @@ + 63 56 44 40 32 ++-------------------------------+---+---+---+---+---------------+---+---+---+---+---------------+-------------------------------+ +| | | D | | A | Segment | | D | | | | +| Base Address 31:24 | G | / | L | V | Limit | P | P | S | Type | Base Address 23:16 | +| | | B | | L | 19:16 | | L | | | | ++-------------------------------+---+---+---+---+---------------+---+---+---+---+---------------+-------------------------------+ +| | | +| Base address 15:0 | Segment Limit 15:0 | +| | | ++---------------------------------------------------------------+---------------------------------------------------------------+ + 31 15 0 \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-5cd4a8fa1ad97cff4bb1f64da13ce9ebfcfc4562.png b/refs/pull/405/merge/_images/ditaa-5cd4a8fa1ad97cff4bb1f64da13ce9ebfcfc4562.png new file mode 100644 index 00000000..521c75de Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-5cd4a8fa1ad97cff4bb1f64da13ce9ebfcfc4562.png differ diff --git a/refs/pull/405/merge/_images/ditaa-5db1739b80a83b12505e4ff749b5e69fccd01f1b.ditaa b/refs/pull/405/merge/_images/ditaa-5db1739b80a83b12505e4ff749b5e69fccd01f1b.ditaa new file mode 100644 index 00000000..0fb5e231 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-5db1739b80a83b12505e4ff749b5e69fccd01f1b.ditaa @@ -0,0 +1,13 @@ ++-----------+ NMI +| | +| |<----------+ +| | +| | +------------+ +| | | | IRQ0 +| | | |<------------+ device0 +| CPU | | | IRQ1 +| | INTR | PIC |<------------+ device1 +| |<----------+ | IRQN +| | | |<------------+ deviceN +| | | | ++-----------+ +------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-5db1739b80a83b12505e4ff749b5e69fccd01f1b.png b/refs/pull/405/merge/_images/ditaa-5db1739b80a83b12505e4ff749b5e69fccd01f1b.png new file mode 100644 index 00000000..f2a2fafc Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-5db1739b80a83b12505e4ff749b5e69fccd01f1b.png differ diff --git a/refs/pull/405/merge/_images/ditaa-5e4d73e3fcb24db9d1f8c16daddf98694c063fe6.ditaa b/refs/pull/405/merge/_images/ditaa-5e4d73e3fcb24db9d1f8c16daddf98694c063fe6.ditaa new file mode 100644 index 00000000..aa92baec --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-5e4d73e3fcb24db9d1f8c16daddf98694c063fe6.ditaa @@ -0,0 +1,29 @@ + Virtual Address ++------------+ +------------------+-----------------+------------------+-------------------+---------------+ +| CR3 | | GLOBAL DIR cEEE| UPPER DIR cDDD| MIDDLE DIR cCCC| TABLE cBBB| OFFSET cAAA | ++------------+ +------------------+-----------------+------------------+-------------------+---------------+ + | | | | | | + | | | | | | PAGE + | | | | | | /----------------------\ + | | | | | | | | + | | | | | | | | + | | +-----------+ | | PAGE GLOBAL | +----------------------+ + | | | | | DIRECTORY +-------->| Physical Address cAAA| + | | | | PAGE MIDDLE | /------------\ +----------------------+ + | +-----------------+ | | DIRECTORY | | | | | + | | | PAGE UPPER | /------------\ | | | | | + | | | DIRECTORY | | | | | | | | + | | PAGE GLOBAL | /------------\ | | | | | | | | + | | DIRECTORY | | | | +------------+ | | | | | + | | /------------\ | | | +--->| cCCC |---+ | +------------+ | | + | | | | | | | +------------+ | +--->| cBBB |---------->\----------------------/ + | | | | | | | | | | +------------+ + | | | | | +------------+ +----->\------------/ | | | + | | | | +---->| cDDD |---+ | | | + | | | | +------------+ +----->\------------/ + | | +------------+ | | + | +----->| cEEE |--+ | | + | +------------+ | | | + | | | +----->\------------/ + | | | + +--------->\------------/ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-5e4d73e3fcb24db9d1f8c16daddf98694c063fe6.png b/refs/pull/405/merge/_images/ditaa-5e4d73e3fcb24db9d1f8c16daddf98694c063fe6.png new file mode 100644 index 00000000..f3a36d4c Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-5e4d73e3fcb24db9d1f8c16daddf98694c063fe6.png differ diff --git a/refs/pull/405/merge/_images/ditaa-5e6f93e563d6e94c14fe3d483f988e0579b05b38.ditaa b/refs/pull/405/merge/_images/ditaa-5e6f93e563d6e94c14fe3d483f988e0579b05b38.ditaa new file mode 100644 index 00000000..3067ca4c --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-5e6f93e563d6e94c14fe3d483f988e0579b05b38.ditaa @@ -0,0 +1,15 @@ ++--------------+-----------------------+--------------+ +| cF88 | c8F8 | cF88 | +| Buffer | Allocated buffer | Buffer | +| Underflow | 0x5a5a5a5a | Overflow | +| Poison | 0x5a5a5a5a | Poison | +| | 0x5a5a5a5a | | ++--------------+-----------------------+--------------+ + ++--------------+-----------------------+--------------+ +| cF88 | c888 | cF88 | +| Buffer | Freed buffer | Buffer | +| Underflow | 0x6b6b6b6b | Overflow | +| Poison | 0x6b6b6b6b | Poison | +| | 0x6b6b6b6b | | ++--------------+-----------------------+--------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-5e6f93e563d6e94c14fe3d483f988e0579b05b38.png b/refs/pull/405/merge/_images/ditaa-5e6f93e563d6e94c14fe3d483f988e0579b05b38.png new file mode 100644 index 00000000..e586bd81 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-5e6f93e563d6e94c14fe3d483f988e0579b05b38.png differ diff --git a/refs/pull/405/merge/_images/ditaa-6d39f541805ae8197b413ec9c79116382abc4dbc.ditaa b/refs/pull/405/merge/_images/ditaa-6d39f541805ae8197b413ec9c79116382abc4dbc.ditaa new file mode 100644 index 00000000..0359fb34 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-6d39f541805ae8197b413ec9c79116382abc4dbc.ditaa @@ -0,0 +1,23 @@ + ^ ^ ^ + | stat | open | read + v v v ++------------------------------------------------------------+ +| | +| Virtual Filesystem Switch | +| | ++------------------------------------------------------------+ + ^ ^ + | | + v v + +-------------+ +-------------+ + | Filesystem | | Filesystem | + | driver | | driver | + +-------------+ +-------------+ + ^ ^ + | | + v v ++------------------------------------------------------------+ +| | +| Block I/O layer | +| | ++------------------------------------------------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-6d39f541805ae8197b413ec9c79116382abc4dbc.png b/refs/pull/405/merge/_images/ditaa-6d39f541805ae8197b413ec9c79116382abc4dbc.png new file mode 100644 index 00000000..c7703a6f Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-6d39f541805ae8197b413ec9c79116382abc4dbc.png differ diff --git a/refs/pull/405/merge/_images/ditaa-709c2e7a68bfcdcfe9c1938d6ef2a0c9b5627931.ditaa b/refs/pull/405/merge/_images/ditaa-709c2e7a68bfcdcfe9c1938d6ef2a0c9b5627931.ditaa new file mode 100644 index 00000000..fa1624c7 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-709c2e7a68bfcdcfe9c1938d6ef2a0c9b5627931.ditaa @@ -0,0 +1,29 @@ + Virtual Address ++------------+ +-------------------+-----------------------------+ +| CR3 | | DIRECTORY cEEE | OFFSET cDDD | ++------------+ +-------------------+-----------------------------+ + | | | + | | | PAGE + | | | /----------------------\ + | | | | | + | | | | | + | | | +----------------------+ + | | +--->| Physical Address cDDD| + | | +----------------------+ + | +-----------------+ | | + | | | | + | | | | + | | PAGE | | + | | DIRECTORY | | + | | /------------\ | | + | | | | +------------------>\----------------------/ + | | | | | + | | | | | + | | | | | + | | | | | + | | +------------+ | + | +----->| cEEE |-------------+ + | +------------+ + | | | + | | | + +---------->\------------/ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-709c2e7a68bfcdcfe9c1938d6ef2a0c9b5627931.png b/refs/pull/405/merge/_images/ditaa-709c2e7a68bfcdcfe9c1938d6ef2a0c9b5627931.png new file mode 100644 index 00000000..ce56a116 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-709c2e7a68bfcdcfe9c1938d6ef2a0c9b5627931.png differ diff --git a/refs/pull/405/merge/_images/ditaa-79e3734c36891f6c04d684aa5caa39f76915dbaf.ditaa b/refs/pull/405/merge/_images/ditaa-79e3734c36891f6c04d684aa5caa39f76915dbaf.ditaa new file mode 100644 index 00000000..d4720eff --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-79e3734c36891f6c04d684aa5caa39f76915dbaf.ditaa @@ -0,0 +1,17 @@ + Socket + File ++------+ Operations +| FILE | ----------------------> +-----------+ ++------+ | read | + | | struct socket_alloc +-----------+ + | | +---------------+ | write | + | +------->| struct socket | +-----------+ + | f_private| +-----------+ | | select | + | | | ... | | +-----------+ + | | +-----------+ | | ... | + | +---------------+ +-----------+ + +--------->| struct inode | + f_inode | +-----------+ | + | | ... | | + | +-----------+ | + +---------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-79e3734c36891f6c04d684aa5caa39f76915dbaf.png b/refs/pull/405/merge/_images/ditaa-79e3734c36891f6c04d684aa5caa39f76915dbaf.png new file mode 100644 index 00000000..995d3a1a Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-79e3734c36891f6c04d684aa5caa39f76915dbaf.png differ diff --git a/refs/pull/405/merge/_images/ditaa-7ee0f9bb5f5af586e043afd47cfbad0adcc34888.ditaa b/refs/pull/405/merge/_images/ditaa-7ee0f9bb5f5af586e043afd47cfbad0adcc34888.ditaa new file mode 100644 index 00000000..60a87752 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-7ee0f9bb5f5af586e043afd47cfbad0adcc34888.ditaa @@ -0,0 +1,16 @@ + +-------+ +-------+ + | CPU 0 | | CPU 1 | + +-------+ +-------+ + A <- A + B B <- A + B + + +-------+ +-------+ +A | 3 | | 1 | A + +-------+ +-------+ +B | 2 | | 3 | B + +-------+ +-------+ + write back caches + +-----------------------------+ +A | 1 | + +-----------------------------+ +B | 2 | + +-----------------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-7ee0f9bb5f5af586e043afd47cfbad0adcc34888.png b/refs/pull/405/merge/_images/ditaa-7ee0f9bb5f5af586e043afd47cfbad0adcc34888.png new file mode 100644 index 00000000..7f954da4 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-7ee0f9bb5f5af586e043afd47cfbad0adcc34888.png differ diff --git a/refs/pull/405/merge/_images/ditaa-85b69602726fa6143fc3ba0ffdb492454864aacf.ditaa b/refs/pull/405/merge/_images/ditaa-85b69602726fa6143fc3ba0ffdb492454864aacf.ditaa new file mode 100644 index 00000000..c88a9570 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-85b69602726fa6143fc3ba0ffdb492454864aacf.ditaa @@ -0,0 +1,29 @@ + w/o privilege transition w/ privilege transition + ++ +---------------------+ +---------------------+ +| | | | | +| | | OLD SS:ESP | OLD SS | NEW SS:ESP from TSS +| +---------------------+ +---------------------+ +| | | | | +| | OLD EFLAGS | | OLD ESP | +| +---------------------+ +---------------------+ +| | | | | +| | OLD CS | | OLD EFLAGS | +| +---------------------+ +---------------------+ +| | | | | +| | OLD EIP | | OLD CS | +| +---------------------+ +---------------------+ +| | | | | +| | (error code) | NEW SS:ESP | OLD EIP | +| +---------------------+ +---------------------+ +| | | | | +| | | | (error code) | NEW SS:ESP +| | | +---------------------+ +| | | | | +| | | | | +| | | | | +| | | | | +| | | | | +| | | | | +| | | | | +v +---------------------+ +---------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-85b69602726fa6143fc3ba0ffdb492454864aacf.png b/refs/pull/405/merge/_images/ditaa-85b69602726fa6143fc3ba0ffdb492454864aacf.png new file mode 100644 index 00000000..0634d8c9 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-85b69602726fa6143fc3ba0ffdb492454864aacf.png differ diff --git a/refs/pull/405/merge/_images/ditaa-8632e22c6d89bd18f97c9cef127444486b5077df.ditaa b/refs/pull/405/merge/_images/ditaa-8632e22c6d89bd18f97c9cef127444486b5077df.ditaa new file mode 100644 index 00000000..a0d8f88b --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-8632e22c6d89bd18f97c9cef127444486b5077df.ditaa @@ -0,0 +1,32 @@ + PGD PMD PT + +----------+ +----------+ +----------+ + | | | | | | Guest Physical Page + +----------+ +----------+ +----------+ +----------+ + | | | | | |----+ | | ++-----+ +----------+ +----------+ +----------+ | | | +| CR3 | | |----+ | |---+ | | | | | ++-----+ +----------+ | +----------+ | +----------+ +--->+----------+ + | | | | | | | | | + +---------> +----------+ +------>+----------+ +---->+----------+ + Write Protected Write Protected Write Protected + | + | +Guest (VM) | + | trap access + | +---------------------+------------------------------------------------------------------------------ + | + | check access, transform GPP to HPP + | + v + + Shadow PGD Shadow PMD Shadow PT + +----------+ +----------+ +----------+ + | | | | | | Host Physical Page + +----------+ +----------+ +----------+ +----------+ + | | | | | |----+ | | + +----------+ +----------+ +----------+ | | | + | |----+ | |---+ | | | | | + +----------+ | +----------+ | +----------+ +--->+----------+ + | | | | | | | | + +----------+ +------>+----------+ +---->+----------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-8632e22c6d89bd18f97c9cef127444486b5077df.png b/refs/pull/405/merge/_images/ditaa-8632e22c6d89bd18f97c9cef127444486b5077df.png new file mode 100644 index 00000000..8bcd5664 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-8632e22c6d89bd18f97c9cef127444486b5077df.png differ diff --git a/refs/pull/405/merge/_images/ditaa-8b00a68b494f72d54b5fad38c88f7265aadaaa0e.ditaa b/refs/pull/405/merge/_images/ditaa-8b00a68b494f72d54b5fad38c88f7265aadaaa0e.ditaa new file mode 100644 index 00000000..bfb4735f --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-8b00a68b494f72d54b5fad38c88f7265aadaaa0e.ditaa @@ -0,0 +1,28 @@ + Process + context + | + v +IRQ10 | irq10 handler +-----------------------------> +-------------+ + | +IRQ20 (lower priority) | +-----------------------------> pending v + | +IRQ5 (higher priority) | irq5 handler +-----------------------------> +-------->---------+ + | + v + | + +--------<---------+ + | + v + | + -------<-------+ + irq20 handler +Pending IRQ20 ------->-------+ + | + v + | + +--------------+ + | + v \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-8b00a68b494f72d54b5fad38c88f7265aadaaa0e.png b/refs/pull/405/merge/_images/ditaa-8b00a68b494f72d54b5fad38c88f7265aadaaa0e.png new file mode 100644 index 00000000..ace5807e Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-8b00a68b494f72d54b5fad38c88f7265aadaaa0e.png differ diff --git a/refs/pull/405/merge/_images/ditaa-8b59fc3f5245ffb5d7089dc80cf2e306c39a62d8.ditaa b/refs/pull/405/merge/_images/ditaa-8b59fc3f5245ffb5d7089dc80cf2e306c39a62d8.ditaa new file mode 100644 index 00000000..2ec3ee01 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-8b59fc3f5245ffb5d7089dc80cf2e306c39a62d8.ditaa @@ -0,0 +1,5 @@ ++--------------+--------+--------+---------+---------+ +| | | | | | +| Superblock | IMAP | DMAP | IZONE | DZONE | +| | | | | | ++--------------+--------+--------+---------+---------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-8b59fc3f5245ffb5d7089dc80cf2e306c39a62d8.png b/refs/pull/405/merge/_images/ditaa-8b59fc3f5245ffb5d7089dc80cf2e306c39a62d8.png new file mode 100644 index 00000000..64ad3b3b Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-8b59fc3f5245ffb5d7089dc80cf2e306c39a62d8.png differ diff --git a/refs/pull/405/merge/_images/ditaa-91073cb05a3f537eb54ab10745c307531e6795a0.ditaa b/refs/pull/405/merge/_images/ditaa-91073cb05a3f537eb54ab10745c307531e6795a0.ditaa new file mode 100644 index 00000000..7042e172 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-91073cb05a3f537eb54ab10745c307531e6795a0.ditaa @@ -0,0 +1,11 @@ + Head + ^ +---------------+ +skb_push | | | | skb_reserve + +---------------+ v + | Data | | skb_pull + ^ | | v +skb_trim | | Tail | + +---------------+ + | | | skb_put + +---------------+ v + End \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-91073cb05a3f537eb54ab10745c307531e6795a0.png b/refs/pull/405/merge/_images/ditaa-91073cb05a3f537eb54ab10745c307531e6795a0.png new file mode 100644 index 00000000..2631fc13 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-91073cb05a3f537eb54ab10745c307531e6795a0.png differ diff --git a/refs/pull/405/merge/_images/ditaa-91f08f7db4b54069e16694eab8d75c06400fc47b.ditaa b/refs/pull/405/merge/_images/ditaa-91f08f7db4b54069e16694eab8d75c06400fc47b.ditaa new file mode 100644 index 00000000..980f08fe --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-91f08f7db4b54069e16694eab8d75c06400fc47b.ditaa @@ -0,0 +1,11 @@ ++----+ +----+ +----+ +| VM | | VM | ... | VM | ++----+ +----+ +----+ + ++-------------------------+ +| Virtual Machine Monitor | ++-------------------------+ + ++-------------------------+ +| Hardware | ++-------------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-91f08f7db4b54069e16694eab8d75c06400fc47b.png b/refs/pull/405/merge/_images/ditaa-91f08f7db4b54069e16694eab8d75c06400fc47b.png new file mode 100644 index 00000000..2d3f9e8a Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-91f08f7db4b54069e16694eab8d75c06400fc47b.png differ diff --git a/refs/pull/405/merge/_images/ditaa-9d23d02ebdff6eeb6bec8044480f055de9852ecc.ditaa b/refs/pull/405/merge/_images/ditaa-9d23d02ebdff6eeb6bec8044480f055de9852ecc.ditaa new file mode 100644 index 00000000..dd860f92 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-9d23d02ebdff6eeb6bec8044480f055de9852ecc.ditaa @@ -0,0 +1,29 @@ + CPU0 CPU1 ++-------------+ +-------------+ +| | | | +| |local IRQs | |local IRQs +| +---------- | +---------- +| | | | +| local APIC | | local APIC | +| | LINT0, LINT1 | | LINT0, LINT1 +| +------------- | +------------- +| | | | ++-------+-----+ +------+------+ + | | + | | + | | ++-------+--------------------------------+------+ +| | +| Interrupt Controller Communication BUS | ++----------------------+------------------------+ + | + | + +--------+--------+ + | | + | I/O APIC | + | | + +--------+--------+ + | + | + | + External interrupts \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-9d23d02ebdff6eeb6bec8044480f055de9852ecc.png b/refs/pull/405/merge/_images/ditaa-9d23d02ebdff6eeb6bec8044480f055de9852ecc.png new file mode 100644 index 00000000..8b40a85e Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-9d23d02ebdff6eeb6bec8044480f055de9852ecc.png differ diff --git a/refs/pull/405/merge/_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.ditaa b/refs/pull/405/merge/_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.ditaa new file mode 100644 index 00000000..8930a0d5 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.ditaa @@ -0,0 +1,29 @@ ++---------------------------+ +| Berkeley Socket Interface | ++---------------------------+ + ++---------------------------+ +| Transport layer | ++-------------+-------------+ +| TCP | UDP | ++-------------+-------------+ + ++---------------------------+ +| Network layer | ++-----+---------+-----------+ +| IP | Routing | NetFilter | ++-----+---------+-----------+ + ++---------------------------+ +| Data link layer | ++-------+-------+-----------+ +| ETH | ARP | BRIDGING | ++-------+-------+-----------+ + ++---------------------------+ +| Queuing discipline | ++---------------------------+ + ++---------------------------+ +| Network device drivers | ++---------------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png b/refs/pull/405/merge/_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png new file mode 100644 index 00000000..2eb36ce1 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png differ diff --git a/refs/pull/405/merge/_images/ditaa-a5f399cb84561893770eb45ceeb827ce6d4a2336.ditaa b/refs/pull/405/merge/_images/ditaa-a5f399cb84561893770eb45ceeb827ce6d4a2336.ditaa new file mode 100644 index 00000000..8439d6f8 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-a5f399cb84561893770eb45ceeb827ce6d4a2336.ditaa @@ -0,0 +1,29 @@ + +------+ + | /sys | + +--+---+ + | + +----------------------------------------------------+-------------------------------------+-----------------------------------------+ + | | | | + v v v v + +-----+ +-------+ +---------+ +--------+ + | bus | | class | | devices | | module | + +--+--+ +---+---+ +----+----+ +---+----+ + | | | | + | | | +-------------+-----------------+ + | | | | | + v v v v v ++------------------------+ +-----------------------+ +-------------------------+ +----------------------+ +-------------------------+ +| mybus: struct bus_type | | myclass: struct class | | mybus0: struct device | | mybus: struct module | | mydriver: struct module | ++-------------+----------+ +----------+------------+ +-----------+-------------+ +----------------------+ +-------------------------+ + | | | + +--------+--------------+ v v + | | +-------------------------------+ +----------------------+ + v v | myclass0: struct class_device | | mydev: struct device | ++---------+ +---------+ +-------------------------------+ +----------------------+ +| devices | | drivers | ++---------+ +---+-----+ + | + v + +--------------------------------+ + | mydriver: struct device_driver | + +--------------------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-a5f399cb84561893770eb45ceeb827ce6d4a2336.png b/refs/pull/405/merge/_images/ditaa-a5f399cb84561893770eb45ceeb827ce6d4a2336.png new file mode 100644 index 00000000..134ffdc8 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-a5f399cb84561893770eb45ceeb827ce6d4a2336.png differ diff --git a/refs/pull/405/merge/_images/ditaa-a5f93e0d17ccdc2ba24828b620d7227f7fc75e33.ditaa b/refs/pull/405/merge/_images/ditaa-a5f93e0d17ccdc2ba24828b620d7227f7fc75e33.ditaa new file mode 100644 index 00000000..5dfed1ef --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-a5f93e0d17ccdc2ba24828b620d7227f7fc75e33.ditaa @@ -0,0 +1,17 @@ + +-------------------+ ^ +0xFFFFFFFF | | | + | | | Kernel space + | | | + +-------------------+ v +0xC0000000 | | ^ + | | | User space + | | | + | | | + | | | + | | | + | | | + | | | + | | | +0x00000000 +-------------------+ v + + 32bit Virtual Address Space \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-a5f93e0d17ccdc2ba24828b620d7227f7fc75e33.png b/refs/pull/405/merge/_images/ditaa-a5f93e0d17ccdc2ba24828b620d7227f7fc75e33.png new file mode 100644 index 00000000..ef11a8e0 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-a5f93e0d17ccdc2ba24828b620d7227f7fc75e33.png differ diff --git a/refs/pull/405/merge/_images/ditaa-ae895f3a8e26b92bf6c6ecbbd71e2c88912d5607.ditaa b/refs/pull/405/merge/_images/ditaa-ae895f3a8e26b92bf6c6ecbbd71e2c88912d5607.ditaa new file mode 100644 index 00000000..9097e4c8 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-ae895f3a8e26b92bf6c6ecbbd71e2c88912d5607.ditaa @@ -0,0 +1,27 @@ ++---------------+ +--------------+ +---------------+ +| Application 1 | | Application2 | ... | Application n | ++---------------+ +--------------+ +---------------+ + | | | + v v v ++--------------------------------+------------------------+ +| Kernel core & subsystems | Generic Drivers | ++--------------------------------+------------------------+ +| Generic Architecture Code | ++---------------------------------------------------------+ +| Architecture Specific Code | +| | +| +-----------+ +--------+ +---------+ +--------+ | +| | Bootstrap | | Memory | | Threads | | Timers | | +| +-----------+ +--------+ +---------+ +--------+ | +| +------+ +----------+ +------------------+ | +| | IRQs | | Syscalls | | Platform Drivers | | +| +------+ +----------+ +------------------+ | +| +------------------+ +---------+ +---------+ | +| | Platform Drivers | | machine | ... | machine | | +| +------------------+ +---------+ +---------+ | ++---------------------------------------------------------+ + | | | + v v v ++--------------------------------------------------------+ +| Hardware | ++--------------------------------------------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-ae895f3a8e26b92bf6c6ecbbd71e2c88912d5607.png b/refs/pull/405/merge/_images/ditaa-ae895f3a8e26b92bf6c6ecbbd71e2c88912d5607.png new file mode 100644 index 00000000..cfb0ecee Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-ae895f3a8e26b92bf6c6ecbbd71e2c88912d5607.png differ diff --git a/refs/pull/405/merge/_images/ditaa-afa57a07e21b1b842554278abe30fea575278452.ditaa b/refs/pull/405/merge/_images/ditaa-afa57a07e21b1b842554278abe30fea575278452.ditaa new file mode 100644 index 00000000..54d47f9f --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-afa57a07e21b1b842554278abe30fea575278452.ditaa @@ -0,0 +1,26 @@ + ^ ^ ^ + | stat | open | read + v v v ++------------------------------------------------------------+ +| Virtual Filesystem Switch | +| | +| | +| /-------\ /--------\ /--------\ | +| | inode |<----------+ dentry |<----------+ FILE | | +| \---+---/ \----+---/ \---+----/ | +| | | | | +| | | | | +| v v v | +| +-------+ +--------+ +-------+ | +| | inode | | dentry | | page | | +| | cache | | cache | | cache | | +| +-------+ +--------+ +-------+ | +| | ++------------------------------------------------------------+ + ^ ^ + | | + v v + +-------------+ +-------------+ + | Filesystem | | Filesystem | + | driver | | driver | + +-------------+ +-------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-afa57a07e21b1b842554278abe30fea575278452.png b/refs/pull/405/merge/_images/ditaa-afa57a07e21b1b842554278abe30fea575278452.png new file mode 100644 index 00000000..de68d467 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-afa57a07e21b1b842554278abe30fea575278452.png differ diff --git a/refs/pull/405/merge/_images/ditaa-b2023fce22479e20bbe08fd76eed87e9a0527688.ditaa b/refs/pull/405/merge/_images/ditaa-b2023fce22479e20bbe08fd76eed87e9a0527688.ditaa new file mode 100644 index 00000000..8255133b --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-b2023fce22479e20bbe08fd76eed87e9a0527688.ditaa @@ -0,0 +1,22 @@ + Interrupt Descriptor + +----------------------------------------------+ + | | + | +------------------+ +--------+ +------+ | + | | segment selector | | offset| | PL | | + | +----+-------------+ +---+----+ +------+ | + | | | | + +----------------------------------------------+ + | | + | | ++-------------+ +----------------------------> +---------------+ +| ^ | ISR address | +| Segment Descriptor | +---------------+ +| +----------------------------------------------+ | +| | | | ++---->| +------------------+ +--------+ +------+ | | + | | base | | limit | | PL | | | + | +---------+--------+ +--------+ +------+ | | + | | | | + +----------------------------------------------+ | + | | + +--------------------------------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-b2023fce22479e20bbe08fd76eed87e9a0527688.png b/refs/pull/405/merge/_images/ditaa-b2023fce22479e20bbe08fd76eed87e9a0527688.png new file mode 100644 index 00000000..59077fd3 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-b2023fce22479e20bbe08fd76eed87e9a0527688.png differ diff --git a/refs/pull/405/merge/_images/ditaa-b26d802c286bda6c559b4dcfa8a7fb27f840463e.ditaa b/refs/pull/405/merge/_images/ditaa-b26d802c286bda6c559b4dcfa8a7fb27f840463e.ditaa new file mode 100644 index 00000000..7f01d04e --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-b26d802c286bda6c559b4dcfa8a7fb27f840463e.ditaa @@ -0,0 +1,23 @@ ++-------+ +-------+ +-------+ +| CPU 0 |<---------------+ | CPU 1 | Invalidate | CPU 0 | +| cache |<-------------+ | | cache |<---+ +---------->| cache | ++-------+ Invalidate | | +-------+ | | +-------+ + | | | | + | | +----------------------------+ +spin_lock(&lock); | | | | + | | READ lock | | + | +---- WRITE lock ---+ | + | | + | READ lock | + +-------------------------------- WRITE lock ----+ + + ... ... ... +READ data READ lock READ lock + | | | + | | | + | | | + +------------------------------+-------------------------+ + | + v + + cache miss \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-b26d802c286bda6c559b4dcfa8a7fb27f840463e.png b/refs/pull/405/merge/_images/ditaa-b26d802c286bda6c559b4dcfa8a7fb27f840463e.png new file mode 100644 index 00000000..24734d5b Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-b26d802c286bda6c559b4dcfa8a7fb27f840463e.png differ diff --git a/refs/pull/405/merge/_images/ditaa-b9ffae65be16d30be11b5eca188a7a143b1b8227.ditaa b/refs/pull/405/merge/_images/ditaa-b9ffae65be16d30be11b5eca188a7a143b1b8227.ditaa new file mode 100644 index 00000000..dc13756f --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-b9ffae65be16d30be11b5eca188a7a143b1b8227.ditaa @@ -0,0 +1,43 @@ ++---------------+ +--------------+ +---------------+ +| Application 1 | | Application2 | ... | Application n | ++---------------+ +--------------+ +---------------+ + | | | + v v v ++--------------------------------------------------------+ +| Kernel | +| | +| +----------------------+ +-------------------+ | +| | Process Management | | Memory Management | | +| +----------------------+ +-------------------+ | +| | +| +------------+ +------------+ +------------+ | +| | Block I/O | | VFS | | Networking | | +| +------------+ +------------+ +------------+ | +| | +| +------------+ +------------+ +------------+ | +| | IPC | | Security | | Crypto | | +| +------------+ +------------+ +------------+ | +| | +| +------------+ +------------+ +------------+ | +| | DRM | | ALSA | | USB | | +| +------------+ +------------+ +------------+ | +| ... | ++--------------------------------------+-----------------+ +| Device drivers | arch | +| | | +| +----+ +-----+ +--------+ +----+ | +----------+ | +| |char| |block| |ethernet| |wifi| | | machine 1| | +| +----+ +-----+ +--------+ +----+ | +----------+ | +| +----------+ +-----+ +----+ +---+ | +----------+ | +| |filesystem| |input| |iio | |usb| | | machine 2| | +| +----------+ +-----+ +----+ +---+ | +----------+ | +| +-----------+ +----------+ +---+ | | +| |framebuffer| | platform | |drm| | ... | +| +-----------+ +----------+ +---+ | | ++-------------------------+----+-------+-----------------+ + | | | + v v v + ++--------------------------------------------------------+ +| Hardware | ++--------------------------------------------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-b9ffae65be16d30be11b5eca188a7a143b1b8227.png b/refs/pull/405/merge/_images/ditaa-b9ffae65be16d30be11b5eca188a7a143b1b8227.png new file mode 100644 index 00000000..2cea5126 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-b9ffae65be16d30be11b5eca188a7a143b1b8227.png differ diff --git a/refs/pull/405/merge/_images/ditaa-bb69666d75b9670e542682753fb8cc9b77ff8894.ditaa b/refs/pull/405/merge/_images/ditaa-bb69666d75b9670e542682753fb8cc9b77ff8894.ditaa new file mode 100644 index 00000000..b1e26eef --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-bb69666d75b9670e542682753fb8cc9b77ff8894.ditaa @@ -0,0 +1,24 @@ ++---------------------+ +| Guest OS | +| +---------------+ | +| | Guest Driver | | +| +---------------+ | +| | ^ | +| | | | ++----+-----------+----+ + | trap | + | access | + +---+-----------+----+ + | | VMM | | + | v | | + | +----------------+ | + | | Virtual Device | | + | +----------------+ | + | | ^ | + | | | | + +--+------------+----+ + | | + v | + +-----------------+ + | Physical Device | + +-----------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-bb69666d75b9670e542682753fb8cc9b77ff8894.png b/refs/pull/405/merge/_images/ditaa-bb69666d75b9670e542682753fb8cc9b77ff8894.png new file mode 100644 index 00000000..86118acb Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-bb69666d75b9670e542682753fb8cc9b77ff8894.png differ diff --git a/refs/pull/405/merge/_images/ditaa-bb8455a43088bf800eece11869f6ff857574605d.ditaa b/refs/pull/405/merge/_images/ditaa-bb8455a43088bf800eece11869f6ff857574605d.ditaa new file mode 100644 index 00000000..f57b13cd --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-bb8455a43088bf800eece11869f6ff857574605d.ditaa @@ -0,0 +1,12 @@ ++--------+ 8MB +-----------+ 4KB +-----------+ +-----------+ 4KB +------------+-----------+------------+ +| | | | | | | | | Persistent | Temporary | Fix-mapped | +| Lowmem | <-----> | VMAP area | <-----> | VMAP area | ... | VMAP area | <-----> | Kernel | Kernel | linear | +| | | | | | | | | Mappings | Mappings | addresses | ++--------+ +-----------+ +-----------+ +-----------+ +------------+-----------+------------+ + : : + | 128MB | + |<------------------------------------------------------------------------------------------------------------->| + | | + | | + VMALLOC_START 4GB + (896MB) \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-bb8455a43088bf800eece11869f6ff857574605d.png b/refs/pull/405/merge/_images/ditaa-bb8455a43088bf800eece11869f6ff857574605d.png new file mode 100644 index 00000000..d7318db0 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-bb8455a43088bf800eece11869f6ff857574605d.png differ diff --git a/refs/pull/405/merge/_images/ditaa-bc662dab7bb3d9ba3a37efbf69b82c513dcaadd4.ditaa b/refs/pull/405/merge/_images/ditaa-bc662dab7bb3d9ba3a37efbf69b82c513dcaadd4.ditaa new file mode 100644 index 00000000..46712923 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-bc662dab7bb3d9ba3a37efbf69b82c513dcaadd4.ditaa @@ -0,0 +1,18 @@ + +--------+ +-------+ data +--------+ + | dentry |-------------->| inode |--------+ | dentry | + +--------+ +-------+ | +--------+ + | ...... | | ..... | | | ...... | + +--------+ +-------+ dir | +--------+ + | dentry | | inode |--------|--+ | dentry | + +--------+ +-------+ | | +--------+ + ^ | | ^ + | | | | + | | | +--------+ + | V v | + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +blocks | | | | | | | | | | | | | | | | | | + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | | + | +------------+ | ++++++++++++ + +--->| superblock | +--->|||||||||||| block management + +------------+ ++++++++++++ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-bc662dab7bb3d9ba3a37efbf69b82c513dcaadd4.png b/refs/pull/405/merge/_images/ditaa-bc662dab7bb3d9ba3a37efbf69b82c513dcaadd4.png new file mode 100644 index 00000000..44ba4e18 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-bc662dab7bb3d9ba3a37efbf69b82c513dcaadd4.png differ diff --git a/refs/pull/405/merge/_images/ditaa-bf1244d1a5c3d99bd8d40148d81cb3e5748c0b94.ditaa b/refs/pull/405/merge/_images/ditaa-bf1244d1a5c3d99bd8d40148d81cb3e5748c0b94.ditaa new file mode 100644 index 00000000..04513e58 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-bf1244d1a5c3d99bd8d40148d81cb3e5748c0b94.ditaa @@ -0,0 +1,34 @@ + struct socket +---------> struct proto_ops + +--------------------+ | +-----------------+ + | struct socket | | | release | + | | | +-----------------+ + +--------------------+ | | bind | + | struct proto_ops * |--------+ +-----------------+ + +--------------------+ | connect | + | ... | +-----------------+ + +---------------+ | accept | + +---------| struct sock * |-------+ +-----------------+ + | +---------------+ | | sendmsg | + | | +-----------------+ + | | | recvmsg | + | | +-----------------+ + | | | poll | + | | +-----------------+ + | | | ... | + | | +-----------------+ + | | + v v +--> struct sk_prot + struct tcp_sock struct tcp_sock | +--------------------+ ++-------------------+ +-------------------+ | | inet_dgram_connect | +| struct inet_sock | | struct inet_sock | | +--------------------+ +| +---------------+ | | +---------------+ | | | inet_sendmsg | +| | struct sock | | | | struct sock | | | +--------------------+ +| | +-----------+ | | | | +-----------+ | | | | udp_poll | +| | | ... | | | | | | ... | | | | +--------------------+ +| | +-----------+ | | | | +-----------+ | | | | inet_release | +| +---------------+ | | +---------------+ | | +--------------------+ +| | sk_prot * | | | | sk_prot * | |--+ | inet_bind | +| +---------------+ | | +---------------+ | +--------------------+ ++-------------------+ +-------------------+ | ... | +| ... | | ... | +--------------------+ ++-------------------+ +-------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-bf1244d1a5c3d99bd8d40148d81cb3e5748c0b94.png b/refs/pull/405/merge/_images/ditaa-bf1244d1a5c3d99bd8d40148d81cb3e5748c0b94.png new file mode 100644 index 00000000..55a414fd Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-bf1244d1a5c3d99bd8d40148d81cb3e5748c0b94.png differ diff --git a/refs/pull/405/merge/_images/ditaa-c11fccb956cdf115910f9f72e1dc14cd7ed549ff.ditaa b/refs/pull/405/merge/_images/ditaa-c11fccb956cdf115910f9f72e1dc14cd7ed549ff.ditaa new file mode 100644 index 00000000..7e5e1cd8 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-c11fccb956cdf115910f9f72e1dc14cd7ed549ff.ditaa @@ -0,0 +1,17 @@ + +------------+ ++-------------+ BUS LOCK | Memory | +| CPU 1 |<------------->| | +| | LOAD (0) | | +| inc v |<--------------| v <- 0 | +| | STORE (1) | | +| |-------------->| v <- 1 | +| | BUS UNLOCK | | +| cEEE |<------------->| | BUS LOCK +-------------+ ++-------------+ | |<------------->| CPU 1 | + | | LOAD (1) | | + | |<--------------| inc v | + | v <- 2 | STORE (2) | | + | |-------------->| | + | | BUS UNLOCK | | + | cEEE |<------------->| cEEE | + +------------+ +-------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-c11fccb956cdf115910f9f72e1dc14cd7ed549ff.png b/refs/pull/405/merge/_images/ditaa-c11fccb956cdf115910f9f72e1dc14cd7ed549ff.png new file mode 100644 index 00000000..8f914f7c Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-c11fccb956cdf115910f9f72e1dc14cd7ed549ff.png differ diff --git a/refs/pull/405/merge/_images/ditaa-c8a3d93d0109b7be6f608871d16adff4aaa933da.ditaa b/refs/pull/405/merge/_images/ditaa-c8a3d93d0109b7be6f608871d16adff4aaa933da.ditaa new file mode 100644 index 00000000..7ede8570 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-c8a3d93d0109b7be6f608871d16adff4aaa933da.ditaa @@ -0,0 +1,21 @@ ++-----+ +--------+ +---------+ +---------+ +| App | | File | | Network | | Display |<--+ +| | | Server | | Server | | Server |-+ | ++-----+ +--------+ +---------+ +---------+ | | + | ^ | | User +-|-|----------------------------------------=-|-|-------=- + | | | | Kernel + | | | | + | | | | + | | | | + | | Reply +----------------------------+ | | + | +--------| |----+ | + +--------->| Micro kernel |------+ + Request | (IPC, Memory, Scheduler) | + | | + +----------------------------+ + | + v ++--------------------------------------------------------+ +| Hardware | ++--------------------------------------------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-c8a3d93d0109b7be6f608871d16adff4aaa933da.png b/refs/pull/405/merge/_images/ditaa-c8a3d93d0109b7be6f608871d16adff4aaa933da.png new file mode 100644 index 00000000..5444c021 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-c8a3d93d0109b7be6f608871d16adff4aaa933da.png differ diff --git a/refs/pull/405/merge/_images/ditaa-cb16db58a2489307b74d4f70256a48c81c65f6c6.ditaa b/refs/pull/405/merge/_images/ditaa-cb16db58a2489307b74d4f70256a48c81c65f6c6.ditaa new file mode 100644 index 00000000..d5ab92c9 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-cb16db58a2489307b74d4f70256a48c81c65f6c6.ditaa @@ -0,0 +1,24 @@ + +-----------+ + | | + +------------------>| Memory |<-----------------+ + | | | | + | +-----------+ | + | ^ | + | | | + v v v ++--------------+ +---------------+ +---------------+ +| | | | | | +| Processor A | | Processor B | | Processor C | +| | | | | | +| | | +-----------+ | | +-----------+ | +| | | | Process 1 | | | | Process 1 | | +| | | +-----------+ | | +-----------+ | +| | | | | | +| +----------+ | | +-----------+ | | +-----------+ | +| | kernel | | | | Process 2 | | | | Process 2 | | +| +----------+ | | +-----------+ | | +-----------+ | +| | | | | | +| | | +-----------+ | | +-----------+ | +| | | | Process 3 | | | | Process 3 | | +| | | +-----------+ | | +-----------+ | ++--------------+ +---------------+ +---------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-cb16db58a2489307b74d4f70256a48c81c65f6c6.png b/refs/pull/405/merge/_images/ditaa-cb16db58a2489307b74d4f70256a48c81c65f6c6.png new file mode 100644 index 00000000..2177b2ec Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-cb16db58a2489307b74d4f70256a48c81c65f6c6.png differ diff --git a/refs/pull/405/merge/_images/ditaa-cc9a2e995be74ee99646ea4bf0e551d766fa92ef.ditaa b/refs/pull/405/merge/_images/ditaa-cc9a2e995be74ee99646ea4bf0e551d766fa92ef.ditaa new file mode 100644 index 00000000..91a56d44 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-cc9a2e995be74ee99646ea4bf0e551d766fa92ef.ditaa @@ -0,0 +1,11 @@ ++-----+ +-----+ +| CR3 | | EPT | ++-----+ +-----+ + | +------------------+ | +----------------+ + | | | | | | + +--------> | Guest Page Table | +-------> | EPT Page Table | ---------------> + | | | | +------------> +------------------+ ------------> +----------------+ + +Guest Virtual Guest Physical Host Physical + Address Address Address \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-cc9a2e995be74ee99646ea4bf0e551d766fa92ef.png b/refs/pull/405/merge/_images/ditaa-cc9a2e995be74ee99646ea4bf0e551d766fa92ef.png new file mode 100644 index 00000000..7dc57080 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-cc9a2e995be74ee99646ea4bf0e551d766fa92ef.png differ diff --git a/refs/pull/405/merge/_images/ditaa-d5d1129b0298a2ea5f116c9d4b246eb1b888db6b.ditaa b/refs/pull/405/merge/_images/ditaa-d5d1129b0298a2ea5f116c9d4b246eb1b888db6b.ditaa new file mode 100644 index 00000000..3831def8 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-d5d1129b0298a2ea5f116c9d4b246eb1b888db6b.ditaa @@ -0,0 +1,18 @@ ++-------------------+ +-------------------+ 0xFFFFFFFF +-------------------+ ^ +| | | | | | | +| | | | | | | Kernel space +| | | | | | | +| User | | Kernel | 0xC0000000 +-------------------+ v +| space | | space | | | ^ +| | | | | | | User space +| | | | | | | +| | | | | | | +| | | | | | | +| | | | | | | +| | | | | | | +| | | | | | | +| | | | | | | ++-------------------+ +-------------------+ 0x00000000 +-------------------+ v + + + (a) 4/4 split (b) 1/3 or2/2 split \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-d5d1129b0298a2ea5f116c9d4b246eb1b888db6b.png b/refs/pull/405/merge/_images/ditaa-d5d1129b0298a2ea5f116c9d4b246eb1b888db6b.png new file mode 100644 index 00000000..a4e49739 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-d5d1129b0298a2ea5f116c9d4b246eb1b888db6b.png differ diff --git a/refs/pull/405/merge/_images/ditaa-d6845a04f0ec792beec598d2a9f4c5b92c65529e.ditaa b/refs/pull/405/merge/_images/ditaa-d6845a04f0ec792beec598d2a9f4c5b92c65529e.ditaa new file mode 100644 index 00000000..a1df2c3a --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-d6845a04f0ec792beec598d2a9f4c5b92c65529e.ditaa @@ -0,0 +1,6 @@ + 15 3 2 1 0 + +------------+----+-----+ + | | | | + Segment selectors | index | TI | RPL | +(CS, DS, SS, ES, FS, GS) | | | | + +------------+----+-----+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-d6845a04f0ec792beec598d2a9f4c5b92c65529e.png b/refs/pull/405/merge/_images/ditaa-d6845a04f0ec792beec598d2a9f4c5b92c65529e.png new file mode 100644 index 00000000..ec679979 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-d6845a04f0ec792beec598d2a9f4c5b92c65529e.png differ diff --git a/refs/pull/405/merge/_images/ditaa-d880751969de8642b2613caaca345d71acea4500.ditaa b/refs/pull/405/merge/_images/ditaa-d880751969de8642b2613caaca345d71acea4500.ditaa new file mode 100644 index 00000000..afdc233d --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-d880751969de8642b2613caaca345d71acea4500.ditaa @@ -0,0 +1,19 @@ + +------+ +------+ + | | | | + | CPU | | DMA | + | | | | + +------+ +------+ + | + | + v + +-----+ +-----+ + | CR3 | | EPT | + +-----+ +-----+ + | +------------------+ | +----------------+ + | | | | | | + +--------> | Guest Page Table | +-------> | EPT Page Table | ---------------> + | | | | +------------> +------------------+ ------------> +----------------+ + +Guest Virtual Guest Physical Host Physical + Address Address Address \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-d880751969de8642b2613caaca345d71acea4500.png b/refs/pull/405/merge/_images/ditaa-d880751969de8642b2613caaca345d71acea4500.png new file mode 100644 index 00000000..b9640142 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-d880751969de8642b2613caaca345d71acea4500.png differ diff --git a/refs/pull/405/merge/_images/ditaa-da31e3d17a4d55e5c3dbc0bd5903306418a896ca.ditaa b/refs/pull/405/merge/_images/ditaa-da31e3d17a4d55e5c3dbc0bd5903306418a896ca.ditaa new file mode 100644 index 00000000..e5527992 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-da31e3d17a4d55e5c3dbc0bd5903306418a896ca.ditaa @@ -0,0 +1,13 @@ + phase 1 ++----------------+ +| critical | phase 2 ++----------------+ +-----------------+ +| | | immediate | phase 3 +| - IRQ disabled | +-----------------+ +----------------+ +| - ACK IRQ +-----+ | | | deferred | +| | +---> - IRQ disabled | +----------------+ ++----------------+ | - device handler| | | + | - EOI IRQ +-----+ | - IRQ enabled | + +-----------------+ +----> - execute later| + | | + +----------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-da31e3d17a4d55e5c3dbc0bd5903306418a896ca.png b/refs/pull/405/merge/_images/ditaa-da31e3d17a4d55e5c3dbc0bd5903306418a896ca.png new file mode 100644 index 00000000..01d66dcb Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-da31e3d17a4d55e5c3dbc0bd5903306418a896ca.png differ diff --git a/refs/pull/405/merge/_images/ditaa-ddd14be50300088958e86912bc5f396797634a3a.ditaa b/refs/pull/405/merge/_images/ditaa-ddd14be50300088958e86912bc5f396797634a3a.ditaa new file mode 100644 index 00000000..c1072e96 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-ddd14be50300088958e86912bc5f396797634a3a.ditaa @@ -0,0 +1,9 @@ + +------------+ + | Memory | ++-------------+ LOAD (0) | | +-------------+ +| CPU 0 |<--------------| v <- 0 | LOAD (0) | CPU 1 | +| | STORE (1) | |-------------->| | +| inc v |-------------->| v <- 1 | STORE (1) | inc v | +| cEEE | | v <- 1 |<--------------| cEEE | ++-------------+ | cEEE | +-------------+ + +------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-ddd14be50300088958e86912bc5f396797634a3a.png b/refs/pull/405/merge/_images/ditaa-ddd14be50300088958e86912bc5f396797634a3a.png new file mode 100644 index 00000000..a20b7dc8 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-ddd14be50300088958e86912bc5f396797634a3a.png differ diff --git a/refs/pull/405/merge/_images/ditaa-def299abebe530d760a6c8f16c791bbb016f9238.ditaa b/refs/pull/405/merge/_images/ditaa-def299abebe530d760a6c8f16c791bbb016f9238.ditaa new file mode 100644 index 00000000..c453cf9b --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-def299abebe530d760a6c8f16c791bbb016f9238.ditaa @@ -0,0 +1,29 @@ + Virtual Address ++------------+ +------------------+----------------+---------------+ +| CR3 | | DIRECTORY cEEE| TABLE cDDD | OFFSET cCCC| ++------------+ +------------------+----------------+---------------+ + | | | | + | | | | PAGE + | | | | /-----------------------\ + | | | | | | + | | | | | | + | | +-----------+ | +-----------------------+ + | | | +--->| Physical Address cCCC| + | | | +-----------------------+ + | +-----------------+ | | | + | | | PAGE | | + | | | TABLE | | + | | PAGE | /------------\ | | + | | DIRECTORY | | | | | + | | /------------\ | | | | | + | | | | | +------------+ +----> \-----------------------/ + | | | | +---->| cDDD |---+ + | | | | +------------+ + | | | | | | + | | | | | | + | | +------------+ | | + | +----->|cEEE |---+ | | + | +------------+ | | | + | | | +---->\------------/ + | | | + +--------->\------------/ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-def299abebe530d760a6c8f16c791bbb016f9238.png b/refs/pull/405/merge/_images/ditaa-def299abebe530d760a6c8f16c791bbb016f9238.png new file mode 100644 index 00000000..edba4a4f Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-def299abebe530d760a6c8f16c791bbb016f9238.png differ diff --git a/refs/pull/405/merge/_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.ditaa b/refs/pull/405/merge/_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.ditaa new file mode 100644 index 00000000..e8571491 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.ditaa @@ -0,0 +1,26 @@ + ^ ^ ^ + | stat | open | read + v v v ++------------------------------------------------------------+ +| Virtual File System | +| | +| | +| /-------\ /--------\ /--------\ | +| | inode |<----------+ dentry |<----------+ FILE | | +| \---+---/ \----+---/ \---+----/ | +| | | | | +| | | | | +| v v v | +| +-------+ +--------+ +-------+ | +| | inode | | dentry | | page | | +| | cache | | cache | | cache | | +| +-------+ +--------+ +-------+ | +| | ++------------------------------------------------------------+ + ^ ^ + | | + v v + +-------------+ +-------------+ + | Filesystem | | Filesystem | + | driver | | driver | + +-------------+ +-------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.png b/refs/pull/405/merge/_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.png new file mode 100644 index 00000000..432e8cf7 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.png differ diff --git a/refs/pull/405/merge/_images/ditaa-e76e44cad2e92f2134ab77f6a09605b29524d039.ditaa b/refs/pull/405/merge/_images/ditaa-e76e44cad2e92f2134ab77f6a09605b29524d039.ditaa new file mode 100644 index 00000000..3c56c556 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-e76e44cad2e92f2134ab77f6a09605b29524d039.ditaa @@ -0,0 +1,10 @@ ++-------------+ +-------------+ +| Application | | Application | ++-------------+ +-------------+ + | | + |read(fd, buff, len) |fork() + | | + v v ++---------------------------------------+ +| Kernel | ++---------------------------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-e76e44cad2e92f2134ab77f6a09605b29524d039.png b/refs/pull/405/merge/_images/ditaa-e76e44cad2e92f2134ab77f6a09605b29524d039.png new file mode 100644 index 00000000..1cfe9759 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-e76e44cad2e92f2134ab77f6a09605b29524d039.png differ diff --git a/refs/pull/405/merge/_images/ditaa-ee04e3e544de75375b914f7645c79d5ae46fe6f3.ditaa b/refs/pull/405/merge/_images/ditaa-ee04e3e544de75375b914f7645c79d5ae46fe6f3.ditaa new file mode 100644 index 00000000..e6ff0ef3 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-ee04e3e544de75375b914f7645c79d5ae46fe6f3.ditaa @@ -0,0 +1,24 @@ +-:------------------------------------------------------------------------------------ + +VFS layer sys_write → vfs_write → do_sync_write → filp->f_op->aio_write + +-:------------------------------------------------------------------------------------ + +Generic socket layer sock_aio_write → sock->ops->sendmsg + +-:------------------------------------------------------------------------------------ + +IP socket layer sk->sk_prot->sendmsg + +-:------------------------------------------------------------------------------------ + +UDP socket layer ip_append_data udp_flush_pending_frames + | | +-:------------------------------+------------------------------+----------------------- + V V +IP socket layer skb = sock_alloc_send_skb(); ip_local_out + skb_queue_tail(sk, skb) + +-:------------------------------------------------------------------------------------ + + routing \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-ee04e3e544de75375b914f7645c79d5ae46fe6f3.png b/refs/pull/405/merge/_images/ditaa-ee04e3e544de75375b914f7645c79d5ae46fe6f3.png new file mode 100644 index 00000000..9e9558ff Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-ee04e3e544de75375b914f7645c79d5ae46fe6f3.png differ diff --git a/refs/pull/405/merge/_images/ditaa-eeb919cd078d0ba5021028fa628bb47d7d6866e2.ditaa b/refs/pull/405/merge/_images/ditaa-eeb919cd078d0ba5021028fa628bb47d7d6866e2.ditaa new file mode 100644 index 00000000..254b15e8 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-eeb919cd078d0ba5021028fa628bb47d7d6866e2.ditaa @@ -0,0 +1,30 @@ + +-------------+ dup2 +-----------------------------+ + | Application |-----+ | libc | + +-------------+ | | | + +---->| C7590 dup2: | + | ... | + | C7592 movl 0x8(%esp),%ecx | + | C7596 movl 0x4(%esp),%ebx | + | C759a movl $0x3f,%eax | ++------------------------------+ C759f int $0x80 | +| | ... +<-----+ +| +-----------------------------+ | +| | +| | +| | +| | +| +------------------------------------------------------------+ | +| | Kernel | | +| | | | ++--->|ENTRY(entry_INT80_32) | | + | ASM_CLAC | | + | pushl %eax # pt_regs->orig_ax | | + | SAVE_ALL pt_regs_ax=$-ENOSYS # save rest | | + | ... | | + | movl %esp, %eax | | + | call do_int80_syscall_32 | | + | .... | | + | RESTORE_REGS 4 # skip orig_eax/error_code | | + | ... | | + | INTERRUPT_RETURN +-+ + +------------------------------------------------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-eeb919cd078d0ba5021028fa628bb47d7d6866e2.png b/refs/pull/405/merge/_images/ditaa-eeb919cd078d0ba5021028fa628bb47d7d6866e2.png new file mode 100644 index 00000000..f19a4b3a Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-eeb919cd078d0ba5021028fa628bb47d7d6866e2.png differ diff --git a/refs/pull/405/merge/_images/ditaa-eff5e0e3b58ce239d5310b22b89c0927be5853bd.ditaa b/refs/pull/405/merge/_images/ditaa-eff5e0e3b58ce239d5310b22b89c0927be5853bd.ditaa new file mode 100644 index 00000000..e38ff2fa --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-eff5e0e3b58ce239d5310b22b89c0927be5853bd.ditaa @@ -0,0 +1,11 @@ + 63 47 42 32 ++------------------------------+---+---+----+---+---------------+ +| | | D | | | | +| offset (16..31 | P | P | | T | | +| | | L | | | | ++------------------------------+---+---+----+---+---------------+ +| | | +| segment selector | offset (0..15) | +| | | ++------------------------------+--------------------------------+ + 31 15 0 \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-eff5e0e3b58ce239d5310b22b89c0927be5853bd.png b/refs/pull/405/merge/_images/ditaa-eff5e0e3b58ce239d5310b22b89c0927be5853bd.png new file mode 100644 index 00000000..9bd95556 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-eff5e0e3b58ce239d5310b22b89c0927be5853bd.png differ diff --git a/refs/pull/405/merge/_images/ditaa-f3703e3f627a948c59f6f960518d5f68eb7becec.ditaa b/refs/pull/405/merge/_images/ditaa-f3703e3f627a948c59f6f960518d5f68eb7becec.ditaa new file mode 100644 index 00000000..ead21664 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-f3703e3f627a948c59f6f960518d5f68eb7becec.ditaa @@ -0,0 +1,6 @@ + +--------------+ +------------+ + logical | | linear | | physical +---------> | Segmentation | --------> | Paging | ----------> + address | Unit | address | Unit | address + | | | | + +--------------+ +------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-f3703e3f627a948c59f6f960518d5f68eb7becec.png b/refs/pull/405/merge/_images/ditaa-f3703e3f627a948c59f6f960518d5f68eb7becec.png new file mode 100644 index 00000000..6d402da7 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-f3703e3f627a948c59f6f960518d5f68eb7becec.png differ diff --git a/refs/pull/405/merge/_images/ditaa-f45246aade5ecc7cfb71f7f103a57f95fc7c2b9e.ditaa b/refs/pull/405/merge/_images/ditaa-f45246aade5ecc7cfb71f7f103a57f95fc7c2b9e.ditaa new file mode 100644 index 00000000..a6b1f07e --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-f45246aade5ecc7cfb71f7f103a57f95fc7c2b9e.ditaa @@ -0,0 +1,31 @@ ++-------+ +| linux | ++-+-----+ + | + +------+--------+---------+---------+--------------+--------------+ + | | | | | | | + | v v v v v v + | +------+ +-------+ +-------+ +--------+ +---------------+ +---------+ + | | arch | | block | | certs | | crypto | | Documentation | | drivers | + | +------+ +-------+ +-------+ +--------+ +---------------+ +---------+ + | + +-------+----------+--------+---------+--------+--------+---------+ + | | | | | | | | + | v v v v v v v + | +----------+ +----+ +---------+ +------+ +-----+ +--------+ +-----+ + | | firmware | | fs | | include | | init | | ipc | | kernel | | lib | + | +----------+ +----+ +---------+ +------+ +-----+ +--------+ +-----+ + | + +-----+------+---------+------------+------------+------------+ + | | | | | | | + | v v v v v v + | +----+ +-----+ +---------+ +---------+ +----------+ +-------+ + | | mm | | net | | samples | | scripts | | security | | sound | + | +----+ +-----+ +---------+ +---------+ +----------+ +-------+ + | + +------+--------+--------+ + | | | + v v v + +-------+ +-----+ +------+ + | tools | | usr | | virt | + +-------+ +-----+ +------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-f45246aade5ecc7cfb71f7f103a57f95fc7c2b9e.png b/refs/pull/405/merge/_images/ditaa-f45246aade5ecc7cfb71f7f103a57f95fc7c2b9e.png new file mode 100644 index 00000000..537372dd Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-f45246aade5ecc7cfb71f7f103a57f95fc7c2b9e.png differ diff --git a/refs/pull/405/merge/_images/ditaa-f6b228332baf165f498d8a1bb0bc0bdb91ae50c5.ditaa b/refs/pull/405/merge/_images/ditaa-f6b228332baf165f498d8a1bb0bc0bdb91ae50c5.ditaa new file mode 100644 index 00000000..45f5a834 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-f6b228332baf165f498d8a1bb0bc0bdb91ae50c5.ditaa @@ -0,0 +1,27 @@ +Userspace Kernel Kernel Userspace + T0 T0 T1 T1 + + | + | syscall +-------------------+ + V --------->| Save user regs on | +-----------------+ + interrupt | the kernel stack | | Save user regs | + +-------------------+ | on kernel stack | + | +-----------------+ + |schedule() | + | |schedule() + V | + +-----------------+ V + | context_switch |------+ +-----------------+ + +-----------------+ | | context_switch | + +-----> +-----------------+ + | + V + +-------------------+ + | Pop user regs | + | from kernel stack | + +-------------------+ + | + | exit syscall + +--------------------> | + | + V \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-f6b228332baf165f498d8a1bb0bc0bdb91ae50c5.png b/refs/pull/405/merge/_images/ditaa-f6b228332baf165f498d8a1bb0bc0bdb91ae50c5.png new file mode 100644 index 00000000..f96c9eb9 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-f6b228332baf165f498d8a1bb0bc0bdb91ae50c5.png differ diff --git a/refs/pull/405/merge/_images/ditaa-f7ee56960e76c3e80fcbe59fafa38c3d93eac261.ditaa b/refs/pull/405/merge/_images/ditaa-f7ee56960e76c3e80fcbe59fafa38c3d93eac261.ditaa new file mode 100644 index 00000000..a9cba28c --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-f7ee56960e76c3e80fcbe59fafa38c3d93eac261.ditaa @@ -0,0 +1,35 @@ + +--+ +--+ +--+ + mydriver.c | | mybus.c | | bus/driver/device core | | kobject core + | | | | | | + | | | | | | + | | | | | | + | | +-----------------------------+ | | +-----------------------------+ | | + | | | my_bus_type +------=>+ struct bus_type | | | + | | +-----------------------------+ | | +-----------------------------+ | | + | | |name | | | |name | | | + | | |uevent() = my_uevent() | | | |uevent() | | | + | | |match() = my_match() | | | |match() | | | + | | +-----------------------------+ | | +-----------------------------+ | | + | | | | | | | | + | | | | +-----------------------------+ | | + | | | | | | ++----------------+ | | +-----------------------------+ | | +-----------------------------+ | | +-------------------+ +| mydriver +------=>+ struct my_driver +------->+ struct device_driver +-------+---->| struct kobject | ++----------------+ | | +-----------------------------+ | | +-----------------------------+ | | | +-------------------+ +| | | | | | | | | name | | | | | k_name | ++----------------+ | | +-----------------------------+ | | +-----------------------------+ | | | +-------------------+ + | | | my_register_driver() | | | | driver_register() | | | | | kobject_add() | + | | | my_unregister_driver() | | | | driver_unregister() | | | | | kobject_delete() | + | | +-----------------------------+ | | +-----------------------------+ | | | +-------------------+ + | | | | | | | + | | | | | | | ++----------------+ | | +-----------------------------+ | | +-----------------------------+ | | | +| mydevice +------=>+ struct my_device +------->+ struct device +-------+ ++----------------+ | | +-----------------------------+ | | +-----------------------------+ | | +| | | | | | | | | bus_id | | | ++----------------+ | | +-----------------------------+ | | +-----------------------------+ | | + | | | my_register_device() | | | | device_register() | | | + | | | my_unregister_device() | | | | device_unregister() | | | + | | +-----------------------------+ | | +-----------------------------+ | | + | | | | | | + +--+ +--+ +--+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-f7ee56960e76c3e80fcbe59fafa38c3d93eac261.png b/refs/pull/405/merge/_images/ditaa-f7ee56960e76c3e80fcbe59fafa38c3d93eac261.png new file mode 100644 index 00000000..9c1194e0 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-f7ee56960e76c3e80fcbe59fafa38c3d93eac261.png differ diff --git a/refs/pull/405/merge/_images/ditaa-f8fcc760ef5dad50d1038ed3426d0fcce12fd3e6.ditaa b/refs/pull/405/merge/_images/ditaa-f8fcc760ef5dad50d1038ed3426d0fcce12fd3e6.ditaa new file mode 100644 index 00000000..aeda4a8a --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-f8fcc760ef5dad50d1038ed3426d0fcce12fd3e6.ditaa @@ -0,0 +1,19 @@ + VM1 (qemu) VM2 (qemu) ++---------------------+ +---------------------+ +| +------+ +------+ | | +------+ +------+ | +| | App1 | | App2 | | | | App1 | | App2 | | +| +------+ +------+ | | +------+ +------+ | +| +-----------------+ | | +-----------------+ | +| | Guest Kernel | | | | Guest Kernel | | +| +-----------------+ | | +-----------------+ | ++---------------------+ +---------------------+ + ++----------------------------------------------------+ +| +-----+ | +| | KVM | Host Linux Kernel | +| +-----+ | ++----------------------------------------------------+ + ++----------------------------------------------------+ +| Hardware with virtualization support | ++----------------------------------------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-f8fcc760ef5dad50d1038ed3426d0fcce12fd3e6.png b/refs/pull/405/merge/_images/ditaa-f8fcc760ef5dad50d1038ed3426d0fcce12fd3e6.png new file mode 100644 index 00000000..57d3e212 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-f8fcc760ef5dad50d1038ed3426d0fcce12fd3e6.png differ diff --git a/refs/pull/405/merge/_images/ditaa-fbe06955ffc165cbdc9cb6074abf0db807b3c5cd.ditaa b/refs/pull/405/merge/_images/ditaa-fbe06955ffc165cbdc9cb6074abf0db807b3c5cd.ditaa new file mode 100644 index 00000000..5febcc5e --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-fbe06955ffc165cbdc9cb6074abf0db807b3c5cd.ditaa @@ -0,0 +1,19 @@ ++---------------------------------------------------------+ +| application programming (EGC, SPG, PP, SPRC, IOC, etc.) | ++---------------------------------------------------------+ + + +----------------------------------+ + | system programming (PC, SO, CPL) | + +----------------------------------+ + user space +----------------------------------------------------------=- + kernel space + +--------------------------+ + | kernel programming (SO2) | + +--------------------------+ + +----------------------------------------------------------=- + + +----------------------------------+ + | hardware (PM, CN1, CN2, PL ) | + +----------------------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-fbe06955ffc165cbdc9cb6074abf0db807b3c5cd.png b/refs/pull/405/merge/_images/ditaa-fbe06955ffc165cbdc9cb6074abf0db807b3c5cd.png new file mode 100644 index 00000000..be0bf3de Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-fbe06955ffc165cbdc9cb6074abf0db807b3c5cd.png differ diff --git a/refs/pull/405/merge/_images/ditaa-fd771038e88b95def30ae9bd4df0b7bd6b7b3503.ditaa b/refs/pull/405/merge/_images/ditaa-fd771038e88b95def30ae9bd4df0b7bd6b7b3503.ditaa new file mode 100644 index 00000000..1ce957b6 --- /dev/null +++ b/refs/pull/405/merge/_images/ditaa-fd771038e88b95def30ae9bd4df0b7bd6b7b3503.ditaa @@ -0,0 +1,16 @@ + Opened files + task_struct +-------------------+ task_struct ++-----------------------+ | FILE | +-----------------------+ +| Thread Group ID (PID) | +--->+-------------------+<---+ | Thread Group ID (PID) | ++-----------------------+ | | .... | | +-----------------------+ +| Thread ID (TID) | | +-------------------+ | | Thread ID (TID) | ++-----------------------+ | | +-----------------------+ +| ... | | | | ... | ++-----------------------+ | | +-----------------------+ +| Opened files |--+ +--| Opened files | ++-----------------------+ Address Space +-----------------------+ +| Address Space |---+ +-------------------+ +---| Address Space | ++-----------------------+ | | | | +-----------------------+ +| ... | +-->| .... |<--+ | ... | ++-----------------------+ | | +-----------------------+ + +-------------------+ \ No newline at end of file diff --git a/refs/pull/405/merge/_images/ditaa-fd771038e88b95def30ae9bd4df0b7bd6b7b3503.png b/refs/pull/405/merge/_images/ditaa-fd771038e88b95def30ae9bd4df0b7bd6b7b3503.png new file mode 100644 index 00000000..0060f6e7 Binary files /dev/null and b/refs/pull/405/merge/_images/ditaa-fd771038e88b95def30ae9bd4df0b7bd6b7b3503.png differ diff --git a/refs/pull/405/merge/_images/dts_node.png b/refs/pull/405/merge/_images/dts_node.png new file mode 100644 index 00000000..2404462c Binary files /dev/null and b/refs/pull/405/merge/_images/dts_node.png differ diff --git a/refs/pull/405/merge/_images/dts_node1.png b/refs/pull/405/merge/_images/dts_node1.png new file mode 100644 index 00000000..2404462c Binary files /dev/null and b/refs/pull/405/merge/_images/dts_node1.png differ diff --git a/refs/pull/405/merge/_images/fib-trie-compressed.png b/refs/pull/405/merge/_images/fib-trie-compressed.png new file mode 100644 index 00000000..44235ff5 Binary files /dev/null and b/refs/pull/405/merge/_images/fib-trie-compressed.png differ diff --git a/refs/pull/405/merge/_images/fib-trie-compressed1.png b/refs/pull/405/merge/_images/fib-trie-compressed1.png new file mode 100644 index 00000000..44235ff5 Binary files /dev/null and b/refs/pull/405/merge/_images/fib-trie-compressed1.png differ diff --git a/refs/pull/405/merge/_images/fib-trie.png b/refs/pull/405/merge/_images/fib-trie.png new file mode 100644 index 00000000..f0da22f1 Binary files /dev/null and b/refs/pull/405/merge/_images/fib-trie.png differ diff --git a/refs/pull/405/merge/_images/fib-trie1.png b/refs/pull/405/merge/_images/fib-trie1.png new file mode 100644 index 00000000..f0da22f1 Binary files /dev/null and b/refs/pull/405/merge/_images/fib-trie1.png differ diff --git a/refs/pull/405/merge/_images/fidb-details.png b/refs/pull/405/merge/_images/fidb-details.png new file mode 100644 index 00000000..c146bc3c Binary files /dev/null and b/refs/pull/405/merge/_images/fidb-details.png differ diff --git a/refs/pull/405/merge/_images/fidb-details1.png b/refs/pull/405/merge/_images/fidb-details1.png new file mode 100644 index 00000000..c146bc3c Binary files /dev/null and b/refs/pull/405/merge/_images/fidb-details1.png differ diff --git a/refs/pull/405/merge/_images/fidb-overview.png b/refs/pull/405/merge/_images/fidb-overview.png new file mode 100644 index 00000000..a9f86970 Binary files /dev/null and b/refs/pull/405/merge/_images/fidb-overview.png differ diff --git a/refs/pull/405/merge/_images/fidb-overview1.png b/refs/pull/405/merge/_images/fidb-overview1.png new file mode 100644 index 00000000..a9f86970 Binary files /dev/null and b/refs/pull/405/merge/_images/fidb-overview1.png differ diff --git a/refs/pull/405/merge/_images/inspect_task_struct.cast b/refs/pull/405/merge/_images/inspect_task_struct.cast new file mode 100644 index 00000000..52cb2df6 --- /dev/null +++ b/refs/pull/405/merge/_images/inspect_task_struct.cast @@ -0,0 +1,849 @@ +{"version": 2, "width": 80, "height": 24, "timestamp": 1615763059, "idle_time_limit": 1.0, "env": {"SHELL": null, "TERM": "xterm"}} +[0.002258, "o", "$ "] +[0.627367, "o", "m"] +[0.68335, "o", "a"] +[0.786756, "o", "k"] +[0.835143, "o", "e"] +[0.987307, "o", " "] +[1.211073, "o", "g"] +[1.44347, "o", "d"] +[1.931409, "o", "b"] +[2.419393, "o", "\r\n"] +[2.425118, "o", "gdb -ex \"target remote localhost:1234\" /linux/vmlinux\r\n"] +[2.46016, "o", "\u001b[35;1m\u001b[35;1mGNU gdb \u001b[m\u001b[35;1m(Ubuntu 9.2-0ubuntu1~20.04) \u001b[m\u001b[35;1m9.2\u001b[m\u001b[35;1m\r\n\u001b[m\u001b[mCopyright (C) 2020 Free Software Foundation, Inc.\r\nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\r\nThis is free software: you are free to change and redistribute it.\r\nThere is NO WARRANTY, to the extent permitted by law.\r\nType \"show copying\" and \"show warranty\" for details.\r\nThis GDB was configured as \"x86_64-linux-gnu\".\r\nType \"show configuration\" for configuration details.\r\nFor bug reporting instructions, please see:\r\n<http://www.gnu.org/software/gdb/bugs/>.\r\nFind the GDB manual and other documentation resources online at:\r\n <http://www.gnu.org/software/gdb/documentation/>.\r\n\r\nFor help, type \"help\".\r\nType \"apropos word\" to search for commands related to \"word\"...\r\n"] +[2.460424, "o", "Reading symbols from \u001b[32m/linux/vmlinux\u001b[m...\r\n"] +[3.047524, "o", "Remote debugging using localhost:1234\r\n"] +[3.067155, "o", "\u001b[33m__lock_acquire\u001b[m (\u001b[36mlock=lock@entry\u001b[m=0xc2416250, \u001b[36msubclass=subclass@entry\u001b[m=0, \u001b[m\r\n"] +[3.067502, "o", " \u001b[m\u001b[36mtrylock=trylock@entry\u001b[m=0, \u001b[36mread=read@entry\u001b[m=0, \u001b[36mcheck=check@entry\u001b[m=1, \u001b[m\r\n"] +[3.06766, "o", "\u001b[m--Type <RET> for more, q to quit, c to continue without paging--"] +[4.708007, "o", "\r\n"] +[4.708796, "o", " \u001b[m\u001b[36mhardirqs_off=hardirqs_off@entry\u001b[m=1, \u001b[36mnest_lock=nest_lock@entry\u001b[m=0x0, \u001b[m\r\n \u001b[m\u001b[36mip=ip@entry\u001b[m=3241676808, \u001b[36mreferences=references@entry\u001b[m=0, \u001b[m\r\n"] +[4.708863, "o", " \u001b[m\u001b[36mpin_count=pin_count@entry\u001b[m=0) at \u001b[32mkernel/locking/lockdep.c\u001b[m:4738\r\n"] +[4.709098, "o", "4738\t\tclass_idx = class - lock_classes;\r\n"] +[4.70932, "o", "(gdb) "] +[6.809114, "o", "l"] +[6.995472, "o", "x"] +[7.138947, "o", "-"] +[7.331348, "o", "p"] +[7.894323, "o", "s"] +[11.123106, "o", "\r\n"] +[11.123178, "o", " TASK PID COMM\r\n"] +[11.12485, "o", "0xc17d02c0 0 swapper/0\r\n"] +[11.126522, "o", "0xc2530040 1 swapper/0\r\n"] +[11.127872, "o", "0xc2534080 2 kthreadd\r\n"] +[11.129364, "o", "0xc25360c0 3 rcu_gp\r\n"] +[11.13074, "o", "0xc2537100 4 rcu_par_gp\r\n"] +[11.132056, "o", "0xc2545140 5 kworker/0:0\r\n"] +[11.133156, "o", "0xc2546180 6 kworker/0:0H\r\n"] +[11.134051, "o", "0xc25481c0 7 kworker/u2:0\r\n"] +[11.135046, "o", "0xc2549000 8 mm_percpu_wq\r\n"] +[11.135873, "o", "0xc254b040 9 ksoftirqd/0\r\n"] +[11.136804, "o", "0xc254c080 10 rcu_sched\r\n"] +[11.137649, "o", "0xc254e0c0 11 migration/0\r\n"] +[11.138414, "o", "0xc2572100 12 cpuhp/0\r\n"] +[11.139254, "o", "0xc2576140 13 kdevtmpfs\r\n"] +[11.140061, "o", "0xc2594180 14 netns\r\n"] +[11.140849, "o", "0xc26211c0 15 oom_reaper\r\n"] +[11.141609, "o", "0xc2623000 16 writeback\r\n"] +[11.142354, "o", "0xc26300c0 32 kblockd\r\n"] +[11.143193, "o", "\u001b[m--Type <RET> for more, q to quit, c to continue without paging--"] +[13.172107, "o", "q"] +[13.386945, "o", "\r\n"] +[13.387104, "o", "Quit\r\n(gdb) "] +[13.924017, "o", "#"] +[14.128394, "o", " "] +[14.691413, "o", "n"] +[14.777001, "o", "o"] +[15.024956, "o", "t"] +[15.200252, "o", "i"] +[15.658237, "o", "\b\u001b[K"] +[15.800549, "o", "\b\u001b[K"] +[18.149577, "o", "\b\u001b[K"] +[18.707978, "o", "\b\u001b[K"] +[18.992922, "o", "l"] +[19.107602, "o", "e"] +[19.28165, "o", "t"] +[19.505188, "o", "s"] +[19.600963, "o", " "] +[19.804348, "o", "l"] +[20.000551, "o", "o"] +[20.142601, "o", "o"] +[20.171715, "o", "k"] +[20.511567, "o", " "] +[20.691626, "o", "a"] +[20.998173, "o", "t"] +[21.083584, "o", " "] +[21.211514, "o", "t"] +[21.323576, "o", "h"] +[21.707293, "o", "e"] +[21.835442, "o", " "] +[23.451569, "o", "f"] +[23.621036, "o", "i"] +[23.690171, "o", "r"] +[23.8906, "o", "s"] +[24.099481, "o", "t"] +[24.459424, "o", " "] +[24.640336, "o", "t"] +[25.216437, "o", "a"] +[25.444316, "o", "s"] +[25.547244, "o", "k"] +[27.204116, "o", "\r\n(gdb) "] +[30.617187, "o", "p"] +[30.764631, "o", "r"] +[30.859261, "o", "i"] +[30.923074, "o", "n"] +[30.971535, "o", "t"] +[31.101722, "o", " "] +[31.377345, "o", "("] +[31.49992, "o", "s"] +[31.665037, "o", "t"] +[31.7159, "o", "r"] +[31.797039, "o", "u"] +[31.891209, "o", "c"] +[32.134894, "o", "t"] +[32.275529, "o", " "] +[32.38782, "o", "t"] +[32.593072, "o", "a"] +[32.670072, "o", "s"] +[32.723656, "o", "k"] +[32.97944, "o", "_"] +[33.411209, "o", "s"] +[33.571094, "o", "t"] +[33.633386, "o", "r"] +[33.723362, "o", "u"] +[33.819607, "o", "c"] +[34.03609, "o", "t"] +[34.243481, "o", " "] +[34.8279, "o", "*"] +[34.939317, "o", ")"] +[41.353684, "o", "0xc17d02"] +[41.353931, "o", "c0"] +[42.556284, "o", "\r\n"] +[42.572593, "o", "$1 = (struct task_struct *) \u001b[34m0xc17d02c0\u001b[m <\u001b[33minit_task\u001b[m>\r\n(gdb) "] +[43.76609, "o", " "] +[44.144961, "o", "\b\u001b[K"] +[44.404337, "o", "#"] +[44.491671, "o", " "] +[44.729417, "o", "n"] +[44.776973, "o", "o"] +[44.964074, "o", "t"] +[45.020048, "o", "i"] +[45.220228, "o", "c"] +[45.307108, "o", "e"] +[45.403404, "o", " "] +[45.579136, "o", "t"] +[45.651669, "o", "h"] +[45.752831, "o", "a"] +[45.851754, "o", "t"] +[45.932833, "o", " "] +[46.080052, "o", "t"] +[46.189538, "o", "h"] +[46.331405, "o", "e"] +[46.464752, "o", " "] +[46.737976, "o", "t"] +[47.031178, "o", "s"] +[47.034726, "o", "a"] +[47.488137, "o", "\b\u001b[K"] +[47.656792, "o", "\b\u001b[K"] +[47.731352, "o", "a"] +[47.842274, "o", "s"] +[47.879582, "o", "k"] +[48.063247, "o", " "] +[48.304771, "o", "i"] +[48.451198, "o", "s"] +[48.568817, "o", " "] +[48.675509, "o", "a"] +[48.836947, "o", "l"] +[48.985894, "o", "l"] +[49.180376, "o", "o"] +[49.335982, "o", "c"] +[49.427444, "o", "a"] +[49.635823, "o", "t"] +[49.691801, "o", "e"] +[49.881213, "o", "d"] +[49.964905, "o", " "] +[50.099764, "o", "d"] +[50.226974, "o", "i"] +[50.321136, "o", "r"] +[50.388547, "o", "e"] +[50.569383, "o", "c"] +[50.777146, "o", "t"] +[50.811594, "o", "l"] +[51.049026, "o", "y"] +[51.154598, "o", " "] +[51.316279, "o", "i"] +[51.381979, "o", "n"] +[51.432314, "o", " "] +[51.556065, "o", "t"] +[51.661287, "o", "h"] +[51.783469, "o", "e"] +[51.867781, "o", " "] +[52.096542, "o", "i"] +[52.241698, "o", "m"] +[52.379699, "o", "a"] +[52.616666, "o", "g"] +[52.684999, "o", "e"] +[54.076647, "o", "\r\n"] +[54.076706, "o", "(gdb) "] +[54.548115, "o", "#"] +[55.481235, "o", " "] +[55.929872, "o", "i"] +[56.729007, "o", "\b\u001b[K"] +[56.836286, "o", "t"] +[56.965048, "o", "h"] +[57.020301, "o", "i"] +[57.152388, "o", " "] +[57.361979, "o", "i"] +[57.484185, "o", "s"] +[58.104718, "o", "\b\u001b[K"] +[58.211525, "o", "\b\u001b[K"] +[58.345772, "o", "\b\u001b[K"] +[58.599277, "o", "s"] +[58.699061, "o", " "] +[58.872073, "o", "i"] +[59.024165, "o", "s"] +[59.121158, "o", " "] +[59.261122, "o", "t"] +[59.342248, "o", "h"] +[59.959054, "o", "e"] +[60.096489, "o", " "] +[60.195746, "o", "f"] +[60.316017, "o", "i"] +[60.40269, "o", "r"] +[60.595528, "o", "s"] +[60.795261, "o", "t"] +[60.875222, "o", " "] +[61.023882, "o", "t"] +[61.219665, "o", "a"] +[61.294759, "o", "s"] +[61.699194, "o", "k"] +[61.947333, "o", " "] +[62.186605, "o", "t"] +[62.292669, "o", "h"] +[62.383993, "o", "a"] +[62.462394, "o", "t"] +[62.611368, "o", " "] +[63.073466, "o", "r"] +[63.232473, "o", "u"] +[63.350378, "o", "n"] +[64.143825, "o", " "] +[64.346129, "o", "d"] +[64.457352, "o", "u"] +[64.594958, "o", "r"] +[64.667077, "o", "i"] +[64.739904, "o", "n"] +[64.819518, "o", "g"] +[64.932011, "o", " "] +[65.416451, "o", "b"] +[65.50703, "o", "o"] +[65.61947, "o", "o"] +[65.723128, "o", "t"] +[66.372533, "o", "\r\n"] +[66.37262, "o", "(gdb) "] +[67.489239, "o", "#"] +[67.69126, "o", " "] +[67.812288, "o", "a"] +[67.939709, "o", "l"] +[68.155397, "o", "s"] +[68.245108, "o", "o"] +[68.428805, "o", " "] +[68.619862, "o", "n"] +[68.642887, "o", "o"] +[68.779469, "o", "t"] +[68.88901, "o", "i"] +[69.043262, "o", "c"] +[69.136781, "o", "e"] +[69.281437, "o", " "] +[69.443731, "o", "t"] +[69.531328, "o", "h"] +[69.659822, "o", "a"] +[69.779992, "o", "t"] +[69.896515, "o", " "] +[70.019759, "o", "t"] +[70.13192, "o", "h"] +[70.217266, "o", "e"] +[70.315651, "o", "r"] +[70.40667, "o", "e"] +[70.467033, "o", " "] +[70.605909, "o", "i"] +[70.709012, "o", "s"] +[70.797622, "o", " "] +[70.954744, "o", "n"] +[71.032528, "o", "o"] +[71.337134, "o", " "] +[71.504564, "o", "i"] +[71.604101, "o", "n"] +[71.680536, "o", "i"] +[71.803535, "o", "t"] +[71.883327, "o", " "] +[72.003128, "o", "t"] +[72.203373, "o", "a"] +[72.295758, "o", "s"] +[72.399629, "o", "k"] +[72.575918, "o", " "] +[72.979851, "o", "y"] +[73.075825, "o", "e"] +[73.264132, "o", "t"] +[73.611752, "o", ","] +[73.708124, "o", " "] +[73.803574, "o", "s"] +[73.955095, "o", "i"] +[74.019777, "o", "n"] +[74.051016, "o", "c"] +[74.141735, "o", "e"] +[74.237855, "o", " "] +[74.355776, "o", "w"] +[74.420644, "o", "e"] +[74.515071, "o", " "] +[74.600642, "o", "a"] +[74.74771, "o", "r"] +[74.836435, "o", "e"] +[74.907223, "o", " "] +[75.018533, "o", "s"] +[75.192824, "o", "t"] +[75.235418, "o", "i"] +[75.404227, "o", "l"] +[75.518303, "o", "l"] +[75.571386, "o", " "] +[75.68698, "o", "b"] +[75.779911, "o", "o"] +[75.907538, "o", "o"] +[75.956027, "o", "t"] +[76.099746, "o", "i"] +[76.180981, "o", "n"] +[76.204263, "o", "g"] +[76.94757, "o", "\r\n(gdb) "] +[77.465313, "o", "#"] +[77.60323, "o", " "] +[77.771746, "o", "l"] +[77.840755, "o", "e"] +[78.01651, "o", "t"] +[78.19322, "o", "s"] +[78.28195, "o", " "] +[78.451553, "o", "w"] +[78.720865, "o", "a"] +[78.83536, "o", "i"] +[78.971292, "o", "t"] +[79.059111, "o", " "] +[79.184909, "o", "f"] +[79.268223, "o", "o"] +[79.37142, "o", "r"] +[79.467247, "o", " "] +[79.5852, "o", "a"] +[79.675245, "o", " "] +[79.827752, "o", "b"] +[79.944592, "o", "i"] +[80.027415, "o", "t"] +[80.187537, "o", "\r\n(gdb) "] +[80.562931, "o", "c"] +[80.795397, "o", "\r\nContinuing.\r\n"] +[121.082722, "o", "^C"] +[121.089999, "o", "\r\nProgram received signal SIGINT, Interrupt.\r\n"] +[121.090173, "o", "\u001b[33mdefault_idle\u001b[m () at \u001b[32march/x86/kernel/process.c\u001b[m:689\r\n689\t}\r\n(gdb) "] +[123.106153, "o", "#"] +[123.405941, "o", " "] +[123.979574, "o", "w"] +[124.068273, "o", "e"] +[124.159089, "o", " "] +[124.51651, "o", "h"] +[124.596335, "o", "i"] +[124.801487, "o", "t"] +[124.932552, "o", " "] +[125.043099, "o", "t"] +[125.187264, "o", "h"] +[125.342082, "o", "e"] +[125.551746, "o", " "] +[126.091803, "o", "i"] +[126.283016, "o", "d"] +[126.38368, "o", "e"] +[126.611562, "o", "l"] +[127.383539, "o", "\b\u001b[K"] +[127.523397, "o", "\b\u001b[K"] +[127.764257, "o", "l"] +[127.885901, "o", "e"] +[128.102388, "o", " "] +[128.628478, "o", "f"] +[128.755103, "o", "u"] +[128.827608, "o", "n"] +[128.899218, "o", "c"] +[129.159741, "o", "t"] +[129.229055, "o", "i"] +[129.266534, "o", "o"] +[129.52278, "o", "n"] +[129.603238, "o", " "] +[129.845, "o", "s"] +[129.95226, "o", "o"] +[130.635332, "o", " "] +[132.650977, "o", "t"] +[132.764212, "o", "h"] +[132.861951, "o", "e"] +[133.002149, "o", " "] +[133.108483, "o", "s"] +[133.264264, "o", "y"] +[133.32105, "o", "s"] +[133.512254, "o", "t"] +[133.577376, "o", "e"] +[133.610919, "o", "m"] +[133.724743, "o", " "] +[133.8519, "o", "p"] +[133.940929, "o", "r"] +[134.043108, "o", "o"] +[134.163485, "o", "b"] +[134.249323, "o", "a"] +[134.360582, "o", "b"] +[134.458498, "o", "l"] +[134.725093, "o", "y"] +[134.796654, "o", " "] +[135.075413, "o", "b"] +[135.132523, "o", "o"] +[135.253576, "o", "o"] +[135.420718, "o", "t"] +[135.572909, "o", "e"] +[135.732266, "o", "d"] +[135.88038, "o", " "] +[136.124706, "o", "u"] +[136.180361, "o", "p"] +[136.691338, "o", "\r\n(gdb) "] +[137.131348, "o", "l"] +[137.857637, "o", "s"] +[138.377273, "o", "-"] +[139.249675, "o", "\b\u001b[K"] +[139.352566, "o", "\b\u001b[K"] +[139.431785, "o", "x"] +[139.546652, "o", "-"] +[139.792902, "o", "p"] +[139.980251, "o", "s"] +[140.380458, "o", "\r\n"] +[140.380619, "o", " TASK PID COMM\r\n"] +[140.381038, "o", "0xc17d02c0 0 swapper/0\r\n"] +[140.382456, "o", "0xc2530040 1 init\r\n"] +[140.383557, "o", "0xc2534080 2 kthreadd\r\n"] +[140.384521, "o", "0xc25360c0 3 rcu_gp\r\n"] +[140.385521, "o", "0xc2537100 4 rcu_par_gp\r\n"] +[140.38645, "o", "0xc2545140 5 kworker/0:0\r\n"] +[140.387399, "o", "0xc2546180 6 kworker/0:0H\r\n"] +[140.388317, "o", "0xc25481c0 7 kworker/u2:0\r\n"] +[140.389206, "o", "0xc2549000 8 mm_percpu_wq\r\n"] +[140.390069, "o", "0xc254b040 9 ksoftirqd/0\r\n"] +[140.390903, "o", "0xc254c080 10 rcu_sched\r\n"] +[140.391626, "o", "0xc254e0c0 11 migration/0\r\n"] +[140.392543, "o", "0xc2572100 12 cpuhp/0\r\n"] +[140.393323, "o", "0xc2576140 13 kdevtmpfs\r\n"] +[140.394242, "o", "0xc2594180 14 netns\r\n"] +[140.395183, "o", "0xc26211c0 15 oom_reaper\r\n"] +[140.396009, "o", "0xc2623000 16 writeback\r\n"] +[140.39683, "o", "0xc26300c0 32 kblockd\r\n"] +[140.397681, "o", "\u001b[m--Type <RET> for more, q to quit, c to continue without paging--"] +[141.757204, "o", "q"] +[142.547532, "o", "\r\n"] +[142.547753, "o", "Quit\r\n(gdb) "] +[143.850961, "o", "#"] +[144.070245, "o", " "] +[144.195434, "o", "w"] +[144.279713, "o", "e"] +[144.408497, "o", " "] +[144.552695, "o", "d"] +[144.65939, "o", "o"] +[144.880631, "o", " "] +[145.079566, "o", "s"] +[145.195271, "o", "e"] +[145.368428, "o", "e"] +[145.607373, "o", "t"] +[145.79615, "o", " "] +[145.89913, "o", "t"] +[146.045195, "o", "h"] +[146.09891, "o", "e"] +[146.227914, "o", " "] +[146.463823, "o", "i"] +[146.543985, "o", "n"] +[146.618976, "o", "i"] +[146.707111, "o", "t"] +[146.83548, "o", " "] +[146.945151, "o", "t"] +[147.163454, "o", "a"] +[147.235326, "o", "s"] +[147.425145, "o", "k"] +[148.247683, "o", ","] +[148.376176, "o", " "] +[148.526531, "o", "s"] +[148.616468, "o", "o"] +[148.722313, "o", " "] +[148.904045, "o", "l"] +[148.97297, "o", "e"] +[149.130799, "o", "t"] +[149.367908, "o", "s"] +[149.544347, "o", " "] +[150.095879, "o", "\b\u001b[K"] +[150.228108, "o", "\b\u001b[K"] +[150.347046, "o", "\b\u001b[K"] +[151.10371, "o", "t"] +[151.28464, "o", "s"] +[151.378986, "o", " "] +[151.536173, "o", "i"] +[151.64024, "o", "n"] +[151.907639, "o", "s"] +[152.111461, "o", "p"] +[152.219417, "o", "e"] +[152.33727, "o", "c"] +[152.609681, "o", "t"] +[152.691632, "o", " "] +[152.883529, "o", "i"] +[153.039608, "o", "t"] +[154.483232, "o", "\r\n"] +[154.483296, "o", "(gdb) "] +[158.688904, "o", "\r\u001b[C\u001b[16@reverse-i-search)`':\u001b[C"] +[159.808627, "o", "\b\b\bp': # we do see the init task, so lets inspect it\b\b\b\b\b\b\b"] +[159.973821, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[Cr': # we hit the idle function so the system probably booted up\u001b[A\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[160.059576, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[17Pi': print (struct task_struct *)0xc17d02c0\r\n\r\u001b[K\u001b[A\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[160.123058, "o", "\b\b\b\u001b[1@n\u001b[C\u001b[C\u001b[C"] +[160.189924, "o", "\b\b\b\u001b[1@t\u001b[C\u001b[C\u001b[C"] +[160.92358, "o", "\r\u001b[C\u001b[21Pgdb)\u001b[C"] +[161.345471, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[162.195311, "o", "\b\b\b\b\b\b\b\b\b\b\u001b[K"] +[166.763546, "o", "0xc2530040"] +[167.811211, "o", "\r\n"] +[167.812061, "o", "$2 = (struct task_struct *) \u001b[34m0xc2530040\u001b[m\r\n(gdb) "] +[170.690863, "o", "print (struct task_struct *)0xc2530040"] +[170.960299, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[171.19283, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[171.767394, "o", "\u001b[C"] +[172.24119, "o", "\u001b[C\u001b[1@(\b"] +[172.752175, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[173.806767, "o", ")"] +[174.75601, "o", "-"] +[175.107407, "o", ">"] +[176.273234, "o", "i"] +[176.403267, "o", "n"] +[176.459331, "o", "i"] +[176.571028, "o", "t"] +[176.939329, "o", "\r\n"] +[176.949546, "o", "There is no member named init.\r\n(gdb) "] +[177.801366, "o", "print ((struct task_struct *)0xc2530040)->init"] +[178.822566, "o", "\b\u001b[K"] +[178.959575, "o", "\b\u001b[K"] +[179.083502, "o", "\b\u001b[K"] +[179.220157, "o", "\b\u001b[K"] +[179.455399, "o", "p"] +[179.55676, "o", "i"] +[179.637515, "o", "d"] +[179.812349, "o", "\r\n"] +[179.828661, "o", "$3 = 1\r\n(gdb) "] +[180.470819, "o", "print ((struct task_struct *)0xc2530040)->pid"] +[181.504206, "o", "\b\b\b\u001b[K"] +[182.272216, "o", "c"] +[182.336938, "o", "o"] +[182.535532, "o", "m"] +[182.634755, "o", "m"] +[183.843339, "o", "\r\n"] +[183.859914, "o", "$4 = \"init\\000er/0\\000\\000\\000\\000\\000\\000\"\r\n(gdb) "] +[185.336129, "o", "#"] +[185.499751, "o", " "] +[185.690685, "o", "l"] +[185.843492, "o", "e"] +[186.031657, "o", "t"] +[186.27479, "o", "s"] +[186.543226, "o", " "] +[186.736697, "o", "t"] +[186.907736, "o", "r"] +[187.010908, "o", "y"] +[187.22462, "o", " "] +[187.408223, "o", "t"] +[187.497188, "o", "o"] +[187.602223, "o", " "] +[187.680452, "o", "t"] +[188.29134, "o", "\b\u001b[K"] +[188.386986, "o", "c"] +[188.499959, "o", "h"] +[188.586567, "o", "a"] +[188.691207, "o", "n"] +[188.76476, "o", "g"] +[188.81181, "o", "e"] +[188.898677, "o", " "] +[189.035371, "o", "t"] +[189.092408, "o", "h"] +[189.223294, "o", "e"] +[189.304291, "o", " "] +[189.442809, "o", "n"] +[189.508884, "o", "a"] +[189.656275, "o", "m"] +[189.76372, "o", "e"] +[190.207667, "o", " "] +[190.430618, "o", "o"] +[190.533474, "o", "f"] +[190.650813, "o", " "] +[190.834946, "o", "i"] +[190.930808, "o", "n"] +[191.033332, "o", "i"] +[191.507208, "o", "\b\u001b[K"] +[191.632261, "o", "\b\u001b[K"] +[191.759484, "o", "\b\u001b[K"] +[191.875256, "o", "t"] +[191.955649, "o", "h"] +[192.066747, "o", "e"] +[192.139401, "o", " "] +[192.263673, "o", "i"] +[192.330469, "o", "n"] +[192.411275, "o", "i"] +[192.486134, "o", "t"] +[192.603117, "o", " "] +[192.760821, "o", "t"] +[193.200036, "o", "a"] +[193.312331, "o", "s"] +[193.394453, "o", "k"] +[193.64356, "o", "\r\n(gdb) "] +[194.059159, "o", "# lets try to change the name of the init task"] +[194.200533, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[Cprint ((struct task_struct *)0xc2530040)->comm"] +[194.696871, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[195.001944, "o", "\u001b[1P"] +[195.130213, "o", "\u001b[1P"] +[195.25889, "o", "\u001b[1P"] +[195.371085, "o", "\u001b[1P"] +[195.467539, "o", "\u001b[1@s"] +[195.576466, "o", "\u001b[1@e"] +[195.674887, "o", "\u001b[C\u001b[1@t\b"] +[196.091385, "o", "\u001b[1P"] +[196.667968, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[197.372014, "o", "="] +[197.836566, "o", "\""] +[198.397868, "o", "m"] +[198.641201, "o", "y"] +[198.786448, "o", " "] +[199.202986, "o", "i"] +[199.328892, "o", "n"] +[199.399589, "o", "i"] +[199.546621, "o", "t"] +[199.953016, "o", "\""] +[200.507538, "o", "\r\n"] +[200.509222, "o", "(gdb) "] +[201.635061, "o", "l"] +[202.13135, "o", "x"] +[202.315347, "o", "-"] +[202.499865, "o", "p"] +[202.599957, "o", "s"] +[203.002948, "o", "\r\n"] +[203.003048, "o", " TASK PID COMM\r\n"] +[203.00358, "o", "0xc17d02c0 0 swapper/0\r\n"] +[203.005085, "o", "0xc2530040 1 my init\r\n"] +[203.006102, "o", "0xc2534080 2 kthreadd\r\n"] +[203.006929, "o", "0xc25360c0 3 rcu_gp\r\n"] +[203.007705, "o", "0xc2537100 4 rcu_par_gp\r\n"] +[203.008617, "o", "0xc2545140 5 kworker/0:0\r\n"] +[203.009353, "o", "0xc2546180 6 kworker/0:0H\r\n"] +[203.010181, "o", "0xc25481c0 7 kworker/u2:0\r\n"] +[203.011118, "o", "0xc2549000 8 mm_percpu_wq\r\n"] +[203.01204, "o", "0xc254b040 9 ksoftirqd/0\r\n"] +[203.012888, "o", "0xc254c080 10 rcu_sched\r\n"] +[203.013708, "o", "0xc254e0c0 11 migration/0\r\n"] +[203.014465, "o", "0xc2572100 12 cpuhp/0\r\n"] +[203.015189, "o", "0xc2576140 13 kdevtmpfs\r\n"] +[203.015958, "o", "0xc2594180 14 netns\r\n"] +[203.016734, "o", "0xc26211c0 15 oom_reaper\r\n"] +[203.017489, "o", "0xc2623000 16 writeback\r\n"] +[203.018341, "o", "0xc26300c0 32 kblockd\r\n"] +[203.019184, "o", "\u001b[m--Type <RET> for more, q to quit, c to continue without paging--"] +[204.630436, "o", "q"] +[205.219018, "o", "\r\n"] +[205.21918, "o", "Quit\r\n(gdb) "] +[205.798038, "o", "#"] +[206.120012, "o", " "] +[206.779589, "o", "i"] +[206.88812, "o", "t"] +[206.992104, "o", " "] +[207.15961, "o", "l"] +[207.320891, "o", "o"] +[207.459826, "o", "o"] +[207.53892, "o", "k"] +[208.587042, "o", "s"] +[208.698803, "o", " "] +[208.831616, "o", "l"] +[209.003424, "o", "i"] +[209.131421, "o", "k"] +[209.216867, "o", "e"] +[209.312937, "o", " "] +[209.428128, "o", "i"] +[209.555208, "o", "t"] +[209.604274, "o", " "] +[209.818705, "o", "w"] +[209.898874, "o", "o"] +[210.09889, "o", "r"] +[210.579589, "o", "k"] +[210.714357, "o", "e"] +[210.840035, "o", "d"] +[210.966315, "o", ","] +[211.052435, "o", " "] +[211.231717, "o", "l"] +[211.310902, "o", "e"] +[211.454859, "o", "t"] +[211.664297, "o", "s"] +[211.723802, "o", " "] +[211.882806, "o", "v"] +[211.998969, "o", "e"] +[212.051506, "o", "r"] +[212.232489, "o", "i"] +[212.359529, "o", "f"] +[212.522225, "o", "y"] +[212.626748, "o", " "] +[212.871092, "o", "o"] +[212.971579, "o", "n"] +[213.059427, "o", " "] +[213.146803, "o", "t"] +[213.258418, "o", "h"] +[213.352468, "o", "e"] +[213.426922, "o", " "] +[213.58702, "o", "s"] +[213.627031, "o", "e"] +[213.712627, "o", "r"] +[213.770319, "o", "i"] +[213.875246, "o", "a"] +[213.970606, "o", "l"] +[214.04505, "o", " "] +[214.281377, "o", "t"] +[214.368606, "o", "e"] +[214.451128, "o", "r"] +[214.525736, "o", "m"] +[214.626505, "o", "i"] +[214.732978, "o", "n"] +[214.843079, "o", "a"] +[214.946548, "o", "l"] +[215.040742, "o", " "] +[215.129001, "o", "a"] +[215.228707, "o", "s"] +[215.440824, "o", " "] +[215.516404, "o", "w"] +[215.602238, "o", "e"] +[215.668078, "o", "l"] +[215.795141, "o", "l"] +[216.115205, "o", "\r\n(gdb) "] +[216.777487, "o", "quit\r\n"] +[216.777925, "o", "A debugging session is active.\r\n\r\n\tInferior 1 [process 1] will be detached.\r\n\r\nQuit anyway? (y or n) "] +[217.515133, "o", "y"] +[217.634805, "o", "\r\nDetaching from program: /linux/vmlinux, process 1\r\n"] +[217.635574, "o", "Ending remote debugging.\r\n"] +[217.635669, "o", "[Inferior 1 (process 1) detached]\r\n"] +[217.641009, "o", "make: *** [qemu/Makefile:54: gdb] Interrupt\r\n"] +[217.64117, "o", "\r\n$ "] +[219.594723, "o", "m"] +[219.722708, "o", "i"] +[219.798934, "o", "n"] +[219.896002, "o", "i"] +[219.930619, "o", "c"] +[220.032412, "o", "o"] +[220.090198, "o", "m"] +[220.218551, "o", "d"] +[220.306723, "o", " "] +[220.370933, "o", "-"] +[220.707384, "o", "D"] +[220.896138, "o", " "] +[221.002084, "o", "s"] +[221.096694, "o", "e"] +[221.183389, "o", "r"] +[221.794618, "o", "i"] +[221.921462, "o", "a"] +[221.996654, "o", "l"] +[222.162988, "o", "."] +[222.392328, "o", "p"] +[222.557563, "o", "t"] +[222.764497, "o", "s"] +[223.187221, "o", "\r\n"] +[223.187455, "o", "sh: 2: minicomd: not found\r\n$ "] +[224.66724, "o", "^[[A"] +[225.402255, "o", "\b \b"] +[225.554826, "o", "\b \b"] +[225.691215, "o", "\b \b\b \b"] +[226.362654, "o", "m"] +[226.467209, "o", "i"] +[226.562857, "o", "n"] +[226.611636, "o", "i"] +[227.616059, "o", "\t"] +[228.031284, "o", "\b\b"] +[228.626209, "o", "c"] +[228.648332, "o", "o"] +[228.698461, "o", "m"] +[228.962825, "o", " "] +[229.102646, "o", "-"] +[229.368508, "o", "D"] +[229.495185, "o", " "] +[229.758139, "o", "s"] +[229.818591, "o", "e"] +[229.898678, "o", "r"] +[229.974762, "o", "i"] +[230.066622, "o", "a"] +[230.152183, "o", "l"] +[230.320361, "o", "."] +[230.535407, "o", "p"] +[230.685811, "o", "t"] +[230.858324, "o", "r"] +[231.475343, "o", "\b \b"] +[231.555055, "o", "s"] +[232.066837, "o", "\r\n"] +[232.067795, "o", "\u001b[!p\u001b[?3;4l\u001b[4l\u001b>\u001b[0m\u001b(B\u001b[?1h\u001b=\u001b[H\u001b[2J"] +[232.068206, "o", "\u001b[?12l\u001b[?25h\nWelcome to minicom 2.7.1\r\n\nOPTIONS: I18n \r\nCompiled on Dec 23 2019, 02:06:26.\r\nPort serial.pts, 23:04:03\r\n\nPress CTRL-A Z for help on special keys\r\n\n"] +[233.35075, "o", "\n"] +[233.351449, "o", "Poky (Yocto Project Reference Distro) 2.3 qemux86 /dev/hvc0"] +[233.351645, "o", "\r\n"] +[233.352178, "o", "\n"] +[233.352783, "o", "qemux86 login: "] +[234.133563, "o", "r"] +[234.195403, "o", "o"] +[234.32743, "o", "o"] +[234.389808, "o", "t"] +[234.499891, "o", "\r\n"] +[234.57783, "o", "root@qemux86:~# "] +[236.736246, "o", "p"] +[236.82051, "o", "s"] +[237.011059, "o", " "] +[237.771638, "o", "|"] +[238.06792, "o", " "] +[238.256099, "o", "g"] +[238.451007, "o", "r"] +[238.539927, "o", "e"] +[238.556716, "o", "p"] +[238.721872, "o", " "] +[238.931081, "o", "i"] +[238.997795, "o", "n"] +[239.083429, "o", "i"] +[239.163794, "o", "t"] +[239.752972, "o", "\r\n"] +[239.829798, "o", " 1 root 2004 S {my init} init [5]"] +[239.830096, "o", "\r\n"] +[239.831476, "o", " 233 root 2828 S grep init"] +[239.831842, "o", "\r\n"] +[239.837405, "o", "root@qemux86:~# "] +[241.836556, "o", "#"] +[242.119664, "o", " "] +[242.29265, "o", "l"] +[242.475695, "o", "o"] +[242.571459, "o", "o"] +[242.659603, "o", "k"] +[242.771906, "o", "s"] +[242.961525, "o", " "] +[242.961819, "o", "l"] +[243.115372, "o", "i"] +[243.267339, "o", "k"] +[243.363311, "o", "e"] +[243.507086, "o", " "] +[243.748592, "o", "i"] +[243.875193, "o", "t"] +[243.947777, "o", " "] +[244.060305, "o", "r"] +[244.234349, "o", "e"] +[244.234757, "o", "a"] +[244.279319, "o", "l"] +[244.391006, "o", "l"] +[244.507177, "o", "y"] +[244.603117, "o", " "] +[244.737167, "o", "w"] +[244.821576, "o", "o"] +[244.925326, "o", "r"] +[245.107148, "o", "k"] +[245.227926, "o", "e"] +[245.314038, "o", "d"] +[245.596368, "o", "!"] +[246.03658, "o", "\r\n"] +[246.038158, "o", "root@qemux86:~# "] +[246.855569, "o", "\u001b[0m\u001b(B\u001b[7m\u001b[20;1H\u001b[K\u001b[?12l\u001b[?25h\u001b[?25lCTRL-A Z for help | 115200 8N1 | NOR | Minicom 2.7.1 | VT102 | Offline | al.pts\u001b[?12l\u001b[?25h\u001b[18;17H"] +[247.531022, "o", "\u001b[8;30H\u001b[?25l\u001b[0m\u001b(B\u001b(0lqqqqqqqqqqqqqqqqqqqqqqk\u001b[9;30Hx\u001b[0m\u001b(B Leave Minicom? \u001b[0m\u001b(B\u001b(0x\u001b[10;30Hx\u001b[0m\u001b(B No \u001b[0m\u001b(B\u001b(0x\u001b[11;30Hmqqqqqqqqqqqqqqqqqqqqqqj\u001b[10;51H\u001b[?25l\u001b[10;33H\u001b[0m\u001b(B\u001b[7m Yes "] +[249.067296, "o", "\u001b[?12l\u001b[?25h\u001b[8;1H\u001b[0m\u001b(BPress CTRL-A Z for help on special keys \u001b[9;1H \u001b[10;1H \u001b[11;1HPoky (Yocto Project Reference Distro) 2.3 qemux86 /de\u001b[18;17H\u001b[0m\u001b(B\u001b[7m\u001b[?12l\u001b[?25h"] +[249.067498, "o", "\u001b[?12l\u001b[?25h\u001b[0m\u001b(B\u001b[H\u001b[2J\u001b[?12l\u001b[?25h\u001b[?1l\u001b>\u001b[!p\u001b[?3;4l\u001b[4l\u001b>"] +[249.067617, "o", "$ "] +[250.232829, "o", "\r\n"] diff --git a/refs/pull/405/merge/_images/intr_x86.cast b/refs/pull/405/merge/_images/intr_x86.cast new file mode 100644 index 00000000..d92b215e --- /dev/null +++ b/refs/pull/405/merge/_images/intr_x86.cast @@ -0,0 +1,3663 @@ +{"version": 2, "width": 80, "height": 24, "timestamp": 1616275302, "idle_time_limit": 0.3, "env": {"SHELL": null, "TERM": "xterm"}} +[0.002597, "o", "$ "] +[1.210773, "o", "m"] +[1.257108, "o", "a"] +[1.329655, "o", "k"] +[1.444271, "o", "e"] +[2.225029, "o", " "] +[2.486972, "o", "g"] +[2.571123, "o", "d"] +[2.712604, "o", "b"] +[3.137145, "o", "\r\n"] +[3.142592, "o", "gdb -ex \"target remote localhost:1234\" /linux/vmlinux\r\n"] +[3.178567, "o", "\u001b[35;1m\u001b[35;1mGNU gdb \u001b[m\u001b[35;1m(Ubuntu 9.2-0ubuntu1~20.04) \u001b[m\u001b[35;1m9.2\u001b[m\u001b[35;1m\r\n\u001b[m\u001b[mCopyright (C) 2020 Free Software Foundation, Inc.\r\nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\r\nThis is free software: you are free to change and redistribute it.\r\nThere is NO WARRANTY, to the extent permitted by law.\r\nType \"show copying\" and \"show warranty\" for details.\r\nThis GDB was configured as \"x86_64-linux-gnu\".\r\nType \"show configuration\" for configuration details.\r\nFor bug reporting instructions, please see:\r\n<http://www.gnu.org/software/gdb/bugs/>.\r\nFind the GDB manual and other documentation resources online at:\r\n <http://www.gnu.org/software/gdb/documentation/>.\r\n\r\nFor help, type \"help\".\r\nType \"apropos word\" to search for commands related to \"word\"...\r\n"] +[3.178839, "o", "Reading symbols from \u001b[32m/linux/vmlinux\u001b[m...\r\n"] +[3.823297, "o", "Remote debugging using localhost:1234\r\n"] +[3.83722, "o", "\u001b[34m0xc15dcb62\u001b[m in \u001b[33mdefault_idle\u001b[m () at \u001b[32m./arch/x86/include/asm/irqflags.h\u001b[m:60\r\n"] +[3.837438, "o", "60\t\tasm volatile(\"sti; hlt\": : :\"memory\");\r\n"] +[3.8378, "o", "(gdb) "] +[4.409342, "o", "#"] +[4.546448, "o", " "] +[4.688783, "o", "l"] +[4.769813, "o", "e"] +[4.896733, "o", "t"] +[5.08933, "o", "s"] +[5.136694, "o", " "] +[5.248955, "o", "i"] +[5.312794, "o", "n"] +[5.544699, "o", "s"] +[7.409078, "o", "p"] +[7.489474, "o", "e"] +[7.549338, "o", "c"] +[7.761283, "o", "t"] +[7.849505, "o", " "] +[7.969004, "o", "t"] +[8.040895, "o", "h"] +[8.152802, "o", "e"] +[8.224916, "o", " "] +[9.001867, "o", "i"] +[9.058176, "o", "n"] +[9.136243, "o", "t"] +[9.208632, "o", "e"] +[9.328647, "o", "r"] +[9.488109, "o", "r"] +[9.560597, "o", "u"] +[9.616715, "o", "p"] +[9.704462, "o", "t"] +[9.768614, "o", " "] +[9.976697, "o", "d"] +[10.145135, "o", "e"] +[10.289399, "o", "s"] +[10.328932, "o", "c"] +[10.52121, "o", "r"] +[10.592935, "o", "i"] +[10.656572, "o", "p"] +[10.772899, "o", "t"] +[10.880715, "o", "o"] +[10.98227, "o", "r"] +[11.128859, "o", " "] +[11.25683, "o", "t"] +[11.337146, "o", "a"] +[11.448688, "o", "b"] +[12.394915, "o", "l"] +[12.872587, "o", "e"] +[12.944672, "o", "\r\n"] +[12.944804, "o", "(gdb) "] +[15.485987, "o", "m"] +[15.546043, "o", "o"] +[15.688577, "o", "n"] +[15.73704, "o", "i"] +[15.832722, "o", "t"] +[15.928729, "o", "o"] +[15.993344, "o", "r"] +[16.057039, "o", " "] +[16.15264, "o", "i"] +[16.208593, "o", "n"] +[16.304808, "o", "f"] +[16.361885, "o", "o"] +[16.464359, "o", " "] +[16.577512, "o", "r"] +[16.655247, "o", "e"] +[16.817514, "o", "g"] +[17.064809, "o", "i"] +[17.297122, "o", "s"] +[17.903967, "o", "t"] +[18.064885, "o", "e"] +[18.144619, "o", "r"] +[18.312803, "o", "s"] +[18.392803, "o", "\r\n"] +[18.392969, "o", "EAX=00000000 EBX=00000000 ECX=ffffffff EDX"] +[18.39299, "o", "=0000"] +[18.393076, "o", "0000\r\r\nESI=00000000 EDI=00000000 EBP=c17cff1c ESP=c17cff18\r\r\nEIP=c15dcb62 EFL=002002"] +[18.393171, "o", "46 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=1\r\r\n"] +[18.393206, "o", "ES =007b 00000000 ffffffff 00cff300 DPL=3 DS [-WA]\r\r\nCS =0060 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]\r\r\nSS =0068 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]\r\r\nDS =007b 00000000 ffffffff 00c"] +[18.393256, "o", "ff300 DPL=3 DS [-WA]\r\r\n"] +[18.393291, "o", "FS =00d8 0e47b000 ffffffff 008f9300 DPL=0 DS16 [-WA]\r\r\n"] +[18.393383, "o", "GS =00e0 cfdcb200 00000018 00409100 DPL=0 DS [--A]\r\r\nLDT=0000 00000000 00000000 00008200 DPL=0 LDT\r"] +[18.393415, "o", "\r\nTR =0080 ff806000 0000407b 00008900 DPL=0 T"] +[18.393444, "o", "SS32-avl\r\r\nGDT= ff801000 000000f"] +[18.393521, "o", "f\r\r\nIDT= ff800000 000007ff\r\r\nCR0=80050033 CR2=08087000 CR3=0"] +[18.393616, "o", "760b000 CR4=00000690\r\r\nDR0=00000000 DR1=00000000 "] +[18.393737, "o", "DR2=00000000 DR3=00000000 \r\r\nDR6=ffff0ff0 DR7=00000400\r\r\nEFER=0000000000000000\r\r\nFCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80\r\r\nFPR0=0000000000000000 0000 FPR1=0000000000000000 0000\r\r\nFPR2=0000000000000000 0000 FPR3=0000000000000000 0000\r\r\nFPR4=0000000000000000 0000 FPR"] +[18.393842, "o", "5=0000000000000000 0000\r\r\nFPR6=0000000000000000 0000 FPR7=0000000000000000 0000\r\r\nXMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000\r\r\nXMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000\r\r\nXMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000\r\r\n"] +[18.393943, "o", "XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000\r\r\n"] +[18.394056, "o", "(gdb) "] +[19.913615, "o", "s"] +[19.986157, "o", "e"] +[20.072668, "o", "t"] +[20.144869, "o", " "] +[20.312693, "o", "$"] +[21.121104, "o", "i"] +[21.208933, "o", "d"] +[21.448991, "o", "t"] +[21.608711, "o", "r"] +[21.849094, "o", "="] +[23.480497, "o", "0"] +[23.632689, "o", "x"] +[26.420845, "o", "ff800000"] +[27.416954, "o", "\r\n"] +[27.43416, "o", "(gdb) "] +[30.696589, "o", "#"] +[30.808186, "o", " "] +[30.960552, "o", "l"] +[31.040432, "o", "e"] +[31.168404, "o", "t"] +[31.344474, "o", "s"] +[31.440553, "o", " "] +[31.560787, "o", "l"] +[31.712465, "o", "o"] +[31.832592, "o", "o"] +[31.896851, "o", "k"] +[32.041676, "o", " "] +[32.224318, "o", "a"] +[32.432482, "o", "t"] +[32.52061, "o", " "] +[32.66456, "o", "t"] +[32.728814, "o", "h"] +[32.872205, "o", "e"] +[32.952481, "o", " "] +[33.048492, "o", "f"] +[33.136789, "o", "i"] +[33.216711, "o", "r"] +[35.611379, "o", "s"] +[35.94449, "o", "t"] +[36.241248, "o", " "] +[36.768841, "o", "e"] +[36.985022, "o", "n"] +[37.104804, "o", "t"] +[37.208381, "o", "r"] +[37.322459, "o", "y"] +[37.569352, "o", "\r\n"] +[37.569487, "o", "(gdb) "] +[53.808615, "o", "p"] +[53.97653, "o", "r"] +[54.409035, "o", "i"] +[54.528791, "o", "n"] +[54.664632, "o", "t"] +[54.816835, "o", " "] +[55.391071, "o", "("] +[56.353133, "o", "\b\u001b[K"] +[56.705533, "o", "*"] +[56.984674, "o", "("] +[57.401646, "o", "u"] +[57.598027, "o", "i"] +[57.661018, "o", "n"] +[57.696843, "o", "t"] +[58.032644, "o", "4"] +[58.392875, "o", "_"] +[58.694782, "o", "\b\u001b[K"] +[58.794268, "o", "\b\u001b[K"] +[58.858317, "o", "6"] +[58.912611, "o", "4"] +[59.10469, "o", "_"] +[59.336364, "o", "t"] +[59.74071, "o", "*"] +[59.880803, "o", ")"] +[60.704722, "o", "$"] +[60.98509, "o", "i"] +[61.094169, "o", "d"] +[61.321053, "o", "t"] +[61.480931, "o", "r"] +[62.248357, "o", "\r\n"] +[62.253459, "o", "$1 = 13933448952811676512\r\n"] +[62.253518, "o", "(gdb) "] +[63.977116, "o", "print *(uint64_t*)$idtr"] +[64.304911, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[64.456992, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[65.080291, "o", "/ *(uint64_t*)$idtr\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[65.416962, "o", "\b\u001b[1P *(uint64_t*)$idtr\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[65.497236, "o", "\u001b[C *(uint64_t*)$idtr\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[65.609571, "o", "/ *(uint64_t*)$idtr\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[65.889038, "o", "x *(uint64_t*)$idtr\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[65.993566, "o", "\r\n"] +[65.993861, "o", "$2 = 0xc15d8e000060e360\r\n(gdb) "] +[68.328319, "o", "#"] +[68.608617, "o", " "] +[71.984353, "o", "t"] +[72.048655, "o", "h"] +[72.144372, "o", "e"] +[72.281093, "o", " "] +[73.216663, "o", "t"] +[73.240818, "o", "o"] +[73.368648, "o", "p"] +[73.464534, "o", " "] +[73.576581, "o", "1"] +[73.85665, "o", "6"] +[74.11258, "o", " "] +[74.26418, "o", "b"] +[74.408592, "o", "i"] +[74.488681, "o", "t"] +[74.736972, "o", "s"] +[74.785856, "o", " "] +[75.320694, "o", "|"] +[75.408819, "o", " "] +[75.928337, "o", "l"] +[76.105728, "o", "o"] +[76.169532, "o", "w"] +[76.257743, "o", "e"] +[76.329013, "o", "r"] +[76.432359, "o", " "] +[76.632745, "o", "1"] +[76.896585, "o", "6"] +[77.265121, "o", " "] +[77.456494, "o", "b"] +[77.55218, "o", "i"] +[77.640654, "o", "t"] +[78.424438, "o", "s"] +[78.576779, "o", " "] +[79.9295, "o", "y"] +[80.207199, "o", "i"] +[81.156076, "o", "e"] +[81.342966, "o", "l"] +[81.464422, "o", "d"] +[81.544827, "o", " "] +[81.712818, "o", "t"] +[81.777406, "o", "h"] +[81.896729, "o", "e"] +[82.016527, "o", " "] +[83.160488, "o", "h"] +[83.234273, "o", "a"] +[83.373947, "o", "n"] +[83.457305, "o", "d"] +[83.560818, "o", "l"] +[83.648667, "o", "e"] +[83.736063, "o", "r"] +[83.832315, "o", " "] +[83.904474, "o", "a"] +[84.01645, "o", "d"] +[84.17622, "o", "d"] +[84.441953, "o", "r"] +[84.515239, "o", "e"] +[84.648335, "o", "s"] +[84.793111, "o", "s"] +[84.889616, "o", "\r\n"] +[84.889676, "o", "(gdb) "] +[87.657834, "o", "p"] +[88.328467, "o", "r"] +[88.457638, "o", "i"] +[88.528292, "o", "n"] +[88.592033, "o", "t"] +[89.216915, "o", " "] +[92.096493, "o", "("] +[92.318607, "o", "v"] +[92.401482, "o", "o"] +[92.466573, "o", "i"] +[92.552621, "o", "d"] +[92.71269, "o", " "] +[93.041067, "o", "*"] +[93.136553, "o", ")"] +[100.020065, "o", "0xc15d"] +[102.915226, "o", "e360"] +[103.87249, "o", "\r\n"] +[103.872714, "o", "$3 = (void *) \u001b[34m0xc15de360\u001b[m <\u001b[33masm_exc_divide_error\u001b[m>\r\n(gdb) "] +[108.216616, "o", "#"] +[109.256576, "o", " "] +[110.240848, "o", "l"] +[110.461673, "o", "o"] +[110.584304, "o", "o"] +[110.624509, "o", "k"] +[110.735996, "o", "s"] +[110.840183, "o", " "] +[111.256571, "o", "l"] +[111.484022, "o", "i"] +[111.992971, "o", "k"] +[112.192703, "o", "e"] +[112.333386, "o", " "] +[112.425705, "o", "t"] +[112.499041, "o", "h"] +[112.600559, "o", "e"] +[112.718099, "o", " "] +[112.88867, "o", "h"] +[112.952432, "o", "a"] +[113.056426, "o", "n"] +[113.690225, "o", "d"] +[113.936437, "o", "l"] +[114.032295, "o", "e"] +[114.112253, "o", "r"] +[114.215985, "o", " "] +[114.377083, "o", "f"] +[114.452839, "o", "o"] +[114.592553, "o", "r"] +[114.66679, "o", " "] +[114.809895, "o", "t"] +[114.903547, "o", "h"] +[114.976958, "o", "e"] +[115.112512, "o", " "] +[116.177138, "o", "d"] +[116.32823, "o", "i"] +[116.424191, "o", "v"] +[116.496866, "o", "i"] +[116.600329, "o", "s"] +[116.712739, "o", "i"] +[116.752259, "o", "o"] +[116.937502, "o", "n"] +[117.0166, "o", " "] +[117.281132, "o", "b"] +[117.360604, "o", "y"] +[117.47323, "o", " "] +[117.704485, "o", "z"] +[117.904681, "o", "e"] +[117.989636, "o", "r"] +[118.096365, "o", "o"] +[118.232856, "o", " "] +[118.720624, "o", "e"] +[118.832219, "o", "x"] +[119.064653, "o", "c"] +[119.150155, "o", "e"] +[119.337024, "o", "p"] +[119.664612, "o", "t"] +[119.760425, "o", "i"] +[119.800127, "o", "o"] +[119.984793, "o", "n"] +[120.26515, "o", "\r\n(gdb) "] +[120.728331, "o", "#"] +[120.920995, "o", " "] +[121.064451, "o", "l"] +[121.160676, "o", "e"] +[121.536815, "o", "t"] +[121.786124, "o", "s"] +[121.896173, "o", " "] +[122.080241, "o", "l"] +[122.240363, "o", "o"] +[122.376315, "o", "o"] +[122.408674, "o", "k"] +[122.624537, "o", " "] +[122.773709, "o", "a"] +[122.945429, "o", "t"] +[123.023878, "o", " "] +[123.953626, "o", "ot"] +[124.080277, "o", "h"] +[124.200363, "o", "er"] +[124.728617, "o", " "] +[125.002233, "o", "h"] +[125.064643, "o", "a"] +[125.184089, "o", "n"] +[125.256259, "o", "d"] +[125.392308, "o", "l"] +[125.488306, "o", "e"] +[125.552441, "o", "r"] +[125.741692, "o", "s"] +[126.768744, "o", "\r\n"] +[126.768865, "o", "(gdb) "] +[127.240409, "o", "#"] +[127.480474, "o", " "] +[127.784631, "o", "b"] +[127.944921, "o", "u"] +[128.040904, "o", "t"] +[128.225533, "o", " "] +[130.732997, "o", "l"] +[130.808467, "o", "e"] +[130.968259, "o", "t"] +[131.176344, "o", "s"] +[131.32975, "o", " "] +[131.488296, "o", "d"] +[131.5519, "o", "e"] +[131.689568, "o", "f"] +[131.785467, "o", "i"] +[131.837318, "o", "n"] +[131.904581, "o", "e"] +[132.024328, "o", " "] +[132.160185, "o", "a"] +[132.271963, "o", " "] +[133.464111, "o", "g"] +[133.584141, "o", "d"] +[133.696892, "o", "b"] +[133.79681, "o", " "] +[134.217167, "o", "m"] +[134.304136, "o", "a"] +[134.408321, "o", "c"] +[134.656512, "o", "r"] +[134.721337, "o", "o"] +[134.822577, "o", " "] +[134.991044, "o", "t"] +[135.071573, "o", "o"] +[135.111997, "o", " "] +[135.272574, "o", "m"] +[135.362308, "o", "a"] +[135.456211, "o", "k"] +[135.544994, "o", "e"] +[135.616461, "o", " "] +[135.727963, "o", "t"] +[135.792452, "o", "h"] +[135.857291, "o", "i"] +[136.000758, "o", "n"] +[136.069751, "o", "g"] +[136.257128, "o", "s"] +[136.328766, "o", " "] +[136.510165, "o", "e"] +[136.633035, "o", "a"] +[136.832209, "o", "s"] +[136.960217, "o", "i"] +[137.048799, "o", "e"] +[137.150086, "o", "r"] +[138.744006, "o", "\r\n(gdb) "] +[139.568515, "o", "d"] +[139.653984, "o", "e"] +[139.784679, "o", "f"] +[139.872147, "o", "i"] +[139.912416, "o", "n"] +[139.993159, "o", "e"] +[140.104365, "o", " "] +[140.296306, "o", "i"] +[140.363786, "o", "d"] +[140.665088, "o", "t"] +[140.92836, "o", "_"] +[141.136493, "o", "e"] +[141.360228, "o", "n"] +[141.448491, "o", "t"] +[141.624792, "o", "r"] +[141.713426, "o", "y"] +[142.721123, "o", "\r\n"] +[142.721216, "o", "Type commands for definition of \"idt_entry\".\r\nEnd with a line saying just \"end\".\r\n>"] +[168.576695, "o", "s"] +[168.624243, "o", "e"] +[168.737408, "o", "t"] +[168.824664, "o", " "] +[169.336803, "o", "$"] +[169.680096, "o", "t"] +[169.88103, "o", "m"] +[170.352694, "o", "p"] +[170.935949, "o", "="] +[173.920126, "o", "\b\u001b[K"] +[174.064076, "o", " "] +[174.216635, "o", "="] +[174.303854, "o", " "] +[177.336069, "o", "("] +[178.712525, "o", "$"] +[179.374062, "o", "d"] +[179.720264, "o", "i"] +[180.160492, "o", "\b\u001b[K"] +[180.289725, "o", "\b\u001b[K"] +[180.43246, "o", "\b\u001b[K"] +[181.432386, "o", "\b\u001b[K"] +[181.864182, "o", "*"] +[182.041353, "o", "("] +[182.320662, "o", "u"] +[183.224845, "o", "i"] +[183.288156, "o", "n"] +[183.424563, "o", "t"] +[183.920426, "o", "6"] +[184.016392, "o", "4"] +[184.22467, "o", "_"] +[184.505022, "o", "t"] +[185.017063, "o", "*"] +[185.520732, "o", ")"] +[186.288322, "o", "("] +[186.812369, "o", "$"] +[187.415985, "o", "i"] +[187.600868, "o", "d"] +[188.142718, "o", "t"] +[188.312029, "o", "r"] +[188.616543, "o", " "] +[189.064819, "o", "+"] +[189.264592, "o", " "] +[189.680228, "o", "8"] +[189.848238, "o", " "] +[190.617403, "o", "*"] +[190.760083, "o", " "] +[191.959835, "o", "%"] +[192.576085, "o", "\b\u001b[K"] +[192.844777, "o", "$"] +[193.048452, "o", "a"] +[193.159941, "o", "r"] +[193.376555, "o", "g"] +[193.982847, "o", "0"] +[194.431687, "o", ")"] +[197.999312, "o", "\r\n"] +[197.999456, "o", ">"] +[198.449303, "o", "p"] +[198.665073, "o", "r"] +[198.735942, "o", "i"] +[198.808033, "o", "n"] +[198.888752, "o", "t"] +[199.016048, "o", " "] +[199.417075, "o", "("] +[199.736133, "o", "v"] +[199.848015, "o", "o"] +[199.944772, "o", "i"] +[200.024132, "o", "d"] +[200.286196, "o", " "] +[200.704083, "o", ")"] +[201.349769, "o", "\b\u001b[K"] +[201.704144, "o", "*"] +[201.872195, "o", ")"] +[203.840273, "o", "("] +[205.772822, "o", "("] +[208.496616, "o", "$"] +[209.18405, "o", "t"] +[209.256793, "o", "m"] +[209.36482, "o", "p"] +[209.775923, "o", ">"] +[209.912509, "o", ">"] +[210.839657, "o", "4"] +[210.888609, "o", "8"] +[211.215805, "o", "<"] +[211.336883, "o", "<"] +[211.61268, "o", "1"] +[211.976222, "o", "6"] +[212.74975, "o", ")"] +[213.984241, "o", "|"] +[214.624311, "o", "("] +[215.122175, "o", "T"] +[215.780469, "o", "\b\u001b[K"] +[215.993115, "o", "$"] +[216.224093, "o", "t"] +[216.34352, "o", "m"] +[216.424, "o", "p"] +[217.560837, "o", "&"] +[218.328697, "o", "0"] +[218.632066, "o", "x"] +[218.968103, "o", "f"] +[219.150939, "o", "f"] +[219.727887, "o", "f"] +[219.863865, "o", "f"] +[220.912413, "o", ")"] +[222.079895, "o", ")"] +[223.568547, "o", "\r\n"] +[223.568676, "o", ">"] +[224.094006, "o", "e"] +[224.223863, "o", "n"] +[224.287703, "o", "d"] +[224.744944, "o", "\r\n"] +[224.745116, "o", "(gdb) "] +[225.951864, "o", "i"] +[226.096427, "o", "d"] +[226.680474, "o", "\b\u001b[K"] +[226.872108, "o", "t"] +[228.156402, "o", "\b\u001b[K"] +[228.205096, "o", "d"] +[228.440636, "o", "t"] +[228.631859, "o", "_"] +[229.039821, "o", "e"] +[229.167518, "o", "n"] +[229.256696, "o", "t"] +[229.433937, "o", "r"] +[229.505089, "o", "y"] +[229.631679, "o", " "] +[229.840572, "o", "0"] +[230.040276, "o", "\r\n"] +[238.488909, "o", "$4 = (void *) \u001b[34m0xc15de360\u001b[m <\u001b[33masm_exc_divide_error\u001b[m>\r\n(gdb) "] +[242.8967, "o", "s"] +[243.00697, "o", "e"] +[243.128131, "o", "t"] +[243.183821, "o", " "] +[243.402228, "o", "$"] +[243.592398, "o", "i"] +[243.967633, "o", "="] +[244.505775, "o", "0"] +[245.649837, "o", "\r\n"] +[245.667678, "o", "(gdb) "] +[246.494615, "o", "i"] +[246.951918, "o", "d"] +[247.159916, "o", "t"] +[247.288617, "o", "_"] +[247.44043, "o", "e"] +[247.606119, "o", "n"] +[247.677569, "o", "t"] +[247.824446, "o", "r"] +[247.919894, "o", "y"] +[248.064502, "o", " "] +[248.368428, "o", "$i"] +[248.812484, "o", "+"] +[248.95182, "o", "+"] +[249.296086, "o", "\r\n"] +[251.440221, "o", "$5 = (void *) \u001b[34m0xc15de360\u001b[m <\u001b[33masm_exc_divide_error\u001b[m>\r\n(gdb) "] +[252.647928, "o", "\r\n"] +[252.648357, "o", "$6 = (void *) \u001b[34m0xc15de460\u001b[m <\u001b[33masm_exc_debug\u001b[m>\r\n(gdb) "] +[253.671712, "o", "\r\n"] +[253.672097, "o", "$7 = (void *) \u001b[34m0xc15dec28\u001b[m <\u001b[33masm_exc_nmi\u001b[m>\r\n(gdb) "] +[254.280864, "o", "\r\n"] +[254.281363, "o", "$8 = (void *) \u001b[34m0xc15de440\u001b[m <\u001b[33masm_exc_int3\u001b[m>\r\n(gdb) "] +[254.976139, "o", "\r\n"] +[254.976557, "o", "$9 = (void *) \u001b[34m0xc15de370\u001b[m <\u001b[33masm_exc_overflow\u001b[m>\r\n(gdb) "] +[255.880408, "o", "\r\n"] +[255.880837, "o", "$10 = (void *) \u001b[34m0xc15de380\u001b[m <\u001b[33masm_exc_bounds\u001b[m>\r\n(gdb) "] +[256.624516, "o", "\r\n"] +[256.625069, "o", "$11 = (void *) \u001b[34m0xc15de430\u001b[m <\u001b[33masm_exc_invalid_op\u001b[m>\r\n(gdb) "] +[259.776172, "o", "#"] +[259.983837, "o", " "] +[260.136287, "o", "n"] +[260.210913, "o", "o"] +[260.615863, "o", "w"] +[260.791336, "o", " "] +[261.016063, "o", "l"] +[261.088278, "o", "e"] +[261.231738, "o", "t"] +[261.455678, "o", "s"] +[261.535942, "o", " "] +[264.927751, "o", "d"] +[265.007746, "o", "i"] +[265.080717, "o", "s"] +[265.76765, "o", "a"] +[265.920288, "o", "s"] +[266.056377, "o", "s"] +[266.663988, "o", "e"] +[266.744341, "o", "m"] +[266.91189, "o", "b"] +[267.063396, "o", "l"] +[267.136112, "o", "e"] +[267.231659, "o", " "] +[271.856077, "o", "o"] +[272.111984, "o", "n"] +[272.262555, "o", "e"] +[272.334059, "o", " "] +[272.495286, "o", "o"] +[272.567329, "o", "f"] +[272.655262, "o", " "] +[272.78918, "o", "t"] +[272.849964, "o", "h"] +[272.944092, "o", "e"] +[273.016315, "o", " "] +[273.112499, "o", "h"] +[273.184169, "o", "a"] +[273.301118, "o", "n"] +[273.399638, "o", "d"] +[273.495596, "o", "l"] +[273.600002, "o", "e"] +[273.672038, "o", "r"] +[273.871971, "o", "s"] +[274.591341, "o", "\r\n(gdb) "] +[281.693904, "o", "d"] +[281.813581, "o", "i"] +[282.81517, "o", "s"] +[283.118047, "o", "a"] +[283.2217, "o", "s"] +[284.374128, "o", "semble "] +[293.053957, "o", "a"] +[293.157762, "o", "s"] +[293.229719, "o", "m"] +[293.708297, "o", "E"] +[294.133992, "o", "\b\u001b[K"] +[294.448654, "o", "_"] +[294.706454, "o", "e"] +[294.829897, "o", "x"] +[295.462678, "o", "c"] +[296.67153, "o", "\u0007_"] +[297.946193, "o", "d"] +[298.135012, "o", "i"] +[298.685772, "o", "\b\u001b[K"] +[299.178835, "o", "i"] +[299.621804, "o", "v"] +[299.733826, "o", "i"] +[299.902348, "o", "de_error "] +[300.549988, "o", "\r\n"] +[300.567393, "o", "Dump of assembler code for function asm_exc_divide_error:\r\n"] +[300.56769, "o", " \u001b[34m0xc15de360\u001b[m <+0>:\tlea 0x0(%esi),%esi\r\n \u001b[34m0xc15de363\u001b[m <+3>:\tcld \r\n \u001b[34m0xc15de364\u001b[m <+4>:\tpush $0x0\r\n \u001b[34m0xc15de366\u001b[m <+6>:\tpush $0xc15d1ff0\r\n"] +[300.567847, "o", " \u001b[34m0xc15de36b\u001b[m <+11>:\tjmp \u001b[34m0xc15dea1f\u001b[m <\u001b[33mhandle_exception\u001b[m>\r\nEnd of assembler dump.\r\n(gdb) "] +[301.973744, "o", "#"] +[302.290429, "o", " "] +[306.773991, "o", "t"] +[306.89402, "o", "h"] +[306.989409, "o", "e"] +[307.078564, "o", " "] +[307.205506, "o", "h"] +[307.269547, "o", "a"] +[307.381896, "o", "n"] +[307.462694, "o", "d"] +[307.606051, "o", "l"] +[307.683098, "o", "e"] +[307.782006, "o", "r"] +[307.90709, "o", " "] +[308.102037, "o", "i"] +[308.205644, "o", "s"] +[308.309779, "o", " "] +[308.649061, "o", "s"] +[308.719819, "o", "a"] +[308.909582, "o", "v"] +[309.045065, "o", "i"] +[309.111041, "o", "n"] +[309.181535, "o", "g"] +[309.357861, "o", " "] +[309.791576, "o", "0"] +[310.205523, "o", "\b\u001b[K"] +[310.317771, "o", "z"] +[310.52606, "o", "e"] +[310.645389, "o", "r"] +[310.709449, "o", "o"] +[311.925803, "o", " "] +[313.89363, "o", "\r\u001b[K(gdb) # the handler is saving zero "] +[316.414294, "o", "a"] +[316.646282, "o", "n"] +[316.757604, "o", "d"] +[317.310478, "o", " "] +[318.758069, "o", "a"] +[318.854419, "o", " "] +[320.037966, "o", "k"] +[320.158956, "o", "e"] +[320.222516, "o", "r"] +[320.27824, "o", "n"] +[320.397617, "o", "e"] +[320.478095, "o", "l"] +[320.573709, "o", " "] +[320.653434, "o", "a"] +[320.765976, "o", "d"] +[320.931418, "o", "d"] +[321.115711, "o", "r"] +[321.16469, "o", "e"] +[321.317561, "o", "s"] +[321.469813, "o", "s"] +[321.533551, "o", " "] +[321.637537, "o", "o"] +[321.77303, "o", "n"] +[322.051753, "o", " "] +[322.229659, "o", "t"] +[322.334768, "o", "h"] +[322.397494, "o", "e"] +[322.493585, "o", " "] +[322.581569, "o", "s"] +[322.726173, "o", "t"] +[322.789718, "o", "a"] +[322.966867, "o", "c"] +[323.01384, "o", "k"] +[323.861459, "o", "\r\n(gdb) "] +[324.400657, "o", "#"] +[324.57396, "o", " "] +[324.718055, "o", "t"] +[324.837389, "o", "h"] +[324.925552, "o", "e"] +[325.053448, "o", "n"] +[325.131599, "o", " "] +[325.541878, "o", "c"] +[325.656711, "o", "a"] +[325.789362, "o", "l"] +[325.917952, "o", "l"] +[326.215003, "o", "s"] +[326.405569, "o", " "] +[327.862046, "o", "a"] +[328.005901, "o", " "] +[328.509434, "o", "g"] +[328.589852, "o", "e"] +[328.718961, "o", "n"] +[328.794376, "o", "e"] +[329.046122, "o", "r"] +[329.197525, "o", "i"] +[329.413451, "o", "c"] +[329.589576, "o", " "] +[334.125557, "o", "e"] +[334.229684, "o", "x"] +[334.294128, "o", "c"] +[334.397658, "o", "c"] +[334.49939, "o", "e"] +[334.582127, "o", "p"] +[334.711478, "o", "t"] +[334.796324, "o", "i"] +[334.829615, "o", "o"] +[335.309853, "o", "\b\u001b[K"] +[337.093887, "o", "o"] +[337.253827, "o", "n"] +[337.758199, "o", "\b"] +[338.268806, "o", "\b"] +[338.299872, "o", "\b"] +[338.329696, "o", "\b"] +[338.52618, "o", "\b"] +[338.693918, "o", "\b"] +[338.898897, "o", "\b"] +[338.940108, "o", "\u001b[1Peption\b\b\b\b\b\b"] +[339.31746, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[339.987467, "o", " "] +[340.501724, "o", "h"] +[340.557371, "o", "a"] +[340.669201, "o", "n"] +[340.781539, "o", "d"] +[340.893346, "o", "l"] +[340.986467, "o", "e"] +[341.107449, "o", "r"] +[341.189818, "o", " "] +[341.310107, "o", "f"] +[341.404177, "o", "u"] +[341.477608, "o", "n"] +[341.589586, "o", "c"] +[341.805591, "o", "t"] +[341.877429, "o", "i"] +[341.917582, "o", "o"] +[342.116466, "o", "n"] +[342.669981, "o", "\r\n(gdb) "] +[344.453707, "o", "p"] +[344.573486, "o", "r"] +[344.651746, "o", "i"] +[344.710394, "o", "n"] +[344.773933, "o", "t"] +[344.853496, "o", " "] +[345.133258, "o", "("] +[345.301217, "o", "v"] +[345.423574, "o", "o"] +[345.509734, "o", "i"] +[345.611679, "o", "d"] +[346.432047, "o", "*"] +[346.853663, "o", "\b\u001b[K"] +[347.541327, "o", "*"] +[347.72567, "o", ")"] +[351.837485, "o", "0xc15d1f"] +[351.838034, "o", "f0"] +[352.917933, "o", "\r\n"] +[352.923702, "o", "$1 = (void *) \u001b[34m0xc15d1ff0\u001b[m <\u001b[33mexc_divide_error\u001b[m>\r\n(gdb) "] +[357.542556, "o", "#"] +[357.837506, "o", " "] +[361.282757, "o", "t"] +[361.413551, "o", "h"] +[361.525554, "o", "is"] +[361.653148, "o", " "] +[362.214023, "o", "l"] +[362.389469, "o", "o"] +[362.541643, "o", "o"] +[362.877329, "o", "k"] +[363.062173, "o", "s"] +[363.118787, "o", " "] +[363.269731, "o", "l"] +[363.453393, "o", "i"] +[363.621546, "o", "k"] +[363.709514, "o", "e"] +[363.862147, "o", " "] +[364.222054, "o", "t"] +[364.349865, "o", "h"] +[364.517649, "o", "e"] +[364.613482, "o", " "] +[365.373866, "o", "\b\u001b[K"] +[365.523605, "o", "\b\u001b[K"] +[365.653717, "o", "\b\u001b[K"] +[365.797269, "o", "\b\u001b[K"] +[366.093498, "o", "a"] +[366.2068, "o", " "] +[366.345557, "o", "p"] +[366.427604, "o", "o"] +[366.62164, "o", "i"] +[366.685247, "o", "n"] +[366.749103, "o", "t"] +[366.830172, "o", "e"] +[366.957418, "o", "r"] +[367.093461, "o", " "] +[367.222757, "o", "t"] +[367.270164, "o", "o"] +[367.350376, "o", " "] +[367.453392, "o", "t"] +[367.549486, "o", "h"] +[367.650301, "o", "e"] +[367.708818, "o", " "] +[367.989708, "o", "a"] +[368.125641, "o", "c"] +[368.378932, "o", "t"] +[368.468498, "o", "u"] +[368.590227, "o", "a"] +[368.710298, "o", "l"] +[368.813341, "o", " "] +[369.021547, "o", "e"] +[373.138639, "o", "c"] +[373.285424, "o", "a"] +[373.493441, "o", "p"] +[373.701029, "o", "t"] +[373.861883, "o", "i"] +[373.909667, "o", "o"] +[374.132304, "o", "\b\u001b[K"] +[374.261891, "o", "\b\u001b[K"] +[374.414046, "o", "\b\u001b[K"] +[374.565314, "o", "\b\u001b[K"] +[374.709345, "o", "\b\u001b[K"] +[374.853559, "o", "\b\u001b[K"] +[374.886, "o", "x"] +[375.125274, "o", "c"] +[375.203406, "o", "e"] +[375.277276, "o", "p"] +[375.42167, "o", "t"] +[375.510506, "o", "i"] +[375.533335, "o", "o"] +[375.701534, "o", "n"] +[375.789484, "o", " "] +[375.965816, "o", "h"] +[375.97305, "o", "a"] +[376.16194, "o", "n"] +[376.453783, "o", "d"] +[376.589277, "o", "l"] +[376.701185, "o", "e"] +[376.765614, "o", "r"] +[376.917157, "o", " "] +[378.366234, "o", "\r\n"] +[378.366312, "o", "(gdb) "] +[378.696508, "o", "#"] +[378.819592, "o", " "] +[378.981518, "o", "i"] +[379.141542, "o", "s"] +[379.261122, "o", " "] +[379.406101, "o", "p"] +[379.469324, "o", "a"] +[379.557497, "o", "s"] +[379.725858, "o", "s"] +[379.816754, "o", "e"] +[379.925361, "o", "d"] +[380.021135, "o", " "] +[380.173176, "o", "t"] +[380.229575, "o", "o"] +[380.333106, "o", " "] +[380.485699, "o", "t"] +[380.605346, "o", "h"] +[380.734993, "o", "e"] +[380.836656, "o", " "] +[382.373895, "o", "g"] +[382.445188, "o", "e"] +[382.525518, "o", "n"] +[382.621654, "o", "e"] +[382.787196, "o", "r"] +[382.978124, "o", "i"] +[383.142264, "o", "c"] +[383.317634, "o", " "] +[383.819866, "o", "h"] +[383.878201, "o", "a"] +[383.99007, "o", "n"] +[384.089685, "o", "d"] +[384.197318, "o", "l"] +[384.277425, "o", "e"] +[384.461334, "o", "_"] +[384.661346, "o", "e"] +[384.79798, "o", "x"] +[385.006099, "o", "c"] +[385.090299, "o", "e"] +[385.170675, "o", "p"] +[385.310365, "o", "t"] +[385.389772, "o", "i"] +[385.421608, "o", "o"] +[385.581386, "o", "n"] +[386.20595, "o", "\r\n"] +[386.206176, "o", "(gdb) "] +[389.230197, "o", "#"] +[390.26918, "o", " "] +[391.325411, "o", "l"] +[391.42176, "o", "e"] +[391.581594, "o", "t"] +[391.774324, "o", "s"] +[391.886397, "o", " "] +[392.301564, "o", "s"] +[392.421411, "o", "e"] +[392.541767, "o", "t"] +[392.623009, "o", " "] +[392.706636, "o", "a"] +[392.840467, "o", " "] +[393.090357, "o", "b"] +[393.453217, "o", "r"] +[393.541455, "o", "e"] +[393.605239, "o", "a"] +[394.046616, "o", "k"] +[394.291075, "o", "p"] +[394.380916, "o", "o"] +[394.621516, "o", "n"] +[394.725214, "o", "t"] +[395.107038, "o", "\b\u001b[K"] +[395.413324, "o", "\b\u001b[K"] +[395.717268, "o", "i"] +[395.797318, "o", "n"] +[395.949174, "o", "t"] +[396.005249, "o", " "] +[396.160391, "o", "t"] +[396.222933, "o", "o"] +[396.301863, "o", " "] +[396.485547, "o", "h"] +[396.525186, "o", "a"] +[396.661547, "o", "n"] +[396.773364, "o", "d"] +[396.853597, "o", "l"] +[396.989123, "o", "e"] +[397.290232, "o", "_"] +[397.493521, "o", "e"] +[397.629719, "o", "x"] +[397.837301, "o", "c"] +[397.901283, "o", "e"] +[397.981223, "o", "p"] +[398.141235, "o", "t"] +[398.262293, "o", "o"] +[398.309802, "o", "p"] +[398.933271, "o", "\b\u001b[K"] +[399.005854, "o", "\b\u001b[K"] +[399.342381, "o", "i"] +[399.390296, "o", "o"] +[399.637201, "o", "n"] +[400.021147, "o", " "] +[400.134629, "o", "a"] +[400.253125, "o", "n"] +[400.333322, "o", "d"] +[400.437249, "o", " "] +[400.549161, "o", "s"] +[400.686474, "o", "e"] +[400.814467, "o", "e"] +[400.933556, "o", " "] +[402.002187, "o", "w"] +[402.205377, "o", "h"] +[402.229328, "o", "a"] +[402.397324, "o", "t"] +[402.4851, "o", " "] +[402.621307, "o", "w"] +[402.725189, "o", "e"] +[402.805449, "o", " "] +[402.949896, "o", "c"] +[403.035235, "o", "a"] +[403.253098, "o", "t"] +[403.437365, "o", "c"] +[403.509643, "o", "h"] +[403.973799, "o", "\r\n(gdb) "] +[404.677037, "o", "b"] +[404.765978, "o", "r"] +[404.837523, "o", "e"] +[404.89348, "o", "a"] +[404.965381, "o", "k"] +[405.069983, "o", " "] +[405.469329, "o", "h"] +[405.573246, "o", "a"] +[405.693381, "o", "n"] +[405.789649, "o", "d"] +[405.870641, "o", "l"] +[406.413246, "o", "\u0007e"] +[406.509294, "o", "e"] +[407.118199, "o", "\b\u001b[K"] +[407.3744, "o", "_"] +[407.550122, "o", "e"] +[407.725281, "o", "x"] +[407.938177, "o", "\u0007"] +[408.415128, "o", "c"] +[408.520749, "o", "\u0007eption"] +[408.893296, "o", "\r\n"] +[408.924833, "o", "Breakpoint 1 at \u001b[34m0xc15dea1f\u001b[m: file \u001b[32march/x86/entry/entry_32.S\u001b[m, line 1154.\r\n(gdb) "] +[416.67716, "o", "c"] +[417.078529, "o", "\r\nContinuing.\r\n"] +[417.083919, "o", "\r\n"] +[417.084103, "o", "Breakpoint 1, \u001b[33mhandle_exception\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:1154\r\n"] +[417.084192, "o", "1154\t\tSAVE_ALL switch_stacks=1 skip_gs=1 unwind_espfix=1\r\n(gdb) "] +[429.509889, "o", "#"] +[429.68491, "o", " "] +[429.877508, "o", "i"] +[429.981148, "o", "f"] +[430.109307, "o", " "] +[430.221386, "o", "w"] +[430.309864, "o", "e"] +[430.590443, "o", " "] +[430.809819, "o", "l"] +[430.989816, "o", "o"] +[431.117, "o", "o"] +[431.189041, "o", "k"] +[431.277218, "o", " "] +[431.437363, "o", "a"] +[431.661354, "o", "t"] +[431.725226, "o", " "] +[431.862491, "o", "t"] +[431.979484, "o", "h"] +[432.045404, "o", "e"] +[432.134089, "o", " "] +[432.277058, "o", "s"] +[432.421149, "o", "t"] +[432.469089, "o", "a"] +[432.667918, "o", "c"] +[432.732989, "o", "k"] +[432.893494, "o", " "] +[433.333128, "o", "w"] +[433.412995, "o", "e"] +[433.500507, "o", " "] +[433.653242, "o", "s"] +[433.757095, "o", "h"] +[433.829678, "o", "o"] +[433.948148, "o", "u"] +[434.073821, "o", "l"] +[434.132601, "o", "d"] +[434.22928, "o", " "] +[434.34112, "o", "f"] +[434.397286, "o", "i"] +[434.492998, "o", "n"] +[434.566083, "o", "d"] +[434.677046, "o", " "] +[434.821839, "o", "t"] +[434.909696, "o", "h"] +[434.995523, "o", "e"] +[435.090817, "o", " "] +[437.581687, "o", "a"] +[437.781198, "o", "c"] +[438.013647, "o", "t"] +[438.077543, "o", "u"] +[438.206204, "o", "a"] +[438.294424, "o", "l"] +[438.416002, "o", " "] +[439.485411, "o", "e"] +[439.630758, "o", "x"] +[439.829008, "o", "c"] +[439.916901, "o", "e"] +[439.964921, "o", "p"] +[440.140749, "o", "t"] +[440.215078, "o", "i"] +[440.253158, "o", "o"] +[440.465997, "o", "n"] +[440.573062, "o", " "] +[441.141509, "o", "h"] +[441.173285, "o", "a"] +[441.333677, "o", "n"] +[441.405478, "o", "d"] +[441.53343, "o", "l"] +[441.605845, "o", "e"] +[441.67794, "o", "r"] +[444.222754, "o", "\r\n"] +[444.222812, "o", "(gdb) "] +[445.323324, "o", "p"] +[445.469488, "o", "r"] +[445.541673, "o", "i"] +[445.605066, "o", "n"] +[445.693078, "o", "t"] +[445.838045, "o", " "] +[449.204742, "o", "("] +[449.662622, "o", "v"] +[449.701787, "o", "o"] +[449.789464, "o", "i"] +[449.861186, "o", "d"] +[449.955706, "o", " "] +[450.269467, "o", "*"] +[450.429896, "o", ")"] +[452.877512, "o", "("] +[453.661196, "o", "\b\u001b[K"] +[454.00543, "o", "(*"] +[454.210726, "o", "("] +[454.700739, "o", "i"] +[455.037441, "o", "\b\u001b[K"] +[455.25302, "o", "u"] +[455.43756, "o", "i"] +[455.510815, "o", "n"] +[455.628939, "o", "t"] +[456.820983, "o", "3"] +[456.909062, "o", "2"] +[457.044863, "o", "_"] +[457.213162, "o", "t"] +[457.685637, "o", " "] +[458.29388, "o", "*"] +[458.455775, "o", ")"] +[459.281591, "o", "e"] +[459.837464, "o", "\b\u001b[K"] +[460.301045, "o", "$"] +[460.868861, "o", "e"] +[461.03713, "o", "s"] +[461.101321, "o", "p"] +[461.786512, "o", ")"] +[464.477246, "o", "\r\n"] +[472.463976, "o", "$2 = (void *) \u001b[34m0xc15d3840\u001b[m <\u001b[33msysvec_apic_timer_interrupt\u001b[m>\r\n(gdb) "] +[483.413856, "o", "#"] +[483.613547, "o", " "] +[484.941064, "o", "t"] +[485.036894, "o", "h"] +[485.101573, "o", "i"] +[485.277486, "o", "s"] +[485.365346, "o", " "] +[485.782102, "o", "l"] +[485.989418, "o", "o"] +[486.117103, "o", "o"] +[486.197077, "o", "k"] +[486.333443, "o", "s"] +[486.413088, "o", " "] +[486.581136, "o", "l"] +[486.733891, "o", "i"] +[486.912819, "o", "k"] +[487.002561, "o", "e"] +[487.095043, "o", " "] +[487.261133, "o", "t"] +[487.333274, "o", "h"] +[487.46896, "o", "e"] +[487.550243, "o", " "] +[495.172835, "o", "t"] +[495.373523, "o", "i"] +[495.437104, "o", "m"] +[495.540612, "o", "e"] +[495.604806, "o", "r"] +[495.74046, "o", " "] +[496.74974, "o", "i"] +[496.813502, "o", "n"] +[496.93292, "o", "t"] +[497.037013, "o", "e"] +[497.229265, "o", "r"] +[497.372827, "o", "r"] +[497.500693, "o", "u"] +[497.556563, "o", "p"] +[497.673852, "o", "t"] +[498.109885, "o", "\r\n"] +[498.110099, "o", "(gdb) "] +[522.221171, "o", "#"] +[522.444874, "o", " "] +[522.684901, "o", "n"] +[522.91456, "o", "e"] +[523.316756, "o", "\b\u001b[K"] +[523.428746, "o", "\b\u001b[K"] +[523.500892, "o", "t"] +[523.644472, "o", "h"] +[523.757109, "o", "e"] +[523.955806, "o", " "] +[524.099169, "o", "n"] +[524.155454, "o", "e"] +[524.22103, "o", "x"] +[524.508979, "o", "t"] +[524.604798, "o", " "] +[525.057219, "o", "i"] +[525.162621, "o", "t"] +[525.389208, "o", "e"] +[525.469892, "o", "m"] +[525.55658, "o", " "] +[525.668816, "o", "o"] +[525.989001, "o", "n"] +[526.192028, "o", " "] +[526.28711, "o", "t"] +[526.422465, "o", "h"] +[526.493339, "o", "e"] +[526.589426, "o", " "] +[526.717587, "o", "s"] +[527.157628, "o", "t"] +[527.290422, "o", "a"] +[527.525162, "o", "c"] +[527.597243, "o", "k"] +[527.724964, "o", " "] +[527.965348, "o", "s"] +[528.029266, "o", "h"] +[528.101143, "o", "o"] +[528.21352, "o", "u"] +[528.373131, "o", "l"] +[528.509865, "o", "d"] +[528.53395, "o", " "] +[528.733472, "o", "b"] +[528.821848, "o", "e"] +[528.876906, "o", " "] +[529.052799, "o", "0"] +[529.726391, "o", "\r\n"] +[529.726579, "o", "(gdb) "] +[531.685101, "o", "# the next item on the stack should be 0"] +[532.28286, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[3Pis looks like the timer interrupt"] +[532.958122, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[4Pprint (void *)(*(uint32_t *)$esp)"] +[533.365021, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b*(uint32_t *)$esp))"] +[533.700966, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b(*(uint32_t *)$esp)"] +[534.021436, "o", "\b"] +[534.221855, "o", "\b"] +[534.373191, "o", "\b"] +[534.530437, "o", "\b"] +[534.692778, "o", "\b"] +[536.140976, "o", "($esp)\b\b\b\b\b"] +[536.886188, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[537.029022, "o", "\b"] +[537.809435, "o", "+)\b"] +[537.989237, "o", "4)\b"] +[538.365079, "o", "\u001b[C)\b"] +[539.157186, "o", "\r\n"] +[539.157943, "o", "$3 = (void *) \u001b[34m0x0\u001b[m\r\n(gdb) "] +[541.245538, "o", "#"] +[541.460923, "o", " "] +[541.588649, "o", "t"] +[541.708909, "o", "h"] +[541.828839, "o", "e"] +[541.909914, "o", " "] +[542.068789, "o", "n"] +[542.109349, "o", "e"] +[542.166431, "o", "x"] +[542.469912, "o", "t"] +[542.558985, "o", " "] +[542.725111, "o", "s"] +[542.813268, "o", "h"] +[542.956594, "o", "o"] +[543.036718, "o", "u"] +[543.185591, "o", "l"] +[543.269565, "o", "d"] +[543.340548, "o", " "] +[543.494185, "o", "b"] +[543.564801, "o", "e"] +[543.637447, "o", " "] +[544.053085, "o", "t"] +[544.124773, "o", "h"] +[544.250569, "o", "e"] +[544.290687, "o", " "] +[544.404605, "o", "o"] +[544.565768, "o", "l"] +[544.65011, "o", "d"] +[544.764418, "o", " "] +[546.425323, "o", "E"] +[547.028847, "o", "I"] +[547.16456, "o", "P"] +[548.300627, "o", "\r\n"] +[548.300792, "o", "(gdb) "] +[548.989397, "o", "# the next should be the old EIP"] +[549.173162, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[Cprint (void *)(*(uint32_t *)($esp+4))"] +[549.899257, "o", "\b"] +[550.129437, "o", "\b"] +[550.282812, "o", "\b"] +[552.748678, "o", "\u001b[1P))\b\b"] +[553.452994, "o", "8))\b\b"] +[554.357074, "o", "\r\n"] +[554.357422, "o", "$4 = (void *) \u001b[34m0xc15dcb62\u001b[m <\u001b[33mdefault_idle\u001b[m+18>\r\n(gdb) "] +[555.42081, "o", "#"] +[555.706632, "o", " "] +[555.853611, "o", "t"] +[555.981142, "o", "h"] +[556.060689, "o", "i"] +[556.180769, "o", "s"] +[556.276646, "o", " "] +[556.452498, "o", "l"] +[556.645524, "o", "o"] +[556.777618, "o", "o"] +[556.860672, "o", "k"] +[557.01089, "o", "s"] +[557.060819, "o", " "] +[557.204509, "o", "l"] +[557.364288, "o", "i"] +[557.524835, "o", "k"] +[557.597177, "o", "e"] +[557.71496, "o", " "] +[557.821078, "o", "a"] +[557.916565, "o", " "] +[558.074038, "o", "k"] +[558.189048, "o", "e"] +[558.261556, "o", "r"] +[558.308555, "o", "n"] +[558.404654, "o", "e"] +[558.500443, "o", "l"] +[558.596666, "o", " "] +[559.580743, "o", "f"] +[559.70893, "o", "u"] +[559.788765, "o", "n"] +[559.885141, "o", "c"] +[560.121613, "o", "t"] +[560.162133, "o", "i"] +[560.209714, "o", "o"] +[560.613052, "o", "n"] +[561.118427, "o", "\r\n(gdb) "] +[561.62926, "o", "#"] +[561.836781, "o", " "] +[561.988412, "o", "t"] +[562.10054, "o", "h"] +[562.164515, "o", "i"] +[562.261046, "o", "s"] +[562.3572, "o", " "] +[562.724997, "o", "m"] +[562.805154, "o", "e"] +[562.892772, "o", "a"] +[563.028918, "o", "n"] +[563.15677, "o", "s"] +[563.493188, "o", " "] +[563.741062, "o", "t"] +[563.886535, "o", "h"] +[563.957787, "o", "a"] +[564.029028, "o", "t"] +[564.180631, "o", " "] +[564.673213, "o", "w"] +[564.781861, "o", "e"] +[564.951458, "o", " "] +[567.116541, "o", "h"] +[567.164956, "o", "a"] +[567.385305, "o", "d"] +[567.533309, "o", " "] +[570.307091, "o", "a"] +[570.973109, "o", "n"] +[571.052577, "o", " "] +[571.196558, "o", "i"] +[571.276673, "o", "n"] +[571.356641, "o", "t"] +[571.437049, "o", "e"] +[571.573147, "o", "r"] +[571.733301, "o", "r"] +[571.820704, "o", "u"] +[571.886457, "o", "p"] +[571.980515, "o", "t"] +[572.061059, "o", " "] +[572.212575, "o", "w"] +[572.26865, "o", "i"] +[572.44514, "o", "t"] +[572.50106, "o", "h"] +[572.649694, "o", " "] +[572.810376, "o", "a"] +[573.596771, "o", "\b\u001b[K"] +[573.719587, "o", "\b\u001b[K"] +[573.948986, "o", "o"] +[574.060044, "o", "u"] +[574.200126, "o", "t"] +[574.245857, "o", " "] +[574.380757, "o", "a"] +[574.452561, "o", " "] +[574.9488, "o", "p"] +[575.129864, "o", "r"] +[575.246245, "o", "i"] +[575.436917, "o", "v"] +[575.500921, "o", "i"] +[575.708822, "o", "l"] +[575.788518, "o", "e"] +[576.069274, "o", "d"] +[576.335142, "o", "g"] +[576.405962, "o", "e"] +[577.434405, "o", " "] +[577.67696, "o", "t"] +[577.88499, "o", "r"] +[577.980284, "o", "a"] +[578.876849, "o", "s"] +[578.980703, "o", "i"] +[579.149228, "o", "t"] +[579.221513, "o", "i"] +[579.26884, "o", "o"] +[579.41719, "o", "n"] +[579.677291, "o", "\r\n(gdb) "] +[589.020658, "o", "#"] +[589.341219, "o", " "] +[589.660946, "o", "s"] +[589.676545, "o", "o"] +[589.89489, "o", " "] +[591.052951, "o", "t"] +[591.257618, "o", "h"] +[591.35662, "o", "e"] +[592.084943, "o", " "] +[592.410388, "o", "n"] +[592.465233, "o", "e"] +[592.604429, "o", "x"] +[592.900822, "o", "t"] +[593.012732, "o", " "] +[595.93505, "o", "v"] +[596.021101, "o", "a"] +[596.124525, "o", "l"] +[596.372663, "o", "u"] +[596.516986, "o", "e"] +[596.533116, "o", " "] +[596.716689, "o", "o"] +[596.916453, "o", "n"] +[597.012654, "o", " "] +[597.149, "o", "s"] +[597.33301, "o", "t"] +[597.396858, "o", "a"] +[597.605076, "o", "c"] +[597.716706, "o", "k"] +[597.781734, "o", " "] +[597.970938, "o", "s"] +[598.061845, "o", "h"] +[598.148867, "o", "o"] +[598.266043, "o", "u"] +[598.412427, "o", "l"] +[598.492956, "o", "d"] +[598.58072, "o", " "] +[598.748929, "o", "b"] +[598.828818, "o", "e"] +[598.986377, "o", " "] +[600.612464, "o", "t"] +[600.701426, "o", "h"] +[600.828697, "o", "e"] +[600.908559, "o", " "] +[604.24482, "o", "o"] +[604.501075, "o", "l"] +[604.637138, "o", "d"] +[604.810185, "o", " "] +[605.22084, "o", "C"] +[605.340414, "o", "S"] +[609.981442, "o", " "] +[610.100291, "o", "a"] +[610.245237, "o", "n"] +[610.285745, "o", "d"] +[610.436727, "o", " "] +[610.55753, "o", "t"] +[610.668519, "o", "h"] +[610.75681, "o", "e"] +[610.860497, "o", " "] +[612.298872, "o", "o"] +[612.500901, "o", "l"] +[612.54844, "o", "d"] +[612.645586, "o", " "] +[612.86999, "o", "E"] +[613.068337, "o", "F"] +[613.14841, "o", "L"] +[613.228911, "o", "A"] +[613.389277, "o", "G"] +[613.509013, "o", "S"] +[614.292855, "o", "\r\n"] +[614.29299, "o", "(gdb) "] +[615.946645, "o", "# so the next value on stack should be the old CS and the old EFLAGS"] +[616.276692, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[Cthis means that we had an interrupt without a priviledge trasition"] +[616.484792, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[33Plooks like a kernel function"] +[617.009785, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[Cprint (void *)(*(uint32_t *)($esp+8))"] +[617.540423, "o", "\b"] +[617.69268, "o", "\b"] +[617.836936, "o", "\b"] +[618.204688, "o", "\u001b[1P))\b\b"] +[620.260979, "o", "1))\b\b"] +[620.381284, "o", "2))\b\b"] +[620.932544, "o", "\r\n"] +[620.933245, "o", "$5 = (void *) \u001b[34m0x60\u001b[m\r\n(gdb) "] +[632.741989, "o", "p"] +[632.876823, "o", "r"] +[633.012803, "o", "i"] +[633.08155, "o", "n"] +[633.188878, "o", "t"] +[633.757256, "o", " "] +[634.436865, "o", "/"] +[634.937002, "o", "x"] +[635.085661, "o", " "] +[635.388506, "o", "$"] +[636.389874, "o", "c"] +[636.468457, "o", "s"] +[636.764836, "o", "\r\n"] +[636.765008, "o", "$6 = 0x60\r\n(gdb) "] +[641.676586, "o", "#"] +[641.884708, "o", " "] +[641.996872, "o", "a"] +[642.091842, "o", "s"] +[642.196689, "o", " "] +[642.364633, "o", "e"] +[642.484294, "o", "x"] +[642.802488, "o", "p"] +[643.045976, "o", "e"] +[643.164662, "o", "c"] +[643.444844, "o", "t"] +[643.508529, "o", "e"] +[643.708582, "o", "d"] +[643.884817, "o", " "] +[651.548692, "o", "t"] +[653.215508, "o", "h"] +[653.281727, "o", "e"] +[653.413871, "o", " "] +[653.644609, "o", "s"] +[653.772321, "o", "a"] +[653.908641, "o", "m"] +[654.164845, "o", "e"] +[654.828484, "o", " "] +[655.301976, "o", "C"] +[655.497877, "o", "S"] +[655.781698, "o", " "] +[656.109023, "o", "v"] +[656.172724, "o", "a"] +[656.308716, "o", "l"] +[656.540506, "o", "u"] +[656.655112, "o", "e"] +[662.412599, "o", " "] +[666.32495, "o", "\b\u001b[K"] +[682.380362, "o", ","] +[682.516746, "o", " "] +[682.812541, "o", "L"] +[683.084916, "o", "ui"] +[683.17327, "o", "n"] +[683.260224, "o", "u"] +[683.34001, "o", "x"] +[683.388145, "o", " "] +[683.805756, "o", "\b\u001b[K"] +[683.924955, "o", "\b\u001b[K"] +[684.052826, "o", "\b\u001b[K"] +[684.187913, "o", "\b\u001b[K"] +[684.316421, "o", "\b\u001b[K"] +[684.452334, "o", "\b\u001b[K"] +[684.588384, "o", "i"] +[684.78853, "o", "n"] +[684.851703, "o", "u"] +[684.951339, "o", "x"] +[685.045154, "o", " "] +[685.154943, "o", "u"] +[685.236579, "o", "s"] +[685.396194, "o", "e"] +[685.50896, "o", "s"] +[685.62021, "o", " "] +[685.748478, "o", "t"] +[685.887377, "o", "e"] +[686.001983, "o", " "] +[686.332372, "o", "\b\u001b[K"] +[686.461598, "o", "\b\u001b[K"] +[686.644619, "o", "h"] +[686.700338, "o", "e"] +[686.7799, "o", " "] +[686.908468, "o", "s"] +[686.996325, "o", "a"] +[687.068521, "o", "m"] +[687.229012, "o", "e"] +[687.306456, "o", " "] +[687.692433, "o", "c"] +[687.79635, "o", "o"] +[687.916226, "o", "d"] +[687.956423, "o", "e"] +[688.052213, "o", " "] +[688.155815, "o", "s"] +[688.297346, "o", "e"] +[688.411731, "o", "l"] +[688.508792, "o", "e"] +[688.589641, "o", "c"] +[688.80467, "o", "t"] +[688.884059, "o", "o"] +[688.972059, "o", "r"] +[689.837294, "o", "\r\n(gdb) "] +[690.13223, "o", "#"] +[690.276507, "o", " "] +[690.468264, "o", "f"] +[690.572263, "o", "o"] +[690.699264, "o", "r"] +[690.983585, "o", " "] +[691.284204, "o", "a"] +[691.372385, "o", "l"] +[691.524311, "o", "l"] +[691.572643, "o", " "] +[691.756121, "o", "t"] +[691.884368, "o", "h"] +[691.968393, "o", "e"] +[692.060258, "o", " "] +[692.396261, "o", "L"] +[692.644795, "o", "i"] +[692.772298, "o", "n"] +[692.846376, "o", "u"] +[692.950449, "o", "x"] +[693.074016, "o", " "] +[693.412476, "o", "k"] +[693.54072, "o", "e"] +[693.60488, "o", "r"] +[693.652141, "o", "n"] +[693.781041, "o", "e"] +[693.842522, "o", "l"] +[693.932546, "o", " "] +[694.093549, "o", "c"] +[694.188975, "o", "o"] +[694.325315, "o", "d"] +[694.372717, "o", "e"] +[699.204488, "o", "\r\n"] +[699.204575, "o", "(gdb) "] +[699.694945, "o", "#"] +[700.025409, "o", " "] +[701.082078, "o", "a"] +[701.219865, "o", "n"] +[701.300717, "o", "d"] +[701.428262, "o", " "] +[701.516018, "o", "a"] +[701.620252, "o", " "] +[701.762559, "o", "d"] +[701.884545, "o", "i"] +[701.964346, "o", "f"] +[702.396072, "o", "f"] +[702.644607, "o", "e"] +[702.772976, "o", "r"] +[702.857454, "o", "e"] +[702.979937, "o", "n"] +[703.105594, "o", "t"] +[703.205114, "o", " "] +[704.469353, "o", "s"] +[704.684404, "o", "e"] +[704.892085, "o", "l"] +[704.948089, "o", "e"] +[705.01199, "o", "c"] +[705.252192, "o", "t"] +[705.378083, "o", "o"] +[705.45294, "o", "r"] +[705.620379, "o", " "] +[705.788126, "o", "f"] +[705.996593, "o", "o"] +[706.156069, "o", "r"] +[706.324525, "o", " "] +[706.563158, "o", "u"] +[706.619009, "o", "s"] +[706.668009, "o", "e"] +[706.738935, "o", "r"] +[707.340183, "o", " "] +[707.444058, "o", "c"] +[707.564119, "o", "o"] +[707.684062, "o", "d"] +[707.740063, "o", "e"] +[709.035117, "o", " "] +[709.180598, "o", "a"] +[709.228019, "o", "s"] +[709.349715, "o", " "] +[709.444522, "o", "w"] +[709.564695, "o", "e"] +[709.588558, "o", "i"] +[709.803763, "o", "l"] +[710.268131, "o", "\b\u001b[K"] +[710.421074, "o", "\b\u001b[K"] +[710.581086, "o", "\b\u001b[K"] +[711.029269, "o", "e"] +[711.172267, "o", " "] +[711.356432, "o", "w"] +[711.452408, "o", "i"] +[711.604825, "o", "l"] +[711.760514, "o", "l"] +[711.809979, "o", " "] +[712.108216, "o", "s"] +[712.284343, "o", "e"] +[712.420395, "o", "e"] +[712.531941, "o", "\r\n"] +[712.531998, "o", "(gdb) "] +[717.364429, "o", "# and a different selector for user code as we will see"] +[717.579692, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[24Pfor all the Linux kernel code"] +[718.022257, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[Cas expected the same CS value, Linux uses the same code selector"] +[718.427912, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[Cprint /x $cs\u001b[K"] +[718.843933, "o", "\b\b\b\b\b\b(void *)(*(uint32_t *)($esp+12))"] +[719.45271, "o", "\b"] +[719.612108, "o", "\b"] +[719.748109, "o", "\b"] +[720.321698, "o", "\u001b[1P))\b\b"] +[722.604741, "o", "6))\b\b"] +[723.284228, "o", "\r\n"] +[723.284909, "o", "$7 = (void *) \u001b[34m0x200246\u001b[m\r\n(gdb) "] +[732.228199, "o", "#"] +[732.483837, "o", " "] +[732.66115, "o", "t"] +[732.804463, "o", "h"] +[732.886263, "o", "e"] +[733.104678, "o", "s"] +[733.16471, "o", "e"] +[733.692292, "o", " "] +[733.789016, "o", "a"] +[733.937223, "o", "r"] +[734.012056, "o", "e"] +[734.069023, "o", " "] +[734.220446, "o", "t"] +[734.286456, "o", "h"] +[734.380547, "o", "e"] +[734.467934, "o", " "] +[734.596123, "o", "o"] +[734.981382, "o", "l"] +[735.133112, "o", "d"] +[735.268121, "o", " "] +[736.004384, "o", "E"] +[736.201581, "o", "F"] +[736.284997, "o", "L"] +[736.38164, "o", "A"] +[736.540379, "o", "G"] +[736.716525, "o", "S"] +[737.628709, "o", "\r\n"] +[737.628991, "o", "(gdb) "] +[756.459919, "o", "#"] +[756.713355, "o", " "] +[756.972562, "o", "l"] +[757.372058, "o", "e"] +[757.555961, "o", "t"] +[757.715745, "o", "s"] +[757.811866, "o", " "] +[757.900933, "o", "s"] +[758.100942, "o", "t"] +[758.252254, "o", "e"] +[758.836667, "o", "p"] +[759.136686, "o", " "] +[759.34112, "o", "t"] +[759.619803, "o", "h"] +[759.723904, "o", "o"] +[759.740077, "o", "r"] +[759.892415, "o", "u"] +[759.988008, "o", "g"] +[760.092285, "o", "h"] +[760.209389, "o", "t"] +[760.52954, "o", "\b\u001b[K"] +[760.659839, "o", "\b\u001b[K"] +[760.796107, "o", "\b\u001b[K"] +[760.924285, "o", "\b\u001b[K"] +[761.060871, "o", "\b\u001b[K"] +[761.49694, "o", "\b\u001b[K"] +[761.677155, "o", "r"] +[761.77997, "o", "o"] +[761.940033, "o", "u"] +[762.444551, "o", "g"] +[762.500741, "o", "h"] +[762.62848, "o", " "] +[762.752533, "o", "t"] +[762.795851, "o", "h"] +[762.901139, "o", "e"] +[762.972318, "o", " "] +[763.076113, "o", "e"] +[763.163768, "o", "x"] +[763.891933, "o", "c"] +[763.964072, "o", "e"] +[764.075829, "o", "p"] +[764.220556, "o", "t"] +[764.299718, "o", "i"] +[764.339842, "o", "o"] +[764.500348, "o", "n"] +[764.580435, "o", " "] +[764.749173, "o", "h"] +[764.805422, "o", "a"] +[764.940176, "o", "n"] +[765.00449, "o", "d"] +[765.172277, "o", "l"] +[765.259869, "o", "e"] +[765.36498, "o", "r"] +[767.092697, "o", "\r\n(gdb) "] +[769.452692, "o", "n"] +[769.492828, "o", "e"] +[769.60402, "o", "x"] +[769.852194, "o", "t"] +[770.75791, "o", "\r\n"] +[770.817206, "o", "\u001b[33mhandle_exception\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:1155\r\n1155\t\tENCODE_FRAME_POINTER\r\n(gdb) "] +[771.979803, "o", "\r\n"] +[771.984483, "o", "1158\t\tGS_TO_REG %ecx\r\n(gdb) "] +[772.901642, "o", "\r\n"] +[772.904154, "o", "1159\t\tmovl\tPT_GS(%esp), %edi\t\t# get the function address\r\n(gdb) "] +[774.044833, "o", "\r\n"] +[774.047555, "o", "1160\t\tREG_TO_PTGS %ecx\r\n(gdb) "] +[775.068367, "o", "\r\n"] +[775.071481, "o", "1161\t\tSET_KERNEL_GS %ecx\r\n(gdb) "] +[776.020547, "o", "\r\n"] +[776.024942, "o", "1164\t\tmovl\tPT_ORIG_EAX(%esp), %edx\t\t# get the error code\r\n(gdb) "] +[777.372032, "o", "\r\n"] +[777.374254, "o", "1165\t\tmovl\t$-1, PT_ORIG_EAX(%esp)\t\t# no syscall to restart\r\n(gdb) "] +[778.932072, "o", "\r\n"] +[778.935109, "o", "1167\t\tmovl\t%esp, %eax\t\t\t# pt_regs pointer\r\n(gdb) "] +[780.084544, "o", "\r\n"] +[780.087079, "o", "1168\t\tCALL_NOSPEC edi\r\n"] +[780.087242, "o", "(gdb) "] +[789.068946, "o", "t"] +[789.163754, "o", "h"] +[789.227926, "o", "i"] +[789.364066, "o", "s"] +[789.475736, "o", " "] +[789.77071, "o", "s"] +[789.845352, "o", "h"] +[789.900666, "o", "o"] +[790.01865, "o", "u"] +[790.164322, "o", "l"] +[790.212024, "o", "d"] +[790.379831, "o", " "] +[790.843865, "o", "c"] +[790.948496, "o", "a"] +[790.98792, "o", "l"] +[791.099624, "o", "l"] +[791.179854, "o", " "] +[791.884188, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[792.124312, "o", "\u001b[1@#"] +[792.300147, "o", "\u001b[1@ "] +[792.523828, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[793.004183, "o", "t"] +[793.108772, "o", "h"] +[793.244482, "o", "e"] +[793.283931, "o", " "] +[794.948292, "o", "a"] +[795.052886, "o", "c"] +[795.267741, "o", "t"] +[795.332027, "o", "u"] +[795.443685, "o", "a"] +[795.53154, "o", "l"] +[795.643762, "o", " "] +[795.755946, "o", "e"] +[795.875998, "o", "x"] +[796.076283, "o", "c"] +[796.163912, "o", "e"] +[796.291666, "o", "p"] +[796.507701, "o", "t"] +[796.564221, "o", "i"] +[796.619819, "o", "o"] +[796.787619, "o", "n"] +[796.876639, "o", " "] +[797.227727, "o", "h"] +[797.347798, "o", "a"] +[797.453011, "o", "n"] +[797.531866, "o", "d"] +[797.643736, "o", "l"] +[797.731685, "o", "e"] +[797.811748, "o", "r"] +[798.716546, "o", "\r\n(gdb) "] +[799.81999, "o", "p"] +[799.969817, "o", "r"] +[800.040246, "o", "i"] +[800.120984, "o", "n"] +[800.180163, "o", "t"] +[800.347919, "o", " "] +[800.969409, "o", "/"] +[801.120768, "o", "x"] +[801.221364, "o", " "] +[801.500176, "o", "$"] +[802.020108, "o", "e"] +[802.260097, "o", "d"] +[802.451977, "o", "i"] +[803.732078, "o", "\r\n"] +[803.732203, "o", "$8 = 0xc15d3840\r\n(gdb) "] +[806.04535, "o", "print /x $edi"] +[806.435671, "o", "\b"] +[806.952968, "o", "\b"] +[806.979538, "o", "\b"] +[807.01104, "o", "\b"] +[807.042755, "o", "\b"] +[807.604211, "o", "\b\u001b[1P $edi\b\b\b\b\b"] +[807.724321, "o", "\b\u001b[1P $edi\b\b\b\b\b"] +[808.12947, "o", "( $edi\b\b\b\b\b"] +[808.30103, "o", "v $edi\b\b\b\b\b"] +[808.400349, "o", "o $edi\b\b\b\b\b"] +[808.459861, "o", "i $edi\b\b\b\b\b"] +[808.54765, "o", "d $edi\b\b\b\b\b"] +[808.691701, "o", "\u001b[C $edi\b\b\b\b\b"] +[808.964799, "o", "* $edi\b\b\b\b\b"] +[809.100734, "o", ") $edi\b\b\b\b\b"] +[809.780431, "o", "\u001b[1P$edi\b\b\b\b"] +[810.188463, "o", "\r\n"] +[810.188589, "o", "$9 = (void *) \u001b[34m0xc15d3840\u001b[m <\u001b[33msysvec_apic_timer_interrupt\u001b[m>\r\n(gdb) "] +[820.684388, "o", "s"] +[821.316168, "o", "t"] +[821.396037, "o", "e"] +[821.563919, "o", "p"] +[821.819873, "o", "i"] +[823.507985, "o", "\r\n"] +[823.511475, "o", "\u001b[34m0xc15e0b05\u001b[m in \u001b[33m__x86_retpoline_edi\u001b[m ()\u001b[m\r\n \u001b[m at \u001b[32m./arch/x86/include/asm/GEN-for-each-reg.h\u001b[m:23\r\n23\tGEN(edi)\r\n(gdb) "] +[827.219827, "o", "b"] +[827.348216, "o", "t"] +[828.148173, "o", "\r\n"] +[828.14836, "o", "#0 \u001b[34m0xc15e0b05\u001b[m in \u001b[33m__x86_retpoline_edi\u001b[m ()\u001b[m\r\n \u001b[m at \u001b[32m./arch/x86/include/asm/GEN-for-each-reg.h\u001b[m:23\r\n#1 \u001b[34m0xc15deb5f\u001b[m in \u001b[33mhandle_exception\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:1168\r\n"] +[828.149581, "o", "#2 \u001b[34m0x00000000\u001b[m in \u001b[33m??\u001b[m ()\r\n"] +[828.150395, "o", "(gdb) "] +[829.675679, "o", "s"] +[829.880802, "o", "t"] +[829.945607, "o", "e"] +[829.998494, "o", "p"] +[830.140786, "o", "i"] +[830.467985, "o", "\r\n"] +[830.470567, "o", "\u001b[34m0xc15e0b11\u001b[m in \u001b[33m__x86_retpoline_edi\u001b[m ()\u001b[m\r\n \u001b[m at \u001b[32m./arch/x86/include/asm/GEN-for-each-reg.h\u001b[m:23\r\n23\tGEN(edi)\r\n"] +[830.470677, "o", "(gdb) "] +[831.507846, "o", "\r\n"] +[831.510731, "o", "\u001b[34m0xc15e0b14\u001b[m\t23\tGEN(edi)\r\n(gdb) "] +[833.044138, "o", "\r\n"] +[833.047651, "o", "\u001b[33msysvec_apic_timer_interrupt\u001b[m (\u001b[36mregs\u001b[m=0xc17cfebc)\u001b[m\r\n \u001b[m at \u001b[32march/x86/kernel/apic/apic.c\u001b[m:1091\r\n"] +[833.047776, "o", "1091\tDEFINE_IDTENTRY_SYSVEC(sysvec_apic_timer_interrupt)\r\n(gdb) "] +[837.992379, "o", "b"] +[838.082464, "o", "t"] +[838.468115, "o", "\r\n"] +[838.468954, "o", "#0 \u001b[33msysvec_apic_timer_interrupt\u001b[m (\u001b[36mregs\u001b[m=0xc17cfebc)\u001b[m\r\n \u001b[m at \u001b[32march/x86/kernel/apic/apic.c\u001b[m:1091\r\n#1 \u001b[34m0xc15deb5f\u001b[m in \u001b[33mhandle_exception\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:1168\r\n"] +[838.470231, "o", "#2 \u001b[34m0x00000000\u001b[m in \u001b[33m??\u001b[m ()\r\n"] +[838.47094, "o", "(gdb) "] +[840.947473, "o", "#"] +[841.144354, "o", " "] +[841.360793, "o", "o"] +[841.42971, "o", "k"] +[842.204191, "o", ","] +[842.341979, "o", " "] +[842.444332, "o", "w"] +[842.539968, "o", "e"] +[842.677559, "o", " "] +[842.867869, "o", "r"] +[842.932437, "o", "e"] +[843.051893, "o", "a"] +[843.267887, "o", "c"] +[843.717425, "o", "h"] +[844.315499, "o", " "] +[844.976743, "o", "\b\u001b[K"] +[845.116092, "o", "e"] +[845.283572, "o", "d"] +[845.419727, "o", " "] +[845.579645, "o", "t"] +[845.69171, "o", "h"] +[845.784239, "o", "e"] +[845.884895, "o", " "] +[846.475528, "o", "e"] +[846.992223, "o", "x"] +[847.779862, "o", "c"] +[847.899595, "o", "e"] +[848.012177, "o", "p"] +[848.237069, "o", "t"] +[848.299719, "o", "i"] +[848.355554, "o", "o"] +[848.548387, "o", "n"] +[848.668273, "o", " "] +[848.883368, "o", "h"] +[848.924119, "o", "a"] +[849.102725, "o", "n"] +[849.195892, "o", "d"] +[849.320334, "o", "l"] +[849.403392, "o", "e"] +[849.469381, "o", "r"] +[849.555461, "o", " "] +[849.683646, "o", "f"] +[849.764172, "o", "u"] +[849.82762, "o", "n"] +[849.940511, "o", "c"] +[850.140061, "o", "t"] +[850.188329, "o", "i"] +[850.236049, "o", "o"] +[850.403561, "o", "n"] +[851.244482, "o", "\r\n(gdb) "] +[851.940142, "o", "#"] +[852.116219, "o", " "] +[852.362087, "o", "l"] +[852.425526, "o", "e"] +[852.572158, "o", "t"] +[852.899784, "o", "s"] +[853.075543, "o", " "] +[853.252474, "o", "s"] +[853.360745, "o", "k"] +[853.555665, "o", "i"] +[853.756754, "o", "p"] +[853.893804, "o", " "] +[854.067629, "o", "w"] +[854.179574, "o", "o"] +[854.479805, "o", "\b\u001b[K"] +[854.580246, "o", "\b\u001b[K"] +[854.691967, "o", "t"] +[854.756166, "o", "o"] +[854.866408, "o", " "] +[854.916837, "o", "t"] +[855.051746, "o", "h"] +[855.13964, "o", "e"] +[855.203583, "o", " "] +[855.484009, "o", "e"] +[855.593676, "o", "n"] +[855.675946, "o", "d"] +[856.363844, "o", "\r\n"] +[856.363913, "o", "(gdb) "] +[857.411824, "o", "f"] +[857.459708, "o", "i"] +[857.596332, "o", "n"] +[857.644121, "o", "i"] +[857.716486, "o", "s"] +[857.825967, "o", "h"] +[859.756006, "o", "\r\n"] +[859.756719, "o", "Run till exit from #0 \u001b[33msysvec_apic_timer_interrupt\u001b[m (\u001b[36mregs\u001b[m=0xc17cfebc)\u001b[m\r\n \u001b[m at \u001b[32march/x86/kernel/apic/apic.c\u001b[m:1091\r\n"] +[859.763094, "o", "\u001b[33mhandle_exception\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:1179\r\n1179\t\tmovl\tPT_CS(%esp), %eax\r\n"] +[859.763267, "o", "(gdb) "] +[862.512345, "o", "n"] +[864.404212, "o", "\r\n"] +[864.406527, "o", "1180\t\tandl\t$SEGMENT_RPL_MASK, %eax\r\n"] +[864.406578, "o", "(gdb) "] +[865.654797, "o", "n"] +[866.267877, "o", "\r\n"] +[866.27079, "o", "1182\t\tcmpl\t$USER_RPL, %eax\t\t\t# returning to v8086 or userspace ?\r\n(gdb) "] +[867.360688, "o", "n"] +[867.708304, "o", "\r\n"] +[867.710843, "o", "1183\t\tjnb\tret_to_user\r\n"] +[867.710968, "o", "(gdb) "] +[868.899288, "o", "n"] +[870.284212, "o", "\r\n"] +[870.287095, "o", "1185\t\tPARANOID_EXIT_TO_KERNEL_MODE\r\n"] +[870.287206, "o", "(gdb) "] +[871.396245, "o", "n"] +[872.356138, "o", "\r\n"] +[872.360073, "o", "1187\t\tRESTORE_REGS 4\r\n(gdb) "] +[873.580284, "o", "n"] +[874.020225, "o", "\r\n"] +[874.06255, "o", "\u001b[33mhandle_exception\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:1188\r\n1188\t\tjmp\t.Lirq_return\r\n(gdb) "] +[880.227976, "o", "s"] +[880.563745, "o", "t"] +[880.663906, "o", "e"] +[880.772059, "o", "p"] +[881.016269, "o", "i"] +[885.107968, "o", "\r\n"] +[885.1111, "o", "\u001b[33mentry_INT80_32\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:1080\r\n1080\t\tINTERRUPT_RETURN\r\n(gdb) "] +[886.896524, "o", "d"] +[887.002145, "o", "i"] +[887.17178, "o", "s"] +[887.267258, "o", "a"] +[887.427617, "o", "s"] +[888.193298, "o", "semble "] +[888.985353, "o", "$"] +[889.2295, "o", "p"] +[889.6279, "o", "c"] +[889.755674, "o", ","] +[890.130259, "o", "+"] +[890.523791, "o", "4"] +[892.275975, "o", "\r\n"] +[892.276128, "o", "Dump of assembler code from 0xc15dea1e to 0xc15dea22:\r\n"] +[892.276217, "o", "=> \u001b[34m0xc15dea1e\u001b[m <\u001b[33mentry_INT80_32\u001b[m+426>:\tiret \r\n \u001b[34m0xc15dea1f\u001b[m <\u001b[33mhandle_exception\u001b[m+0>:\tcld \r\n"] +[892.276254, "o", " \u001b[34m0xc15dea20\u001b[m <\u001b[33mhandle_exception\u001b[m+1>:\tpush %fs\r\nEnd of assembler dump.\r\n"] +[892.276365, "o", "(gdb) "] +[900.885286, "o", "#"] +[901.051387, "o", " "] +[903.108694, "o", "w"] +[903.195526, "o", "e"] +[903.331464, "o", " "] +[903.507641, "o", "r"] +[903.579802, "o", "e"] +[903.651849, "o", "a"] +[903.827191, "o", "c"] +[903.915925, "o", "h"] +[904.018162, "o", "e"] +[904.084005, "o", "d"] +[904.193456, "o", " "] +[904.340005, "o", "t"] +[904.419249, "o", "h"] +[904.50751, "o", "e"] +[904.619508, "o", " "] +[905.050041, "o", "e"] +[905.142961, "o", "n"] +[905.242133, "o", "d"] +[905.356107, "o", " "] +[906.418504, "o", "o"] +[906.483992, "o", "f"] +[906.571581, "o", " "] +[906.731762, "o", "t"] +[906.788765, "o", "h"] +[906.915517, "o", "e"] +[907.019539, "o", " "] +[907.226477, "o", "e"] +[907.376179, "o", "x"] +[907.627505, "o", "c"] +[908.25994, "o", "e"] +[908.371671, "o", "p"] +[908.580147, "o", "t"] +[908.635847, "o", "i"] +[908.675142, "o", "o"] +[908.868113, "o", "n"] +[909.147401, "o", " "] +[910.283243, "o", "h"] +[910.34774, "o", "a"] +[910.539401, "o", "n"] +[910.94662, "o", "d"] +[911.099697, "o", "l"] +[912.379334, "o", "i"] +[912.463978, "o", "n"] +[912.578486, "o", "g"] +[915.172176, "o", "\r\n"] +[915.17238, "o", "(gdb) "] +[915.627306, "o", "#"] +[915.802899, "o", " "] +[916.01211, "o", "i"] +[916.132261, "o", "r"] +[916.480252, "o", "e"] +[916.740283, "o", "t"] +[916.875718, "o", " "] +[917.027976, "o", "t"] +[917.707571, "o", "\b\u001b[K"] +[917.850998, "o", "w"] +[917.987234, "o", "i"] +[918.164289, "o", "l"] +[918.345294, "o", "l"] +[918.428587, "o", " "] +[921.142498, "o", "p"] +[921.315361, "o", "o"] +[921.379736, "o", "p"] +[922.235945, "o", " "] +[922.523391, "o", "t"] +[922.65927, "o", "h"] +[922.77948, "o", "e"] +[922.931826, "o", " "] +[923.619616, "o", "o"] +[923.81968, "o", "l"] +[924.348218, "o", "d"] +[924.483915, "o", " "] +[924.803599, "o", "E"] +[925.091333, "o", "I"] +[925.204834, "o", "P"] +[925.859791, "o", ","] +[926.323847, "o", " "] +[926.628744, "o", "O"] +[926.836056, "o", "L"] +[926.972515, "o", "D"] +[927.555719, "o", " "] +[927.860637, "o", "C"] +[927.956656, "o", "S"] +[928.131232, "o", " "] +[928.283599, "o", "a"] +[928.379165, "o", "n"] +[928.499395, "o", "d"] +[928.572276, "o", " "] +[930.399792, "o", "o"] +[930.579592, "o", "l"] +[930.747191, "o", "d "] +[936.451423, "o", "E"] +[936.651497, "o", "F"] +[936.724116, "o", "L"] +[936.803501, "o", "A"] +[936.944129, "o", "G"] +[937.017988, "o", "S"] +[940.419551, "o", "\r\n(gdb) "] +[940.703548, "o", "#"] +[940.867379, "o", " "] +[941.131995, "o", "a"] +[941.236387, "o", "n"] +[941.315354, "o", "d"] +[941.428119, "o", " "] +[941.545304, "o", "r"] +[941.595714, "o", "e"] +[941.780241, "o", "s"] +[941.875308, "o", "u"] +[942.324162, "o", "m"] +[942.479946, "o", "e"] +[942.595786, "o", " "] +[942.724262, "o", "t"] +[942.828484, "o", "h"] +[942.914989, "o", "e"] +[943.019342, "o", " "] +[943.291437, "o", "p"] +[943.427129, "o", "r"] +[943.492285, "o", "e"] +[943.680718, "o", "v"] +[943.762965, "o", "i"] +[943.827585, "o", "o"] +[944.003395, "o", "u"] +[944.075376, "o", "s"] +[944.179349, "o", " "] +[944.620027, "o", "e"] +[944.800545, "o", "x"] +[944.880871, "o", "e"] +[945.076374, "o", "c"] +[945.355484, "o", "t"] +[945.451345, "o", "i"] +[945.499272, "o", "o"] +[945.699588, "o", "n"] +[945.868687, "o", " "] +[946.332003, "o", "f"] +[946.451626, "o", "l"] +[946.715244, "o", "o"] +[949.939268, "o", "w"] +[952.179651, "o", "\r\n(gdb) "] +[953.872763, "o", "s"] +[954.104233, "o", "t"] +[954.220454, "o", "e"] +[954.523396, "o", "p"] +[954.699106, "o", "i"] +[957.155393, "o", "\r\n"] +[957.157788, "o", "\u001b[34m0xc15dcb62\u001b[m in \u001b[33mdefault_idle\u001b[m () at \u001b[32m./arch/x86/include/asm/irqflags.h\u001b[m:60\r\n60\t\tasm volatile(\"sti; hlt\": : :\"memory\");\r\n"] +[957.157838, "o", "(gdb) "] +[959.275429, "o", "#"] +[959.427369, "o", " "] +[959.547282, "o", "a"] +[959.660394, "o", "n"] +[959.739359, "o", "d"] +[959.843798, "o", " "] +[959.9766, "o", "w"] +[960.047887, "o", "e"] +[960.172093, "o", " "] +[960.315666, "o", "a"] +[960.419302, "o", "r"] +[960.491251, "o", "e"] +[960.579224, "o", " "] +[960.77959, "o", "b"] +[960.851343, "o", "a"] +[960.915682, "o", "c"] +[961.049011, "o", "k"] +[961.201567, "o", " "] +[962.4203, "o", "i"] +[962.475459, "o", "n"] +[962.61159, "o", " "] +[962.714878, "o", "t"] +[962.851242, "o", "h"] +[962.931223, "o", "e"] +[963.051282, "o", " "] +[963.907009, "o", "o"] +[964.042918, "o", "r"] +[964.123059, "o", "i"] +[964.251116, "o", "g"] +[964.299084, "o", "i"] +[964.45136, "o", "n"] +[964.555122, "o", "a"] +[964.931034, "o", "l"] +[965.155018, "o", " "] +[972.371607, "o", "f"] +[972.555443, "o", "u"] +[972.643143, "o", "n"] +[972.76443, "o", "c"] +[973.027243, "o", "t"] +[973.075346, "o", "i"] +[973.13917, "o", "o"] +[973.344676, "o", "n"] +[973.499763, "o", " "] +[976.467642, "o", "\r\n"] +[976.467915, "o", "(gdb) "] +[996.435802, "o", "quit\r\n"] +[996.436065, "o", "A debugging session is active.\r\n\r\n\tInferior 1 [process 1] will be detached.\r\n\r\nQuit anyway? (y or n) "] +[997.892586, "o", "y"] +[998.379483, "o", "\r\nDetaching from program: /linux/vmlinux, process 1\r\n"] +[998.380309, "o", "Ending remote debugging.\r\n"] +[998.380413, "o", "[Inferior 1 (process 1) detached]\r\n"] +[998.387415, "o", "$ "] +[1004.003082, "o", "^L"] +[1004.78691, "o", "\b \b\b \b"] +[1005.515685, "o", "#"] +[1005.891313, "o", " "] +[1006.098914, "o", "n"] +[1006.171159, "o", "o"] +[1006.251338, "o", "w"] +[1006.379746, "o", " "] +[1006.642949, "o", "l"] +[1006.756392, "o", "e"] +[1006.972256, "o", "t"] +[1007.451427, "o", "s"] +[1008.78733, "o", " "] +[1011.707191, "o", "t"] +[1011.922977, "o", "r"] +[1012.075141, "o", "y"] +[1012.211589, "o", " "] +[1012.407443, "o", "t"] +[1012.496215, "o", "o"] +[1012.63914, "o", " "] +[1013.171266, "o", "d"] +[1013.280435, "o", "o"] +[1013.382917, "o", " "] +[1013.699697, "o", "a"] +[1015.067856, "o", " "] +[1017.747341, "o", "p"] +[1017.899377, "o", "r"] +[1018.02099, "o", "i"] +[1018.144684, "o", "v"] +[1018.219465, "o", "i"] +[1018.435513, "o", "l"] +[1018.578748, "o", "e"] +[1018.898886, "o", "d"] +[1019.160504, "o", "g"] +[1019.315664, "o", "e"] +[1020.651137, "o", " "] +[1020.795118, "o", "t"] +[1020.971166, "o", "r"] +[1021.085116, "o", "a"] +[1021.231631, "o", "n"] +[1021.387101, "o", "s"] +[1021.675097, "o", "i"] +[1021.867216, "o", "t"] +[1021.930784, "o", "i"] +[1021.994802, "o", "o"] +[1022.227196, "o", "n"] +[1022.34665, "o", " "] +[1032.083575, "o", "^[[D"] +[1032.923178, "o", "\b \b"] +[1033.050768, "o", "\b \b"] +[1033.195851, "o", "\b \b\b \b"] +[1033.355124, "o", "\b \b"] +[1034.275365, "o", "\r\n"] +[1034.275424, "o", "$ "] +[1035.090995, "o", "#"] +[1035.571157, "o", " "] +[1038.299127, "o", "f"] +[1038.418833, "o", "o"] +[1038.546673, "o", "r"] +[1038.643075, "o", " "] +[1038.811737, "o", "t"] +[1038.986934, "o", "h"] +[1039.075088, "o", "a"] +[1039.171894, "o", "t"] +[1039.290797, "o", " "] +[1039.714845, "o", "w"] +[1040.060445, "o", "e"] +[1040.579062, "o", " "] +[1040.715253, "o", "w"] +[1040.835144, "o", "i"] +[1041.008189, "o", "l"] +[1041.188661, "o", "l"] +[1062.274587, "o", " "] +[1063.994677, "o", "r"] +[1064.066586, "o", "u"] +[1064.258739, "o", "n"] +[1064.754719, "o", " "] +[1064.866336, "o", "a"] +[1064.95491, "o", " "] +[1069.779045, "o", "u"] +[1069.842686, "o", "s"] +[1069.898904, "o", "e"] +[1069.992062, "o", "r"] +[1070.090743, "o", "s"] +[1070.186611, "o", "p"] +[1070.271994, "o", "a"] +[1070.335417, "o", "c"] +[1070.435046, "o", "e"] +[1070.490858, "o", " "] +[1070.667137, "o", "l"] +[1070.843138, "o", "o"] +[1070.978461, "o", "o"] +[1071.042789, "o", "p"] +[1072.299918, "o", "\r\n$ "] +[1072.677072, "o", "#"] +[1072.8757, "o", " "] +[1073.123342, "o", "t"] +[1073.187116, "o", "o"] +[1073.234967, "o", " "] +[1073.64715, "o", "m"] +[1073.723177, "o", "a"] +[1074.003257, "o", "x"] +[1074.066757, "o", "i"] +[1074.242917, "o", "m"] +[1074.440397, "o", "e"] +[1074.951277, "o", "\b \b"] +[1075.082786, "o", "i"] +[1075.154841, "o", "z"] +[1075.306772, "o", "e"] +[1075.362669, "o", " "] +[1075.507002, "o", "t"] +[1075.563397, "o", "h"] +[1075.667216, "o", "e"] +[1075.759055, "o", " "] +[1075.971488, "o", "c"] +[1076.40312, "o", "h"] +[1076.538776, "o", "a"] +[1076.822943, "o", "n"] +[1077.090772, "o", "c"] +[1077.179219, "o", "e"] +[1077.274764, "o", " "] +[1077.427, "o", "o"] +[1077.538624, "o", "f"] +[1077.6266, "o", " "] +[1080.099022, "o", "c"] +[1080.220601, "o", "a"] +[1080.435652, "o", "t"] +[1080.642958, "o", "c"] +[1080.754845, "o", "h"] +[1080.890696, "o", "i"] +[1080.970811, "o", "n"] +[1081.066751, "o", "g"] +[1081.187186, "o", " "] +[1081.450963, "o", "a"] +[1081.535893, "o", " "] +[1082.419055, "o", "u"] +[1082.554783, "o", "s"] +[1082.707252, "o", "e"] +[1082.778665, "o", "r"] +[1082.907521, "o", " "] +[1083.155048, "o", "-"] +[1083.642635, "o", ">"] +[1083.82688, "o", " "] +[1083.995373, "o", "i"] +[1084.106729, "o", "r"] +[1084.15548, "o", "r"] +[1084.226868, "o", "q"] +[1084.523026, "o", " "] +[1084.722585, "o", "t"] +[1084.890951, "o", "r"] +[1084.955439, "o", "a"] +[1085.066325, "o", "n"] +[1085.170702, "o", "s"] +[1085.490659, "o", "i"] +[1085.791096, "o", "t"] +[1085.864736, "o", "i"] +[1085.89322, "o", "o"] +[1086.098742, "o", "n"] +[1086.763832, "o", " "] +[1093.283335, "o", "\r\n"] +[1093.285702, "o", "$ "] +[1094.41432, "o", "^[[A"] +[1094.786061, "o", "^[[A"] +[1095.389595, "o", "\b \b"] +[1095.895038, "o", "\b \b"] +[1095.9211, "o", "\b \b\b \b"] +[1095.953965, "o", "\b \b"] +[1095.985163, "o", "\b \b"] +[1096.0314, "o", "\b \b\b \b"] +[1096.289423, "o", "m"] +[1096.384651, "o", "i"] +[1096.91055, "o", "n"] +[1096.977922, "o", "i"] +[1097.17697, "o", "c"] +[1097.232856, "o", "o"] +[1097.320687, "o", "m"] +[1097.841256, "o", " "] +[1098.864769, "o", "-"] +[1099.174029, "o", "D"] +[1099.281202, "o", " "] +[1099.616635, "o", "s"] +[1099.680677, "o", "e"] +[1099.776722, "o", "r"] +[1099.840456, "o", "i"] +[1100.020817, "o", "a"] +[1100.128658, "o", "l"] +[1100.313642, "o", "."] +[1100.528928, "o", "p"] +[1100.712992, "o", "t"] +[1101.260834, "o", "s"] +[1101.369434, "o", "\r\n"] +[1101.370212, "o", "\u001b[!p\u001b[?3;4l\u001b[4l\u001b>\u001b[0m\u001b(B\u001b[?1h\u001b=\u001b[H\u001b[2J"] +[1101.370539, "o", "\u001b[?12l\u001b[?25h\nWelcome to minicom 2.7.1\r\n\nOPTIONS: I18n \r\nCompiled on Dec 23 2019, 02:06:26.\r\nPort serial.pts, 22:39:44\r\n\nPress CTRL-A Z for help on special keys\r\n\n"] +[1102.49074, "o", "\n"] +[1102.491207, "o", "Poky (Yocto Project Reference Distro) 2.3 qemux86 /dev/hvc0"] +[1102.491482, "o", "\r\n"] +[1102.492003, "o", "\n"] +[1102.492481, "o", "qemux86 login: "] +[1102.921642, "o", "r"] +[1103.001363, "o", "o"] +[1103.129677, "o", "o"] +[1103.217562, "o", "t"] +[1103.322957, "o", "\r\n"] +[1103.376683, "o", "root@qemux86:~# "] +[1104.675056, "o", "\r\n"] +[1104.676255, "o", "root@qemux86:~# "] +[1107.089642, "o", "i"] +[1107.298186, "o", "="] +[1107.529893, "o", "0"] +[1107.802507, "o", ";"] +[1108.129744, "o", " "] +[1108.378208, "o", "w"] +[1108.433774, "o", "h"] +[1108.489985, "o", "i"] +[1108.641622, "o", "l"] +[1108.713754, "o", "e"] +[1108.834396, "o", " "] +[1108.945519, "o", "t"] +[1109.082068, "o", "r"] +[1109.161673, "o", "u"] +[1109.601342, "o", "e"] +[1110.130521, "o", ";"] +[1110.937837, "o", " "] +[1111.081655, "o", "d"] +[1111.170074, "o", "o"] +[1113.96216, "o", " "] +[1115.225582, "o", "i"] +[1115.635039, "o", "="] +[1115.993851, "o", "$"] +[1116.177231, "o", "["] +[1116.512499, "o", "i"] +[1116.955475, "o", "\b\u001b[16;1H\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\u001b[15;41H\u001b[K"] +[1117.241465, "o", "$"] +[1117.490132, "o", "i"] +[1118.170026, "o", "+"] +[1118.473776, "o", "1"] +[1118.641428, "o", "]"] +[1120.374762, "o", ";"] +[1120.986189, "o", " "] +[1122.00169, "o", "d"] +[1122.042127, "o", "o"] +[1122.224768, "o", "n"] +[1122.362033, "o", "e"] +[1123.097725, "o", " "] +[1124.041576, "o", "&"] +[1124.842453, "o", "\r\n"] +[1124.846558, "o", "root@qemux86:~# "] +[1125.945623, "o", "t"] +[1126.06538, "o", "o"] +[1126.153341, "o", "p"] +[1126.819453, "o", "\r\n"] +[1127.026599, "o", "\u001b[1;1H\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\u001b[1;1H\u001b[KMem: 30712K used, 209968K free, 172K shrd, 368K buff, 4344K cached"] +[1127.026754, "o", "\r\n"] +[1127.026857, "o", "CPU: 86% usr 13% sys 0% nic 0% idle 0% io 0% irq 0% sirq"] +[1127.027083, "o", "\r\n"] +[1127.027772, "o", "Load average: 0.28 0.65 0.45 2/38 348"] +[1127.027961, "o", "\r\n"] +[1127.044934, "o", "\u001b[0m\u001b(B\u001b[7m PID PPID USER STAT VSZ %VSZ %CPU COMMAND"] +[1127.045363, "o", "\r\n"] +[1127.050449, "o", "\u001b[0m\u001b(B 347 345 root R 2972 1% 80% -sh"] +[1127.050668, "o", "\r\n"] +[1127.051028, "o", " 348 345 root R 2828 1% 7% top"] +[1127.051127, "o", "\r\n"] +[1127.052058, "o", " 10 2 root IW 0 0% 7% [rcu_sched]"] +[1127.052239, "o", "\r\n"] +[1127.05275, "o", " 345 1 root S 2972 1% 0% -sh"] +[1127.052867, "o", "\r\n"] +[1127.057884, "o", " 198 1 root S 2828 1% 0% /sbin/syslogd -n -O /var/log/messages"] +[1127.058054, "o", "\r\n"] +[1127.058664, "o", " 201 1 root S 2828 1% 0% /sbin/klogd -n"] +[1127.058723, "o", "\r\n"] +[1127.059444, "o", " 207 1 root S 2828 1% 0% /sbin/getty 38400 tty1"] +[1127.059553, "o", "\r\n"] +[1127.060102, "o", " 209 1 root S 2828 1% 0% /sbin/getty 38400 tty2"] +[1127.060272, "o", "\r\n"] +[1127.06083, "o", " 210 1 root S 2828 1% 0% /sbin/getty 38400 tty3"] +[1127.060931, "o", "\r\n"] +[1127.066093, "o", " 211 1 root S 2828 1% 0% /sbin/getty 38400 tty4"] +[1127.066277, "o", "\r\n"] +[1127.066919, "o", " 212 1 root S 2828 1% 0% /sbin/getty 38400 tty5"] +[1127.067167, "o", "\r\n"] +[1127.067611, "o", " 187 1 root S 2828 1% 0% udhcpc -R -b -p /var/run/udhcpc.eth0.p\u001b[16;80H"] +[1127.067744, "o", "\r\n"] +[1127.068254, "o", " 1 0 root S 2004 1% 0% init [5]"] +[1127.068396, "o", "\r\n"] +[1127.06884, "o", " 42 2 root SWN 0 0% 0% [kmemleak]"] +[1127.068996, "o", "\r\n"] +[1127.074239, "o", " 9 2 root SW 0 0% 0% [ksoftirqd/0]"] +[1127.074463, "o", "\r\n"] +[1127.074935, "o", " 39 2 root IW 0 0% 0% [kworker/0:2-eve]"] +[1127.07527, "o", "\r\n"] +[1127.07566, "o", " 13 2 root SW 0 0% 0% [kdevtmpfs]"] +[1127.075843, "o", "\r\n"] +[1127.076346, "o", " 38 2 root IW 0 0% 0% [kworker/u2:1-ev]"] +[1127.076463, "o", "\r\n"] +[1127.07694, "o", " 34 2 root IW< 0 0% 0% [kworker/0:1H-kb]"] +[1127.077152, "o", "\r\n"] +[1127.081642, "o", " 43 2 root SW 0 0% 0% [jbd2/vda-8]\r"] +[1132.126436, "o", "\u001b[1;1H\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\u001b[1;1H\u001b[KMem: 30772K used, 209908K free, 172K shrd, 368K buff, 4344K cached"] +[1132.126724, "o", "\r\n"] +[1132.126816, "o", "CPU: 97% usr 2% sys 0% nic 0% idle 0% io 0% irq 0% sirq"] +[1132.12694, "o", "\r\n"] +[1132.127521, "o", "Load average: 0.34 0.66 0.46 2/38 348"] +[1132.127666, "o", "\r\n"] +[1132.128837, "o", "\u001b[0m\u001b(B\u001b[7m PID PPID USER STAT VSZ %VSZ %CPU COMMAND"] +[1132.129009, "o", "\r\n"] +[1132.134166, "o", "\u001b[0m\u001b(B 347 345 root R 2972 1% 99% -sh"] +[1132.134454, "o", "\r\n"] +[1132.135025, "o", " 348 345 root R 2972 1% 1% top"] +[1132.135336, "o", "\r\n"] +[1132.135943, "o", " 345 1 root S 2972 1% 0% -sh"] +[1132.13614, "o", "\r\n"] +[1132.13659, "o", " 198 1 root S 2828 1% 0% /sbin/syslogd -n -O /var/log/messages"] +[1132.136798, "o", "\r\n"] +[1132.141677, "o", " 201 1 root S 2828 1% 0% /sbin/klogd -n"] +[1132.141859, "o", "\r\n"] +[1132.142517, "o", " 207 1 root S 2828 1% 0% /sbin/getty 38400 tty1"] +[1132.142783, "o", "\r\n"] +[1132.143294, "o", " 209 1 root S 2828 1% 0% /sbin/getty 38400 tty2"] +[1132.14353, "o", "\r\n"] +[1132.143957, "o", " 210 1 root S 2828 1% 0% /sbin/getty 38400 tty3"] +[1132.144265, "o", "\r\n"] +[1132.1447, "o", " 211 1 root S 2828 1% 0% /sbin/getty 38400 tty4"] +[1132.14492, "o", "\r\n"] +[1132.150219, "o", " 212 1 root S 2828 1% 0% /sbin/getty 38400 tty5"] +[1132.150349, "o", "\r\n"] +[1132.150878, "o", " 187 1 root S 2828 1% 0% udhcpc -R -b -p /var/run/udhcpc.eth0.p\u001b[15;80H"] +[1132.151051, "o", "\r\n"] +[1132.151431, "o", " 1 0 root S 2004 1% 0% init [5]"] +[1132.151581, "o", "\r\n"] +[1132.152171, "o", " 42 2 root SWN 0 0% 0% [kmemleak]"] +[1132.152327, "o", "\r\n"] +[1132.152911, "o", " 9 2 root SW 0 0% 0% [ksoftirqd/0]"] +[1132.153024, "o", "\r\n"] +[1132.157768, "o", " 10 2 root IW 0 0% 0% [rcu_sched]"] +[1132.157995, "o", "\r\n"] +[1132.158368, "o", " 39 2 root IW 0 0% 0% [kworker/0:2-eve]"] +[1132.158645, "o", "\r\n"] +[1132.159109, "o", " 13 2 root SW 0 0% 0% [kdevtmpfs]"] +[1132.159346, "o", "\r\n"] +[1132.159794, "o", " 38 2 root IW 0 0% 0% [kworker/u2:1-ev]"] +[1132.159838, "o", "\r\n"] +[1132.160264, "o", " 34 2 root IW< 0 0% 0% [kworker/0:1H-kb]"] +[1132.16044, "o", "\r\n"] +[1132.160661, "o", " 43 2 root SW 0 0% 0% [jbd2/vda-8]\r"] +[1133.586006, "o", "\n\u001b[23;80H \u001b[24;1H"] +[1133.589361, "o", "root@qemux86:~# "] +[1135.56963, "o", "#"] +[1135.761792, "o", " "] +[1136.825768, "o", "o"] +[1136.897392, "o", "k"] +[1137.009583, "o", " "] +[1137.185503, "o", "t"] +[1137.313332, "o", "h"] +[1137.433542, "o", "e"] +[1137.538696, "o", " "] +[1137.849713, "o", "C"] +[1137.905725, "o", "P"] +[1138.081863, "o", "U"] +[1138.649702, "o", " "] +[1138.833525, "o", "i"] +[1138.937694, "o", "s"] +[1139.001327, "o", " "] +[1139.201449, "o", "m"] +[1139.26509, "o", "o"] +[1139.417946, "o", "s"] +[1139.697189, "o", "t"] +[1139.785468, "o", "ly"] +[1140.337652, "o", " "] +[1140.521323, "o", "ru"] +[1140.577507, "o", "nn"] +[1140.785505, "o", "in"] +[1140.865534, "o", "g"] +[1141.073726, "o", " "] +[1142.521937, "o", "u"] +[1142.625315, "o", "s"] +[1142.681312, "o", "e"] +[1142.746069, "o", "r"] +[1142.89747, "o", "s"] +[1143.000997, "o", "p"] +[1144.048991, "o", "a"] +[1144.46552, "o", "c"] +[1144.569368, "o", "e"] +[1144.713469, "o", " "] +[1145.721142, "o", "c"] +[1145.849051, "o", "o"] +[1145.937576, "o", "d"] +[1146.129514, "o", "e"] +[1149.698062, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[1149.699006, "o", "root@qemux86:~# "] +[1150.777065, "o", "#"] +[1151.009906, "o", " "] +[1151.217704, "o", "l"] +[1151.289227, "o", "e"] +[1151.48157, "o", "t"] +[1151.689748, "o", "s"] +[1151.817419, "o", " "] +[1152.13751, "o", "g"] +[1152.209163, "o", "o"] +[1152.345232, "o", " "] +[1152.921542, "o", "b"] +[1152.985042, "o", "a"] +[1153.12187, "o", "c"] +[1153.225154, "o", "k"] +[1153.368917, "o", " "] +[1153.521092, "o", "t"] +[1153.59312, "o", "o"] +[1153.673022, "o", " "] +[1153.75302, "o", "t"] +[1153.881685, "o", "h"] +[1153.929562, "o", "e"] +[1154.025017, "o", " "] +[1154.154048, "o", "d"] +[1154.193966, "o", "e"] +[1154.296968, "o", "b"] +[1154.353443, "o", "u"] +[1154.513136, "o", "g"] +[1154.665637, "o", "g"] +[1154.74519, "o", "e"] +[1154.841208, "o", "r"] +[1157.898001, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[1157.898871, "o", "root@qemux86:~# "] +[1159.312239, "o", "\u001b[0m\u001b(B\u001b[7m\r\u001b[K\u001b[?12l\u001b[?25h\u001b[?25lCTRL-A Z for help | 115200 8N1 | NOR | Minicom 2.7.1 | VT102 | Offline | al.pts\u001b[?12l\u001b[?25h\u001b[24;17H"] +[1159.680333, "o", "\u001b[8;30H\u001b[?25l\u001b[0m\u001b(B\u001b(0lqqqqqqqqqqqqqqqqqqqqqqk\u001b[9;30Hx\u001b[0m\u001b(B Leave Minicom? \u001b[0m\u001b(B\u001b(0x\u001b[10;30Hx\u001b[0m\u001b(B No \u001b[0m\u001b(B\u001b(0x\u001b[11;30Hmqqqqqqqqqqqqqqqqqqqqqqj\u001b[10;51H\u001b[?25l\u001b[10;33H\u001b[0m\u001b(B\u001b[7m Yes "] +[1160.319825, "o", "\u001b[?12l\u001b[?25h\u001b[8;1H\u001b[0m\u001b(B 209 1 root S 2828 1% 0% /sbin/getty\u001b[9;1H 210 1 root S 2828 1% 0% /sbin/getty\u001b[10;1H 211 1 root S 2828 1% 0% /sbin/getty\u001b[11;1H 212 1 root S 2828 1% 0% /sbin/getty\u001b[24;17H\u001b[0m\u001b(B\u001b[7m\u001b[?12l\u001b[?25h"] +[1160.320008, "o", "\u001b[?12l\u001b[?25h\u001b[0m\u001b(B\u001b[H\u001b[2J\u001b[?12l\u001b[?25h\u001b[?1l\u001b>\u001b[!p\u001b[?3;4l\u001b[4l\u001b>"] +[1160.32013, "o", "$ "] +[1161.688843, "o", "m"] +[1161.800345, "o", "a"] +[1161.856099, "o", "k"] +[1162.008302, "o", "e"] +[1162.072387, "o", " "] +[1162.328258, "o", "g"] +[1162.408339, "o", "d"] +[1162.488446, "o", "b"] +[1162.904659, "o", "\r\n"] +[1162.910043, "o", "gdb -ex \"target remote localhost:1234\" /linux/vmlinux\r\n"] +[1162.944541, "o", "\u001b[35;1m\u001b[35;1mGNU gdb \u001b[m\u001b[35;1m(Ubuntu 9.2-0ubuntu1~20.04) \u001b[m\u001b[35;1m9.2\u001b[m\u001b[35;1m\r\n\u001b[m\u001b[mCopyright (C) 2020 Free Software Foundation, Inc.\r\nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\r\nThis is free software: you are free to change and redistribute it.\r\nThere is NO WARRANTY, to the extent permitted by law.\r\nType \"show copying\" and \"show warranty\" for details.\r\nThis GDB was configured as \"x86_64-linux-gnu\".\r\nType \"show configuration\" for configuration details.\r\nFor bug reporting instructions, please see:\r\n<http://www.gnu.org/software/gdb/bugs/>.\r\nFind the GDB manual and other documentation resources online at:\r\n <http://www.gnu.org/software/gdb/documentation/>.\r\n\r\n"] +[1162.944647, "o", "For help, type \"help\".\r\nType \"apropos word\" to search for commands related to \"word\"...\r\n"] +[1162.945021, "o", "Reading symbols from \u001b[32m/linux/vmlinux\u001b[m...\r\n"] +[1163.591264, "o", "Remote debugging using localhost:1234\r\n"] +[1163.599772, "o", "\u001b[34m0x448ac101\u001b[m in \u001b[33m??\u001b[m ()\r\n"] +[1163.600288, "o", "(gdb) "] +[1167.808759, "o", "#"] +[1168.054699, "o", " "] +[1174.704625, "o", "u"] +[1174.784712, "o", "s"] +[1174.864648, "o", "e"] +[1174.944398, "o", "r"] +[1175.057207, "o", "s"] +[1175.176743, "o", "p"] +[1175.225215, "o", "a"] +[1175.345433, "o", "c"] +[1175.433465, "o", "e"] +[1175.601394, "o", " "] +[1175.744383, "o", "a"] +[1175.920469, "o", "d"] +[1176.072352, "o", "d"] +[1176.321026, "o", "r"] +[1176.656814, "o", "e"] +[1176.832588, "o", "s"] +[1176.960611, "o", "s"] +[1177.072884, "o", ","] +[1177.168436, "o", " "] +[1177.329116, "o", "g"] +[1177.404147, "o", "o"] +[1177.448381, "o", "o"] +[1177.598144, "o", "d"] +[1177.662444, "o", "!"] +[1180.24054, "o", "\r\n"] +[1180.24062, "o", "(gdb) "] +[1181.720922, "o", "b"] +[1181.80043, "o", "r"] +[1181.86486, "o", "e"] +[1181.929251, "o", "a"] +[1182.024706, "o", "k"] +[1182.105515, "o", " "] +[1195.76893, "o", "h"] +[1195.849596, "o", "a"] +[1195.960904, "o", "n"] +[1196.088828, "o", "d"] +[1196.176629, "o", "l"] +[1196.496808, "o", "e"] +[1196.672653, "o", "_"] +[1197.256752, "o", "e"] +[1197.416356, "o", "x"] +[1197.656574, "o", "c"] +[1197.720445, "o", "e"] +[1197.793172, "o", "p"] +[1197.945795, "o", "t"] +[1198.018687, "o", "i"] +[1198.052227, "o", "o"] +[1198.226222, "o", "n"] +[1198.528674, "o", "\r\n"] +[1198.579682, "o", "Breakpoint 1 at \u001b[34m0xc15dea1f\u001b[m: file \u001b[32march/x86/entry/entry_32.S\u001b[m, line 1154.\r\n"] +[1198.57999, "o", "(gdb) "] +[1200.261062, "o", "c"] +[1200.433433, "o", "\r\nContinuing.\r\n"] +[1200.436772, "o", "\r\n"] +[1200.437049, "o", "Breakpoint 1, \u001b[33mhandle_exception\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:1154\r\n1154\t\tSAVE_ALL switch_stacks=1 skip_gs=1 unwind_espfix=1\r\n"] +[1200.437198, "o", "(gdb) "] +[1228.112751, "o", "b"] +[1228.201197, "o", "t"] +[1228.329203, "o", "\r\n"] +[1228.331815, "o", "#0 \u001b[33mhandle_exception\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:1154\r\n"] +[1228.332762, "o", "#1 \u001b[34m0xc15d3840\u001b[m in \u001b[33m??\u001b[m () at \u001b[32march/x86/kernel/setup.c\u001b[m:755\r\nBacktrace stopped: previous frame inner to this frame (corrupt stack?)\r\n(gdb) "] +[1239.893902, "o", "#"] +[1240.072314, "o", " "] +[1240.184169, "o", "l"] +[1240.272133, "o", "e"] +[1240.416193, "o", "t"] +[1240.603099, "o", "s"] +[1240.678107, "o", " "] +[1243.392803, "o", "l"] +[1243.592484, "o", "o"] +[1243.744272, "o", "o"] +[1243.856711, "o", "k"] +[1244.075404, "o", " "] +[1244.232286, "o", "a"] +[1244.712632, "o", "t"] +[1244.792148, "o", " "] +[1244.904252, "o", "t"] +[1244.992334, "o", "h"] +[1245.091434, "o", "e"] +[1245.173492, "o", " "] +[1245.336103, "o", "s"] +[1245.497425, "o", "t"] +[1245.54492, "o", "a"] +[1245.720423, "o", "c"] +[1245.784262, "o", "k"] +[1245.872308, "o", " "] +[1245.984224, "o", "a"] +[1246.272808, "o", "a"] +[1246.688388, "o", "\b\u001b[K"] +[1246.744332, "o", "g"] +[1246.816332, "o", "a"] +[1246.968488, "o", "i"] +[1247.040167, "o", "n"] +[1247.809286, "o", "\r\n"] +[1247.809419, "o", "(gdb) "] +[1248.16016, "o", "#"] +[1248.32863, "o", " "] +[1248.496948, "o", "t"] +[1248.608703, "o", "h"] +[1248.751015, "o", "e"] +[1249.152273, "o", " "] +[1249.304321, "o", "f"] +[1249.401613, "o", "i"] +[1249.560984, "o", "r"] +[1249.933296, "o", "s"] +[1250.168173, "o", "t"] +[1250.449313, "o", " "] +[1250.767425, "o", "i"] +[1250.969452, "o", "t"] +[1251.048783, "o", "e"] +[1251.160335, "o", "m"] +[1251.328476, "o", " "] +[1251.528696, "o", "o"] +[1251.744914, "o", "n"] +[1251.845411, "o", " "] +[1251.96225, "o", "t"] +[1252.081386, "o", "e"] +[1252.096296, "o", "h"] +[1252.25686, "o", " "] +[1252.376629, "o", "s"] +[1252.504275, "o", "t"] +[1252.560027, "o", "a"] +[1252.824826, "o", "\b\u001b[K"] +[1252.968895, "o", "\b\u001b[K"] +[1253.112952, "o", "\b\u001b[K"] +[1253.248719, "o", "\b\u001b[K"] +[1253.368406, "o", "\b\u001b[K"] +[1253.576566, "o", "\b\u001b[K"] +[1253.769049, "o", "h"] +[1253.848377, "o", "e"] +[1253.928207, "o", " "] +[1254.07566, "o", "s"] +[1254.224132, "o", "t"] +[1254.256299, "o", "a"] +[1254.46369, "o", "c"] +[1254.528393, "o", "k"] +[1254.62412, "o", " "] +[1254.792238, "o", "s"] +[1254.896183, "o", "h"] +[1254.976616, "o", "o"] +[1255.095813, "o", "u"] +[1255.233173, "o", "l"] +[1255.328849, "o", "d"] +[1255.422248, "o", " "] +[1255.640996, "o", "b"] +[1255.712744, "o", "e"] +[1255.832174, "o", " "] +[1256.211236, "o", "t"] +[1256.280666, "o", "h"] +[1256.400446, "o", "e"] +[1256.487918, "o", " "] +[1258.854607, "o", "t"] +[1258.941545, "o", "i"] +[1259.024791, "o", "m"] +[1259.04853, "o", "e"] +[1259.121157, "o", "r"] +[1259.224098, "o", " "] +[1259.360266, "o", "h"] +[1259.408186, "o", "a"] +[1259.552178, "o", "n"] +[1259.616451, "o", "d"] +[1259.762455, "o", "l"] +[1259.841476, "o", "e"] +[1259.913474, "o", "r"] +[1260.720512, "o", "\r\n(gdb) "] +[1261.704102, "o", "p"] +[1261.847725, "o", "r"] +[1261.936837, "o", "i"] +[1261.984576, "o", "n"] +[1262.066128, "o", "t"] +[1262.145208, "o", " "] +[1262.424767, "o", "("] +[1262.624087, "o", "v"] +[1262.737455, "o", "o"] +[1263.000827, "o", "d"] +[1263.399755, "o", "\b\u001b[K"] +[1263.544234, "o", "i"] +[1263.648825, "o", "d"] +[1263.792709, "o", " "] +[1264.222987, "o", "*"] +[1264.367238, "o", ")"] +[1264.648392, "o", "("] +[1267.639225, "o", "*"] +[1267.776229, "o", "("] +[1269.23218, "o", "u"] +[1269.400337, "o", "i"] +[1269.448756, "o", "n"] +[1269.579068, "o", "t"] +[1269.800118, "o", "3"] +[1269.872245, "o", "2"] +[1270.048002, "o", "_"] +[1270.200422, "o", "t"] +[1270.579908, "o", "*"] +[1270.696635, "o", ")"] +[1271.552099, "o", "$"] +[1271.941288, "o", "e"] +[1272.232936, "o", "p"] +[1272.416525, "o", "s"] +[1273.783112, "o", "\b\u001b[K"] +[1273.87923, "o", "\b\u001b[K"] +[1273.942963, "o", "s"] +[1274.127877, "o", "p"] +[1274.688937, "o", ")"] +[1277.832273, "o", "\r\n"] +[1277.834178, "o", "$1 = (void *) \u001b[34m0xc15d3840\u001b[m <\u001b[33msysvec_apic_timer_interrupt\u001b[m>\r\n(gdb) "] +[1280.216526, "o", "#"] +[1280.440317, "o", " "] +[1280.905338, "o", "n"] +[1281.006222, "o", "e"] +[1281.096051, "o", "x"] +[1281.352079, "o", "t"] +[1281.45623, "o", " "] +[1281.512205, "o", "w"] +[1281.592294, "o", "e"] +[1281.728646, "o", " "] +[1281.887957, "o", "s"] +[1282.014283, "o", "h"] +[1282.096593, "o", "o"] +[1282.208553, "o", "u"] +[1282.336615, "o", "l"] +[1282.448312, "o", "d"] +[1282.49654, "o", " "] +[1282.784631, "o", "h"] +[1282.889574, "o", "a"] +[1283.030069, "o", "v"] +[1283.096451, "o", "e"] +[1283.14104, "o", " "] +[1283.336121, "o", " "] +[1283.640365, "o", "0"] +[1284.105053, "o", "\b\u001b[K"] +[1284.232359, "o", "\b\u001b[K"] +[1284.456187, "o", "0"] +[1286.217444, "o", ","] +[1286.428228, "o", " "] +[1286.634031, "o", "t"] +[1286.725784, "o", "h"] +[1286.864535, "o", "e"] +[1286.968074, "o", "n"] +[1287.047946, "o", " "] +[1287.143945, "o", "t"] +[1287.24016, "o", "h"] +[1287.312374, "o", "e"] +[1287.434149, "o", " "] +[1287.648797, "o", "o"] +[1287.853749, "o", "l"] +[1287.93696, "o", "d"] +[1288.056131, "o", " "] +[1288.917063, "o", "E"] +[1289.135849, "o", "I"] +[1289.231925, "o", "P"] +[1291.056219, "o", "\r\n(gdb) "] +[1292.1377, "o", "p"] +[1292.411602, "o", "r"] +[1292.528097, "o", "i"] +[1292.599943, "o", "n"] +[1293.344827, "o", "\b\b\b\b# next we should have 0, then the old EIP"] +[1294.000313, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[9Pprint (void *)(*(uint32_t*)$esp)"] +[1294.377399, "o", "\b"] +[1294.664387, "o", "\b"] +[1294.842701, "o", "\b"] +[1294.944346, "o", "\b"] +[1295.296547, "o", "\b"] +[1295.886427, "o", "($esp)\b\b\b\b\b"] +[1296.416543, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[1296.608222, "o", "\b"] +[1297.026087, "o", "+)\b\b\u001b[1P)\b"] +[1297.560139, "o", "+)\b"] +[1297.916844, "o", "4)\b"] +[1298.397975, "o", "\u001b[C)\b"] +[1299.632357, "o", "\r\n"] +[1299.633204, "o", "$2 = (void *) \u001b[34m0x0\u001b[m\r\n(gdb) "] +[1300.373248, "o", "print (void *)(*(uint32_t*)($esp+4))"] +[1300.688192, "o", "\b"] +[1300.856538, "o", "\b"] +[1301.000194, "o", "\b"] +[1301.168188, "o", "\u001b[1P))\b\b"] +[1301.952667, "o", "8))\b\b"] +[1302.457015, "o", "\r\n"] +[1302.458153, "o", "$3 = (void *) \u001b[34m0x448abff0\u001b[m\r\n(gdb) "] +[1303.41604, "o", "#"] +[1303.712934, "o", " "] +[1304.968705, "o", "t"] +[1305.080618, "o", "h"] +[1305.112913, "o", "i"] +[1305.320332, "o", "s"] +[1305.450583, "o", " "] +[1305.784044, "o", "c"] +[1305.879818, "o", "e"] +[1306.01577, "o", "r"] +[1306.215986, "o", "t"] +[1306.408455, "o", "a"] +[1306.509271, "o", "i"] +[1306.568281, "o", "n"] +[1306.736051, "o", "l"] +[1306.968107, "o", "y"] +[1307.032157, "o", " "] +[1307.240792, "o", "l"] +[1307.392111, "o", "o"] +[1307.523872, "o", "o"] +[1307.56085, "o", "k"] +[1307.704084, "o", "s"] +[1307.760884, "o", " "] +[1308.464805, "o", "l"] +[1308.632045, "o", "i"] +[1308.784287, "o", "k"] +[1308.847688, "o", "e"] +[1308.920087, "o", " "] +[1309.088096, "o", "a"] +[1309.16807, "o", " "] +[1310.540839, "o", "u"] +[1310.625164, "o", "s"] +[1310.681276, "o", "e"] +[1310.7603, "o", "r"] +[1310.887811, "o", "s"] +[1310.960368, "o", "p"] +[1311.072017, "o", "a"] +[1311.145256, "o", "c"] +[1311.223973, "o", "e"] +[1311.368353, "o", " "] +[1311.457182, "o", "a"] +[1311.601448, "o", "d"] +[1311.769504, "o", "d"] +[1311.968497, "o", "r"] +[1312.000587, "o", "e"] +[1312.160017, "o", "s"] +[1312.296067, "o", "s"] +[1312.672663, "o", "\r\n(gdb) "] +[1313.104304, "o", "#"] +[1313.247936, "o", " "] +[1313.591981, "o", "s"] +[1313.663257, "o", "o"] +[1313.7933, "o", " "] +[1314.376222, "o", "a"] +[1314.488137, "o", " "] +[1315.711982, "o", "p"] +[1315.873232, "o", "r"] +[1315.976308, "o", "i"] +[1316.097279, "o", "v"] +[1316.192412, "o", "i"] +[1317.808159, "o", "l"] +[1317.888621, "o", "e"] +[1318.806197, "o", "g"] +[1318.880036, "o", "e"] +[1319.007839, "o", " "] +[1320.044197, "o", "t"] +[1320.232041, "o", "r"] +[1320.37594, "o", "a"] +[1320.790313, "o", "n"] +[1320.960849, "o", "s"] +[1321.043584, "o", "i"] +[1321.228877, "o", "t"] +[1321.2893, "o", "i"] +[1321.328086, "o", "o"] +[1321.488163, "o", "n"] +[1321.560022, "o", " "] +[1321.743979, "o", "h"] +[1321.784015, "o", "a"] +[1321.883377, "o", "s"] +[1321.978322, "o", " "] +[1322.432097, "o", "h"] +[1322.504039, "o", "a"] +[1322.64008, "o", "p"] +[1322.751806, "o", "p"] +[1322.840014, "o", "e"] +[1322.952267, "o", "n"] +[1323.065126, "o", "e"] +[1323.222808, "o", "d"] +[1324.320102, "o", "\r\n(gdb) "] +[1328.287918, "o", "#"] +[1328.5767, "o", " "] +[1328.728319, "o", "t"] +[1328.807873, "o", "h"] +[1328.922227, "o", "e"] +[1329.031848, "o", " "] +[1329.201101, "o", "n"] +[1329.255849, "o", "e"] +[1329.3283, "o", "x"] +[1329.632289, "o", "t"] +[1329.720295, "o", " "] +[1329.85636, "o", "t"] +[1330.070787, "o", "w"] +[1330.180591, "o", "o"] +[1330.327382, "o", " "] +[1331.600174, "o", "v"] +[1331.688922, "o", "a"] +[1331.800273, "o", "l"] +[1331.967863, "o", "u"] +[1332.879624, "o", "e"] +[1333.008092, "o", "s"] +[1333.129677, "o", " "] +[1333.260857, "o", "o"] +[1333.408013, "o", "n"] +[1333.491288, "o", " "] +[1333.585346, "o", "t"] +[1333.67251, "o", "h"] +[1333.744198, "o", "e"] +[1333.824197, "o", " "] +[1333.927752, "o", "s"] +[1334.023852, "o", "t"] +[1334.088274, "o", "a"] +[1334.278186, "o", "c"] +[1334.312208, "o", "k"] +[1334.4004, "o", " "] +[1334.479627, "o", "s"] +[1334.569724, "o", "h"] +[1334.653599, "o", "o"] +[1334.761086, "o", "u"] +[1334.879876, "o", "l"] +[1334.967955, "o", "d"] +[1335.039806, "o", " "] +[1337.127967, "o", "b"] +[1337.568187, "o", "e"] +[1337.733548, "o", " "] +[1337.829755, "o", "t"] +[1337.920319, "o", "h"] +[1337.983981, "o", "e"] +[1338.096372, "o", " "] +[1338.472148, "o", "o"] +[1338.656814, "o", "l"] +[1338.768352, "o", "d"] +[1338.916423, "o", " "] +[1339.202871, "o", "C"] +[1339.327983, "o", "S"] +[1339.440216, "o", " "] +[1339.57566, "o", "a"] +[1339.70382, "o", "n"] +[1339.800022, "o", "d"] +[1339.878404, "o", " "] +[1342.408345, "o", "o"] +[1342.521478, "o", "d"] +[1342.569261, "o", "l"] +[1342.687708, "o", " "] +[1342.896122, "o", "E"] +[1343.07254, "o", "F"] +[1343.160126, "o", "L"] +[1343.252373, "o", "A"] +[1346.581722, "o", "G"] +[1346.645084, "o", "S"] +[1346.984099, "o", "\r\n(gdb) "] +[1349.368274, "o", "# the next two values on the stack should be the old CS and old EFLAGS"] +[1349.503807, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[30Pso a privilege transition has happened"] +[1349.640129, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[Cthis certainly looks like a userspace address"] +[1350.086523, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[11Pprint (void *)(*(uint32_t*)($esp+8))"] +[1350.592191, "o", "\b"] +[1350.744442, "o", "\b"] +[1350.871908, "o", "\b"] +[1351.056417, "o", "\u001b[1P))\b\b"] +[1351.150322, "o", "1))\b\b"] +[1351.246318, "o", "2))\b\b"] +[1351.576371, "o", "\r\n"] +[1351.577107, "o", "$4 = (void *) \u001b[34m0x73\u001b[m\r\n(gdb) "] +[1352.136702, "o", "print (void *)(*(uint32_t*)($esp+12))"] +[1352.288158, "o", "\b"] +[1352.424696, "o", "\b"] +[1352.593518, "o", "\b"] +[1353.016482, "o", "\u001b[1P))\b\b"] +[1353.136234, "o", "4))\b\b"] +[1360.824627, "o", "\r\n"] +[1360.825733, "o", "$5 = (void *) \u001b[34m0x2820000\u001b[m\r\n"] +[1360.825786, "o", "(gdb) "] +[1363.824749, "o", "#"] +[1363.925525, "o", " "] +[1364.090304, "o", "l"] +[1364.897579, "o", "\b\u001b[K"] +[1365.125951, "o", "y"] +[1365.207584, "o", "o"] +[1365.719749, "o", "\b\u001b[K"] +[1365.840063, "o", "\b\u001b[K"] +[1366.048291, "o", "n"] +[1366.112558, "o", "o"] +[1366.280917, "o", "t"] +[1366.405468, "o", "i"] +[1366.600048, "o", "c"] +[1366.688182, "o", "e"] +[1366.799955, "o", " "] +[1366.953361, "o", "t"] +[1367.071836, "o", "h"] +[1367.188867, "o", "a"] +[1367.287932, "o", "t"] +[1367.379658, "o", " "] +[1367.521389, "o", "t"] +[1367.607602, "o", "h"] +[1367.695693, "o", "e"] +[1367.815874, "o", " "] +[1373.74383, "o", "o"] +[1373.896155, "o", "l"] +[1374.000406, "o", "d"] +[1374.05883, "o", " "] +[1374.488016, "o", "C"] +[1374.560064, "o", "S"] +[1374.70417, "o", " "] +[1374.927765, "o", "i"] +[1375.048476, "o", "s"] +[1375.159989, "o", " "] +[1375.523958, "o", "d"] +[1375.672027, "o", "i"] +[1375.823809, "o", "f"] +[1376.352436, "o", "f"] +[1376.488975, "o", "e"] +[1376.653416, "o", "r"] +[1376.712524, "o", "e"] +[1376.847597, "o", "n"] +[1377.00774, "o", "t"] +[1377.337116, "o", " "] +[1380.176217, "o", "\r\n"] +[1380.17633, "o", "(gdb) "] +[1381.519619, "o", "p"] +[1381.727674, "o", "r"] +[1381.807962, "o", "i"] +[1381.847678, "o", "n"] +[1381.992661, "o", "t"] +[1382.213413, "o", " "] +[1383.487682, "o", "/"] +[1383.720038, "o", " "] +[1384.284125, "o", "$"] +[1384.785109, "o", "\b\u001b[K"] +[1384.896215, "o", "\b\u001b[K"] +[1384.992093, "o", "x"] +[1385.119757, "o", " "] +[1385.462147, "o", "$"] +[1385.975882, "o", "c"] +[1386.039807, "o", "s"] +[1387.288752, "o", "\r\n"] +[1387.288917, "o", "$6 = 0x60\r\n(gdb) "] +[1392.071906, "o", "#"] +[1392.183952, "o", " "] +[1392.530314, "o", "s"] +[1392.64009, "o", "o"] +[1392.760001, "o", " "] +[1392.935708, "o", "w"] +[1393.023798, "o", "e"] +[1393.143801, "o", " "] +[1394.480397, "o", "s"] +[1394.552322, "o", "h"] +[1394.616216, "o", "o"] +[1394.741538, "o", "u"] +[1394.8873, "o", "l"] +[1394.991717, "o", "d"] +[1395.119869, "o", " "] +[1395.764404, "o", "h"] +[1395.81421, "o", "a"] +[1395.96834, "o", "v"] +[1396.047828, "o", "e"] +[1396.087582, "o", " "] +[1396.24761, "o", "t"] +[1396.51192, "o", "w"] +[1396.608042, "o", "o"] +[1396.706285, "o", " "] +[1396.859207, "o", "e"] +[1396.952619, "o", "x"] +[1397.184817, "o", "t"] +[1397.343837, "o", "r"] +[1397.408411, "o", "a"] +[1397.599725, "o", " "] +[1400.600069, "o", "v"] +[1400.655484, "o", "a"] +[1400.767453, "o", "l"] +[1400.91153, "o", "u"] +[1400.983774, "o", "e"] +[1401.175892, "o", "s"] +[1401.208238, "o", " "] +[1401.319824, "o", "o"] +[1401.502175, "o", "n"] +[1401.582375, "o", " "] +[1401.63978, "o", "t"] +[1401.768209, "o", "h"] +[1401.823535, "o", "e"] +[1401.888547, "o", " "] +[1402.096021, "o", "s"] +[1402.263991, "o", "t"] +[1402.335885, "o", "a"] +[1403.287574, "o", "c"] +[1403.423212, "o", "k"] +[1405.773719, "o", ":"] +[1405.903731, "o", " "] +[1406.199721, "o", "o"] +[1406.368541, "o", "l"] +[1406.416058, "o", "d"] +[1406.503703, "o", " "] +[1406.701576, "o", "E"] +[1406.904167, "o", "S"] +[1407.007965, "o", "P"] +[1407.240691, "o", " "] +[1407.39138, "o", "a"] +[1407.527755, "o", "n"] +[1407.608416, "o", "d"] +[1407.695859, "o", " "] +[1407.807966, "o", "o"] +[1407.976125, "o", "l"] +[1408.048128, "o", "d"] +[1408.141001, "o", " "] +[1408.353815, "o", "S"] +[1408.495468, "o", "S"] +[1410.367923, "o", "\r\n(gdb) "] +[1969.053941, "o", "# we should have two extra values on stack: old ESP and old SS"] +[1969.262191, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[Cprint /x $cs\u001b[K"] +[1969.635988, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C# notice that CS is different "] +[1970.061803, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[Cprint (void *)(*(uint32_t*)($esp+16))"] +[1970.590698, "o", "\b"] +[1970.742563, "o", "\b"] +[1970.877824, "o", "\b"] +[1971.518067, "o", "\b"] +[1971.789987, "o", "\u001b[1P6))\b\b\b"] +[1971.925709, "o", "\u001b[1P))\b\b"] +[1972.062369, "o", "2))\b\b"] +[1972.414001, "o", "0))\b\b"] +[1975.022556, "o", "\r\n"] +[1975.023378, "o", "$10 = (void *) \u001b[34m0xbfe27990\u001b[m\r\n(gdb) "] +[1976.069818, "o", "print (void *)(*(uint32_t*)($esp+20))"] +[1976.403385, "o", "\b"] +[1976.549892, "o", "\b"] +[1976.709579, "o", "\b"] +[1977.038119, "o", "\b"] +[1979.18221, "o", "\u001b[1P0))\b\b\b"] +[1979.334363, "o", "\u001b[1P))\b\b"] +[1979.446076, "o", "2))\b\b"] +[1979.598023, "o", "4))\b\b"] +[1981.981611, "o", "\r\n"] +[1981.982297, "o", "$11 = (void *) \u001b[34m0x7b\u001b[m\r\n(gdb) "] +[1987.957905, "o", "#"] +[1988.1735, "o", " "] +[1988.405662, "o", "n"] +[1988.453735, "o", "o"] +[1988.565807, "o", "t"] +[1988.725502, "o", "i"] +[1988.858572, "o", "c"] +[1988.926557, "o", "e"] +[1989.043672, "o", " "] +[1989.14232, "o", "t"] +[1989.261751, "o", "h"] +[1989.301689, "o", "a"] +[1989.405339, "o", "t"] +[1989.541661, "o", " "] +[1992.358583, "o", "S"] +[1992.501591, "o", "S"] +[1992.677657, "o", " "] +[1992.982405, "o", "i"] +[1993.088714, "o", "s"] +[1993.267478, "o", " "] +[1993.477794, "o", "a"] +[1993.582886, "o", "l"] +[1994.310019, "o", "s"] +[1994.421693, "o", "o"] +[1994.501651, "o", " "] +[1997.285443, "o", "d"] +[1997.421795, "o", "i"] +[1997.533942, "o", "f"] +[1997.678316, "o", "f"] +[1997.8058, "o", "e"] +[1997.965947, "o", "r"] +[1998.085951, "o", "e"] +[1998.357808, "o", "n"] +[1998.494273, "o", "t"] +[1998.651186, "o", " "] +[1998.827228, "o", "t"] +[1998.967293, "o", "h"] +[1999.030052, "o", "en"] +[1999.197533, "o", " "] +[1999.55771, "o", "t"] +[1999.637997, "o", "h"] +[1999.741665, "o", "e"] +[1999.849221, "o", " "] +[2000.044744, "o", "c"] +[2000.117566, "o", "u"] +[2000.278172, "o", "r"] +[2000.413666, "o", "r"] +[2000.493754, "o", "e"] +[2000.557567, "o", "n"] +[2000.715842, "o", "t"] +[2000.813749, "o", " "] +[2001.213728, "o", "s"] +[2001.357872, "o", "s"] +[2002.046006, "o", "\r\n(gdb) "] +[2002.357919, "o", "p"] +[2002.549923, "o", "r"] +[2002.613931, "o", "i"] +[2002.685486, "o", "n"] +[2002.782565, "o", "t"] +[2002.885912, "o", " "] +[2003.285786, "o", "/"] +[2003.517441, "o", "x"] +[2003.597579, "o", " "] +[2003.984994, "o", "$"] +[2005.414711, "o", "s"] +[2005.55787, "o", "s"] +[2006.605906, "o", "\r\n"] +[2006.606043, "o", "$12 = 0x68\r\n(gdb) "] +[2012.613496, "o", "#"] +[2012.765597, "o", " "] +[2012.869808, "o", "a"] +[2012.981679, "o", "n"] +[2013.045602, "o", "d"] +[2013.157599, "o", " "] +[2013.359393, "o", "t"] +[2013.420279, "o", "o"] +[2013.462073, "o", " "] +[2013.693767, "o", "c"] +[2013.76528, "o", "o"] +[2013.861277, "o", "n"] +[2013.910528, "o", "f"] +[2014.01357, "o", "i"] +[2014.262175, "o", "r"] +[2014.381666, "o", "m"] +[2014.558588, "o", " "] +[2014.693456, "o", "t"] +[2014.805673, "o", "h"] +[2014.93382, "o", "a"] +[2014.97489, "o", "t"] +[2015.946969, "o", " "] +[2020.233739, "o", " 0xbfe27990"] +[2020.77356, "o", " "] +[2021.302126, "o", "i"] +[2021.43803, "o", "s"] +[2021.534611, "o", " "] +[2021.725567, "o", "a"] +[2022.560398, "o", " "] +[2022.830342, "o", "u"] +[2022.933333, "o", "s"] +[2023.038594, "o", "e"] +[2023.101613, "o", "r"] +[2023.714446, "o", "s"] +[2023.826778, "o", "p"] +[2023.909568, "o", "a"] +[2023.965588, "o", "c"] +[2024.062612, "o", "e"] +[2024.141261, "o", " "] +[2024.285484, "o", "s"] +[2024.39776, "o", "t"] +[2024.454087, "o", "a"] +[2024.666852, "o", "c"] +[2024.708226, "o", "k"] +[2024.98393, "o", " "] +[2026.886057, "o", "\r\n(gdb) "] +[2027.325884, "o", "#"] +[2027.71743, "o", " "] +[2027.981779, "o", "l"] +[2028.063253, "o", "e"] +[2028.205611, "o", "t"] +[2028.317878, "o", " "] +[2028.502039, "o", "j"] +[2028.645923, "o", "u"] +[2028.813377, "o", "m"] +[2028.893359, "o", "p"] +[2028.990456, "o", " "] +[2029.172262, "o", "b"] +[2029.245318, "o", "a"] +[2029.334424, "o", "c"] +[2029.42394, "o", "k"] +[2029.510273, "o", " "] +[2029.701962, "o", "t"] +[2029.74145, "o", "o"] +[2029.861488, "o", " "] +[2029.957501, "o", "t"] +[2030.101868, "o", "h"] +[2030.166747, "o", "e"] +[2030.285553, "o", " "] +[2031.173547, "o", "t"] +[2031.253912, "o", "e"] +[2031.334197, "o", "r"] +[2031.421792, "o", "m"] +[2031.501571, "o", "i"] +[2031.621782, "o", "n"] +[2031.72392, "o", "a"] +[2031.829432, "o", "l"] +[2032.245715, "o", "\r\n(gdb) "] +[2033.431185, "o", "quit\r\n"] +[2033.431243, "o", "A debugging session is active.\r\n\r\n\tInferior 1 [process 1] will be detached.\r\n\r\nQuit anyway? (y or n) "] +[2034.445451, "o", "y"] +[2034.541829, "o", "\r\nDetaching from program: /linux/vmlinux, process 1\r\n"] +[2034.542671, "o", "Ending remote debugging.\r\n"] +[2034.542784, "o", "[Inferior 1 (process 1) detached]\r\n"] +[2034.548935, "o", "make: *** [qemu/Makefile:54: gdb] Interrupt\r\n"] +[2034.548997, "o", "\r\n$ "] +[2035.149297, "o", "m"] +[2035.309489, "o", "i"] +[2035.429356, "o", "n"] +[2035.629299, "o", "c"] +[2036.205576, "o", "\b \b"] +[2036.373293, "o", "i"] +[2036.669373, "o", "c"] +[2036.82129, "o", "o"] +[2036.909198, "o", "m"] +[2037.126024, "o", "d"] +[2037.50137, "o", " "] +[2037.741686, "o", "\b \b"] +[2037.861471, "o", "\b \b"] +[2037.973342, "o", " "] +[2038.069309, "o", "-"] +[2039.956556, "o", "D"] +[2041.021427, "o", " "] +[2041.348903, "o", "s"] +[2041.429401, "o", "e"] +[2041.509259, "o", "r"] +[2041.573313, "o", "i"] +[2041.685198, "o", "a"] +[2041.757143, "o", "l"] +[2041.917485, "o", "."] +[2042.108869, "o", "p"] +[2042.253212, "o", "t"] +[2042.477348, "o", "s"] +[2043.621531, "o", "\r\n"] +[2043.622396, "o", "\u001b[!p\u001b[?3;4l\u001b[4l\u001b>\u001b[0m\u001b(B\u001b[?1h\u001b=\u001b[H\u001b[2J"] +[2043.622745, "o", "\u001b[?12l\u001b[?25h\nWelcome to minicom 2.7.1\r\n\nOPTIONS: I18n \r\nCompiled on Dec 23 2019, 02:06:26.\r\nPort serial.pts, 22:50:04\r\n\nPress CTRL-A Z for help on special keys\r\n\n"] +[2044.554156, "o", "\n"] +[2044.562897, "o", "root@qemux86:~# "] +[2047.455019, "o", "t"] +[2047.542613, "o", "o"] +[2047.606554, "o", "p"] +[2047.996772, "o", "\r\n"] +[2048.379869, "o", "\u001b[1;1H\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\u001b[1;1H\u001b[KMem: 31172K used, 209508K free, 172K shrd, 368K buff, 4344K cached"] +[2048.380063, "o", "\r\n"] +[2048.380683, "o", "CPU: 31% usr 68% sys 0% nic 0% idle 0% io 0% irq 0% sirq"] +[2048.380824, "o", "\r\n"] +[2048.381861, "o", "Load average: 1.12 0.81 0.53 4/40 386"] +[2048.38202, "o", "\r\n"] +[2048.456891, "o", "\u001b[0m\u001b(B\u001b[7m PID PPID USER STAT VSZ %VSZ %CPU COMMAND"] +[2048.457162, "o", "\r\n"] +[2048.457905, "o", "\u001b[0m\u001b(B 347 345 root R 3124 1% 26% -sh"] +[2048.45804, "o", "\r\n"] +[2048.472796, "o", " 1 0 root S 2004 1% 16% init [5]"] +[2048.473041, "o", "\r\n"] +[2048.473661, "o", " 374 345 root R 2828 1% 11% top"] +[2048.473774, "o", "\r\n"] +[2048.475752, "o", " 10 2 root IW 0 0% 5% [rcu_sched]"] +[2048.47595, "o", "\r\n"] +[2048.476546, "o", " 345 1 root S 2972 1% 0% -sh"] +[2048.476691, "o", "\r\n"] +[2048.477249, "o", " 198 1 root S 2828 1% 0% /sbin/syslogd -n -O /var/log/messages"] +[2048.477504, "o", "\r\n"] +[2048.477969, "o", " 201 1 root S 2828 1% 0% /sbin/klogd -n"] +[2048.47827, "o", "\r\n"] +[2048.483281, "o", " 187 1 root S 2828 1% 0% udhcpc -R -b -p /var/run/udhcpc.eth0.p\u001b[12;80H"] +[2048.483527, "o", "\r\n"] +[2048.484037, "o", " 207 1 root S 2828 1% 0% /sbin/getty 38400 tty1"] +[2048.48425, "o", "\r\n"] +[2048.484667, "o", " 209 1 root S 2828 1% 0% /sbin/getty 38400 tty2"] +[2048.484914, "o", "\r\n"] +[2048.48537, "o", " 210 1 root S 2828 1% 0% /sbin/getty 38400 tty3"] +[2048.485513, "o", "\r\n"] +[2048.486013, "o", " 211 1 root S 2828 1% 0% /sbin/getty 38400 tty4"] +[2048.48629, "o", "\r\n"] +[2048.490808, "o", " 212 1 root S 2828 1% 0% /sbin/getty 38400 tty5"] +[2048.491041, "o", "\r\n"] +[2048.491575, "o", " 42 2 root SWN 0 0% 0% [kmemleak]"] +[2048.491767, "o", "\r\n"] +[2048.492158, "o", " 9 2 root SW 0 0% 0% [ksoftirqd/0]"] +[2048.492351, "o", "\r\n"] +[2048.492729, "o", " 39 2 root IW 0 0% 0% [kworker/0:2-eve]"] +[2048.492892, "o", "\r\n"] +[2048.493419, "o", " 13 2 root SW 0 0% 0% [kdevtmpfs]"] +[2048.493507, "o", "\r\n"] +[2048.493872, "o", " 38 2 root IW 0 0% 0% [kworker/u2:1-ev]"] +[2048.494245, "o", "\r\n"] +[2048.499119, "o", " 7 2 root IW 0 0% 0% [kworker/u2:0-ev]"] +[2048.499359, "o", "\r\n"] +[2048.499523, "o", " 34 2 root IW< 0 0% 0% [kworker/0:1H-kb]\r"] +[2049.597664, "o", "\n\u001b[23;80H \u001b[24;1H"] +[2049.601147, "o", "root@qemux86:~# "] +[2050.846207, "o", "c"] +[2050.950473, "o", "a"] +[2051.318748, "o", "t"] +[2051.478115, "o", " "] +[2051.6701, "o", "/"] +[2051.789863, "o", "p"] +[2051.862219, "o", "r"] +[2052.118358, "o", "o"] +[2052.357989, "o", "c"] +[2052.462199, "o", "/"] +[2054.438526, "o", "3"] +[2055.37389, "o", "4"] +[2055.414188, "o", "7"] +[2055.710106, "o", "/"] +[2055.966042, "o", "m"] +[2056.030253, "o", "a"] +[2056.126617, "o", "p"] +[2056.237966, "o", "s"] +[2056.751199, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.776691, "o", "08048000-080c2000 r-xp 00000000 fe:00 669 /bin/busybox.nosuid"] +[2056.776882, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.777068, "o", "080c2000-080c3000 r--p 00079000 fe:00 669 /bin/busybox.nosuid"] +[2056.777196, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.77744, "o", "080c3000-080c4000 rw-p 0007a000 fe:00 669 /bin/busybox.nosuid"] +[2056.777507, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.777832, "o", "080c4000-080c6000 rw-p 00000000 00:00 0 "] +[2056.777966, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.784163, "o", "08572000-08593000 rw-p 00000000 00:00 0 [heap]"] +[2056.784397, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.784596, "o", "4480c000-4482e000 r-xp 00000000 fe:00 576 /lib/ld-2.25.so"] +[2056.784771, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.784985, "o", "4482e000-4482f000 r--p 00021000 fe:00 576 /lib/ld-2.25.so"] +[2056.785371, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.785477, "o", "4482f000-44830000 rw-p 00022000 fe:00 576 /lib/ld-2.25.so"] +[2056.785705, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.785842, "o", "44832000-449a9000 r-xp 00000000 fe:00 581 /lib/libc-2.25.so"] +[2056.786153, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.786344, "o", "449a9000-449ab000 r--p 00176000 fe:00 581 /lib/libc-2.25.so"] +[2056.786584, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.786747, "o", "449ab000-449ac000 rw-p 00178000 fe:00 581 /lib/libc-2.25.so"] +[2056.786978, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.787073, "o", "449ac000-449af000 rw-p 00000000 00:00 0 "] +[2056.787189, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.787414, "o", "449b1000-44a09000 r-xp 00000000 fe:00 641 /lib/libm-2.25.so"] +[2056.787514, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.787629, "o", "44a09000-44a0a000 r--p 00057000 fe:00 641 /lib/libm-2.25.so"] +[2056.787795, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.787962, "o", "44a0a000-44a0b000 rw-p 00058000 fe:00 641 /lib/libm-2.25.so"] +[2056.788132, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.78828, "o", "b7f1e000-b7f44000 rw-p 00000000 00:00 0 "] +[2056.788532, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.788657, "o", "b7f61000-b7f77000 r-xp 00000000 fe:00 579 /lib/libnsl-2.25.so"] +[2056.788811, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.789014, "o", "b7f77000-b7f78000 r--p 00015000 fe:00 579 /lib/libnsl-2.25.so"] +[2056.789111, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.789243, "o", "b7f78000-b7f79000 rw-p 00016000 fe:00 579 /lib/libnsl-2.25.so"] +[2056.789421, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.789588, "o", "b7f79000-b7f7b000 rw-p 00000000 00:00 0 "] +[2056.789746, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.789877, "o", "b7f7b000-b7f82000 r-xp 00000000 fe:00 608 /lib/libnss_compat-2.25.so"] +[2056.790117, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.79029, "o", "b7f82000-b7f83000 ---p 00007000 fe:00 608 /lib/libnss_compat-2.25.so"] +[2056.790438, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.790597, "o", "b7f83000-b7f84000 r--p 00007000 fe:00 608 /lib/libnss_compat-2.25.so"] +[2056.790802, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.790899, "o", "b7f84000-b7f85000 rw-p 00008000 fe:00 608 /lib/libnss_compat-2.25.so"] +[2056.791055, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.791213, "o", "b7f86000-b7f88000 rw-p 00000000 00:00 0 "] +[2056.79138, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.791605, "o", "b7f88000-b7f8c000 r--p 00000000 00:00 0 [vvar]"] +[2056.791733, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.791833, "o", "b7f8c000-b7f8e000 r-xp 00000000 00:00 0 [vdso]"] +[2056.792086, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.792209, "o", "bfe08000-bfe29000 rw-p 00000000 00:00 0 [stack]"] +[2056.792366, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[2056.81284, "o", "root@qemux86:~# "] +[2062.022254, "o", "#"] +[2062.222725, "o", " "] +[2064.231146, "o", " "] +[2064.231511, "o", "0"] +[2064.231736, "o", "x"] +[2064.232109, "o", "b"] +[2064.232357, "o", "f"] +[2064.23262, "o", "e"] +[2064.23285, "o", "2"] +[2064.23307, "o", "7"] +[2064.233356, "o", "9"] +[2064.233643, "o", "9"] +[2064.233852, "o", "0"] +[2065.526575, "o", " "] +[2068.24684, "o", "p"] +[2068.37458, "o", "o"] +[2069.389314, "o", "i"] +[2069.477747, "o", "n"] +[2069.598037, "o", "t"] +[2069.838099, "o", "s"] +[2069.974039, "o", " "] +[2071.190877, "o", "t"] +[2071.230772, "o", "o"] +[2071.325977, "o", " "] +[2073.598171, "o", "s"] +[2074.46266, "o", "t"] +[2074.559024, "o", "a"] +[2074.798529, "o", "c"] +[2074.862792, "o", "k"] +[2076.69481, "o", " "] +[2076.942032, "o", "i"] +[2077.014286, "o", "n"] +[2077.197566, "o", "d"] +[2077.31816, "o", "e"] +[2077.485824, "o", "e"] +[2077.597694, "o", "d"] diff --git a/refs/pull/405/merge/_images/kernel-virtmem-map.png b/refs/pull/405/merge/_images/kernel-virtmem-map.png new file mode 100644 index 00000000..25ffb7a6 Binary files /dev/null and b/refs/pull/405/merge/_images/kernel-virtmem-map.png differ diff --git a/refs/pull/405/merge/_images/kernel-virtmem-map1.png b/refs/pull/405/merge/_images/kernel-virtmem-map1.png new file mode 100644 index 00000000..25ffb7a6 Binary files /dev/null and b/refs/pull/405/merge/_images/kernel-virtmem-map1.png differ diff --git a/refs/pull/405/merge/_images/kernel_threads.cast b/refs/pull/405/merge/_images/kernel_threads.cast new file mode 100644 index 00000000..9001f42b --- /dev/null +++ b/refs/pull/405/merge/_images/kernel_threads.cast @@ -0,0 +1,1350 @@ +{"version": 2, "width": 80, "height": 24, "timestamp": 1615904217, "idle_time_limit": 1.0, "env": {"SHELL": null, "TERM": "xterm"}} +[0.002092, "o", "$ "] +[1.411094, "o", "m"] +[1.492191, "o", "a"] +[1.57441, "o", "k"] +[1.686334, "o", "e"] +[1.750754, "o", " "] +[1.951, "o", "g"] +[2.039054, "o", "d"] +[2.111579, "o", "b"] +[2.350633, "o", "\r\n"] +[2.356524, "o", "gdb -ex \"target remote localhost:1234\" /linux/vmlinux\r\n"] +[2.390298, "o", "\u001b[35;1m\u001b[35;1mGNU gdb \u001b[m\u001b[35;1m(Ubuntu 9.2-0ubuntu1~20.04) \u001b[m\u001b[35;1m9.2\u001b[m\u001b[35;1m\r\n\u001b[m\u001b[mCopyright (C) 2020 Free Software Foundation, Inc.\r\nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\r\nThis is free software: you are free to change and redistribute it.\r\nThere is NO WARRANTY, to the extent permitted by law.\r\nType \"show copying\" and \"show warranty\" for details.\r\nThis GDB was configured as \"x86_64-linux-gnu\".\r\nType \"show configuration\" for configuration details.\r\nFor bug reporting instructions, please see:\r\n<http://www.gnu.org/software/gdb/bugs/>.\r\nFind the GDB manual and other documentation resources online at:\r\n <http://www.gnu.org/software/gdb/documentation/>.\r\n\r\nFor help, type \"help\".\r\nType \"apropos word\" to search for commands related to \"word\"...\r\n"] +[2.390737, "o", "Reading symbols from \u001b[32m/linux/vmlinux\u001b[m...\r\n"] +[2.944725, "o", "Remote debugging using localhost:1234\r\n"] +[2.957375, "o", "\u001b[33mdefault_idle\u001b[m () at \u001b[32march/x86/kernel/process.c\u001b[m:689\r\n"] +[2.95746, "o", "689\t}\r\n"] +[2.957779, "o", "(gdb) "] +[5.428286, "o", "l"] +[5.524636, "o", "s"] +[5.780627, "o", "-"] +[6.367098, "o", "p"] +[6.509506, "o", "x"] +[7.278986, "o", "\r\n"] +[7.279172, "o", "Undefined command: \"ls-px\". Try \"help\".\r\n(gdb) "] +[8.676984, "o", "l"] +[8.850763, "o", "x"] +[9.039146, "o", "-"] +[9.318467, "o", "p"] +[9.500473, "o", "s"] +[9.750891, "o", "\r\n"] +[9.751114, "o", " TASK PID COMM\r\n"] +[9.75236, "o", "0xc17d02c0 0 swapper/0\r\n"] +[9.75369, "o", "0xc2530040 1 init\r\n"] +[9.7548, "o", "0xc2534080 2 kthreadd\r\n"] +[9.755807, "o", "0xc25360c0 3 rcu_gp\r\n"] +[9.756742, "o", "0xc2537100 4 rcu_par_gp\r\n"] +[9.757706, "o", "0xc2546180 6 kworker/0:0H\r\n"] +[9.758707, "o", "0xc25481c0 7 kworker/u2:0\r\n"] +[9.759604, "o", "0xc2549000 8 mm_percpu_wq\r\n"] +[9.76062, "o", "0xc254b040 9 ksoftirqd/0\r\n"] +[9.761626, "o", "0xc254c080 10 rcu_sched\r\n"] +[9.762529, "o", "0xc254e0c0 11 migration/0\r\n"] +[9.763454, "o", "0xc2572100 12 cpuhp/0\r\n"] +[9.764416, "o", "0xc2576140 13 kdevtmpfs\r\n"] +[9.765286, "o", "0xc2593180 14 netns\r\n"] +[9.766329, "o", "0xc26211c0 15 oom_reaper\r\n"] +[9.76739, "o", "0xc2623000 16 writeback\r\n"] +[9.768316, "o", "0xc25cd1c0 32 kblockd\r\n"] +[9.769188, "o", "0xc2638180 33 kworker/0:1\r\n"] +[9.770027, "o", "0xc2637140 34 kworker/0:1H\r\n"] +[9.770898, "o", "0xc2636100 35 kswapd0\r\n"] +[9.771804, "o", "0xc2634080 37 acpi_thermal_pm\r\n"] +[9.77276, "o", "0xc26350c0 38 kworker/u2:1\r\n"] +[9.773599, "o", "\u001b[m--Type <RET> for more, q to quit, c to continue without paging--"] +[16.511474, "o", "\r\n0xc2631040 39 kworker/0:2\r\n"] +[16.512921, "o", "0xc2630000 40 khvcd\r\n"] +[16.513907, "o", "0xc25d9180 41 ipv6_addrconf\r\n"] +[16.514686, "o", "0xc2627080 42 kmemleak\r\n"] +[16.515495, "o", "0xc26170c0 43 jbd2/vda-8\r\n"] +[16.516313, "o", "0xc2625040 44 ext4-rsv-conver\r\n"] +[16.517171, "o", "0xc842a1c0 187 udhcpc\r\n"] +[16.518006, "o", "0xcb365040 198 syslogd\r\n"] +[16.518734, "o", "0xc6730140 201 klogd\r\n"] +[16.519451, "o", "0xc260f100 207 getty\r\n"] +[16.520309, "o", "0xcb37a080 208 getty\r\n"] +[16.521243, "o", "0xc8431000 209 getty\r\n"] +[16.522122, "o", "0xc4b8a180 210 getty\r\n"] +[16.523042, "o", "0xcb375100 211 getty\r\n"] +[16.524007, "o", "0xca6931c0 212 getty\r\n"] +[16.524667, "o", "(gdb) "] +[18.27663, "o", " "] +[19.237048, "o", "\b\u001b[K"] +[19.663197, "o", "#"] +[19.822869, "o", " "] +[21.012324, "o", "n"] +[21.079126, "o", "o"] +[21.3069, "o", "t"] +[21.565299, "o", "e"] +[21.791988, "o", " "] +[21.989943, "o", "t"] +[22.079654, "o", "h"] +[22.152775, "o", "a"] +[22.271404, "o", "t"] +[22.358257, "o", " "] +[22.495177, "o", "t"] +[22.616552, "o", "h"] +[22.689874, "o", "e"] +[22.759133, "o", "r"] +[22.851398, "o", "e"] +[22.944484, "o", " "] +[23.047542, "o", "a"] +[23.143223, "o", "r"] +[23.236144, "o", "e"] +[23.30143, "o", " "] +[23.479486, "o", "s"] +[23.726797, "o", "e"] +[23.996443, "o", "v"] +[24.285069, "o", "e"] +[24.769554, "o", "\b\u001b[K"] +[24.888103, "o", "\b\u001b[K"] +[25.372766, "o", "v"] +[25.486693, "o", "e"] +[25.780145, "o", "r"] +[25.831058, "o", "a"] +[25.957718, "o", "l"] +[26.079508, "o", " "] +[26.253337, "o", "t"] +[26.309159, "o", "a"] +[26.511159, "o", "s"] +[26.601906, "o", "k"] +[26.721828, "o", "s"] +[27.244749, "o", " "] +[28.574755, "o", "t"] +[28.854002, "o", "a"] +[29.471312, "o", "\b\u001b[K"] +[29.676745, "o", "h"] +[29.754496, "o", "a"] +[29.887311, "o", "t"] +[29.958997, "o", " "] +[30.166519, "o", "s"] +[30.315248, "o", "t"] +[30.393086, "o", "a"] +[30.975307, "o", "r"] +[31.599184, "o", "t"] +[31.752243, "o", " "] +[31.879063, "o", "w"] +[31.967152, "o", "i"] +[32.078599, "o", "t"] +[32.166707, "o", "h"] +[32.270994, "o", " "] +[32.471433, "o", "t"] +[32.542586, "o", "h"] +[32.686761, "o", "e"] +[32.763813, "o", " "] +[33.296049, "o", "L"] +[33.87867, "o", "\b\u001b[K"] +[35.524303, "o", "K"] +[36.343905, "o", "\b\u001b[K"] +[36.510508, "o", "k"] +[37.48386, "o", " "] +[37.8357, "o", "l"] +[37.922486, "o", "e"] +[38.118439, "o", "t"] +[38.276721, "o", "t"] +[38.376646, "o", "e"] +[38.503033, "o", "r"] +[38.911624, "o", "\r\n(gdb) "] +[39.276285, "o", "#"] +[39.519145, "o", " "] +[39.750673, "o", "t"] +[39.85472, "o", "h"] +[39.950603, "o", "e"] +[40.108249, "o", "s"] +[40.271864, "o", "e"] +[40.511774, "o", " "] +[40.801505, "o", "("] +[41.030531, "o", "b"] +[41.118878, "o", "u"] +[41.230505, "o", "t"] +[41.314769, "o", " "] +[41.740861, "o", "n"] +[41.824881, "o", "o"] +[42.019385, "o", "t"] +[42.14018, "o", " "] +[42.254553, "o", "o"] +[42.338673, "o", "n"] +[42.493789, "o", "l"] +[42.662862, "o", "y"] +[42.75931, "o", " "] +[42.916086, "o", "t"] +[43.020488, "o", "h"] +[43.084785, "o", "e"] +[43.263329, "o", "s"] +[43.362693, "o", "e"] +[43.608998, "o", ")"] +[43.774713, "o", " "] +[43.894708, "o", "a"] +[44.062643, "o", "r"] +[44.118689, "o", "e"] +[44.2443, "o", " "] +[44.431308, "o", "k"] +[44.550679, "o", "e"] +[44.612908, "o", "r"] +[44.708174, "o", "n"] +[44.790351, "o", "e"] +[44.894934, "o", "l"] +[44.974263, "o", " "] +[45.204614, "o", "t"] +[45.327253, "o", "h"] +[45.388938, "o", "r"] +[45.438216, "o", "e"] +[45.518535, "o", "a"] +[45.773446, "o", "d"] +[45.822653, "o", "s"] +[46.775316, "o", "\r\n(gdb) "] +[53.767289, "o", "#"] +[54.624466, "o", " "] +[54.85786, "o", "t"] +[54.962973, "o", "h"] +[55.108379, "o", "e"] +[55.926781, "o", " "] +[56.132174, "o", "p"] +[56.246669, "o", "s"] +[56.342818, "o", " "] +[56.523069, "o", "u"] +[56.729793, "o", "t"] +[56.791601, "o", "i"] +[56.998652, "o", "l"] +[57.102951, "o", "i"] +[57.433973, "o", "t"] +[57.510405, "o", "y"] +[57.663099, "o", " "] +[57.931719, "o", "m"] +[58.030756, "o", "a"] +[58.234054, "o", "r"] +[58.334973, "o", "k"] +[58.532386, "o", "s"] +[58.678812, "o", " "] +[58.88646, "o", "t"] +[58.982125, "o", "h"] +[59.094825, "o", "e"] +[59.236552, "o", "n"] +[59.630822, "o", " "] +[59.967128, "o", "w"] +[60.050881, "o", "i"] +[60.182217, "o", "t"] +[60.246628, "o", "h"] +[60.499501, "o", " "] +[60.996343, "o", "b"] +[61.062202, "o", "r"] +[61.15963, "o", "a"] +[61.606658, "o", "c"] +[61.710465, "o", "k"] +[61.790986, "o", "e"] +[61.926711, "o", "t"] +[62.094782, "o", "s"] +[62.243636, "o", " "] +[63.711846, "o", "["] +[63.806682, "o", "["] +[64.356046, "o", "\b\u001b[K"] +[64.620136, "o", "]"] +[65.375322, "o", "\r\n(gdb) "] +[68.557209, "o", "quit\r\n"] +[68.557963, "o", "A debugging session is active.\r\n\r\n\tInferior 1 [process 1] will be detached.\r\n\r\nQuit anyway? (y or n) "] +[69.452475, "o", "y"] +[69.607083, "o", "\r\nDetaching from program: /linux/vmlinux, process 1\r\n"] +[69.608099, "o", "Ending remote debugging.\r\n"] +[69.608145, "o", "[Inferior 1 (process 1) detached]\r\n"] +[69.613792, "o", "$ "] +[72.387606, "o", "m"] +[72.556239, "o", "i"] +[72.678491, "o", "n"] +[72.735372, "o", "i"] +[72.83213, "o", "c"] +[72.939861, "o", "o"] +[72.974432, "o", "m"] +[73.12681, "o", "d"] +[73.245949, "o", " "] +[73.451736, "o", "-"] +[73.787899, "o", "D"] +[73.926861, "o", " "] +[74.062585, "o", "s"] +[74.110529, "o", "e"] +[74.20401, "o", "r"] +[74.254354, "o", "i"] +[74.383866, "o", "a"] +[74.964635, "o", "l"] +[75.158299, "o", "."] +[75.358153, "o", "p"] +[75.483515, "o", "t"] +[75.690025, "o", "s"] +[75.791116, "o", "\r\n"] +[75.792551, "o", "sh: 2: minicomd: not found\r\n$ "] +[77.369862, "o", "^[[A"] +[78.147033, "o", "\b \b"] +[78.246726, "o", "\b \b"] +[78.374032, "o", "\b \b\b \b"] +[78.726508, "o", "m"] +[78.830234, "o", "i"] +[78.942715, "o", "n"] +[78.998286, "o", "i"] +[79.16445, "o", "c"] +[79.219047, "o", "o"] +[79.28939, "o", "m"] +[79.699735, "o", " "] +[79.851281, "o", "-"] +[80.22679, "o", "D"] +[80.359667, "o", " "] +[80.494074, "o", "s"] +[80.58978, "o", "e"] +[80.665833, "o", "r"] +[80.734429, "o", "i"] +[80.831438, "o", "a"] +[80.902218, "o", "l"] +[81.065769, "o", "."] +[81.235249, "o", "p"] +[81.354437, "o", "t"] +[81.667451, "o", "s"] +[82.015056, "o", "\r\n"] +[82.0318, "o", "\u001b[!p\u001b[?3;4l\u001b[4l\u001b>\u001b[0m\u001b(B\u001b[?1h\u001b=\u001b[H\u001b[2J"] +[82.032263, "o", "\u001b[?12l\u001b[?25h\nWelcome to minicom 2.7.1\r\n\nOPTIONS: I18n \r\nCompiled on Dec 23 2019, 02:06:26.\r\nPort serial.pts, 11:09:49\r\n\nPress CTRL-A Z for help on special keys\r\n\n"] +[82.665267, "o", "\n"] +[82.670205, "o", "Poky (Yocto Project Reference Distro) 2.3 qemux86 /dev/hvc0"] +[82.670382, "o", "\r\n"] +[82.671379, "o", "\n"] +[82.673617, "o", "qemux86 login: "] +[83.310781, "o", "r"] +[83.35226, "o", "o"] +[83.486962, "o", "o"] +[83.559101, "o", "t"] +[83.640496, "o", "\r\n"] +[83.807489, "o", "root@qemux86:~# "] +[84.151513, "o", "p"] +[84.239303, "o", "s"] +[84.353291, "o", "\r\n"] +[84.365744, "o", " PID USER VSZ STAT COMMAND"] +[84.366019, "o", "\r\n"] +[84.382473, "o", " 1 root 2004 S init [5]"] +[84.382916, "o", "\r\n"] +[84.384492, "o", " 2 root 0 SW [kthreadd]"] +[84.384691, "o", "\r\n"] +[84.385851, "o", " 3 root 0 IW< [rcu_gp]"] +[84.386047, "o", "\r\n"] +[84.387605, "o", " 4 root 0 IW< [rcu_par_gp]"] +[84.387746, "o", "\r\n"] +[84.388848, "o", " 6 root 0 IW< [kworker/0:0H-ev]"] +[84.388994, "o", "\r\n"] +[84.38998, "o", " 7 root 0 IW [kworker/u2:0-ev]"] +[84.390164, "o", "\r\n"] +[84.391562, "o", " 8 root 0 IW< [mm_percpu_wq]"] +[84.391813, "o", "\r\n"] +[84.392754, "o", " 9 root 0 SW [ksoftirqd/0]"] +[84.392996, "o", "\r\n"] +[84.393827, "o", " 10 root 0 IW [rcu_sched]"] +[84.394025, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.395414, "o", " 11 root 0 SW [migration/0]"] +[84.395571, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.396462, "o", " 12 root 0 SW [cpuhp/0]"] +[84.39663, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.397513, "o", " 13 root 0 SW [kdevtmpfs]"] +[84.397659, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.399276, "o", " 14 root 0 IW< [netns]"] +[84.399499, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.40051, "o", " 15 root 0 SW [oom_reaper]"] +[84.400715, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.4016, "o", " 16 root 0 IW< [writeback]"] +[84.401763, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.403336, "o", " 32 root 0 IW< [kblockd]"] +[84.403515, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.404416, "o", " 33 root 0 IW [kworker/0:1-mm_]"] +[84.404597, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.405656, "o", " 34 root 0 IW< [kworker/0:1H-kb]"] +[84.405869, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.407531, "o", " 35 root 0 SW [kswapd0]"] +[84.40772, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.408696, "o", " 37 root 0 IW< [acpi_thermal_pm]"] +[84.408838, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.409754, "o", " 38 root 0 IW [kworker/u2:1-ev]"] +[84.409941, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.411415, "o", " 39 root 0 IW [kworker/0:2-eve]"] +[84.411603, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.412584, "o", " 40 root 0 SW [khvcd]"] +[84.412802, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.413892, "o", " 41 root 0 IW< [ipv6_addrconf]"] +[84.414073, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.415589, "o", " 42 root 0 SWN [kmemleak]"] +[84.415761, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.416609, "o", " 43 root 0 SW [jbd2/vda-8]"] +[84.416767, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.417633, "o", " 44 root 0 IW< [ext4-rsv-conver]"] +[84.417776, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.419678, "o", " 187 root 2828 S udhcpc -R -b -p /var/run/udhcpc.eth0.pid -i eth0"] +[84.419824, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.421049, "o", " 198 root 2828 S /sbin/syslogd -n -O /var/log/messages"] +[84.421222, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.422318, "o", " 201 root 2828 S /sbin/klogd -n"] +[84.422683, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.424349, "o", " 207 root 2828 S /sbin/getty 38400 tty1"] +[84.424461, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.425792, "o", " 208 root 2972 S -sh\r\n\u001b[23;80H \u001b[24;1H"] +[84.427611, "o", " 209 root 2828 S /sbin/getty 38400 tty2"] +[84.427768, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.428986, "o", " 210 root 2828 S /sbin/getty 38400 tty3"] +[84.429144, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.430325, "o", " 211 root 2828 S /sbin/getty 38400 tty4"] +[84.430573, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.432246, "o", " 212 root 2828 S /sbin/getty 38400 tty5"] +[84.43239, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.433849, "o", " 932 root 2976 R ps"] +[84.434032, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[84.437908, "o", "root@qemux86:~# "] +[99.144067, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[99.145467, "o", "root@qemux86:~# "] +[99.862108, "o", "\u001b[0m\u001b(B\u001b[7m\r\u001b[K\u001b[?12l\u001b[?25h\u001b[?25lCTRL-A Z for help | 115200 8N1 | NOR | Minicom 2.7.1 | VT102 | Offline | al.pts\u001b[?12l\u001b[?25h\u001b[24;17H"] +[100.044152, "o", "\u001b[8;30H\u001b[?25l\u001b[0m\u001b(B\u001b(0lqqqqqqqqqqqqqqqqqqqqqqk\u001b[9;30Hx\u001b[0m\u001b(B Leave Minicom? \u001b[0m\u001b(B\u001b(0x\u001b[10;30Hx\u001b[0m\u001b(B No \u001b[0m\u001b(B\u001b(0x\u001b[11;30Hmqqqqqqqqqqqqqqqqqqqqqqj\u001b[10;51H\u001b[?25l\u001b[10;33H\u001b[0m\u001b(B\u001b[7m Yes "] +[100.583354, "o", "\u001b[?12l\u001b[?25h\u001b[8;1H\u001b[0m\u001b(B 40 root 0 SW [khvcd] \u001b[9;1H 41 root 0 IW< [ipv6_addrconf] \u001b[10;1H 42 root 0 SWN [kmemleak] \u001b[11;1H 43 root 0 SW [jbd2/vda-8] \u001b[24;17H\u001b[0m\u001b(B\u001b[7m\u001b[?12l\u001b[?25h\u001b[?12l\u001b[?25h"] +[100.583429, "o", "\u001b[0m\u001b(B\u001b[H\u001b[2J\u001b[?12l\u001b[?25h\u001b[?1l\u001b>\u001b[!p\u001b[?3;4l\u001b[4l\u001b>"] +[100.58371, "o", "$ "] +[101.414149, "o", "^[[A"] +[101.566416, "o", "^[[A"] +[101.886558, "o", "^[[A"] +[102.335042, "o", "\b \b"] +[102.842375, "o", "\b \b"] +[102.872862, "o", "\b \b\b \b"] +[102.904871, "o", "\b \b"] +[102.937132, "o", "\b \b"] +[102.969648, "o", "\b \b\b \b"] +[103.01399, "o", "\b \b"] +[103.046078, "o", "\b \b"] +[103.079602, "o", "\b \b\b \b"] +[103.486251, "o", "m"] +[103.572083, "o", "a"] +[103.611934, "o", "m"] +[103.642732, "o", "k"] +[103.734628, "o", "e"] +[103.837599, "o", " "] +[104.06262, "o", "g"] +[104.35936, "o", "\b \b"] +[104.491737, "o", "\b \b"] +[104.620252, "o", "\b \b"] +[104.731786, "o", "\b \b"] +[104.904506, "o", "k"] +[105.139616, "o", "\b \b"] +[105.26003, "o", "\b \b"] +[105.374543, "o", "k"] +[105.47003, "o", "e"] +[105.550545, "o", " "] +[105.946754, "o", "g"] +[106.106541, "o", "d"] +[106.171182, "o", "b"] +[106.471309, "o", "\r\n"] +[106.477162, "o", "gdb -ex \"target remote localhost:1234\" /linux/vmlinux\r\n"] +[106.511747, "o", "\u001b[35;1m\u001b[35;1mGNU gdb \u001b[m\u001b[35;1m(Ubuntu 9.2-0ubuntu1~20.04) \u001b[m\u001b[35;1m9.2\u001b[m\u001b[35;1m\r\n\u001b[m\u001b[mCopyright (C) 2020 Free Software Foundation, Inc.\r\nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\r\nThis is free software: you are free to change and redistribute it.\r\nThere is NO WARRANTY, to the extent permitted by law.\r\nType \"show copying\" and \"show warranty\" for details.\r\nThis GDB was configured as \"x86_64-linux-gnu\".\r\nType \"show configuration\" for configuration details.\r\nFor bug reporting instructions, please see:\r\n<http://www.gnu.org/software/gdb/bugs/>.\r\nFind the GDB manual and other documentation resources online at:\r\n <http://www.gnu.org/software/gdb/documentation/>.\r\n\r\nFor help, type \"help\".\r\nType \"apropos word\" to search for commands related to \"word\"...\r\n"] +[106.512051, "o", "Reading symbols from \u001b[32m/linux/vmlinux\u001b[m...\r\n"] +[107.070342, "o", "Remote debugging using localhost:1234\r\n"] +[107.082871, "o", "\u001b[33mdefault_idle\u001b[m () at \u001b[32march/x86/kernel/process.c\u001b[m:689\r\n"] +[107.082941, "o", "689\t}\r\n"] +[107.083245, "o", "(gdb) "] +[108.67027, "o", "l"] +[108.79013, "o", "s"] +[110.752881, "o", "-"] +[111.158637, "o", "\b\u001b[K"] +[111.294213, "o", "\b\u001b[K"] +[111.375362, "o", "x"] +[111.56393, "o", "-"] +[112.075891, "o", "p"] +[112.716755, "o", "s"] +[112.983024, "o", "\r\n"] +[112.983204, "o", " TASK PID COMM\r\n"] +[112.984424, "o", "0xc17d02c0 0 swapper/0\r\n"] +[112.985648, "o", "0xc2530040 1 init\r\n"] +[112.986756, "o", "0xc2534080 2 kthreadd\r\n"] +[112.987788, "o", "0xc25360c0 3 rcu_gp\r\n"] +[112.98883, "o", "0xc2537100 4 rcu_par_gp\r\n"] +[112.989979, "o", "0xc2546180 6 kworker/0:0H\r\n"] +[112.990945, "o", "0xc25481c0 7 kworker/u2:0\r\n"] +[112.991808, "o", "0xc2549000 8 mm_percpu_wq\r\n"] +[112.992762, "o", "0xc254b040 9 ksoftirqd/0\r\n"] +[112.993594, "o", "0xc254c080 10 rcu_sched\r\n"] +[112.994443, "o", "0xc254e0c0 11 migration/0\r\n"] +[112.995327, "o", "0xc2572100 12 cpuhp/0\r\n"] +[112.996231, "o", "0xc2576140 13 kdevtmpfs\r\n"] +[112.997154, "o", "0xc2593180 14 netns\r\n"] +[112.997928, "o", "0xc26211c0 15 oom_reaper\r\n"] +[112.998731, "o", "0xc2623000 16 writeback\r\n"] +[112.999501, "o", "0xc25cd1c0 32 kblockd\r\n"] +[113.000229, "o", "0xc2638180 33 kworker/0:1\r\n"] +[113.000993, "o", "0xc2637140 34 kworker/0:1H\r\n"] +[113.001713, "o", "0xc2636100 35 kswapd0\r\n"] +[113.002441, "o", "0xc2634080 37 acpi_thermal_pm\r\n"] +[113.003341, "o", "0xc26350c0 38 kworker/u2:1\r\n"] +[113.004215, "o", "\u001b[m--Type <RET> for more, q to quit, c to continue without paging--"] +[114.273671, "o", "q"] +[116.3102, "o", "\r\n"] +[116.31037, "o", "Quit\r\n(gdb) "] +[117.96624, "o", "#"] +[118.254117, "o", " "] +[118.40776, "o", "l"] +[118.491374, "o", "e"] +[118.654629, "o", "t"] +[118.828047, "o", "s"] +[118.945063, "o", " "] +[119.111903, "o", "i"] +[119.185942, "o", "n"] +[119.254491, "o", "s"] +[119.411189, "o", "p"] +[119.478562, "o", "e"] +[119.566175, "o", "c"] +[120.054814, "o", "t"] +[121.318467, "o", " "] +[122.796389, "o", "t"] +[122.876021, "o", "h"] +[123.006447, "o", "e"] +[123.121491, "o", " "] +[123.486383, "o", "k"] +[123.662142, "o", "s"] +[123.761024, "o", "o"] +[123.827853, "o", "f"] +[124.056733, "o", "t"] +[124.884417, "o", "i"] +[124.998466, "o", "r"] +[125.090886, "o", "q"] +[125.458436, "o", "d"] +[126.11713, "o", " "] +[126.34268, "o", "k"] +[126.423265, "o", "e"] +[126.470594, "o", "r"] +[126.581815, "o", "n"] +[126.662065, "o", "e"] +[126.766791, "o", "l"] +[126.867196, "o", " "] +[127.013848, "o", "t"] +[127.11873, "o", "h"] +[127.196182, "o", "r"] +[127.252684, "o", "e"] +[127.302566, "o", "a"] +[127.525289, "o", "d"] +[127.612912, "o", "s"] +[128.91899, "o", "\b\u001b[K"] +[129.079044, "o", "\r\n"] +[129.079153, "o", "(gdb) "] +[134.822513, "o", "p"] +[134.98218, "o", "r"] +[135.04637, "o", "i"] +[135.095337, "o", "n"] +[135.213449, "o", "t"] +[135.367892, "o", " "] +[135.948456, "o", "("] +[137.420016, "o", "("] +[137.64176, "o", "s"] +[137.791566, "o", "t"] +[137.847118, "o", "r"] +[137.958465, "o", "u"] +[138.060018, "o", "c"] +[138.267908, "o", "t"] +[138.871323, "o", " "] +[139.042958, "o", "t"] +[139.103241, "o", "a"] +[139.242309, "o", "s"] +[139.308529, "o", "k"] +[139.510379, "o", "_"] +[139.682368, "o", "s"] +[139.887398, "o", "u"] +[140.423883, "o", "\b\u001b[K"] +[140.518478, "o", "t"] +[140.671075, "o", "r"] +[140.742392, "o", "u"] +[140.875932, "o", "c"] +[141.086603, "o", "t"] +[141.483711, "o", "*"] +[141.670866, "o", ")"] +[143.13397, "o", "0xc254b040"] +[144.158432, "o", ")"] +[144.861881, "o", "-"] +[145.332921, "o", ">"] +[145.765653, "o", "\u0007"] +[146.052545, "o", "\r\nDisplay all 156 possibilities? (y or n)"] +[148.83855, "o", "\r\n(gdb) print ((struct task_struct*)0xc254b040)->"] +[151.566382, "o", "m"] +[151.708377, "o", "m"] +[152.208982, "o", " "] +[152.590906, "o", "\r\n"] +[152.606852, "o", "$1 = (struct mm_struct *) \u001b[34m0x0\u001b[m\r\n(gdb) "] +[153.7479, "o", "#"] +[153.990068, "o", " "] +[154.220116, "o", "n"] +[154.293473, "o", "o"] +[154.476203, "o", "t"] +[154.549343, "o", "i"] +[154.718407, "o", "c"] +[154.792436, "o", "e"] +[155.435468, "o", " "] +[155.623648, "o", "t"] +[155.71801, "o", "h"] +[155.820625, "o", "a"] +[155.910595, "o", "t"] +[156.03814, "o", " "] +[156.275706, "o", "t"] +[156.374535, "o", "h"] +[156.467813, "o", "e"] +[156.534298, "o", "r"] +[156.606573, "o", "e"] +[156.708536, "o", " "] +[156.820267, "o", "i"] +[156.926727, "o", "s"] +[157.036148, "o", " "] +[157.260091, "o", "n"] +[157.332754, "o", "o"] +[157.521488, "o", " "] +[157.621793, "o", "a"] +[157.950278, "o", "d"] +[158.123876, "o", "d"] +[158.332801, "o", "r"] +[158.382158, "o", "e"] +[158.571143, "o", "s"] +[158.688164, "o", "s"] +[158.818238, "o", " "] +[158.910157, "o", "s"] +[159.013842, "o", "p"] +[159.102999, "o", "a"] +[159.299519, "o", "c"] +[159.363577, "o", "e"] +[159.494688, "o", " "] +[159.600096, "o", "a"] +[159.85968, "o", "s"] +[160.022336, "o", "s"] +[160.13205, "o", "o"] +[160.270871, "o", "c"] +[160.335137, "o", "i"] +[160.382535, "o", "a"] +[160.580297, "o", "t"] +[160.636041, "o", "e"] +[160.792826, "o", "d"] +[160.878038, "o", " "] +[160.990215, "o", "w"] +[161.078373, "o", "i"] +[161.214096, "o", "t"] +[161.286032, "o", "h"] +[161.382406, "o", " "] +[161.466374, "o", "t"] +[161.573907, "o", "h"] +[161.654564, "o", "e"] +[161.770776, "o", " "] +[161.918309, "o", "k"] +[162.030649, "o", "e"] +[162.070539, "o", "r"] +[162.155973, "o", "n"] +[162.237838, "o", "e"] +[162.295025, "o", "l"] +[162.42764, "o", " "] +[163.094332, "o", "\b\u001b[K"] +[163.222493, "o", "\b\u001b[K"] +[164.206568, "o", "\b\u001b[K"] +[164.339329, "o", "\b\u001b[K"] +[164.468159, "o", "\b\u001b[K"] +[164.590204, "o", "\b\u001b[K"] +[164.724112, "o", "\b\u001b[K"] +[164.892234, "o", "t"] +[165.055837, "o", "\b\u001b[K"] +[165.198298, "o", "\b\u001b[K"] +[165.335496, "o", "\b\u001b[K"] +[165.468275, "o", "\b\u001b[K"] +[165.62238, "o", "\b\u001b[K"] +[166.246756, "o", "t"] +[166.326615, "o", "h"] +[166.382333, "o", "i"] +[166.4519, "o", "s"] +[166.541987, "o", " "] +[166.708252, "o", "t"] +[166.819081, "o", "a"] +[166.908185, "o", "s"] +[167.053111, "o", "k"] +[167.36667, "o", "\r\n(gdb) "] +[170.791095, "o", "# notice that there is no address space associated with this task"] +[171.750239, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[21Pprint ((struct task_struct*)0xc254b040)->mm "] +[172.23017, "o", "\b\u001b[K"] +[172.386797, "o", "\b\u001b[K"] +[172.531384, "o", "\b\u001b[K"] +[172.873833, "o", "f"] +[173.203858, "o", "i"] +[173.365186, "o", "les "] +[174.539751, "o", "\b\u001b[K"] +[174.715458, "o", "-"] +[175.180139, "o", ">"] +[175.871471, "o", "\u0007"] +[176.032089, "o", "\r\nclose_on_exec_init fdtab open_fds_init\r\ncount file_lock resize_in_progress\r\nfd_array full_fds_bits_init resize_wait\r\nfdt next_fd \r\n(gdb) print ((struct task_struct*)0xc254b040)->files->"] +[177.45997, "o", "f"] +[177.754961, "o", "d"] +[178.438573, "o", "_"] +[179.441568, "o", "a"] +[179.67653, "o", "r"] +[179.854296, "o", "r"] +[179.966081, "o", "ay "] +[180.934307, "o", "\r\n"] +[180.954674, "o", "$2 = {\u001b[34m0x0\u001b[m \u001b[2m<repeats \u001b[m\u001b[2m32\u001b[m\u001b[2m times>\u001b[m}\r\n(gdb) "] +[182.787841, "o", "#"] +[183.110265, "o", " "] +[183.479449, "o", "a"] +[183.614116, "o", "l"] +[183.783304, "o", "s"] +[183.866187, "o", "o"] +[184.006426, "o", " "] +[184.275627, "o", "n"] +[184.333689, "o", "o"] +[184.82741, "o", "t"] +[184.926539, "o", "i"] +[185.106651, "o", "c"] +[185.165936, "o", "e"] +[185.308254, "o", " "] +[185.430403, "o", "t"] +[185.517961, "o", "h"] +[185.584954, "o", "a"] +[185.670047, "o", "t"] +[186.034584, "o", " "] +[186.222612, "o", "t"] +[186.315392, "o", "h"] +[186.405867, "o", "e"] +[186.477735, "o", "r"] +[186.570951, "o", "e"] +[186.621919, "o", " "] +[186.749962, "o", "a"] +[186.814544, "o", "r"] +[186.915797, "o", "e"] +[186.971487, "o", " "] +[187.165461, "o", "n"] +[187.246091, "o", "o"] +[187.346347, "o", " "] +[187.559526, "o", "o"] +[187.668583, "o", "p"] +[187.718056, "o", "e"] +[188.950305, "o", "n"] +[189.132854, "o", "e"] +[189.278635, "o", "d"] +[189.470868, "o", " "] +[189.824985, "o", "f"] +[189.950471, "o", "i"] +[190.036377, "o", "l"] +[190.103353, "o", "e"] +[190.302439, "o", "s"] +[193.022303, "o", "\r\n(gdb) "] +[206.790997, "o", "b"] +[206.883683, "o", "t"] +[207.622064, "o", "\r\n"] +[207.622477, "o", "#0 \u001b[33mdefault_idle\u001b[m () at \u001b[32march/x86/kernel/process.c\u001b[m:689\r\n#1 \u001b[34m0xc102c18d\u001b[m in \u001b[33march_cpu_idle\u001b[m () at \u001b[32march/x86/kernel/process.c\u001b[m:680\r\n"] +[207.628692, "o", "#2 \u001b[34m0xc15de082\u001b[m in \u001b[33mdefault_idle_call\u001b[m () at \u001b[32mkernel/sched/idle.c\u001b[m:112\r\n"] +[207.628733, "o", "#3 \u001b[34m0xc108d875\u001b[m in \u001b[33mcpuidle_idle_call\u001b[m () at \u001b[32mkernel/sched/idle.c\u001b[m:194\r\n"] +[207.62875, "o", "#4 \u001b[33mdo_idle\u001b[m () at \u001b[32mkernel/sched/idle.c\u001b[m:299\r\n"] +[207.635135, "o", "#5 \u001b[34m0xc108dbd5\u001b[m in \u001b[33mcpu_startup_entry\u001b[m (\u001b[36mstate=state@entry\u001b[m=CPUHP_ONLINE)\u001b[m\r\n \u001b[m at \u001b[32mkernel/sched/idle.c\u001b[m:395\r\n#6 \u001b[34m0xc15d6100\u001b[m in \u001b[33mrest_init\u001b[m () at \u001b[32minit/main.c\u001b[m:721\r\n#7 \u001b[34m0xc18c77de\u001b[m in \u001b[33march_call_rest_init\u001b[m () at \u001b[32minit/main.c\u001b[m:845\r\n"] +[207.635417, "o", "#8 \u001b[34m0xc18c7c30\u001b[m in \u001b[33mstart_kernel\u001b[m () at \u001b[32minit/main.c\u001b[m:1061\r\n"] +[207.637653, "o", "#9 \u001b[34m0xc18c7218\u001b[m in \u001b[33mi386_start_kernel\u001b[m () at \u001b[32march/x86/kernel/head32.c\u001b[m:56\r\n"] +[207.638067, "o", "#10 \u001b[34m0xc10001db\u001b[m in \u001b[33mstartup_32_smp\u001b[m () at \u001b[32march/x86/kernel/head_32.S\u001b[m:327\r\n"] +[207.638979, "o", "#11 \u001b[34m0x00000000\u001b[m in \u001b[33m??\u001b[m ()\r\n"] +[207.639304, "o", "(gdb) "] +[221.379671, "o", "#"] +[221.574477, "o", " "] +[221.763647, "o", "t"] +[221.859656, "o", "h"] +[221.910208, "o", "i"] +[222.230146, "o", "s"] +[223.003102, "o", " "] +[223.24279, "o", "d"] +[223.342376, "o", "o"] +[223.407244, "o", "e"] +[223.515893, "o", "s"] +[223.822602, "o", " "] +[224.052215, "o", "n"] +[224.126804, "o", "o"] +[224.262025, "o", "t"] +[224.350204, "o", " "] +[224.566282, "o", "l"] +[224.715391, "o", "o"] +[224.851651, "o", "o"] +[224.892089, "o", "k"] +[225.071297, "o", " "] +[225.204093, "o", "a"] +[225.777377, "o", "\b\u001b[K"] +[225.938217, "o", "l"] +[226.117327, "o", "i"] +[226.267363, "o", "k"] +[226.381869, "o", "e"] +[226.453866, "o", " "] +[226.610517, "o", "a"] +[226.678686, "o", " "] +[227.092186, "o", "k"] +[227.652524, "o", "\b\u001b[K"] +[227.802894, "o", "\b\u001b[K"] +[228.462601, "o", " "] +[228.691067, "o", "b"] +[228.726474, "o", "a"] +[228.861766, "o", "c"] +[228.973894, "o", "k"] +[229.137284, "o", "t"] +[229.283711, "o", "r"] +[229.350451, "o", "a"] +[229.511061, "o", "c"] +[229.59807, "o", "e"] +[229.749979, "o", " "] +[230.186502, "o", "f"] +[230.257607, "o", "o"] +[230.38212, "o", "r"] +[230.453689, "o", " "] +[230.550129, "o", "a"] +[230.679919, "o", " "] +[234.654082, "o", "e"] +[234.740562, "o", "r"] +[235.011631, "o", "\b\u001b[K"] +[235.118657, "o", "\b\u001b[K"] +[235.298981, "o", "k"] +[235.390755, "o", "e"] +[235.437752, "o", "r"] +[235.526007, "o", "n"] +[235.623409, "o", "e"] +[235.763733, "o", "l"] +[235.773498, "o", " "] +[236.126636, "o", "t"] +[236.241013, "o", "h"] +[236.33206, "o", "r"] +[236.397333, "o", "e"] +[236.446064, "o", "a"] +[236.607301, "o", "d"] +[240.062311, "o", "\r\n"] +[240.062479, "o", "(gdb) "] +[240.711316, "o", "#"] +[240.90636, "o", " "] +[241.166191, "o", "l"] +[241.419451, "o", "e"] +[241.659109, "o", "t"] +[241.86961, "o", "s"] +[242.043257, "o", " "] +[244.843651, "o", "p"] +[244.918102, "o", "p"] +[245.016449, "o", "u"] +[245.158034, "o", "t"] +[245.244774, "o", " "] +[245.393348, "o", "a"] +[245.41361, "o", " "] +[245.76255, "o", "\b\u001b[K"] +[245.881592, "o", "\b\u001b[K"] +[246.006241, "o", "\b\u001b[K"] +[246.137238, "o", "\b\u001b[K"] +[246.272147, "o", "\b\u001b[K"] +[246.395526, "o", "\b\u001b[K"] +[246.574088, "o", "i"] +[246.677415, "o", "t"] +[247.062963, "o", "\b\u001b[K"] +[247.181883, "o", "\b\u001b[K"] +[247.334239, "o", "u"] +[247.446138, "o", "t"] +[247.546923, "o", " "] +[247.67005, "o", "a"] +[247.773321, "o", " "] +[248.004601, "o", "b"] +[248.078817, "o", "r"] +[248.151286, "o", "e"] +[248.214162, "o", "a"] +[248.299871, "o", "k"] +[248.541708, "o", "p"] +[248.628067, "o", "o"] +[248.811761, "o", "i"] +[248.876511, "o", "n"] +[248.971272, "o", "t"] +[249.125851, "o", " "] +[249.392141, "o", "i"] +[249.555648, "o", "n"] +[250.946185, "o", "\b\u001b[K"] +[251.077786, "o", "\b\u001b[K"] +[251.710112, "o", "t"] +[251.812957, "o", "o"] +[252.861908, "o", " "] +[253.182436, "o", "\b\u001b[K"] +[253.293631, "o", "\b\u001b[K"] +[253.398191, "o", "\b\u001b[K"] +[253.766615, "o", "n"] +[254.131587, "o", "\b\u001b[K"] +[254.315781, "o", "i"] +[254.376792, "o", "n"] +[254.433173, "o", " "] +[254.573627, "o", "t"] +[254.631208, "o", "h"] +[254.750211, "o", "e"] +[254.82721, "o", " "] +[255.077806, "o", "c"] +[255.181875, "o", "o"] +[255.237745, "o", "n"] +[255.36349, "o", "t"] +[255.413945, "o", "e"] +[255.601549, "o", "x"] +[255.798133, "o", "t"] +[255.870077, "o", " "] +[256.177252, "o", "s"] +[256.356189, "o", "w"] +[256.420864, "o", "i"] +[256.530677, "o", "t"] +[256.731915, "o", "c"] +[256.77443, "o", "h"] +[256.883801, "o", " "] +[258.571714, "o", "r"] +[258.640714, "o", "o"] +[258.712151, "o", "u"] +[258.829888, "o", "t"] +[258.924193, "o", "i"] +[258.975067, "o", "n"] +[259.069473, "o", "e"] +[259.19488, "o", " "] +[259.366391, "o", "a"] +[259.47005, "o", "n"] +[259.557575, "o", "d"] +[259.654709, "o", " "] +[260.19587, "o", "w"] +[260.29212, "o", "a"] +[260.381822, "o", "i"] +[260.533426, "o", "t"] +[260.606091, "o", " "] +[260.739803, "o", "f"] +[260.798442, "o", "o"] +[261.681096, "o", "r"] +[262.777308, "o", " "] +[262.951854, "o", "a"] +[263.061053, "o", " "] +[263.308236, "o", "k"] +[263.390265, "o", "e"] +[264.173829, "o", "r"] +[264.245576, "o", "n"] +[264.382178, "o", "e \r"] +[264.493978, "o", "l"] +[264.674766, "o", " "] +[265.043389, "o", "t"] +[265.139075, "o", "h"] +[265.206648, "o", "r"] +[265.278568, "o", "e"] +[265.317655, "o", "a"] +[265.498561, "o", "d"] +[265.589679, "o", " "] +[265.76644, "o", "t"] +[265.821599, "o", "o"] +[265.886969, "o", " "] +[266.331796, "o", "b"] +[266.403363, "o", "e"] +[266.508099, "o", " "] +[266.655882, "o", "s"] +[266.917726, "o", "c"] +[267.287361, "o", "h"] +[267.381853, "o", "e"] +[267.523815, "o", "d"] +[267.574051, "o", "u"] +[267.763154, "o", "l"] +[267.820226, "o", "e"] +[267.957836, "o", "d"] +[268.446383, "o", "\r\n(gdb) "] +[269.741828, "o", "b"] +[269.808224, "o", "r"] +[269.870671, "o", "e"] +[269.893739, "o", "a"] +[269.998105, "o", "k"] +[270.085623, "o", " "] +[270.571466, "o", "_"] +[270.699335, "o", "_"] +[271.977106, "o", "c"] +[272.129589, "o", "o"] +[272.205444, "o", "n"] +[272.312765, "o", "t"] +[272.366081, "o", "e"] +[272.470791, "o", "\u0007"] +[273.62, "o", "\b\u001b[K"] +[273.74179, "o", "\b\u001b[K"] +[273.885881, "o", "\b\u001b[K"] +[274.018615, "o", "\b\u001b[K"] +[274.143134, "o", "\b\u001b[K"] +[274.263468, "o", "s"] +[274.422194, "o", "i"] +[274.501319, "o", "w"] +[274.719655, "o", "\u0007"] +[275.053997, "o", "\b\u001b[K"] +[275.187562, "o", "\b\u001b[K"] +[275.286581, "o", "w"] +[275.384725, "o", "i"] +[275.506637, "o", "\u0007tch_to"] +[276.392894, "o", "_"] +[276.621962, "o", "a"] +[276.699043, "o", "s"] +[276.905128, "o", "m "] +[277.262339, "o", "\r\n"] +[277.291402, "o", "Breakpoint 1 at \u001b[34m0xc10018e8\u001b[m: file \u001b[32march/x86/entry/entry_32.S\u001b[m, line 765.\r\n(gdb) "] +[280.133879, "o", "c"] +[281.222045, "o", "\b\u001b[K"] +[281.395261, "o", "\u0007"] +[281.857003, "o", "c"] +[282.237722, "o", "\b\u001b[K"] +[282.79563, "o", "l"] +[282.94158, "o", "i"] +[283.034854, "o", "s"] +[283.499366, "o", "\b\u001b[K"] +[283.624926, "o", "\b\u001b[K"] +[283.746958, "o", "\b\u001b[K"] +[284.082629, "o", "c"] +[284.174072, "o", "\r\nContinuing.\r\n"] +[284.176343, "o", "\r\n"] +[284.176419, "o", "Breakpoint 1, \u001b[33m__switch_to_asm\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:765\r\n"] +[284.176491, "o", "765\t\tpushl\t%ebp\r\n(gdb) "] +[284.835414, "o", "l"] +[284.989635, "o", "i"] +[285.046355, "o", "s"] +[285.255024, "o", "t"] +[285.341593, "o", " "] +[287.197351, "o", "7"] +[287.491808, "o", "5"] +[287.755423, "o", "\b\u001b[K"] +[287.867358, "o", "6"] +[287.926098, "o", "0"] +[288.134096, "o", "\r\n"] +[288.135789, "o", "755\t/*\r\n756\t * %eax: prev task\r\n757\t * %edx: next task\r\n758\t */\r\n759\t.pushsection .text, \"ax\"\r\n760\tSYM_CODE_START(__switch_to_asm)\r\n761\t\t/*\r\n762\t\t * Save callee-saved registers\r\n763\t\t * This must match the order in struct inactive_task_frame\r\n764\t\t */\r\n"] +[288.135987, "o", "(gdb) "] +[288.699747, "o", "b"] +[288.811578, "o", "r"] +[288.862172, "o", "e"] +[288.942284, "o", "a"] +[289.033603, "o", "k"] +[289.355453, "o", " "] +[290.255841, "o", "\b\u001b[K"] +[290.384911, "o", "\b\u001b[K"] +[290.523826, "o", "\b\u001b[K"] +[290.661962, "o", "\b\u001b[K"] +[290.807839, "o", "\b\u001b[K"] +[290.941606, "o", "\b\u001b[K"] +[291.36621, "o", "\u0007"] +[292.275081, "o", "p"] +[292.451403, "o", "r"] +[292.517991, "o", "i"] +[292.602359, "o", "n"] +[292.667764, "o", "t"] +[292.766382, "o", " "] +[293.12916, "o", "("] +[293.699471, "o", "("] +[293.957439, "o", "t"] +[294.147806, "o", "a"] +[294.293733, "o", "s"] +[294.373217, "o", "k"] +[294.587807, "o", "_"] +[294.715863, "o", "s"] +[294.887282, "o", "t"] +[294.933917, "o", "r"] +[294.997435, "o", "u"] +[295.132333, "o", "c"] +[295.506086, "o", "\b\u001b[K"] +[296.004542, "o", "\b\u001b[K"] +[296.035262, "o", "\b\u001b[K"] +[296.084305, "o", "\b\u001b[K"] +[296.11605, "o", "\b\u001b[K"] +[296.147494, "o", "\b\u001b[K"] +[296.178799, "o", "\b\u001b[K"] +[296.317612, "o", "\b\u001b[K"] +[296.463433, "o", "\b\u001b[K"] +[296.718813, "o", "\b\u001b[K"] +[296.814308, "o", "s"] +[296.96261, "o", "t"] +[297.013641, "o", "r"] +[297.061739, "o", "u"] +[297.219398, "o", "c"] +[297.398522, "o", "t"] +[297.437315, "o", " "] +[297.542878, "o", "t"] +[297.637975, "o", "a"] +[297.747511, "o", "s"] +[297.819434, "o", "k"] +[298.016074, "o", "_"] +[298.117426, "o", "s"] +[298.27901, "o", "t"] +[298.342356, "o", "r"] +[298.422953, "o", "u"] +[298.524196, "o", "c"] +[298.698718, "o", "t"] +[298.989581, "o", "*"] +[298.997725, "o", "("] +[299.132205, "o", ")"] +[299.518034, "o", "\b\u001b[K"] +[299.613309, "o", "\b\u001b[K"] +[299.770424, "o", ")"] +[299.910219, "o", ")"] +[301.062221, "o", "\b\u001b[K"] +[301.485963, "o", "$"] +[302.314939, "o", "e"] +[304.099819, "o", "a"] +[304.402235, "o", "x"] +[304.916033, "o", ")"] +[305.422261, "o", "-"] +[305.88182, "o", ">"] +[306.029879, "o", "c"] +[306.133893, "o", "o"] +[306.256156, "o", "m"] +[306.398024, "o", "m"] +[306.597814, "o", "\r\n"] +[306.615485, "o", "$3 = \"swapper/0\\000\\000\\000\\000\\000\\000\"\r\n(gdb) "] +[310.517841, "o", "#"] +[310.726136, "o", " "] +[313.62966, "o", "\b\u001b[K"] +[313.774295, "o", "\b\u001b[K"] +[313.91453, "o", "\u0007"] +[315.397631, "o", "#"] +[315.577077, "o", " "] +[315.878097, "o", "c"] +[315.989862, "o", "u"] +[316.183243, "o", "r"] +[316.309684, "o", "r"] +[316.389297, "o", "e"] +[316.850982, "o", "n"] +[317.125964, "o", " "] +[317.295363, "o", "t"] +[317.403069, "o", "h"] +[317.478569, "o", "r"] +[317.551332, "o", "e"] +[317.594205, "o", "a"] +[317.751491, "o", "d"] +[317.949486, "o", "\b\u001b[K"] +[318.464381, "o", "\b\u001b[K"] +[318.487912, "o", "\b\u001b[K"] +[318.519446, "o", "\b\u001b[K"] +[318.55032, "o", "\b\u001b[K"] +[318.680362, "o", "\b\u001b[K"] +[318.817765, "o", "\b\u001b[K"] +[318.957945, "o", "t"] +[319.089737, "o", " "] +[319.291116, "o", "t"] +[319.389904, "o", "h"] +[319.647007, "o", "r"] +[319.74256, "o", "e"] +[319.78242, "o", "a"] +[319.942132, "o", "d"] +[320.030061, "o", " "] +[320.141699, "o", "i"] +[320.233772, "o", "s"] +[320.349512, "o", " "] +[320.443032, "o", "s"] +[320.80826, "o", "t"] +[320.90173, "o", "i"] +[321.069829, "o", "l"] +[321.204297, "o", "l"] +[321.259689, "o", " "] +[321.588152, "o", "s"] +[321.794884, "o", "w"] +[321.871903, "o", "a"] +[321.981533, "o", "p"] +[322.102066, "o", "p"] +[322.186971, "o", "e"] +[322.261993, "o", "r"] +[322.405556, "o", "\r\n"] +[322.405607, "o", "(gdb) "] +[322.726159, "o", "c"] +[322.901526, "o", "\r\nContinuing.\r\n"] +[322.912896, "o", "\r\n"] +[322.913085, "o", "Breakpoint 1, \u001b[33m__switch_to_asm\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:765\r\n765\t\tpushl\t%ebp\r\n(gdb) "] +[324.760917, "o", "c"] +[325.18249, "o", "\b# current thread is still swapper"] +[325.878372, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[Cprint ((struct task_struct*)$eax)->comm"] +[327.053947, "o", "\r\n"] +[327.071409, "o", "$4 = \"rcu_sched\\000\\000\\000\\000\\000\\000\"\r\n(gdb) "] +[329.503754, "o", "#"] +[330.910795, "o", "\b\u001b[K"] +[334.523368, "o", "c"] +[335.314474, "o", "\b\u001b[K"] +[335.958257, "o", "b"] +[336.018706, "o", "t"] +[337.398802, "o", "\r\n"] +[337.414221, "o", "#0 \u001b[33m__switch_to_asm\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:765\r\n"] +[337.414915, "o", "#1 \u001b[34m0xc15d8277\u001b[m in \u001b[33mcontext_switch\u001b[m (\u001b[36mrf\u001b[m=0xc2561eb4, \u001b[36mnext\u001b[m=<optimized out>, \u001b[m\r\n"] +[337.414988, "o", " \u001b[m\u001b[36mprev\u001b[m=0xc254c080, \u001b[36mrq\u001b[m=0xcfdcb700) at \u001b[32mkernel/sched/core.c\u001b[m:3779\r\n"] +[337.415254, "o", "#2 \u001b[33m__schedule\u001b[m (\u001b[36mpreempt\u001b[m=<optimized out>, \u001b[36mpreempt@entry\u001b[m=false)\u001b[m\r\n \u001b[m at \u001b[32mkernel/sched/core.c\u001b[m:4528\r\n#3 \u001b[34m0xc15d86ce\u001b[m in \u001b[33mschedule\u001b[m () at \u001b[32mkernel/sched/core.c\u001b[m:4606\r\n"] +[337.442508, "o", "#4 \u001b[34m0xc15dd6a7\u001b[m in \u001b[33mschedule_timeout\u001b[m (\u001b[36mtimeout=timeout@entry\u001b[m=1)\u001b[m\r\n \u001b[m at \u001b[32mkernel/time/timer.c\u001b[m:1871\r\n#5 \u001b[34m0xc10dcfa0\u001b[m in \u001b[33mrcu_gp_fqs_loop\u001b[m () at \u001b[32mkernel/rcu/tree.c\u001b[m:1928\r\n"] +[337.44868, "o", "#6 \u001b[33mrcu_gp_kthread\u001b[m (\u001b[36munused=unused@entry\u001b[m=0x0) at \u001b[32mkernel/rcu/tree.c\u001b[m:2102\r\n"] +[337.449075, "o", "#7 \u001b[34m0xc107c753\u001b[m in \u001b[33mkthread\u001b[m (\u001b[36m_create\u001b[m=0xc2408ca0) at \u001b[32mkernel/kthread.c\u001b[m:292\r\n#8 \u001b[34m0xc1001960\u001b[m in \u001b[33mret_from_fork\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:850\r\n"] +[337.449715, "o", "#9 \u001b[34m0x00000000\u001b[m in \u001b[33m??\u001b[m ()\r\n"] +[337.450155, "o", "(gdb) "] +[340.203269, "o", "t"] +[340.851246, "o", "\b\u001b[K"] +[341.14753, "o", "#"] +[341.387109, "o", " "] +[341.451102, "o", " "] +[341.661207, "o", "t"] +[341.978747, "o", "\b\u001b[K"] +[342.107108, "o", "\b\u001b[K"] +[342.349889, "o", "t"] +[342.491659, "o", "h"] +[342.515285, "o", "i"] +[342.699961, "o", "s"] +[342.805615, "o", " "] +[343.002237, "o", "l"] +[343.18705, "o", "o"] +[343.303844, "o", "o"] +[343.390559, "o", "k"] +[343.554804, "o", "s"] +[343.653215, "o", " "] +[343.835557, "o", "l"] +[343.978652, "o", "i"] +[344.125443, "o", "k"] +[344.223034, "o", "e"] +[344.312753, "o", " "] +[344.440075, "o", "a"] +[344.512933, "o", " "] +[344.889199, "o", "k"] +[345.025482, "o", "e"] +[345.045973, "o", "r"] +[345.140636, "o", "n"] +[345.237924, "o", "e"] +[345.325469, "o", "l"] +[345.422476, "o", " "] +[345.621936, "o", "t"] +[345.741317, "o", "h"] +[345.826829, "o", "r"] +[345.901016, "o", "e"] +[345.937951, "o", "a"] +[346.083099, "o", "d"] +[348.901657, "o", "\r\n(gdb) "] +[349.394054, "o", "#"] +[349.654109, "o", " "] +[350.307681, "o", "n"] +[350.395153, "o", "o"] +[350.899543, "o", "t"] +[351.003489, "o", "i"] +[351.17943, "o", "c"] +[351.246088, "o", "e"] +[351.469435, "o", " "] +[352.502347, "o", "t"] +[352.66686, "o", "h"] +[352.760953, "o", "a"] +[352.894464, "o", "t"] +[353.085035, "o", " "] +[355.643772, "o", "a"] +[356.059323, "o", " "] +[356.227601, "o", "k"] +[356.343137, "o", "e"] +[356.405474, "o", "r"] +[356.477181, "o", "n"] +[356.57342, "o", "e"] +[356.659084, "o", "l"] +[356.761894, "o", " "] +[356.941633, "o", "t"] +[357.045635, "o", "h"] +[357.112728, "o", "r"] +[357.179646, "o", "e"] +[357.241188, "o", "a"] +[357.707008, "o", "d"] +[357.885383, "o", " "] +[358.117478, "o", "s"] +[358.283371, "o", "t"] +[358.343069, "o", "a"] +[358.452513, "o", "r"] +[359.795314, "o", "t"] +[360.037755, "o", "s"] +[360.458901, "o", " "] +[366.070028, "o", "f"] +[366.133469, "o", "r"] +[366.261029, "o", "o"] +[366.381485, "o", "m"] +[366.530389, "o", " "] +[366.597727, "o", "a"] +[366.725499, "o", " "] +[366.850841, "o", "s"] +[366.979612, "o", "p"] +[367.024724, "o", "e"] +[367.237378, "o", "c"] +[367.357012, "o", "i"] +[367.437107, "o", "a"] +[367.618604, "o", "l"] +[367.985673, "o", " "] +[368.269841, "o", "f"] +[368.365828, "o", "o"] +[368.554828, "o", "r"] +[368.650754, "o", "k"] +[371.995165, "o", " "] +[372.946533, "o", "\b\u001b[K"] +[375.702282, "o", "\r\n"] +[375.702404, "o", "(gdb) "] +[398.867113, "o", "#"] +[399.146887, "o", " "] +[399.331616, "o", "a"] +[399.597434, "o", "l"] +[399.730647, "o", "s"] +[399.805839, "o", "o"] +[399.909163, "o", " "] +[400.11739, "o", "n"] +[400.165148, "o", "o"] +[400.285605, "o", "t"] +[400.365312, "o", "i"] +[400.485439, "o", "c"] +[400.579979, "o", "e"] +[400.65356, "o", " "] +[400.806284, "o", "a"] +[401.194396, "o", "t"] +[401.781734, "o", "\b\u001b[K"] +[401.914341, "o", "\b\u001b[K"] +[402.030244, "o", "t"] +[402.145374, "o", "h"] +[402.245147, "o", "a"] +[402.309402, "o", "t"] +[402.382045, "o", " "] +[402.525574, "o", "a"] +[402.629039, "o", "l"] +[402.754007, "o", "l"] +[402.821383, "o", " "] +[402.990226, "o", "k"] +[403.06459, "o", "e"] +[403.117803, "o", "r"] +[403.205019, "o", "n"] +[403.318207, "o", "e"] +[403.341663, "o", "l"] +[403.429692, "o", " "] +[403.629956, "o", "t"] +[403.741843, "o", "h"] +[403.808117, "o", "r"] +[403.88467, "o", "e"] +[403.95492, "o", "a"] +[404.141474, "o", "d"] +[404.205018, "o", "s"] +[404.326094, "o", " "] +[404.539117, "o", "u"] +[404.589606, "o", "s"] +[404.733589, "o", "e"] +[404.869205, "o", " "] +[407.242269, "o", "t"] +[407.32576, "o", "h"] +[407.4612, "o", "e"] +[407.541613, "o", " "] +[407.762738, "o", "k"] +[409.130554, "o", "t"] +[409.621372, "o", "h"] +[409.695796, "o", "r"] +[409.741875, "o", "e"] +[409.789943, "o", "a"] +[409.939027, "o", "d"] +[410.021602, "o", " "] +[410.218404, "o", "f"] +[410.323032, "o", "u"] +[410.371459, "o", "n"] +[410.474746, "o", "c"] +[410.688493, "o", "t"] +[410.7416, "o", "i"] +[410.779033, "o", "o"] +[411.003284, "o", "n"] +[411.093928, "o", " "] +[412.117382, "o", "t"] +[412.189337, "o", "o"] +[412.341309, "o", " "] +[412.506227, "o", "n"] +[412.589441, "o", "i"] +[412.850878, "o", "t"] +[412.986206, "o", "i"] +[413.427046, "o", "\b\u001b[K"] +[413.554719, "o", "\b\u001b[K"] +[413.677038, "o", "\b\u001b[K"] +[413.835017, "o", "\b\u001b[K"] +[414.005774, "o", "i"] +[414.484917, "o", "n"] +[414.540995, "o", "i"] +[414.693336, "o", "t"] +[414.7614, "o", "i"] +[414.863364, "o", "a"] +[414.998825, "o", "l"] +[415.062427, "o", "i \r"] +[415.166791, "o", "z"] +[415.3332, "o", "e"] +[415.478198, "o", "\r\n(gdb) "] +[442.445477, "o", "quit\r\n"] +[442.445561, "o", "A debugging session is active.\r\n\r\n\tInferior 1 [process 1] will be detached.\r\n\r\nQuit anyway? (y or n) "] +[442.970982, "o", "y"] +[443.214441, "o", "\r\n"] +[443.214527, "o", "Detaching from program: /linux/vmlinux, process 1\r\n"] +[443.215393, "o", "Ending remote debugging.\r\n"] +[443.215436, "o", "[Inferior 1 (process 1) detached]\r\n"] +[443.220945, "o", "$ "] +[444.348773, "o", "\r\n"] diff --git a/refs/pull/405/merge/_images/ksoftirqd-packet-flood.cast b/refs/pull/405/merge/_images/ksoftirqd-packet-flood.cast new file mode 100644 index 00000000..6f239238 --- /dev/null +++ b/refs/pull/405/merge/_images/ksoftirqd-packet-flood.cast @@ -0,0 +1,462 @@ +{"version": 2, "width": 80, "height": 24, "timestamp": 1616354478, "idle_time_limit": 1.0, "env": {"SHELL": null, "TERM": "xterm"}} +[0.002236, "o", "$ "] +[1.852599, "o", "m"] +[2.132922, "o", "i"] +[2.332344, "o", "n"] +[2.388604, "o", "i"] +[2.612998, "o", "c"] +[2.684655, "o", "o"] +[2.747904, "o", "m"] +[2.877702, "o", " "] +[3.052747, "o", "-"] +[3.317509, "o", "D"] +[3.468219, "o", " "] +[3.652408, "o", "s"] +[3.741658, "o", "e"] +[3.820052, "o", "r"] +[3.884557, "o", "i"] +[4.017426, "o", "a"] +[4.097078, "o", "l"] +[4.294502, "o", "."] +[4.483502, "o", "p"] +[4.604408, "o", "t"] +[4.836403, "o", "s"] +[5.173772, "o", "\r\n"] +[5.174525, "o", "\u001b[!p\u001b[?3;4l\u001b[4l\u001b>\u001b[0m\u001b(B"] +[5.174615, "o", "\u001b[?1h\u001b=\u001b[H\u001b[2J"] +[5.174986, "o", "\u001b[?12l\u001b[?25h\nWelcome to minicom 2.7.1\r\n\nOPTIONS: I18n \r\nCompiled on Dec 23 2019, 02:06:26.\r\nPort serial.pts, 19:21:04\r\n\nPress CTRL-A Z for help on special keys\r\n\n"] +[6.310469, "o", "\n"] +[6.311875, "o", "root@qemux86:~# "] +[7.981099, "o", "t"] +[8.029191, "o", "o"] +[8.086076, "o", "p"] +[8.245555, "o", "\r\n"] +[8.399818, "o", "\u001b[1;1H\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\u001b[1;1H\u001b[KMem: 34424K used, 206256K free, 3836K shrd, 380K buff, 8008K cached"] +[8.399997, "o", "\r\n"] +[8.400309, "o", "CPU: 0% usr 8% sys 0% nic 91% idle 0% io 0% irq 0% sirq"] +[8.400449, "o", "\r\n"] +[8.40103, "o", "Load average: 0.10 0.30 0.18 1/37 5529"] +[8.401214, "o", "\r\n"] +[8.41045, "o", "\u001b[0m\u001b(B\u001b[7m PID PPID USER STAT VSZ %VSZ %CPU COMMAND"] +[8.41063, "o", "\r\n"] +[8.411801, "o", "\u001b[0m\u001b(B 5529 5474 root R 2828 1% 6% top"] +[8.411997, "o", "\r\n"] +[8.412704, "o", " 10 2 root IW 0 0% 3% [rcu_sched]"] +[8.412931, "o", "\r\n"] +[8.413466, "o", " 5474 1 root S 2972 1% 0% -sh"] +[8.41367, "o", "\r\n"] +[8.414183, "o", " 198 1 root S 2828 1% 0% /sbin/syslogd -n -O /var/log/messages"] +[8.414369, "o", "\r\n"] +[8.41567, "o", " 187 1 root S 2828 1% 0% udhcpc -R -b -p /var/run/udhcpc.eth0.p\u001b[9;80H"] +[8.415869, "o", "\r\n"] +[8.416317, "o", " 201 1 root S 2828 1% 0% /sbin/klogd -n"] +[8.416484, "o", "\r\n"] +[8.41698, "o", " 207 1 root S 2828 1% 0% /sbin/getty 38400 tty1"] +[8.417134, "o", "\r\n"] +[8.417626, "o", " 209 1 root S 2828 1% 0% /sbin/getty 38400 tty2"] +[8.417853, "o", "\r\n"] +[8.418241, "o", " 210 1 root S 2828 1% 0% /sbin/getty 38400 tty3"] +[8.418372, "o", "\r\n"] +[8.419445, "o", " 211 1 root S 2828 1% 0% /sbin/getty 38400 tty4"] +[8.419591, "o", "\r\n"] +[8.420058, "o", " 212 1 root S 2828 1% 0% /sbin/getty 38400 tty5"] +[8.420184, "o", "\r\n"] +[8.42079, "o", " 1 0 root S 2004 1% 0% init [5]"] +[8.420935, "o", "\r\n"] +[8.421371, "o", " 9 2 root SW 0 0% 0% [ksoftirqd/0]"] +[8.421516, "o", "\r\n"] +[8.421919, "o", " 42 2 root SWN 0 0% 0% [kmemleak]"] +[8.422058, "o", "\r\n"] +[8.422446, "o", " 39 2 root IW 0 0% 0% [kworker/0:2-mm_]"] +[8.422821, "o", "\r\n"] +[8.423488, "o", " 13 2 root SW 0 0% 0% [kdevtmpfs]"] +[8.423618, "o", "\r\n"] +[8.424021, "o", " 7 2 root IW 0 0% 0% [kworker/u2:0-ev]"] +[8.424538, "o", "\r\n"] +[8.424606, "o", " 38 2 root IW 0 0% 0% [kworker/u2:1-ev]"] +[8.4247, "o", "\r\n"] +[8.425134, "o", " 34 2 root IW< 0 0% 0% [kworker/0:1H-kb]"] +[8.425281, "o", "\r\n"] +[8.425506, "o", " 43 2 root SW 0 0% 0% [jbd2/vda-8]\r"] +[13.447981, "o", "\u001b[1;1H\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\u001b[1;1H\u001b[KMem: 34424K used, 206256K free, 3836K shrd, 380K buff, 8008K cached"] +[13.448168, "o", "\r\n"] +[13.44854, "o", "CPU: 0% usr 0% sys 0% nic 99% idle 0% io 0% irq 0% sirq"] +[13.448659, "o", "\r\n"] +[13.449284, "o", "Load average: 0.09 0.30 0.18 1/37 5529"] +[13.449591, "o", "\r\n"] +[13.451544, "o", "\u001b[0m\u001b(B\u001b[7m PID PPID USER STAT VSZ %VSZ %CPU COMMAND"] +[13.451812, "o", "\r\n"] +[13.452307, "o", "\u001b[0m\u001b(B 5529 5474 root R 2972 1% 1% top"] +[13.452473, "o", "\r\n"] +[13.45301, "o", " 5474 1 root S 2972 1% 0% -sh"] +[13.453275, "o", "\r\n"] +[13.453876, "o", " 198 1 root S 2828 1% 0% /sbin/syslogd -n -O /var/log/messages"] +[13.454093, "o", "\r\n"] +[13.454812, "o", " 187 1 root S 2828 1% 0% udhcpc -R -b -p /var/run/udhcpc.eth0.p\u001b[8;80H"] +[13.454925, "o", "\r\n"] +[13.455729, "o", " 201 1 root S 2828 1% 0% /sbin/klogd -n"] +[13.455941, "o", "\r\n"] +[13.456477, "o", " 207 1 root S 2828 1% 0% /sbin/getty 38400 tty1"] +[13.456654, "o", "\r\n"] +[13.457185, "o", " 209 1 root S 2828 1% 0% /sbin/getty 38400 tty2"] +[13.457362, "o", "\r\n"] +[13.457758, "o", " 210 1 root S 2828 1% 0% /sbin/getty 38400 tty3"] +[13.457938, "o", "\r\n"] +[13.458413, "o", " 211 1 root S 2828 1% 0% /sbin/getty 38400 tty4"] +[13.458715, "o", "\r\n"] +[13.459436, "o", " 212 1 root S 2828 1% 0% /sbin/getty 38400 tty5"] +[13.459594, "o", "\r\n"] +[13.460002, "o", " 1 0 root S 2004 1% 0% init [5]"] +[13.46014, "o", "\r\n"] +[13.46068, "o", " 10 2 root IW 0 0% 0% [rcu_sched]"] +[13.460878, "o", "\r\n"] +[13.461278, "o", " 9 2 root SW 0 0% 0% [ksoftirqd/0]"] +[13.4614, "o", "\r\n"] +[13.461837, "o", " 42 2 root SWN 0 0% 0% [kmemleak]"] +[13.46196, "o", "\r\n"] +[13.462358, "o", " 39 2 root IW 0 0% 0% [kworker/0:2-eve]"] +[13.462478, "o", "\r\n"] +[13.463428, "o", " 13 2 root SW 0 0% 0% [kdevtmpfs]"] +[13.46356, "o", "\r\n"] +[13.463973, "o", " 7 2 root IW 0 0% 0% [kworker/u2:0-ev]"] +[13.464125, "o", "\r\n"] +[13.464593, "o", " 38 2 root IW 0 0% 0% [kworker/u2:1-ev]"] +[13.464709, "o", "\r\n"] +[13.465189, "o", " 34 2 root IW< 0 0% 0% [kworker/0:1H-kb]"] +[13.465323, "o", "\r\n"] +[13.465519, "o", " 43 2 root SW 0 0% 0% [jbd2/vda-8]\r"] +[18.487741, "o", "\u001b[1;1H\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\u001b[1;1H\u001b[KMem: 34424K used, 206256K free, 3836K shrd, 380K buff, 8008K cached"] +[18.488024, "o", "\r\n"] +[18.488389, "o", "CPU: 0% usr 0% sys 0% nic 99% idle 0% io 0% irq 0% sirq"] +[18.488672, "o", "\r\n"] +[18.489375, "o", "Load average: 0.08 0.29 0.18 1/37 5529"] +[18.489628, "o", "\r\n"] +[18.491955, "o", "\u001b[0m\u001b(B\u001b[7m PID PPID USER STAT VSZ %VSZ %CPU COMMAND"] +[18.492108, "o", "\r\n"] +[18.492801, "o", "\u001b[0m\u001b(B 5529 5474 root R 2972 1% 1% top"] +[18.493112, "o", "\r\n"] +[18.493653, "o", " 5474 1 root S 2972 1% 0% -sh"] +[18.493772, "o", "\r\n"] +[18.494187, "o", " 198 1 root S 2828 1% 0% /sbin/syslogd -n -O /var/log/messages"] +[18.494394, "o", "\r\n"] +[18.495284, "o", " 187 1 root S 2828 1% 0% udhcpc -R -b -p /var/run/udhcpc.eth0.p\u001b[8;80H"] +[18.495442, "o", "\r\n"] +[18.495842, "o", " 201 1 root S 2828 1% 0% /sbin/klogd -n"] +[18.49601, "o", "\r\n"] +[18.496439, "o", " 207 1 root S 2828 1% 0% /sbin/getty 38400 tty1"] +[18.49661, "o", "\r\n"] +[18.497041, "o", " 209 1 root S 2828 1% 0% /sbin/getty 38400 tty2"] +[18.497175, "o", "\r\n"] +[18.497594, "o", " 210 1 root S 2828 1% 0% /sbin/getty 38400 tty3"] +[18.497754, "o", "\r\n"] +[18.498242, "o", " 211 1 root S 2828 1% 0% /sbin/getty 38400 tty4"] +[18.498393, "o", "\r\n"] +[18.499275, "o", " 212 1 root S 2828 1% 0% /sbin/getty 38400 tty5"] +[18.499412, "o", "\r\n"] +[18.499785, "o", " 1 0 root S 2004 1% 0% init [5]"] +[18.499938, "o", "\r\n"] +[18.500316, "o", " 10 2 root IW 0 0% 0% [rcu_sched]"] +[18.50045, "o", "\r\n"] +[18.500827, "o", " 9 2 root SW 0 0% 0% [ksoftirqd/0]"] +[18.500944, "o", "\r\n"] +[18.501445, "o", " 42 2 root SWN 0 0% 0% [kmemleak]"] +[18.50159, "o", "\r\n"] +[18.502138, "o", " 39 2 root IW 0 0% 0% [kworker/0:2-eve]"] +[18.502298, "o", "\r\n"] +[18.50317, "o", " 13 2 root SW 0 0% 0% [kdevtmpfs]"] +[18.503323, "o", "\r\n"] +[18.50372, "o", " 7 2 root IW 0 0% 0% [kworker/u2:0-ev]"] +[18.50386, "o", "\r\n"] +[18.504334, "o", " 38 2 root IW 0 0% 0% [kworker/u2:1-ev]"] +[18.504402, "o", "\r\n"] +[18.504755, "o", " 34 2 root IW< 0 0% 0% [kworker/0:1H-kb]"] +[18.504906, "o", "\r\n"] +[18.505094, "o", " 43 2 root SW 0 0% 0% [jbd2/vda-8]\r"] +[19.166233, "o", "\n\u001b[23;80H \u001b[24;1H"] +[19.169564, "o", "root@qemux86:~# "] +[23.887009, "o", "i"] +[24.003278, "o", "f"] +[25.38907, "o", "\b\u001b[K"] +[25.612968, "o", "p"] +[25.845698, "o", " "] +[26.036611, "o", "l"] +[26.229837, "o", "i"] +[26.685128, "o", "\b\u001b[K"] +[26.805031, "o", "\b\u001b[K"] +[26.89406, "o", "a"] +[26.974792, "o", "d"] +[27.125316, "o", "d"] +[27.30899, "o", "r"] +[27.389767, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[27.405865, "o", "1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000"] +[27.406054, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[27.406659, "o", " link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00"] +[27.406961, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[27.408609, "o", " inet 127.0.0.1/8 scope host lo"] +[27.408902, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[27.409235, "o", " valid_lft forever preferred_lft forever"] +[27.409376, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[27.40968, "o", " inet6 ::1/128 scope host "] +[27.409834, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[27.410081, "o", " valid_lft forever preferred_lft forever"] +[27.41027, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[27.411406, "o", "2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000"] +[27.41166, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[27.41196, "o", " link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff\r\n\u001b[23;80H \u001b[24;1H"] +[27.412383, "o", " inet 172.213.0.18/24 brd 172.213.0.255 scope global eth0\r\n\u001b[23;80H \u001b[24;1H"] +[27.412724, "o", " valid_lft forever preferred_lft forever"] +[27.412907, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[27.413445, "o", "3: sit0@NONE: <NOARP> mtu 1480 qdisc noop qlen 1000"] +[27.413562, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[27.413865, "o", " link/sit 0.0.0.0 brd 0.0.0.0"] +[27.414033, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[27.416761, "o", "root@qemux86:~# "] +[38.933061, "o", "\u001b[0m\u001b(B\u001b[7m\r\u001b[K\u001b[?12l\u001b[?25h\u001b[?25lCTRL-A Z for help | 115200 8N1 | NOR | Minicom 2.7.1 | VT102 | Offline | al.pts\u001b[?12l\u001b[?25h"] +[38.933124, "o", "\u001b[24;17H"] +[40.700594, "o", "\u001b[8;30H\u001b[?25l\u001b[0m\u001b(B\u001b(0lqqqqqqqqqqqqqqqqqqqqqqk\u001b[9;30Hx\u001b[0m\u001b(B Leave Minicom? \u001b[0m\u001b(B\u001b(0x\u001b[10;30Hx\u001b[0m\u001b(B No \u001b[0m\u001b(B\u001b(0x\u001b[11;30Hmqqqqqqqqqqqqqqqqqqqqqqj\u001b[10;51H\u001b[?25l\u001b[10;33H\u001b[0m\u001b(B\u001b[7m Yes "] +[42.276438, "o", "\u001b[?12l\u001b[?25h\u001b[8;1H\u001b[0m\u001b(B 38 2 root IW 0 0% 0% [kworker/u2\u001b[9;1H 34 2 root IW< 0 0% 0% [kworker/0:\u001b[10;1H 43 2 root SW 0 0% 0% [jbd2/vda-8\u001b[11;1Hroot@qemux86:~# ip addr \u001b[24;17H\u001b[0m\u001b(B\u001b[7m\u001b[?12l\u001b[?25h"] +[42.276595, "o", "\u001b[?12l\u001b[?25h\u001b[0m\u001b(B\u001b[H\u001b[2J\u001b[?12l\u001b[?25h\u001b[?1l\u001b>\u001b[!p\u001b[?3;4l\u001b[4l\u001b>"] +[42.276685, "o", "$ "] +[73.938043, "o", "n"] +[74.028267, "o", "o"] +[74.219846, "o", "h"] +[74.436234, "o", "u"] +[74.53207, "o", "p"] +[74.781125, "o", " "] +[75.188776, "o", "s"] +[75.276111, "o", "u"] +[75.916849, "o", "d"] +[75.992557, "o", "o"] +[76.120543, "o", " "] +[76.4366, "o", "p"] +[76.56442, "o", "i"] +[76.748589, "o", "n"] +[76.852263, "o", "g"] +[76.916772, "o", " "] +[77.073216, "o", "-"] +[77.184444, "o", "f"] +[77.284511, "o", " "] +[79.70078, "o", "172.213.0.18"] +[80.644466, "o", " "] +[81.313662, "o", "&"] +[81.95608, "o", "\r\n"] +[81.956239, "o", "$ "] +[81.956532, "o", "nohup: ignoring input and appending output to 'nohup.out'\r\n"] +[83.107734, "o", "\r\n$ "] +[84.435832, "o", "m"] +[84.532479, "o", "i"] +[84.643806, "o", "n"] +[84.820208, "o", "c"] +[84.891586, "o", "o"] +[84.971776, "o", "m"] +[92.307554, "o", " "] +[92.403882, "o", "-"] +[92.675839, "o", "D"] +[92.787506, "o", " "] +[93.563841, "o", "s"] +[93.652089, "o", "e"] +[93.715884, "o", "r"] +[93.763667, "o", "i"] +[93.875947, "o", "a"] +[93.93975, "o", "l"] +[94.116003, "o", "."] +[94.364381, "o", "p"] +[94.484616, "o", "t"] +[94.700067, "o", "s"] +[94.995562, "o", "\r\n"] +[94.996318, "o", "\u001b[!p\u001b[?3;4l\u001b[4l\u001b>\u001b[0m\u001b(B"] +[94.996448, "o", "\u001b[?1h\u001b=\u001b[H\u001b[2J"] +[94.996773, "o", "\u001b[?12l\u001b[?25h\nWelcome to minicom 2.7.1\r\n\nOPTIONS: I18n \r\nCompiled on Dec 23 2019, 02:06:26.\r\nPort serial.pts, 19:21:44\r\n\nPress CTRL-A Z for help on special keys\r\n\n"] +[95.525135, "o", "\n"] +[95.526362, "o", "root@qemux86:~# "] +[96.060597, "o", "t"] +[96.108363, "o", "o"] +[96.159286, "o", "p"] +[96.338736, "o", "\r\n"] +[96.58656, "o", "\u001b[1;1H\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\u001b[1;1H\u001b[KMem: 34432K used, 206248K free, 3836K shrd, 384K buff, 8008K cached"] +[96.58739, "o", "\r\n"] +[96.590639, "o", "CPU: 0% usr 28% sys 0% nic 7% idle 0% io 0% irq 64% sirq"] +[96.591015, "o", "\r\n"] +[96.595524, "o", "Load average: 0.32 0.29 0.18 2/37 5531"] +[96.595722, "o", "\r\n"] +[96.608711, "o", "\u001b[0m\u001b(B\u001b[7m PID PPID USER STAT VSZ %VSZ %CPU COMMAND"] +[96.608982, "o", "\r\n"] +[96.609479, "o", "\u001b[0m\u001b(B 9 2 root RW 0 0% 50% [ksoftirqd/0]"] +[96.609654, "o", "\r\n"] +[96.610278, "o", " 5531 5474 root R 2828 1% 14% top"] +[96.610432, "o", "\r\n"] +[96.621162, "o", " 10 2 root IW 0 0% 14% [rcu_sched]"] +[96.62135, "o", "\r\n"] +[96.621869, "o", " 5474 1 root S 2972 1% 0% -sh"] +[96.621996, "o", "\r\n"] +[96.622532, "o", " 198 1 root S 2828 1% 0% /sbin/syslogd -n -O /var/log/messages"] +[96.622802, "o", "\r\n"] +[96.623253, "o", " 187 1 root S 2828 1% 0% udhcpc -R -b -p /var/run/udhcpc.eth0.p\u001b[10;80H"] +[96.623426, "o", "\r\n"] +[96.623854, "o", " 201 1 root S 2828 1% 0% /sbin/klogd -n"] +[96.62401, "o", "\r\n"] +[96.624429, "o", " 207 1 root S 2828 1% 0% /sbin/getty 38400 tty1"] +[96.624607, "o", "\r\n"] +[96.625129, "o", " 209 1 root S 2828 1% 0% /sbin/getty 38400 tty2"] +[96.625226, "o", "\r\n"] +[96.62562, "o", " 210 1 root S 2828 1% 0% /sbin/getty 38400 tty3"] +[96.625825, "o", "\r\n"] +[96.626246, "o", " 211 1 root S 2828 1% 0% /sbin/getty 38400 tty4"] +[96.626462, "o", "\r\n"] +[96.635421, "o", " 212 1 root S 2828 1% 0% /sbin/getty 38400 tty5"] +[96.635574, "o", "\r\n"] +[96.635889, "o", " 1 0 root S 2004 1% 0% init [5]"] +[96.636113, "o", "\r\n"] +[96.636631, "o", " 42 2 root SWN 0 0% 0% [kmemleak]"] +[96.636739, "o", "\r\n"] +[96.637233, "o", " 39 2 root IW 0 0% 0% [kworker/0:2-mm_]"] +[96.637352, "o", "\r\n"] +[96.637676, "o", " 7 2 root IW 0 0% 0% [kworker/u2:0-ev]"] +[96.637783, "o", "\r\n"] +[96.638119, "o", " 13 2 root SW 0 0% 0% [kdevtmpfs]"] +[96.638283, "o", "\r\n"] +[96.643324, "o", " 38 2 root IW 0 0% 0% [kworker/u2:1-ev]"] +[96.643513, "o", "\r\n"] +[96.644008, "o", " 43 2 root SW 0 0% 0% [jbd2/vda-8]"] +[96.644118, "o", "\r\n"] +[96.644439, "o", " 34 2 root IW< 0 0% 0% [kworker/0:1H-kb]\r"] +[101.701434, "o", "\u001b[1;1H\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\u001b[1;1H\u001b[KMem: 34520K used, 206160K free, 3840K shrd, 388K buff, 8008K cached"] +[101.701499, "o", "\r\n"] +[101.701748, "o", "CPU: 0% usr 11% sys 0% nic 17% idle 0% io 0% irq 70% sirq"] +[101.701978, "o", "\r\n"] +[101.702444, "o", "Load average: 0.29 0.29 0.18 2/37 5541"] +[101.702673, "o", "\r\n"] +[101.715916, "o", "\u001b[0m\u001b(B\u001b[7m PID PPID USER STAT VSZ %VSZ %CPU COMMAND"] +[101.71616, "o", "\r\n"] +[101.716771, "o", "\u001b[0m\u001b(B 9 2 root SW 0 0% 43% [ksoftirqd/0]"] +[101.71689, "o", "\r\n"] +[101.717274, "o", " 10 2 root IW 0 0% 17% [rcu_sched]"] +[101.717579, "o", "\r\n"] +[101.717921, "o", " 5531 5474 root R 2972 1% 1% top"] +[101.718166, "o", "\r\n"] +[101.718688, "o", " 1 0 root S 2004 1% 1% init [5]"] +[101.718868, "o", "\r\n"] +[101.726882, "o", " 5474 1 root S 2972 1% 0% -sh"] +[101.727162, "o", "\r\n"] +[101.738059, "o", " 198 1 root S 2828 1% 0% /sbin/syslogd -n -O /var/log/messages"] +[101.738201, "o", "\r\n"] +[101.738825, "o", " 187 1 root S 2828 1% 0% udhcpc -R -b -p /var/run/udhcpc.eth0.p\u001b[11;80H"] +[101.739146, "o", "\r\n"] +[101.739547, "o", " 201 1 root S 2828 1% 0% /sbin/klogd -n"] +[101.739785, "o", "\r\n"] +[101.74017, "o", " 207 1 root S 2828 1% 0% /sbin/getty 38400 tty1"] +[101.740448, "o", "\r\n"] +[101.740861, "o", " 209 1 root S 2828 1% 0% /sbin/getty 38400 tty2"] +[101.745102, "o", "\r\n"] +[101.761351, "o", " 210 1 root S 2828 1% 0% /sbin/getty 38400 tty3"] +[101.761869, "o", "\r\n"] +[101.769943, "o", " 211 1 root S 2828 1% 0% /sbin/getty 38400 tty4"] +[101.770407, "o", "\r\n"] +[101.777249, "o", " 212 1 root S 2828 1% 0% /sbin/getty 38400 tty5"] +[101.777746, "o", "\r\n"] +[101.782585, "o", " 42 2 root SWN 0 0% 0% [kmemleak]"] +[101.78294, "o", "\r\n"] +[101.789941, "o", " 39 2 root IW 0 0% 0% [kworker/0:2-eve]"] +[101.790104, "o", "\r\n"] +[101.790657, "o", " 7 2 root IW 0 0% 0% [kworker/u2:0-fl]"] +[101.790924, "o", "\r\n"] +[101.791318, "o", " 13 2 root SW 0 0% 0% [kdevtmpfs]"] +[101.791471, "o", "\r\n"] +[101.791821, "o", " 38 2 root IW 0 0% 0% [kworker/u2:1-ev]"] +[101.792047, "o", "\r\n"] +[101.792515, "o", " 43 2 root SW 0 0% 0% [jbd2/vda-8]"] +[101.792624, "o", "\r\n"] +[101.792795, "o", " 34 2 root IW< 0 0% 0% [kworker/0:1H-kb]\r"] +[106.850435, "o", "\u001b[1;1H\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\u001b[1;1H\u001b[KMem: 34512K used, 206168K free, 3840K shrd, 388K buff, 8012K cached"] +[106.850593, "o", "\r\n"] +[106.850752, "o", "CPU: 0% usr 7% sys 0% nic 17% idle 0% io 0% irq 74% sirq"] +[106.850895, "o", "\r\n"] +[106.851563, "o", "Load average: 0.35 0.30 0.19 2/37 5541"] +[106.851692, "o", "\r\n"] +[106.852789, "o", "\u001b[0m\u001b(B\u001b[7m PID PPID USER STAT VSZ %VSZ %CPU COMMAND"] +[106.852952, "o", "\r\n"] +[106.8535, "o", "\u001b[0m\u001b(B 9 2 root RW 0 0% 43% [ksoftirqd/0]"] +[106.853632, "o", "\r\n"] +[106.854315, "o", " 10 2 root IW 0 0% 17% [rcu_sched]"] +[106.854348, "o", "\r\n"] +[106.865859, "o", " 5531 5474 root R 2972 1% 1% top"] +[106.866331, "o", "\r\n"] +[106.870104, "o", " 5474 1 root S 2972 1% 0% -sh"] +[106.870466, "o", "\r\n"] +[106.879321, "o", " 198 1 root S 2828 1% 0% /sbin/syslogd -n -O /var/log/messages"] +[106.879486, "o", "\r\n"] +[106.880046, "o", " 187 1 root S 2828 1% 0% udhcpc -R -b -p /var/run/udhcpc.eth0.p\u001b[10;80H"] +[106.880262, "o", "\r\n"] +[106.880647, "o", " 201 1 root S 2828 1% 0% /sbin/klogd -n"] +[106.880836, "o", "\r\n"] +[106.881316, "o", " 207 1 root S 2828 1% 0% /sbin/getty 38400 tty1"] +[106.881433, "o", "\r\n"] +[106.881896, "o", " 209 1 root S 2828 1% 0% /sbin/getty 38400 tty2"] +[106.882036, "o", "\r\n"] +[106.882496, "o", " 210 1 root S 2828 1% 0% /sbin/getty 38400 tty3"] +[106.882685, "o", "\r\n"] +[106.892921, "o", " 211 1 root S 2828 1% 0% /sbin/getty 38400 tty4"] +[106.893509, "o", "\r\n"] +[106.90363, "o", " 212 1 root S 2828 1% 0% /sbin/getty 38400 tty5"] +[106.903807, "o", "\r\n"] +[106.904182, "o", " 1 0 root S 2004 1% 0% init [5]"] +[106.904433, "o", "\r\n"] +[106.904902, "o", " 42 2 root SWN 0 0% 0% [kmemleak]"] +[106.905429, "o", "\r\n"] +[106.905782, "o", " 39 2 root IW 0 0% 0% [kworker/0:2-eve]"] +[106.906003, "o", "\r\n"] +[106.906469, "o", " 7 2 root IW 0 0% 0% [kworker/u2:0-fl]"] +[106.906625, "o", "\r\n"] +[106.909123, "o", " 13 2 root SW 0 0% 0% [kdevtmpfs]"] +[106.909318, "o", "\r\n"] +[106.909667, "o", " 38 2 root IW 0 0% 0% [kworker/u2:1-ev]"] +[106.909813, "o", "\r\n"] +[106.91024, "o", " 43 2 root SW 0 0% 0% [jbd2/vda-8]"] +[106.910514, "o", "\r\n"] +[106.91072, "o", " 34 2 root IW< 0 0% 0% [kworker/0:1H-kb]\r"] +[111.956876, "o", "\u001b[1;1H\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\u001b[1;1H\u001b[KMem: 34512K used, 206168K free, 3848K shrd, 388K buff, 8020K cached\r\n"] +[111.9573, "o", "CPU: 0% usr 12% sys 0% nic 15% idle 0% io 0% irq 71% sirq"] +[111.957432, "o", "\r\n"] +[111.957933, "o", "Load average: 0.32 0.29 0.19 2/37 5551"] +[111.958189, "o", "\r\n"] +[111.97146, "o", "\u001b[0m\u001b(B\u001b[7m PID PPID USER STAT VSZ %VSZ %CPU COMMAND"] +[111.971723, "o", "\r\n"] +[111.972186, "o", "\u001b[0m\u001b(B 9 2 root RW 0 0% 44% [ksoftirqd/0]"] +[111.972254, "o", "\r\n"] +[111.972813, "o", " 10 2 root IW 0 0% 17% [rcu_sched]"] +[111.972939, "o", "\r\n"] +[111.973495, "o", " 1 0 root S 2004 1% 2% init [5]"] +[111.973663, "o", "\r\n"] +[111.974138, "o", " 5531 5474 root R 2972 1% 1% top"] +[111.974365, "o", "\r\n"] +[111.980464, "o", " 198 1 root S 2828 1% 0% /sbin/syslogd -n -O /var/log/messages"] +[111.980996, "o", "\r\n"] +[111.994119, "o", " 5474 1 root S 2972 1% 0% -sh"] +[111.994451, "o", "\r\n"] +[112.002489, "o", " 187 1 root S 2828 1% 0% udhcpc -R -b -p /var/run/udhcpc.eth0.p\u001b[11;80H"] +[112.003179, "o", "\r\n"] +[112.017546, "o", " 201 1 root S 2828 1% 0% /sbin/klogd -n"] +[112.018026, "o", "\r\n"] +[112.026893, "o", " 207 1 root S 2828 1% 0% /sbin/getty 38400 tty1"] +[112.027036, "o", "\r\n"] +[112.027601, "o", " 209 1 root S 2828 1% 0% /sbin/getty 38400 tty2"] +[112.027845, "o", "\r\n"] +[112.028265, "o", " 210 1 root S 2828 1% 0% /sbin/getty 38400 tty3"] +[112.028403, "o", "\r\n"] +[112.028856, "o", " 211 1 root S 2828 1% 0% /sbin/getty 38400 tty4"] +[112.028978, "o", "\r\n"] +[112.029317, "o", " 212 1 root S 2828 1% 0% /sbin/getty 38400 tty5"] +[112.029507, "o", "\r\n"] +[112.029848, "o", " 42 2 root SWN 0 0% 0% [kmemleak]"] +[112.030002, "o", "\r\n"] +[112.030344, "o", " 39 2 root IW 0 0% 0% [kworker/0:2-mm_]"] +[112.030576, "o", "\r\n"] +[112.040702, "o", " 7 2 root IW 0 0% 0% [kworker/u2:0-fl]\r\n"] +[112.041062, "o", " 13 2 root SW 0 0% 0% [kdevtmpfs]"] +[112.041124, "o", "\r\n"] +[112.041624, "o", " 38 2 root IW 0 0% 0% [kworker/u2:1-ev]"] +[112.041812, "o", "\r\n"] +[112.042352, "o", " 43 2 root SW 0 0% 0% [jbd2/vda-8]"] +[112.042485, "o", "\r\n"] +[112.042865, "o", " 34 2 root IW< 0 0% 0% [kworker/0:1H-kb]\r"] +[115.116387, "o", "\n\u001b[23;80H \u001b[24;1H"] diff --git a/refs/pull/405/merge/_images/list_evolution.png b/refs/pull/405/merge/_images/list_evolution.png new file mode 100644 index 00000000..aa44396d Binary files /dev/null and b/refs/pull/405/merge/_images/list_evolution.png differ diff --git a/refs/pull/405/merge/_images/list_evolution1.png b/refs/pull/405/merge/_images/list_evolution1.png new file mode 100644 index 00000000..aa44396d Binary files /dev/null and b/refs/pull/405/merge/_images/list_evolution1.png differ diff --git a/refs/pull/405/merge/_images/lro.png b/refs/pull/405/merge/_images/lro.png new file mode 100644 index 00000000..4c781b96 Binary files /dev/null and b/refs/pull/405/merge/_images/lro.png differ diff --git a/refs/pull/405/merge/_images/lro1.png b/refs/pull/405/merge/_images/lro1.png new file mode 100644 index 00000000..4c781b96 Binary files /dev/null and b/refs/pull/405/merge/_images/lro1.png differ diff --git a/refs/pull/405/merge/_images/minfs.png b/refs/pull/405/merge/_images/minfs.png new file mode 100644 index 00000000..affd8230 Binary files /dev/null and b/refs/pull/405/merge/_images/minfs.png differ diff --git a/refs/pull/405/merge/_images/minfs1.png b/refs/pull/405/merge/_images/minfs1.png new file mode 100644 index 00000000..affd8230 Binary files /dev/null and b/refs/pull/405/merge/_images/minfs1.png differ diff --git a/refs/pull/405/merge/_images/minfs_arch.png b/refs/pull/405/merge/_images/minfs_arch.png new file mode 100644 index 00000000..6778e663 Binary files /dev/null and b/refs/pull/405/merge/_images/minfs_arch.png differ diff --git a/refs/pull/405/merge/_images/minfs_arch1.png b/refs/pull/405/merge/_images/minfs_arch1.png new file mode 100644 index 00000000..6778e663 Binary files /dev/null and b/refs/pull/405/merge/_images/minfs_arch1.png differ diff --git a/refs/pull/405/merge/_images/net-dev-hw.png b/refs/pull/405/merge/_images/net-dev-hw.png new file mode 100644 index 00000000..8d52e5fa Binary files /dev/null and b/refs/pull/405/merge/_images/net-dev-hw.png differ diff --git a/refs/pull/405/merge/_images/net-dev-hw1.png b/refs/pull/405/merge/_images/net-dev-hw1.png new file mode 100644 index 00000000..8d52e5fa Binary files /dev/null and b/refs/pull/405/merge/_images/net-dev-hw1.png differ diff --git a/refs/pull/405/merge/_images/page-fault-handling.png b/refs/pull/405/merge/_images/page-fault-handling.png new file mode 100644 index 00000000..7f60933a Binary files /dev/null and b/refs/pull/405/merge/_images/page-fault-handling.png differ diff --git a/refs/pull/405/merge/_images/page-fault-handling1.png b/refs/pull/405/merge/_images/page-fault-handling1.png new file mode 100644 index 00000000..7f60933a Binary files /dev/null and b/refs/pull/405/merge/_images/page-fault-handling1.png differ diff --git a/refs/pull/405/merge/_images/paging.png b/refs/pull/405/merge/_images/paging.png new file mode 100644 index 00000000..53f7fb18 Binary files /dev/null and b/refs/pull/405/merge/_images/paging.png differ diff --git a/refs/pull/405/merge/_images/paging1.png b/refs/pull/405/merge/_images/paging1.png new file mode 100644 index 00000000..53f7fb18 Binary files /dev/null and b/refs/pull/405/merge/_images/paging1.png differ diff --git a/refs/pull/405/merge/_images/read.png b/refs/pull/405/merge/_images/read.png new file mode 100644 index 00000000..4502fb42 Binary files /dev/null and b/refs/pull/405/merge/_images/read.png differ diff --git a/refs/pull/405/merge/_images/read1.png b/refs/pull/405/merge/_images/read1.png new file mode 100644 index 00000000..4502fb42 Binary files /dev/null and b/refs/pull/405/merge/_images/read1.png differ diff --git a/refs/pull/405/merge/_images/read2.png b/refs/pull/405/merge/_images/read2.png new file mode 100644 index 00000000..6f04b13e Binary files /dev/null and b/refs/pull/405/merge/_images/read2.png differ diff --git a/refs/pull/405/merge/_images/read21.png b/refs/pull/405/merge/_images/read21.png new file mode 100644 index 00000000..6f04b13e Binary files /dev/null and b/refs/pull/405/merge/_images/read21.png differ diff --git a/refs/pull/405/merge/_images/routing-cache.png b/refs/pull/405/merge/_images/routing-cache.png new file mode 100644 index 00000000..47dcdcb2 Binary files /dev/null and b/refs/pull/405/merge/_images/routing-cache.png differ diff --git a/refs/pull/405/merge/_images/routing-cache1.png b/refs/pull/405/merge/_images/routing-cache1.png new file mode 100644 index 00000000..47dcdcb2 Binary files /dev/null and b/refs/pull/405/merge/_images/routing-cache1.png differ diff --git a/refs/pull/405/merge/_images/schematic.png b/refs/pull/405/merge/_images/schematic.png new file mode 100644 index 00000000..89020fb9 Binary files /dev/null and b/refs/pull/405/merge/_images/schematic.png differ diff --git a/refs/pull/405/merge/_images/schematic1.png b/refs/pull/405/merge/_images/schematic1.png new file mode 100644 index 00000000..89020fb9 Binary files /dev/null and b/refs/pull/405/merge/_images/schematic1.png differ diff --git a/refs/pull/405/merge/_images/selectors-and-segments.cast b/refs/pull/405/merge/_images/selectors-and-segments.cast new file mode 100644 index 00000000..2c04bbeb --- /dev/null +++ b/refs/pull/405/merge/_images/selectors-and-segments.cast @@ -0,0 +1,1818 @@ +{"version": 2, "width": 80, "height": 24, "timestamp": 1617704245, "idle_time_limit": 1.0, "env": {"SHELL": null, "TERM": "xterm"}} +[0.002359, "o", "$ "] +[1.205759, "o", "m"] +[1.286489, "o", "a"] +[1.349222, "o", "k"] +[1.526553, "o", "e"] +[1.643724, "o", " "] +[2.348906, "o", "g"] +[2.575307, "o", "d"] +[2.64632, "o", "b"] +[3.052572, "o", "\r\n"] +[3.074798, "o", "gdb -ex \"target remote localhost:1234\" /linux/vmlinux\r\n"] +[3.117199, "o", "\u001b[35;1m\u001b[35;1mGNU gdb \u001b[m\u001b[35;1m(Ubuntu 9.2-0ubuntu1~20.04) \u001b[m\u001b[35;1m9.2\u001b[m\u001b[35;1m\r\n\u001b[m\u001b[mCopyright (C) 2020 Free Software Foundation, Inc.\r\nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\r\nThis is free software: you are free to change and redistribute it.\r\nThere is NO WARRANTY, to the extent permitted by law.\r\nType \"show copying\" and \"show warranty\" for details.\r\nThis GDB was configured as \"x86_64-linux-gnu\".\r\nType \"show configuration\" for configuration details.\r\nFor bug reporting instructions, please see:\r\n<http://www.gnu.org/software/gdb/bugs/>.\r\nFind the GDB manual and other documentation resources online at:\r\n <http://www.gnu.org/software/gdb/documentation/>.\r\n\r\nFor help, type \"help\".\r\nType \"apropos word\" to search for commands related to \"word\"...\r\n"] +[3.117763, "o", "Reading symbols from \u001b[32m/linux/vmlinux\u001b[m...\r\n"] +[3.768166, "o", "Remote debugging using localhost:1234\r\n"] +[3.781924, "o", "\u001b[34m0xc15dcb62\u001b[m in \u001b[33mdefault_idle\u001b[m () at \u001b[32m./arch/x86/include/asm/irqflags.h\u001b[m:60\r\n"] +[3.781966, "o", "60\t\tasm volatile(\"sti; hlt\": : :\"memory\");\r\n"] +[3.782406, "o", "(gdb) "] +[4.626339, "o", "b"] +[4.768564, "o", "t"] +[5.44911, "o", "\r\n"] +[5.449728, "o", "#0 \u001b[34m0xc15dcb62\u001b[m in \u001b[33mdefault_idle\u001b[m () at \u001b[32m./arch/x86/include/asm/irqflags.h\u001b[m:60\r\n"] +[5.449863, "o", "#1 \u001b[34m0xc102a0dd\u001b[m in \u001b[33march_cpu_idle\u001b[m () at \u001b[32march/x86/kernel/process.c\u001b[m:680\r\n"] +[5.459029, "o", "#2 \u001b[34m0xc15dcee2\u001b[m in \u001b[33mdefault_idle_call\u001b[m () at \u001b[32mkernel/sched/idle.c\u001b[m:112\r\n#3 \u001b[34m0xc1087fb5\u001b[m in \u001b[33mcpuidle_idle_call\u001b[m () at \u001b[32mkernel/sched/idle.c\u001b[m:194\r\n#4 \u001b[33mdo_idle\u001b[m () at \u001b[32mkernel/sched/idle.c\u001b[m:299\r\n"] +[5.466862, "o", "#5 \u001b[34m0xc1088295\u001b[m in \u001b[33mcpu_startup_entry\u001b[m (\u001b[36mstate=state@entry\u001b[m=CPUHP_ONLINE)\u001b[m\r\n \u001b[m at \u001b[32mkernel/sched/idle.c\u001b[m:395\r\n#6 \u001b[34m0xc15d4ffb\u001b[m in \u001b[33mrest_init\u001b[m () at \u001b[32minit/main.c\u001b[m:721\r\n"] +[5.467037, "o", "#7 \u001b[34m0xc18cd7c4\u001b[m in \u001b[33march_call_rest_init\u001b[m () at \u001b[32minit/main.c\u001b[m:845\r\n#8 \u001b[34m0xc18cdc08\u001b[m in \u001b[33mstart_kernel\u001b[m () at \u001b[32minit/main.c\u001b[m:1061\r\n"] +[5.469609, "o", "#9 \u001b[34m0xc18cd218\u001b[m in \u001b[33mi386_start_kernel\u001b[m () at \u001b[32march/x86/kernel/head32.c\u001b[m:56\r\n"] +[5.470029, "o", "#10 \u001b[34m0xc10001db\u001b[m in \u001b[33mstartup_32_smp\u001b[m () at \u001b[32march/x86/kernel/head_32.S\u001b[m:327\r\n"] +[5.471491, "o", "#11 \u001b[34m0x00000000\u001b[m in \u001b[33m??\u001b[m ()\r\n"] +[5.472127, "o", "(gdb) "] +[6.957539, "o", "#"] +[7.184578, "o", " "] +[9.085494, "o", "i"] +[9.274558, "o", "t"] +[9.385268, "o", " "] +[9.560048, "o", "l"] +[9.72648, "o", "o"] +[9.838927, "o", "o"] +[9.918898, "o", "k"] +[10.059084, "o", "s"] +[10.113284, "o", " "] +[10.246361, "o", "l"] +[10.418976, "o", "i"] +[10.565605, "o", "k"] +[10.641569, "o", "e"] +[10.747208, "o", " "] +[10.9907, "o", "w"] +[11.09312, "o", "e"] +[11.231124, "o", " "] +[11.334085, "o", "a"] +[11.487572, "o", "r"] +[11.577493, "o", "e"] +[11.670981, "o", " "] +[12.627311, "o", "i"] +[12.911014, "o", "n"] +[13.064828, "o", " "] +[13.249479, "o", "k"] +[13.37127, "o", "e"] +[13.460074, "o", "r"] +[13.510226, "o", "n"] +[13.635205, "o", "e"] +[13.973161, "o", "l"] +[14.662931, "o", " "] +[15.131825, "o", "r"] +[15.214966, "o", "u"] +[15.358966, "o", "n"] +[15.487497, "o", "n"] +[15.654743, "o", "i"] +[15.831262, "o", "n"] +[15.996438, "o", "g"] +[16.146163, "o", " "] +[18.220116, "o", "w"] +[18.288027, "o", "i"] +[18.436822, "o", "t"] +[18.509192, "o", "h"] +[18.613143, "o", " "] +[18.807172, "o", "p"] +[18.897976, "o", "r"] +[19.013978, "o", "i"] +[19.204046, "o", "v"] +[19.283747, "o", "i"] +[19.47738, "o", "l"] +[19.544513, "o", "e"] +[19.78487, "o", "g"] +[19.880492, "o", "e"] +[20.602829, "o", " "] +[22.510059, "o", "0"] +[23.73426, "o", "\r\n"] +[23.734632, "o", "(gdb) "] +[24.495347, "o", "#"] +[24.632234, "o", " "] +[24.800588, "o", "l"] +[24.880492, "o", "e"] +[25.0523, "o", "t"] +[25.277878, "o", "s"] +[25.388396, "o", " "] +[25.613203, "o", "c"] +[25.720735, "o", "o"] +[25.817537, "o", "n"] +[25.855844, "o", "f"] +[25.973067, "o", "i"] +[26.212741, "o", "r"] +[26.386844, "o", "m"] +[26.496098, "o", " "] +[26.694327, "o", "t"] +[26.77636, "o", "h"] +[26.823023, "o", "i"] +[26.999112, "o", "s"] +[27.144801, "o", " "] +[27.434198, "o", "b"] +[27.494331, "o", "y"] +[27.714979, "o", " "] +[28.054888, "o", "l"] +[28.257672, "o", "o"] +[28.393068, "o", "o"] +[28.459965, "o", "k"] +[28.691808, "o", "i"] +[28.73292, "o", "n"] +[28.878271, "o", "g"] +[28.991934, "o", " "] +[29.143258, "o", "a"] +[29.367682, "o", "t"] +[29.494524, "o", " "] +[29.62679, "o", "t"] +[29.774843, "o", "h"] +[29.893124, "o", "e"] +[30.004863, "o", " "] +[38.956259, "o", "c"] +[39.046244, "o", "o"] +[39.159799, "o", "d"] +[39.244625, "o", "e"] +[39.30416, "o", " "] +[39.48092, "o", "s"] +[39.597493, "o", "e"] +[39.737666, "o", "l"] +[39.800726, "o", "e"] +[39.892586, "o", "c"] +[40.103179, "o", "t"] +[40.210366, "o", "o"] +[40.277594, "o", "r"] +[40.672707, "o", "\r\n"] +[40.673041, "o", "(gdb) "] +[41.394093, "o", "p"] +[41.550842, "o", "r"] +[41.704995, "o", "i"] +[41.773529, "o", "n"] +[41.869581, "o", "t"] +[42.223515, "o", " "] +[42.884229, "o", "/"] +[43.24162, "o", "$"] +[43.945015, "o", "\b\u001b[K"] +[44.294995, "o", "x"] +[44.490102, "o", " "] +[45.85674, "o", "$"] +[47.797713, "o", "c"] +[47.900134, "o", "s"] +[48.160261, "o", "\r\n"] +[48.160574, "o", "$1 = 0x60\r\n(gdb) "] +[52.875773, "o", "#"] +[53.057592, "o", " "] +[53.270518, "o", "n"] +[53.33, "o", "o"] +[53.420243, "o", "w"] +[53.516445, "o", " "] +[53.674458, "o", "l"] +[53.733163, "o", "e"] +[53.927126, "o", "t"] +[54.113039, "o", "s"] +[54.210531, "o", " "] +[54.350529, "o", "p"] +[54.509267, "o", "r"] +[54.597743, "o", "i"] +[54.668833, "o", "n"] +[54.807039, "o", "t"] +[54.905672, "o", " "] +[55.026232, "o", "t"] +[55.167086, "o", "h"] +[55.301416, "o", "e"] +[55.432852, "o", " "] +[58.048587, "o", "i"] +[58.185341, "o", "n"] +[58.275582, "o", "d"] +[58.355005, "o", "e"] +[58.575251, "o", "x"] +[59.228376, "o", " "] +[59.353553, "o", "f"] +[59.455246, "o", "o"] +[59.576325, "o", "r"] +[59.691869, "o", " "] +[59.775251, "o", "t"] +[59.864488, "o", "h"] +[59.931228, "o", "e"] +[60.017051, "o", " "] +[60.143587, "o", "c"] +[60.242612, "o", "o"] +[60.346778, "o", "d"] +[60.409921, "o", "e"] +[60.503901, "o", " "] +[60.653751, "o", "s"] +[60.791714, "o", "e"] +[60.927913, "o", "l"] +[60.995147, "o", "e"] +[61.100077, "o", "c"] +[61.301378, "o", "t"] +[61.409292, "o", "o"] +[61.472267, "o", "r"] +[61.999105, "o", "\r\n"] +[61.999211, "o", "(gdb) "] +[62.755519, "o", "p"] +[62.920307, "o", "r"] +[63.030171, "o", "i"] +[63.093306, "o", "n"] +[63.153238, "o", "t"] +[63.291438, "o", " "] +[63.834425, "o", "/"] +[64.026843, "o", "x"] +[64.200482, "o", " "] +[64.675073, "o", "\b\u001b[K"] +[64.821291, "o", "\b\u001b[K"] +[64.946712, "o", "\b\u001b[K"] +[66.373086, "o", "$"] +[66.734489, "o", "c"] +[66.85103, "o", "s"] +[67.689872, "o", ">"] +[67.812115, "o", ">"] +[91.768538, "o", "3"] +[92.507215, "o", "\r\n"] +[92.50757, "o", "$2 = 12\r\n(gdb) "] +[97.002473, "o", "#"] +[97.167356, "o", " "] +[97.43684, "o", "a"] +[97.554333, "o", "n"] +[98.078151, "o", "d"] +[98.230006, "o", " "] +[98.41845, "o", "n"] +[98.500863, "o", "o"] +[98.58555, "o", "w"] +[98.697065, "o", " "] +[98.902575, "o", "l"] +[99.036005, "o", "e"] +[99.242403, "o", "t"] +[99.457412, "o", "s"] +[99.570468, "o", " "] +[99.705253, "o", "p"] +[99.822772, "o", "r"] +[99.930937, "o", "i"] +[100.014833, "o", "n"] +[100.091449, "o", "t"] +[100.226161, "o", " "] +[100.331035, "o", "t"] +[100.564914, "o", "e"] +[100.990115, "o", "\b\u001b[K"] +[101.195011, "o", "h"] +[101.275921, "o", "e"] +[101.38122, "o", " "] +[103.755803, "o", "d"] +[103.824373, "o", "e"] +[103.946792, "o", "s"] +[104.052577, "o", "c"] +[104.247014, "o", "r"] +[104.904532, "o", "i"] +[105.058074, "o", "p"] +[105.226938, "o", "t"] +[105.297817, "o", "o"] +[105.408466, "o", "r"] +[105.513496, "o", " "] +[105.845144, "o", "f"] +[105.958437, "o", "o"] +[106.09132, "o", "r"] +[106.167673, "o", " "] +[106.430415, "o", "e"] +[106.855237, "o", "\b\u001b[K"] +[106.932061, "o", "s"] +[107.37581, "o", "e"] +[107.53021, "o", "l"] +[107.576069, "o", "e"] +[107.686763, "o", "c"] +[107.960174, "o", "t"] +[108.090163, "o", "o"] +[108.18428, "o", "r"] +[108.853073, "o", " "] +[109.180343, "o", "1"] +[109.290367, "o", "2"] +[109.8445, "o", "\r\n"] +[109.844823, "o", "(gdb) "] +[111.689231, "o", "#"] +[111.887764, "o", " "] +[112.2626, "o", "f"] +[112.390326, "o", "i"] +[112.490975, "o", "r"] +[112.741024, "o", "s"] +[112.893713, "o", "t"] +[112.982635, "o", " "] +[114.599914, "o", "g"] +[114.696218, "o", "e"] +[114.908597, "o", "t"] +[115.088006, "o", " "] +[115.172965, "o", "t"] +[115.352084, "o", "h"] +[115.459941, "o", "e"] +[115.604134, "o", " "] +[117.664675, "o", "G"] +[117.981042, "o", "T"] +[119.326974, "o", "D"] +[119.594969, "o", " "] +[121.590078, "o", "r"] +[121.687724, "o", "e"] +[121.886761, "o", "g"] +[121.987087, "o", "i"] +[122.037275, "o", "s"] +[122.222018, "o", "t"] +[122.330302, "o", "e"] +[122.429404, "o", "r"] +[123.050835, "o", " "] +[123.19778, "o", "v"] +[123.241349, "o", "a"] +[123.389395, "o", "l"] +[123.597067, "o", "u"] +[123.836279, "o", "e"] +[124.041227, "o", "\r\n"] +[124.041348, "o", "(gdb) "] +[126.327766, "o", "m"] +[126.44815, "o", "o"] +[126.814981, "o", "n"] +[126.886507, "o", "i"] +[127.037664, "o", "t"] +[127.148862, "o", "o"] +[127.266202, "o", "r"] +[127.368858, "o", " "] +[129.678077, "o", "s"] +[129.7363, "o", "h"] +[129.800484, "o", "o"] +[129.908385, "o", "w"] +[130.033271, "o", " "] +[131.662846, "o", "\b\u001b[K"] +[131.803395, "o", "\b\u001b[K"] +[131.940196, "o", "\b\u001b[K"] +[132.073194, "o", "\b\u001b[K"] +[132.18792, "o", "\b\u001b[K"] +[132.45787, "o", "i"] +[132.530376, "o", "n"] +[132.776408, "o", "g"] +[132.872135, "o", "o"] +[132.986392, "o", " "] +[133.379472, "o", "\b\u001b[K"] +[133.511446, "o", "\b\u001b[K"] +[133.626516, "o", "\b\u001b[K"] +[133.786323, "o", "f"] +[133.863781, "o", "o"] +[133.998018, "o", " "] +[134.086118, "o", "r"] +[134.560701, "o", "e"] +[134.886634, "o", "g"] +[134.991773, "o", "i"] +[135.080584, "o", "s"] +[135.2521, "o", "t"] +[135.343722, "o", "e"] +[135.452922, "o", "r"] +[135.647215, "o", "s"] +[135.73628, "o", "\r\n"] +[135.73688, "o", "EAX=0000"] +[135.737118, "o", "0000 EBX=00000000 ECX=ffffffff EDX=0"] +[135.737339, "o", "0000000\r\r\n"] +[135.737619, "o", "ESI=00000000 EDI=00000000 EBP=c17cff1"] +[135.737925, "o", "c ESP=c17cff18\r\r\nEIP=c15dcb62 EFL=0020024"] +[135.738173, "o", "6 [---Z-P-] CPL=0 II=0 A20=1 "] +[135.738429, "o", "SMM=0 HLT=1\r\r\nES =007b 00000000 ffffffff 00cff300 DPL=3 DS "] +[135.738589, "o", " [-WA]\r\r\nCS =006"] +[135.738828, "o", "0 00000000 ffffffff 00cf9a00 DPL=0 CS"] +[135.739037, "o", "32 [-R-]\r\r\nSS =0068 00000000"] +[135.739202, "o", " ffffffff 00cf9300 DPL=0 DS"] +[135.739242, "o", " [-WA]"] +[135.739526, "o", "\r\r\n"] +[135.739726, "o", "DS =007b 00000000 ffffffff 00cff300 DPL=3 DS ["] +[135.739962, "o", "-WA]\r\r\nFS =00d8 0e47b000 ffffffff 00"] +[135.740249, "o", "8f9300 DPL=0 DS16 [-WA]\r\r\nGS =00e0 cfdc"] +[135.740452, "o", "b200 00000018 00409100 DPL=0 DS [--"] +[135.740678, "o", "A]\r\r\nLDT=0000 0000000"] +[135.740839, "o", "0 00000000 00008200 DPL=0 LDT"] +[135.741014, "o", "\r\r\nTR =0080 ff806"] +[135.741163, "o", "000 0000407b 00008900 DPL"] +[135.741313, "o", "=0 TSS32-avl\r\r\n"] +[135.741459, "o", "GDT= ff801000 000000"] +[135.741543, "o", "ff\r\r\nIDT= ff800000 "] +[135.741584, "o", "000007ff\r\r\nCR0=80050"] +[135.741622, "o", "033 CR2=080919ab CR3=0"] +[135.741657, "o", "a450000 CR4=00000690\r"] +[135.741692, "o", "\r\nDR0=00000000 D"] +[135.741729, "o", "R1=00000000 DR2=0000"] +[135.741757, "o", "0000 DR3=0000000"] +[135.741795, "o", "0 \r\r\nDR6=ffff0ff0 D"] +[135.741835, "o", "R7=00000400\r\r\nEFER=000"] +[135.741869, "o", "0000000000000\r\r\n"] +[135.741904, "o", "FCW=037f FSW=0000 [S"] +[135.741935, "o", "T=0] FTW=00 MXCSR=0"] +[135.741964, "o", "0001f80\r\r\nFP"] +[135.742009, "o", "R0=0000000000000000 0000 FPR1"] +[135.742053, "o", "=0000000000000000 0000\r\r\n"] +[135.742095, "o", "FPR2=0000000000000000 0000 "] +[135.742136, "o", "FPR3=0000000000000000 000"] +[135.742173, "o", "0\r\r\nFPR4=0000000"] +[135.742212, "o", "000000000 0000 FPR5=000000"] +[135.742251, "o", "0000000000 0000\r\r\n"] +[135.742292, "o", "FPR6=0000000000000000 0000 FPR7=00000"] +[135.742328, "o", "00000000000 0000\r\r\n"] +[135.742365, "o", "XMM00=000000000000000"] +[135.7424, "o", "00000000000000000 XMM"] +[135.742436, "o", "01=0000000000000000000"] +[135.742472, "o", "0000000000000\r\r\n"] +[135.742508, "o", "XMM02=000000000000000"] +[135.742541, "o", "00000000000000000 XM"] +[135.742574, "o", "M03=00000000000000000"] +[135.742609, "o", "000000000000000\r\r\n"] +[135.742645, "o", "XMM04=000000000000"] +[135.74268, "o", "00000000000000000000 "] +[135.742716, "o", "XMM05=000000000000000000"] +[135.742753, "o", "00000000000000\r\r\n"] +[135.742792, "o", "XMM06=00000000000000000"] +[135.742829, "o", "000000000000000 XMM07=0"] +[135.74287, "o", "00000000000000000000000000"] +[135.742906, "o", "00000\r\r\n"] +[135.742943, "o", "(gdb) "] +[141.08448, "o", "g"] +[142.487912, "o", "\b\u001b[K"] +[142.687201, "o", "s"] +[142.782022, "o", "e"] +[142.929487, "o", "t"] +[143.097996, "o", " "] +[143.953732, "o", "$"] +[144.988721, "o", "g"] +[145.23854, "o", "d"] +[145.51718, "o", "t"] +[145.779607, "o", "r"] +[145.912464, "o", "="] +[154.09522, "o", "ff801000"] +[155.179972, "o", "\b"] +[155.680268, "o", "\b"] +[155.710228, "o", "\b"] +[155.740097, "o", "\b"] +[155.770866, "o", "\b"] +[155.801924, "o", "\b"] +[155.83298, "o", "\b"] +[155.863409, "o", "\b"] +[155.893282, "o", "\b"] +[155.923804, "o", "\b"] +[155.954806, "o", "\b"] +[156.173502, "o", "\u001b[C"] +[156.329491, "o", "\u001b[C"] +[156.44832, "o", "\u001b[C"] +[157.136526, "o", "0ff801000\b\b\b\b\b\b\b\b"] +[157.277804, "o", "xff801000\b\b\b\b\b\b\b\b"] +[157.772194, "o", "\r\n"] +[157.793131, "o", "(gdb) "] +[165.346319, "o", "#"] +[165.531054, "o", " "] +[165.974981, "o", "d"] +[166.056174, "o", "e"] +[166.210313, "o", "s"] +[166.277392, "o", "c"] +[166.519134, "o", "r"] +[166.620771, "o", "i"] +[166.731554, "o", "p"] +[166.883229, "o", "t"] +[166.955686, "o", "o"] +[167.072479, "o", "r"] +[167.204083, "o", " "] +[167.85161, "o", "\b\u001b[K"] +[167.982418, "o", "s"] +[168.100856, "o", " "] +[168.564966, "o", "h"] +[168.64102, "o", "a"] +[168.823243, "o", "v"] +[168.894548, "o", "e"] +[168.970183, "o", " "] +[169.176948, "o", "8"] +[169.334163, "o", " "] +[169.573922, "o", "b"] +[169.624225, "o", "y"] +[169.858766, "o", "t"] +[169.930975, "o", "e"] +[170.144177, "o", "s"] +[172.414362, "o", "\r\n"] +[172.414409, "o", "(gdb) "] +[173.311252, "o", "p"] +[173.662611, "o", "r"] +[173.785984, "o", "i"] +[173.865018, "o", "n"] +[173.983028, "o", "t"] +[174.148239, "o", " "] +[175.179933, "o", "/"] +[175.318199, "o", "x"] +[176.328504, "o", " "] +[178.585994, "o", "("] +[179.152768, "o", "u"] +[179.670353, "o", "i"] +[179.715934, "o", "n"] +[180.433924, "o", "t"] +[180.712095, "o", "6"] +[180.79663, "o", "4"] +[181.065001, "o", "_"] +[181.287562, "o", "t"] +[181.668811, "o", ")"] +[183.515012, "o", "$"] +[185.687333, "o", "\b\u001b[K"] +[185.866732, "o", "\b\u001b[K"] +[186.602865, "o", "*"] +[186.86583, "o", ")"] +[187.515633, "o", "$"] +[189.118783, "o", "d"] +[190.202703, "o", "\b\u001b[K"] +[190.355202, "o", "g"] +[190.666691, "o", "d"] +[190.945529, "o", "t"] +[191.772629, "o", "r"] +[192.777949, "o", "\b"] +[193.278082, "o", "\b"] +[193.30829, "o", "\b"] +[193.338654, "o", "\b"] +[193.369524, "o", "\b"] +[193.399722, "o", "\b"] +[193.430236, "o", "\b"] +[193.460701, "o", "\b"] +[193.491262, "o", "\b"] +[193.521133, "o", "\b"] +[193.551404, "o", "\b"] +[193.581346, "o", "\b"] +[193.612343, "o", "\b"] +[193.642766, "o", "\b"] +[193.673954, "o", "\b"] +[193.704329, "o", "\b"] +[193.735075, "o", "\b"] +[193.766105, "o", "\b"] +[193.968996, "o", "\u001b[C"] +[194.133982, "o", "\u001b[C"] +[195.116582, "o", "\u001b[C(uint64_t*)$gdtr\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"] +[195.840287, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[196.582034, "o", ")"] +[197.108677, "o", "["] +[197.615, "o", "1"] +[197.748952, "o", "2"] +[197.846455, "o", "]"] +[199.192246, "o", "\r\n"] +[199.200699, "o", "$3 = 0xcf9a000000ffff\r\n"] +[199.20087, "o", "(gdb) "] +[200.899642, "o", "print /x ((uint64_t*)$gdtr)[12]"] +[201.157767, "o", "\b"] +[201.65802, "o", "\b"] +[201.688325, "o", "\b"] +[201.718252, "o", "\b"] +[201.74874, "o", "\b"] +[201.779962, "o", "\b"] +[201.811199, "o", "\b"] +[201.842097, "o", "\b"] +[201.87248, "o", "\b"] +[201.903057, "o", "\b"] +[201.933056, "o", "\b"] +[201.963408, "o", "\b"] +[201.993637, "o", "\b"] +[202.024063, "o", "\b"] +[202.054562, "o", "\b"] +[202.08602, "o", "\b"] +[202.116448, "o", "\b"] +[202.145957, "o", "\b"] +[202.177003, "o", "\b"] +[202.207484, "o", "\b"] +[202.237255, "o", "\b"] +[202.267668, "o", "\b"] +[202.29822, "o", "\b"] +[202.328265, "o", "\b"] +[202.603106, "o", "\u001b[C"] +[202.908862, "o", "\b\u001b[1P ((uint64_t*)$gdtr)[12]\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[203.068444, "o", "z ((uint64_t*)$gdtr)[12]\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[203.245412, "o", "\r\n"] +[203.245996, "o", "$4 = 0x00cf9a000000ffff\r\n"] +[203.246341, "o", "(gdb) "] +[213.714469, "o", "#"] +[213.924177, "o", " "] +[216.1305, "o", "d"] +[216.188454, "o", "e"] +[216.363086, "o", "c"] +[216.450319, "o", "o"] +[216.564475, "o", "d"] +[216.634156, "o", "e"] +[216.77561, "o", " "] +[216.897562, "o", "t"] +[217.009052, "o", "h"] +[217.107284, "o", "e"] +[217.195724, "o", " "] +[217.436172, "o", "l"] +[217.641538, "o", "i"] +[217.77799, "o", "m"] +[217.84922, "o", "i"] +[217.98972, "o", "t"] +[220.023935, "o", "\r\n"] +[220.024319, "o", "(gdb) "] +[220.290728, "o", "p"] +[220.450692, "o", "r"] +[220.533847, "o", "i"] +[220.588309, "o", "n"] +[220.673191, "o", "t"] +[220.969452, "o", " "] +[221.640322, "o", "/"] +[221.835579, "o", "x"] +[222.015648, "o", " "] +[229.910833, "o", "0"] +[230.018988, "o", "x"] +[235.196883, "o", "ffff"] +[236.417946, "o", " "] +[236.798758, "o", "*"] +[237.041762, "o", " "] +[239.365773, "o", "4"] +[239.475724, "o", "0"] +[239.686894, "o", "9"] +[240.006818, "o", "6"] +[241.88331, "o", "\r\n"] +[241.883649, "o", "$5 = 0xffff000\r\n(gdb) "] +[247.790867, "o", "#"] +[247.888405, "o", " "] +[248.078816, "o", "l"] +[248.234787, "o", "i"] +[248.378544, "o", "m"] +[248.444722, "o", "i"] +[248.608612, "o", "t"] +[248.721834, "o", " "] +[248.969296, "o", "i"] +[249.108096, "o", "s"] +[249.213166, "o", " "] +[249.852357, "o", "s"] +[249.970989, "o", "e"] +[250.175166, "o", "t"] +[250.316772, "o", " "] +[250.519205, "o", "t"] +[250.639319, "o", "o"] +[250.753856, "o", " "] +[251.306554, "o", "4"] +[251.870532, "o", "G"] +[252.09369, "o", "B"] +[253.582197, "o", "\r\n"] +[253.582499, "o", "(gdb) "] +[360.143066, "o", "s"] +[360.281378, "o", "e"] +[360.470522, "o", "t"] +[360.613987, "o", " "] +[361.843991, "o", "$"] +[362.851023, "o", "k"] +[362.985051, "o", "e"] +[363.042871, "o", "r"] +[363.130172, "o", "n"] +[363.188481, "o", "e"] +[363.324746, "o", "l"] +[363.842416, "o", "_"] +[365.495183, "o", "c"] +[365.631849, "o", "o"] +[365.731124, "o", "d"] +[365.781546, "o", "e"] +[371.021879, "o", "="] +[371.101039, "o", " "] +[371.423014, "o", "\b\u001b[K"] +[371.56274, "o", "\b\u001b[K"] +[371.676663, "o", " "] +[371.793814, "o", "="] +[371.916711, "o", " "] +[378.293839, "o", "((uint64_t*)$gdtr)[12]"] +[380.299588, "o", "\r\n"] +[380.320761, "o", "(gdb) "] +[382.691282, "o", "p"] +[383.391885, "o", "\b\u001b[K"] +[384.142072, "o", "#"] +[384.312701, "o", " "] +[384.457712, "o", "d"] +[384.555394, "o", "e"] +[384.722997, "o", "c"] +[384.799253, "o", "o"] +[384.920935, "o", "d"] +[384.993824, "o", "e"] +[385.075237, "o", " "] +[385.230561, "o", "t"] +[385.306128, "o", "h"] +[385.402699, "o", "e"] +[385.524367, "o", " "] +[385.683035, "o", "b"] +[385.742431, "o", "a"] +[385.818729, "o", "s"] +[385.945102, "o", "e"] +[386.563467, "o", "\r\n"] +[386.563785, "o", "(gdb) "] +[387.807248, "o", "p"] +[388.007592, "o", "r"] +[388.058408, "o", "i"] +[388.11304, "o", "n"] +[388.226837, "o", "t"] +[388.33127, "o", " "] +[388.554004, "o", "/"] +[388.663181, "o", "x"] +[388.747275, "o", " "] +[400.152432, "o", "$kernel_code"] +[401.172444, "o", ">"] +[401.31128, "o", ">"] +[402.246532, "o", "3"] +[402.36536, "o", "2"] +[403.041876, "o", ")"] +[403.470546, "o", "\b"] +[403.971061, "o", "\b"] +[404.00112, "o", "\b"] +[404.031651, "o", "\b"] +[404.062697, "o", "\b"] +[404.093786, "o", "\b"] +[404.124324, "o", "\b"] +[404.154917, "o", "\b"] +[404.186219, "o", "\b"] +[404.215797, "o", "\b"] +[404.245841, "o", "\b"] +[404.277153, "o", "\b"] +[404.307534, "o", "\b"] +[404.337518, "o", "\b"] +[404.367197, "o", "\b"] +[404.39724, "o", "\b"] +[404.427051, "o", "\b"] +[404.457149, "o", "\b"] +[404.487796, "o", "\b"] +[404.518995, "o", "\b"] +[404.717726, "o", "\u001b[C"] +[404.856778, "o", "\u001b[C"] +[404.998772, "o", "\u001b[C"] +[405.714354, "o", "($kernel_code>>32)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"] +[406.325269, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[408.028055, "o", "&"] +[409.373772, "o", "0"] +[409.514542, "o", "x"] +[409.995675, "o", "F"] +[410.205691, "o", "F"] +[410.76551, "o", "0"] +[411.008743, "o", "0"] +[411.636305, "o", "0"] +[411.810194, "o", "0"] +[412.647261, "o", "0"] +[412.820582, "o", "0"] +[413.342493, "o", ")"] +[413.718701, "o", "\b"] +[414.218638, "o", "\b"] +[414.248087, "o", "\b"] +[414.278658, "o", "\b"] +[414.309504, "o", "\b"] +[414.339242, "o", "\b"] +[414.369913, "o", "\b"] +[414.401266, "o", "\b"] +[414.431457, "o", "\b"] +[414.462205, "o", "\b"] +[414.492336, "o", "\b"] +[414.522837, "o", "\b"] +[414.553148, "o", "\b"] +[414.583161, "o", "\b"] +[414.614069, "o", "\b"] +[414.644562, "o", "\b"] +[414.675091, "o", "\b"] +[414.706454, "o", "\b"] +[414.737365, "o", "\b"] +[414.767321, "o", "\b"] +[414.797448, "o", "\b"] +[414.82805, "o", "\b"] +[414.858649, "o", "\b"] +[414.888968, "o", "\b"] +[414.918934, "o", "\b"] +[414.949273, "o", "\b"] +[414.979232, "o", "\b"] +[415.009292, "o", "\b"] +[415.039545, "o", "\b"] +[415.195848, "o", "\b"] +[415.379056, "o", "\b"] +[415.654254, "o", "\u001b[C"] +[416.120906, "o", "\u001b[C($kernel_code>>32)&0xFF000000)\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[416.670056, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[417.156581, "o", "|"] +[418.078121, "o", "("] +[418.078121, "o", "("] +[418.501176, "o", "$"] +[419.061164, "o", "k"] +[419.257984, "o", "e"] +[419.35113, "o", "r"] +[419.389884, "o", "n"] +[419.462042, "o", "e"] +[419.567743, "o", "l"] +[419.859026, "o", "_"] +[420.010047, "o", "c"] +[420.089005, "o", "o"] +[420.193463, "o", "d"] +[420.274683, "o", "e"] +[423.236442, "o", ">"] +[423.370439, "o", ">"] +[425.001308, "o", "1"] +[425.061638, "o", "6"] +[426.234482, "o", ")"] +[427.499144, "o", "&"] +[428.572962, "o", "0"] +[428.702492, "o", "x"] +[429.690473, "o", "0"] +[429.827397, "o", "0"] +[430.421525, "o", "F"] +[430.556561, "o", "F"] +[431.06108, "o", "F"] +[431.192942, "o", "F"] +[431.550652, "o", "F"] +[431.692892, "o", "F"] +[432.118055, "o", ")"] +[433.280631, "o", "\r\n"] +[493.456846, "o", "$9 = 0x0\r\n(gdb) "] +[499.686291, "o", "#"] +[499.879719, "o", " "] +[500.923126, "o", "b"] +[500.981395, "o", "a"] +[501.053439, "o", "s"] +[501.206446, "o", "e"] +[501.347024, "o", " "] +[501.498974, "o", "i"] +[501.603969, "o", "s"] +[501.939405, "o", " "] +[502.084015, "o", "0"] +[502.685399, "o", "\r\n"] +[502.685665, "o", "(gdb) "] +[505.05193, "o", "#"] +[506.321549, "o", " "] +[506.981152, "o", "d"] +[507.072632, "o", "e"] +[507.249979, "o", "c"] +[507.287012, "o", "o"] +[507.464576, "o", "d"] +[507.54832, "o", "e"] +[507.691229, "o", " "] +[507.964173, "o", "t"] +[508.11861, "o", "h"] +[508.267776, "o", "e"] +[508.361951, "o", " "] +[508.80405, "o", "p"] +[508.905761, "o", "r"] +[509.016474, "o", "i"] +[509.158256, "o", "v"] +[509.217248, "o", "i"] +[509.408068, "o", "l"] +[509.508072, "o", "e"] +[509.914455, "o", "g"] +[509.994915, "o", "e"] +[511.133299, "o", "\b"] +[511.633839, "o", "\b"] +[511.664354, "o", "\b"] +[511.694443, "o", "\b"] +[511.725474, "o", "\b"] +[511.756119, "o", "\b"] +[511.786986, "o", "\b"] +[511.818226, "o", "\b"] +[512.015711, "o", "\b"] +[512.25971, "o", "rprivilege\b\b\b\b\b\b\b\b\b"] +[512.39865, "o", "qprivilege\b\b\b\b\b\b\b\b\b"] +[512.600873, "o", "uprivilege\b\b\b\b\b\b\b\b\b"] +[512.651473, "o", "iprivilege\b\b\b\b\b\b\b\b\b"] +[512.754197, "o", "rprivilege\b\b\b\b\b\b\b\b\b"] +[512.836059, "o", "eprivilege\b\b\b\b\b\b\b\b\b"] +[513.846698, "o", "\b\u001b[1Pprivilege\b\b\b\b\b\b\b\b\b"] +[513.976248, "o", "\b\u001b[1Pprivilege\b\b\b\b\b\b\b\b\b"] +[514.095038, "o", "\b\u001b[1Pprivilege\b\b\b\b\b\b\b\b\b"] +[514.217603, "o", "\b\u001b[1Pprivilege\b\b\b\b\b\b\b\b\b"] +[514.348636, "o", "\b\u001b[1Pprivilege\b\b\b\b\b\b\b\b\b"] +[514.462555, "o", "eprivilege\b\b\b\b\b\b\b\b\b"] +[514.684859, "o", "qprivilege\b\b\b\b\b\b\b\b\b"] +[514.871245, "o", "uprivilege\b\b\b\b\b\b\b\b\b"] +[514.908025, "o", "iprivilege\b\b\b\b\b\b\b\b\b"] +[514.972336, "o", "rprivilege\b\b\b\b\b\b\b\b\b"] +[515.040145, "o", "eprivilege\b\b\b\b\b\b\b\b\b"] +[515.195378, "o", "dprivilege\b\b\b\b\b\b\b\b\b"] +[515.274181, "o", " privilege\b\b\b\b\b\b\b\b\b"] +[515.57074, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[516.018703, "o", " "] +[516.187684, "o", "l"] +[516.246874, "o", "e"] +[516.472241, "o", "v"] +[516.555511, "o", "e"] +[516.581353, "o", "l"] +[517.033643, "o", "\r\n"] +[517.033753, "o", "(gdb) "] +[518.250999, "o", "p"] +[518.390471, "o", "r"] +[518.47528, "o", "i"] +[518.539113, "o", "n"] +[518.59094, "o", "t"] +[518.697485, "o", " "] +[518.870622, "o", "/"] +[518.974887, "o", "x"] +[519.117062, "o", " "] +[541.606002, "o", "$"] +[544.466982, "o", "k"] +[544.572664, "o", "e"] +[544.632867, "o", "r"] +[544.722191, "o", "n"] +[544.773134, "o", "e"] +[544.907561, "o", "l"] +[545.179853, "o", "_"] +[545.326522, "o", "c"] +[545.386052, "o", "o"] +[545.50024, "o", "d"] +[545.567089, "o", "e"] +[545.90589, "o", ">"] +[546.035073, "o", ">"] +[546.773187, "o", "4"] +[546.97104, "o", "5"] +[547.369708, "o", ")"] +[547.761588, "o", "\b\b\b"] +[548.152916, "o", "\b\b\b\b\b\b"] +[548.498199, "o", "\b\b\b\b\b\b\b"] +[549.243467, "o", "\b"] +[549.640345, "o", "($kernel_code>>45)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"] +[550.024338, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[550.898538, "o", "&"] +[551.862487, "o", "3"] +[552.10327, "o", "\r\n"] +[552.103562, "o", "$10 = 0x0\r\n(gdb) "] +[554.033804, "o", "#"] +[554.232669, "o", " "] +[554.419128, "o", "k"] +[554.519684, "o", "e"] +[555.554111, "o", "r"] +[556.306276, "o", "n"] +[556.564753, "o", "e"] +[556.649777, "o", "l"] +[556.812466, "o", " "] +[557.304025, "o", "p"] +[557.473156, "o", "r"] +[557.570501, "o", "i"] +[557.787916, "o", "v"] +[557.846584, "o", "i"] +[558.020526, "o", "l"] +[558.087162, "o", "e"] +[558.286556, "o", "g"] +[558.375973, "o", "e"] +[559.006899, "o", "\b\u001b[K"] +[559.154619, "o", "\b\u001b[K"] +[559.862659, "o", "e"] +[560.565269, "o", "\r\n"] +[560.565382, "o", "(gdb) "] +[566.281427, "o", "#"] +[566.60638, "o", " "] +[566.88704, "o", "n"] +[566.979938, "o", "o"] +[567.097734, "o", "w"] +[567.217521, "o", " "] +[567.40312, "o", "l"] +[567.48597, "o", "e"] +[567.691523, "o", "t"] +[567.944728, "o", "s"] +[568.133886, "o", " "] +[568.530377, "o", "d"] +[568.722282, "o", " "] +[569.182034, "o", "\b\u001b[K"] +[569.330181, "o", "o"] +[569.464696, "o", " "] +[569.582842, "o", "t"] +[569.71244, "o", "h"] +[569.775485, "o", "e"] +[569.904672, "o", " "] +[570.06808, "o", "s"] +[570.113381, "o", "a"] +[570.267076, "o", "m"] +[570.401127, "o", "e"] +[570.54668, "o", " "] +[571.537724, "o", "f"] +[571.657201, "o", "o"] +[571.830889, "o", "r"] +[571.931437, "o", " "] +[573.275644, "o", "u"] +[573.370696, "o", "s"] +[573.478114, "o", "e"] +[573.547114, "o", "r"] +[573.753181, "o", "s"] +[573.888213, "o", "p"] +[573.935344, "o", "a"] +[574.131183, "o", "c"] +[574.286447, "o", "e"] +[575.340632, "o", "\r\n"] +[575.340777, "o", "(gdb) "] +[575.738126, "o", "#"] +[575.938845, "o", " "] +[576.16047, "o", "f"] +[576.290807, "o", "i"] +[576.374712, "o", "r"] +[576.561113, "o", "s"] +[576.696249, "o", "t"] +[576.792918, "o", " "] +[581.320765, "o", "s"] +[581.435293, "o", "e"] +[581.551576, "o", "t"] +[581.69328, "o", "u"] +[581.77331, "o", "p"] +[582.019538, "o", " "] +[582.184776, "o", "a"] +[582.341777, "o", " "] +[582.940185, "o", "p"] +[583.323301, "o", "r"] +[583.369325, "o", "e"] +[583.536369, "o", "n"] +[584.034225, "o", "\b\u001b[K"] +[584.16717, "o", "\b\u001b[K"] +[584.29082, "o", "\b\u001b[K"] +[584.411253, "o", "\b\u001b[K"] +[584.683076, "o", "b"] +[584.765623, "o", "r"] +[584.845741, "o", "e"] +[584.922373, "o", "a"] +[584.981172, "o", "k"] +[585.213372, "o", "p"] +[585.312638, "o", "o"] +[585.50566, "o", "i"] +[585.538534, "o", "n"] +[585.679473, "o", "t"] +[585.76966, "o", " "] +[586.004301, "o", "t"] +[586.134879, "o", "o"] +[586.349202, "o", " "] +[586.655069, "o", "a"] +[586.776202, "o", " "] +[586.989063, "o", "s"] +[587.158287, "o", "y"] +[587.231328, "o", "s"] +[587.430585, "o", "t"] +[587.481228, "o", "e"] +[587.580052, "o", "m"] +[587.651081, "o", " "] +[588.604948, "o", "\b\u001b[K"] +[589.104855, "o", "\b\u001b[K"] +[589.135382, "o", "\b\u001b[K"] +[589.165688, "o", "\b\u001b[K"] +[589.197272, "o", "\b\u001b[K"] +[589.227213, "o", "\b\u001b[K"] +[589.258689, "o", "\b\u001b[K"] +[589.289664, "o", "\b\u001b[K"] +[589.318764, "o", "\b\u001b[K"] +[589.348938, "o", "\b\u001b[K"] +[589.844186, "o", " "] +[589.954736, "o", "t"] +[590.043756, "o", "h"] +[590.136384, "o", "e"] +[590.207131, "o", " "] +[590.312478, "o", "s"] +[590.426546, "o", "y"] +[590.468176, "o", "s"] +[590.614861, "o", "t"] +[590.700094, "o", "e"] +[591.025033, "o", "l"] +[592.076639, "o", "\b\u001b[K"] +[592.265751, "o", "m"] +[592.354996, "o", " "] +[592.477158, "o", "c"] +[592.527122, "o", "a"] +[592.591157, "o", "l"] +[592.688401, "o", "l"] +[592.749225, "o", " "] +[592.888391, "o", "e"] +[592.997816, "o", "n"] +[593.106259, "o", "t"] +[593.286703, "o", "r"] +[593.354202, "o", "y"] +[593.592532, "o", "\r\n"] +[593.592811, "o", "(gdb) "] +[594.298864, "o", "b"] +[594.370713, "o", "r"] +[594.483049, "o", "e"] +[594.563026, "o", "a"] +[594.63206, "o", "k"] +[594.734457, "o", " "] +[595.876785, "o", "e"] +[595.974998, "o", "n"] +[596.08727, "o", "t"] +[596.265929, "o", "r"] +[596.355891, "o", "y"] +[596.67381, "o", "_"] +[601.569523, "o", "\u0007"] +[601.660172, "o", "\r\nentry_32.S entry_SYSENTER_32 entry_number \r\nentry_INT80_32 entry_eip entry_stack_page \r\n(gdb) break entry_S"] +[603.152017, "o", "\b\u001b[K"] +[603.60971, "o", "I"] +[603.858406, "o", "N"] +[604.204372, "o", "T80_32 "] +[605.312061, "o", "\r\n"] +[605.363107, "o", "Breakpoint 1 at \u001b[34m0xc15de874\u001b[m: file \u001b[32march/x86/entry/entry_32.S\u001b[m, line 1020.\r\n"] +[605.363155, "o", "(gdb) "] +[606.887754, "o", "c"] +[608.705129, "o", "\r\n"] +[608.705459, "o", "Continuing.\r\n"] +[610.971565, "o", "\r\n"] +[610.971946, "o", "Breakpoint 1, \u001b[34m0xc15de874\u001b[m in \u001b[33mentry_INT80_32\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:1020\r\n"] +[610.972302, "o", "1020\t\tjmp\t.Lsysenter_flags_fixed\r\n"] +[610.972535, "o", "(gdb) "] +[616.192863, "o", "n"] +[617.72471, "o", "\r\n"] +[617.734068, "o", "1054\t\tpushl\t%eax\t\t\t/* pt_regs->orig_ax */\r\n"] +[617.734278, "o", "(gdb) "] +[619.7212, "o", "#"] +[619.906381, "o", " "] +[620.188614, "o", "s"] +[620.422791, "o", "t"] +[620.477236, "o", "e"] +[620.659615, "o", "p"] +[621.259597, "o", " "] +[621.492054, "o", "t"] +[621.59708, "o", "h"] +[621.685757, "o", "r"] +[621.736727, "o", "o"] +[621.981907, "o", "u"] +[622.322864, "o", "\b\u001b[K"] +[622.460272, "o", "\b\u001b[K"] +[622.594567, "o", "\b\u001b[K"] +[622.718254, "o", "\b\u001b[K"] +[622.947025, "o", "r"] +[623.072527, "o", "o"] +[623.203739, "o", "u"] +[623.609466, "o", "\b\u001b[K"] +[623.751747, "o", "\b\u001b[K"] +[623.853592, "o", "\b\u001b[K"] +[624.129617, "o", "h"] +[624.399671, "o", "r"] +[624.477659, "o", "o"] +[624.624296, "o", "u"] +[624.734072, "o", "g"] +[624.834819, "o", "h"] +[624.960495, "o", " "] +[625.036927, "o", "t"] +[625.128099, "o", "h"] +[625.206121, "o", "e"] +[625.324744, "o", " "] +[625.524612, "o", "s"] +[625.726291, "o", "y"] +[625.819857, "o", "s"] +[625.995635, "o", "t"] +[626.050073, "o", "e"] +[626.118718, "o", "m"] +[626.245506, "o", " "] +[626.448433, "o", "c"] +[626.490398, "o", "a"] +[626.60857, "o", "l"] +[626.748098, "o", "l"] +[626.867184, "o", " "] +[627.249677, "o", "u"] +[627.324825, "o", "n"] +[627.753751, "o", "t"] +[627.862279, "o", "i"] +[627.950531, "o", "l"] +[628.071181, "o", " "] +[628.193645, "o", "t"] +[628.325551, "o", "h"] +[628.396454, "o", "e"] +[628.50338, "o", " "] +[628.954182, "o", "e"] +[629.072892, "o", "n"] +[629.169954, "o", "d"] +[629.907936, "o", "\r\n"] +[629.90828, "o", "(gdb) "] +[632.365504, "o", "d"] +[632.443146, "o", "e"] +[632.536882, "o", "l"] +[632.664697, "o", " "] +[632.875456, "o", "b"] +[633.037126, "o", "e"] +[633.128086, "o", "a"] +[633.208296, "o", "k"] +[633.771397, "o", "\b\u001b[K"] +[633.909143, "o", "\b\u001b[K"] +[634.023021, "o", "\b\u001b[K"] +[634.081351, "o", "r"] +[634.166271, "o", "e"] +[634.258451, "o", "a"] +[634.315484, "o", "k"] +[637.580479, "o", "\r\n"] +[637.580605, "o", "Delete all breakpoints? (y or n) "] +[638.161286, "o", "y"] +[638.358828, "o", "\r\n"] +[638.359126, "o", "(gdb) "] +[638.816338, "o", "n"] +[639.01657, "o", "\r\n"] +[639.02752, "o", "\u001b[33mentry_INT80_32\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:1056\r\n1056\t\tSAVE_ALL pt_regs_ax=$-ENOSYS switch_stacks=1\t/* save rest */\r\n"] +[639.027905, "o", "(gdb) "] +[639.989246, "o", "\r\n"] +[640.089993, "o", "\u001b[33mentry_INT80_32\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:1058\r\n1058\t\tmovl\t%esp, %eax\r\n(gdb) "] +[640.575852, "o", "\r\n"] +[640.584316, "o", "1059\t\tcall\tdo_int80_syscall_32\r\n"] +[640.584404, "o", "(gdb) "] +[641.020396, "o", "\r\n"] +[641.043758, "o", "1064\t\tSWITCH_TO_ENTRY_STACK\r\n"] +[641.043903, "o", "(gdb) "] +[642.078973, "o", "\r\n"] +[642.131705, "o", "\u001b[33mentry_INT80_32\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:1065\r\n1065\t\tCHECK_AND_APPLY_ESPFIX\r\n(gdb) "] +[643.550621, "o", "\r\n"] +[643.569874, "o", "1068\t\tSWITCH_TO_USER_CR3 scratch_reg=%eax\r\n(gdb) "] +[645.089643, "o", "\r\n"] +[645.097692, "o", "1073\t\tRESTORE_REGS pop=4\t\t\t# skip orig_eax/error_code\r\n"] +[645.09795, "o", "(gdb) "] +[646.112248, "o", "\r\n"] +[646.177685, "o", "\u001b[33mentry_INT80_32\u001b[m () at \u001b[32march/x86/entry/entry_32.S\u001b[m:1080\r\n1080\t\tINTERRUPT_RETURN\r\n"] +[646.177724, "o", "(gdb) "] +[650.665768, "o", "\r\n"] +[650.685116, "o", "\u001b[34m0x448d167d\u001b[m in \u001b[33m??\u001b[m ()\r\n"] +[650.686558, "o", "(gdb) "] +[655.046392, "o", "#"] +[655.210079, "o", " "] +[655.404159, "o", "t"] +[655.481148, "o", "h"] +[655.531965, "o", "i"] +[655.669289, "o", "s"] +[655.756962, "o", " "] +[656.023425, "o", "l"] +[656.230497, "o", "o"] +[656.350096, "o", "o"] +[656.430194, "o", "k"] +[656.543202, "o", "s"] +[656.614577, "o", " "] +[656.747584, "o", "l"] +[656.90921, "o", "i"] +[657.044202, "o", "k"] +[657.15373, "o", "e"] +[657.207156, "o", " "] +[657.321091, "o", "a"] +[657.405793, "o", " "] +[657.735833, "o", "u"] +[657.828575, "o", "s"] +[657.933278, "o", "e"] +[658.002691, "o", "r"] +[658.288285, "o", " "] +[658.450784, "o", "s"] +[658.550787, "o", "p"] +[658.610481, "o", "a"] +[658.76577, "o", "c"] +[658.84823, "o", "e"] +[658.919578, "o", " "] +[658.996235, "o", "a"] +[659.117812, "o", "d"] +[659.253844, "o", "d"] +[659.433193, "o", "r"] +[659.48534, "o", "e"] +[659.60751, "o", "s"] +[659.754908, "o", "s"] +[659.888093, "o", ","] +[659.977163, "o", " "] +[660.161783, "o", "l"] +[660.22061, "o", "e"] +[660.384788, "o", "t"] +[660.593814, "o", "s"] +[660.725078, "o", " "] +[661.244123, "o", "c"] +[661.390876, "o", "h"] +[661.490006, "o", "e"] +[661.556587, "o", "c"] +[661.641873, "o", "k"] +[661.806617, "o", " "] +[662.017518, "o", "t"] +[662.09433, "o", "h"] +[662.20504, "o", "e"] +[662.271583, "o", " "] +[662.406577, "o", "c"] +[662.496568, "o", "o"] +[662.695698, "o", "d"] +[663.60129, "o", "e"] +[663.748373, "o", " "] +[663.955006, "o", "s"] +[664.114279, "o", "e"] +[664.25419, "o", "l"] +[664.303753, "o", "e"] +[664.381874, "o", "c"] +[664.587642, "o", "t"] +[664.674974, "o", "o"] +[664.749721, "o", "r"] +[665.224982, "o", "\r\n"] +[665.225096, "o", "(gdb) "] +[665.695276, "o", "p"] +[665.792372, "o", "r"] +[665.897882, "o", "i"] +[665.94532, "o", "n"] +[666.023454, "o", "t"] +[666.0908, "o", " "] +[666.432583, "o", "x"] +[666.832639, "o", "\b\u001b[K"] +[667.03479, "o", "/"] +[667.144708, "o", "x"] +[667.249841, "o", " "] +[667.530074, "o", "$"] +[667.849312, "o", "c"] +[667.93295, "o", "s"] +[668.402085, "o", "\r\n"] +[668.403271, "o", "$11 = 0x73\r\n"] +[668.404009, "o", "(gdb) "] +[672.252423, "o", "#"] +[673.194564, "o", " "] +[673.675156, "o", "t"] +[673.760362, "o", "h"] +[673.882635, "o", "e"] +[673.994028, "o", " "] +[674.513812, "o", "p"] +[674.706893, "o", "r"] +[674.804439, "o", "i"] +[674.94746, "o", "v"] +[675.010894, "o", "i"] +[675.188625, "o", "l"] +[675.265228, "o", "e"] +[675.511041, "o", "g"] +[675.587286, "o", "e"] +[675.739396, "o", " "] +[675.935171, "o", "l"] +[676.005954, "o", "e"] +[676.202384, "o", "v"] +[676.294477, "o", "e"] +[676.354083, "o", "l"] +[676.485263, "o", " "] +[676.602646, "o", "i"] +[676.704354, "o", "s"] +[676.784185, "o", " "] +[676.981088, "o", "3"] +[677.195168, "o", ","] +[677.326062, "o", " "] +[677.604308, "o", "s"] +[677.666906, "o", "o"] +[677.785998, "o", " "] +[678.506076, "o", "i"] +[678.655711, "o", "n"] +[678.780883, "o", "e"] +[678.940158, "o", "e"] +[679.044873, "o", "d"] +[679.222637, "o", " "] +[679.56275, "o", "\b\u001b[K"] +[679.698968, "o", "\b\u001b[K"] +[679.830282, "o", "\b\u001b[K"] +[679.983681, "o", "\b\u001b[K"] +[680.311095, "o", "d"] +[680.410929, "o", "e"] +[680.580716, "o", "e"] +[680.692035, "o", "d"] +[680.797568, "o", " "] +[680.979638, "o", "w"] +[681.042251, "o", "e"] +[681.132403, "o", " "] +[681.247785, "o", "a"] +[681.393117, "o", "r"] +[681.475054, "o", "e"] +[681.54512, "o", " "] +[682.162527, "o", "i"] +[682.280131, "o", "n"] +[682.527043, "o", "u"] +[682.867049, "o", "\b\u001b[K"] +[682.971752, "o", " "] +[683.475284, "o", "\b\u001b[K"] +[683.616692, "o", "\b\u001b[K"] +[683.74114, "o", "\b\u001b[K"] +[683.998681, "o", "r"] +[684.057732, "o", "u"] +[684.122526, "o", "n"] +[684.271564, "o", "i"] +[684.326317, "o", "n"] +[684.689606, "o", "\b\u001b[K"] +[684.828735, "o", "\b\u001b[K"] +[685.172894, "o", "n"] +[685.301489, "o", "i"] +[685.385224, "o", "n"] +[685.524585, "o", "g"] +[685.652293, "o", " "] +[685.800678, "o", "i"] +[685.887831, "o", "n"] +[685.944332, "o", " "] +[686.069441, "o", "u"] +[686.162036, "o", "s"] +[686.243565, "o", "e"] +[686.317807, "o", "r"] +[686.376218, "o", " "] +[686.540215, "o", "m"] +[686.598979, "o", "o"] +[686.625005, "o", "d"] +[686.723705, "o", "e"] +[686.778902, "o", "\r\n"] +[686.779014, "o", "(gdb) "] +[692.53241, "o", "#"] +[692.721453, "o", " "] +[692.892056, "o", "l"] +[693.024663, "o", "e"] +[693.193954, "o", "t"] +[693.371269, "o", "s"] +[693.597078, "o", "g"] +[693.885546, "o", "\b\u001b[K"] +[693.978727, "o", " "] +[694.049596, "o", "g"] +[694.108902, "o", "e"] +[694.247468, "o", "t"] +[694.345634, "o", " "] +[694.511566, "o", "t"] +[694.587774, "o", "h"] +[694.6909, "o", "e"] +[694.771112, "o", " "] +[694.863811, "o", "s"] +[694.977826, "o", "e"] +[695.074086, "o", "l"] +[695.155131, "o", "e"] +[695.229863, "o", "c"] +[695.442999, "o", "t"] +[695.821135, "o", "o"] +[695.950336, "o", "r"] +[696.053426, "o", "\r\n"] +[696.053731, "o", "(gdb) "] +[696.74081, "o", "p"] +[696.882904, "o", "r"] +[696.95492, "o", "i"] +[697.03238, "o", "n"] +[697.104735, "o", "t"] +[697.202097, "o", " "] +[697.420614, "o", "."] +[697.660736, "o", "x"] +[698.088723, "o", "\b\u001b[K"] +[698.214544, "o", "\b\u001b[K"] +[698.416446, "o", "/"] +[698.57942, "o", "x"] +[698.684619, "o", " "] +[699.479828, "o", "$"] +[699.980736, "o", "c"] +[700.065109, "o", "s"] +[700.396996, "o", ">"] +[700.526326, "o", ">"] +[700.713679, "o", "3"] +[700.79379, "o", "2"] +[701.128706, "o", "\b\u001b[K"] +[701.345675, "o", "\b\u001b[K"] +[701.604745, "o", "3"] +[702.59867, "o", "\r\n"] +[702.599922, "o", "$12 = 0xe\r\n"] +[702.600842, "o", "(gdb) "] +[705.06673, "o", "\u0007"] +[705.324321, "o", "print /x $cs>>3"] +[705.503241, "o", "\b"] +[706.003691, "o", "\b"] +[706.034303, "o", "\b"] +[706.064471, "o", "\b"] +[706.095291, "o", "\b"] +[706.125113, "o", "\b"] +[706.155725, "o", "\b"] +[706.523474, "o", "\u001b[C"] +[706.779876, "o", "\b\u001b[1P$cs>>3\b\b\b\b\b\b"] +[706.91489, "o", "\b\u001b[1P$cs>>3\b\b\b\b\b\b"] +[707.042101, "o", "\b\u001b[1P$cs>>3\b\b\b\b\b\b"] +[707.262476, "o", "\r\n"] +[707.263867, "o", "$13 = 14\r\n"] +[707.264707, "o", "(gdb) "] +[718.972351, "o", "s"] +[719.055223, "o", "e"] +[719.204699, "o", "t"] +[719.38757, "o", " "] +[719.750857, "o", "$"] +[721.845151, "o", "u"] +[721.971635, "o", "s"] +[722.053169, "o", "e"] +[722.146473, "o", "r"] +[722.392609, "o", "_"] +[729.373498, "o", "c"] +[729.521886, "o", "o"] +[729.630095, "o", "d"] +[729.712985, "o", "e"] +[730.34708, "o", "="] +[742.363689, "o", "((uint64_t*)$gdtr)["] +[743.594954, "o", "1"] +[744.208712, "o", "4"] +[745.162637, "o", "]"] +[746.699323, "o", "\r\n"] +[746.707477, "o", "(gdb) "] +[747.302209, "o", "p"] +[747.409252, "o", "r"] +[747.545136, "o", "i"] +[747.603175, "o", "n"] +[747.629656, "o", "t"] +[747.765806, "o", " "] +[747.957777, "o", "/"] +[748.073233, "o", "z"] +[748.193756, "o", " "] +[748.536198, "o", "$"] +[748.849674, "o", "u"] +[748.981324, "o", "s"] +[749.09022, "o", "e"] +[749.141073, "o", "r"] +[749.742629, "o", "_"] +[750.000935, "o", "c"] +[750.098552, "o", "o"] +[750.20873, "o", "d"] +[750.312852, "o", "e"] +[750.456634, "o", "\r\n"] +[750.457831, "o", "$14 = 0x00cffa000000ffff\r\n"] +[750.458525, "o", "(gdb) "] +[760.922271, "o", "#"] +[761.152125, "o", " "] +[761.321912, "o", "l"] +[761.483755, "o", "e"] +[761.677907, "o", "t"] +[761.977657, "o", "s"] +[762.451478, "o", " "] +[763.858006, "o", "p"] +[764.048606, "o", "r"] +[764.12853, "o", "i"] +[764.205234, "o", "n"] +[764.281491, "o", "t"] +[764.423725, "o", " "] +[764.529463, "o", "t"] +[764.642091, "o", "h"] +[764.76313, "o", "e"] +[764.906969, "o", " "] +[766.022913, "o", "b"] +[766.141544, "o", "a"] +[766.245647, "o", "s"] +[766.449316, "o", "e"] +[768.319525, "o", "\r\n"] +[768.319645, "o", "(gdb) "] +[809.07354, "o", "print /x (($user_code>>32)&0xFF000000)|(($kernel_code>>16)&0x00FFFFFF)\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[809.256141, "o", "\u001b[C"] +[809.75659, "o", "\u001b[C"] +[809.786818, "o", "\u001b[C"] +[809.817626, "o", "\u001b[C"] +[809.848195, "o", "\u001b[C"] +[809.878997, "o", "\u001b[C"] +[809.909101, "o", "\u001b[C"] +[809.940364, "o", "\u001b[C"] +[809.970702, "o", "\u001b[C"] +[810.001365, "o", "\u001b[C"] +[810.031559, "o", "\u001b[C"] +[810.062018, "o", "\u001b[C"] +[810.093057, "o", "\u001b[C"] +[810.123449, "o", "\u001b[C"] +[810.153727, "o", "\u001b[C"] +[810.184235, "o", "\u001b[C"] +[810.214952, "o", "\u001b[C"] +[810.246219, "o", "\u001b[C"] +[810.276599, "o", "\u001b[C"] +[810.306915, "o", "\u001b[C"] +[810.336951, "o", "\u001b[C"] +[810.367283, "o", "\u001b[C"] +[810.397779, "o", "\u001b[C"] +[810.428429, "o", "\u001b[C"] +[810.458566, "o", "\u001b[C"] +[810.488834, "o", "\u001b[C"] +[810.519269, "o", "\u001b[C"] +[810.549961, "o", "\u001b[C"] +[810.580356, "o", "\u001b[C"] +[810.611188, "o", "\u001b[C"] +[810.641482, "o", "\u001b[C"] +[810.671188, "o", "\u001b[C"] +[810.702462, "o", "\u001b[C"] +[810.975545, "o", "\b"] +[811.264615, "o", "\b\u001b[1P_code>>16)&0x00FFFFFF)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"] +[811.40386, "o", "\b\u001b[1P_code>>16)&0x00FFFFFF)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"] +[811.523682, "o", "\b\u001b[1P_code>>16)&0x00FFFFFF)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"] +[811.647806, "o", "\b\u001b[1P_code>>16)&0x00FFFFFF)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"] +[811.784493, "o", "\b\u001b[1P_code>>16)&0x00FFFFFF)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"] +[811.945961, "o", "\b\u001b[1P_code>>16)&0x00FFFFFF)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"] +[812.551148, "o", "u_code>>16)&0x00FFFFFF)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"] +[812.666049, "o", "s_code>>16)&0x00FFFFFF)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"] +[812.733865, "o", "e_code>>16)&0x00FFFFFF)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"] +[812.804219, "o", "r_code>>16)&0x00FFFFFF)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"] +[813.471435, "o", "\r\n"] +[813.472787, "o", "$15 = 0x0\r\n"] +[813.473756, "o", "(gdb) "] +[815.049124, "o", "#"] +[815.227758, "o", " "] +[816.113222, "o", "a"] +[816.244562, "o", "n"] +[816.316434, "o", "d"] +[816.425143, "o", " "] +[816.637818, "o", "t"] +[816.711367, "o", "h"] +[816.826612, "o", "e"] +[816.890874, "o", " "] +[817.064052, "o", "l"] +[817.240246, "o", "i"] +[817.356865, "o", "m"] +[817.432586, "o", "i"] +[817.56418, "o", "t"] +[818.009451, "o", "\r\n"] +[818.009561, "o", "(gdb) "] +[818.432237, "o", "p"] +[818.564952, "o", "r"] +[818.698167, "o", "i"] +[818.724308, "o", "n"] +[818.826911, "o", "t"] +[818.919965, "o", " "] +[819.207993, "o", "/"] +[819.381762, "o", "x"] +[819.508217, "o", " "] +[820.316542, "o", "$"] +[820.975916, "o", "u"] +[821.115032, "o", "s"] +[821.207129, "o", "e"] +[821.270953, "o", "r"] +[821.414288, "o", "_"] +[821.602876, "o", "c"] +[821.687005, "o", "o"] +[821.816962, "o", "d"] +[821.884079, "o", "e"] +[823.356186, "o", "&"] +[824.379479, "o", "0"] +[824.519435, "o", "x"] +[825.853806, "o", "f"] +[826.065333, "o", "f"] +[826.251408, "o", "f"] +[826.528401, "o", "f"] +[827.075458, "o", ")"] +[827.392703, "o", "\b"] +[827.893571, "o", "\b"] +[827.923588, "o", "\b"] +[827.953933, "o", "\b"] +[827.984307, "o", "\b"] +[828.014987, "o", "\b"] +[828.046374, "o", "\b"] +[828.076921, "o", "\b"] +[828.10759, "o", "\b"] +[828.137907, "o", "\b"] +[828.1682, "o", "\b"] +[828.198418, "o", "\b"] +[828.229355, "o", "\b"] +[828.259187, "o", "\b"] +[828.289623, "o", "\b"] +[828.320693, "o", "\b"] +[828.35114, "o", "\b"] +[828.382249, "o", "\b"] +[829.085558, "o", "($user_code&0xffff)\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[829.708728, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[830.400685, "o", "*"] +[830.93294, "o", "4"] +[831.02888, "o", "0"] +[831.20694, "o", "9"] +[831.583008, "o", "5"] +[832.196999, "o", "\b\u001b[K"] +[832.544697, "o", "6"] +[833.211351, "o", "\r\n"] +[833.21263, "o", "$16 = 0xffff000\r\n"] +[833.213594, "o", "(gdb) "] +[836.747221, "o", "#"] +[836.966915, "o", " "] +[837.122971, "o", "l"] +[837.264712, "o", "i"] +[837.415757, "o", "k"] +[837.487956, "o", "e"] +[837.582304, "o", " "] +[837.796811, "o", "b"] +[837.86537, "o", "e"] +[838.009048, "o", "f"] +[838.13558, "o", "o"] +[838.276445, "o", "r"] +[838.322393, "o", "e"] +[838.696696, "o", ","] +[838.845816, "o", " "] +[839.780549, "o", "b"] +[839.849384, "o", "a"] +[839.927552, "o", "s"] +[840.041133, "o", "e"] +[840.157198, "o", " "] +[840.376833, "o", "="] +[840.582513, "o", " "] +[840.751071, "o", "0"] +[840.957989, "o", " "] +[841.359805, "o", "\b\u001b[K"] +[841.654447, "o", " "] +[842.09277, "o", "\b\u001b[K"] +[842.473777, "o", ","] +[842.5702, "o", " "] +[842.730569, "o", "l"] +[842.881001, "o", "i"] +[843.046392, "o", "m"] +[843.149457, "o", "i"] +[843.28806, "o", "t"] +[843.603712, "o", "="] +[844.085459, "o", "4"] +[844.905693, "o", "G"] +[845.388067, "o", "\r\n(gdb) "] +[846.021339, "o", "#"] +[846.1873, "o", " "] +[846.362737, "o", "f"] +[846.424606, "o", "i"] +[846.539695, "o", "n"] +[847.063757, "o", "a"] +[847.427324, "o", "l"] +[847.539554, "o", "l"] +[847.791174, "o", "y"] +[847.863453, "o", " "] +[848.073511, "o", "l"] +[848.146045, "o", "e"] +[848.331511, "o", "t"] +[848.502747, "o", "s"] +[848.612159, "o", " "] +[848.811446, "o", "p"] +[849.033555, "o", "i"] +[849.47643, "o", "\b\u001b[K"] +[849.592317, "o", "r"] +[849.689119, "o", "i"] +[849.750955, "o", "n"] +[849.865499, "o", " "] +[849.912217, "o", "t"] +[850.068171, "o", "h"] +[850.185347, "o", "t"] +[850.663395, "o", "e"] +[850.892227, "o", "\b\u001b[K"] +[851.01506, "o", "\b\u001b[K"] +[851.090625, "o", "e"] +[851.184358, "o", " "] +[852.40202, "o", "p"] +[852.541371, "o", "r"] +[852.627033, "o", "i"] +[852.852467, "o", "v"] +[853.112142, "o", "\b\u001b[K"] +[853.234241, "o", "\b\u001b[K"] +[853.353082, "o", "\b\u001b[K"] +[853.454046, "o", "r"] +[853.673116, "o", "\b\u001b[K"] +[853.791573, "o", "\b\u001b[K"] +[853.958148, "o", "r"] +[854.049767, "o", "e"] +[854.151012, "o", "q"] +[854.43396, "o", "u"] +[854.480219, "o", "i"] +[854.525939, "o", "r"] +[854.602678, "o", "e"] +[854.764555, "o", "d"] +[854.917843, "o", " "] +[855.307316, "o", "p"] +[855.579807, "o", "r"] +[855.701494, "o", "i"] +[855.941647, "o", "v"] +[856.022055, "o", "i"] +[856.206419, "o", "l"] +[856.294774, "o", "e"] +[856.534217, "o", "g"] +[856.613545, "o", "e"] +[856.970087, "o", "\r\n"] +[856.970197, "o", "(gdb) "] +[858.880707, "o", "p"] +[859.008756, "o", "r"] +[859.084916, "o", "i"] +[859.148296, "o", "n"] +[859.194996, "o", "t"] +[859.279003, "o", " "] +[859.509048, "o", "/"] +[859.653839, "o", "x"] +[859.789865, "o", " "] +[860.019894, "o", "$"] +[861.401365, "o", "u"] +[861.442956, "o", "s"] +[861.564205, "o", "e"] +[861.621157, "o", "r"] +[861.743186, "o", "_"] +[861.895258, "o", "c"] +[862.01297, "o", "o"] +[862.137427, "o", "d"] +[862.21639, "o", "e"] +[862.540725, "o", ">"] +[862.850378, "o", ">"] +[864.616721, "o", "4"] +[864.804028, "o", "5"] +[865.120143, "o", ")"] +[865.47208, "o", "\b"] +[865.9722, "o", "\b"] +[866.002112, "o", "\b"] +[866.032795, "o", "\b"] +[866.063313, "o", "\b"] +[866.093033, "o", "\b"] +[866.123273, "o", "\b"] +[866.153238, "o", "\b"] +[866.183841, "o", "\b"] +[866.214712, "o", "\b"] +[866.245027, "o", "\b"] +[866.275735, "o", "\b"] +[866.306467, "o", "\b"] +[866.569002, "o", "\b"] +[866.786537, "o", "\b"] +[867.202622, "o", "($user_code>>45)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"] +[867.699393, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[868.510852, "o", "&"] +[869.114958, "o", "3"] +[869.282934, "o", "\r\n"] +[869.284128, "o", "$17 = 0x3\r\n"] +[869.28494, "o", "(gdb) "] +[870.908449, "o", "#"] +[871.210682, "o", " "] +[872.957141, "o", "a"] +[873.042207, "o", "s"] +[873.160801, "o", " "] +[873.311215, "o", "e"] +[873.710163, "o", "x"] +[873.882767, "o", "p"] +[873.963709, "o", "e"] +[874.171292, "o", "c"] +[874.382806, "o", "t"] +[874.467515, "o", "e"] +[874.657769, "o", "d"] +[874.790228, "o", ","] +[874.907512, "o", " "] +[875.097689, "o", "p"] +[875.201934, "o", "r"] +[875.282314, "o", "i"] +[875.630355, "o", "v"] +[875.863496, "o", "i"] +[876.094037, "o", "l"] +[876.277817, "o", "e"] +[876.501288, "o", "g"] +[876.578121, "o", "e"] +[876.773456, "o", " "] +[876.998859, "o", "3"] +[877.119419, "o", " "] +[877.673306, "o", "="] +[877.818837, "o", " "] +[878.24644, "o", "u"] +[878.372011, "o", "s"] +[878.430652, "o", "e"] +[878.495114, "o", "r"] +[878.622827, "o", " "] +[879.099481, "o", "o"] +[879.154198, "o", "d"] +[879.223305, "o", "e"] +[879.476677, "o", "\b\u001b[K"] +[879.606628, "o", "\b\u001b[K"] +[879.778496, "o", "\b\u001b[K"] +[880.000743, "o", "m"] +[880.050628, "o", "o"] +[880.127009, "o", "d"] +[880.191324, "o", "e"] +[880.418045, "o", "\r\n"] +[880.418349, "o", "(gdb) "] diff --git a/refs/pull/405/merge/_images/skb.png b/refs/pull/405/merge/_images/skb.png new file mode 100644 index 00000000..db956dc1 Binary files /dev/null and b/refs/pull/405/merge/_images/skb.png differ diff --git a/refs/pull/405/merge/_images/skb1.png b/refs/pull/405/merge/_images/skb1.png new file mode 100644 index 00000000..db956dc1 Binary files /dev/null and b/refs/pull/405/merge/_images/skb1.png differ diff --git a/refs/pull/405/merge/_images/slab-coloring.png b/refs/pull/405/merge/_images/slab-coloring.png new file mode 100644 index 00000000..1391ce55 Binary files /dev/null and b/refs/pull/405/merge/_images/slab-coloring.png differ diff --git a/refs/pull/405/merge/_images/slab-coloring1.png b/refs/pull/405/merge/_images/slab-coloring1.png new file mode 100644 index 00000000..1391ce55 Binary files /dev/null and b/refs/pull/405/merge/_images/slab-coloring1.png differ diff --git a/refs/pull/405/merge/_images/slab-detailed-arch.png b/refs/pull/405/merge/_images/slab-detailed-arch.png new file mode 100644 index 00000000..77a0cc81 Binary files /dev/null and b/refs/pull/405/merge/_images/slab-detailed-arch.png differ diff --git a/refs/pull/405/merge/_images/slab-detailed-arch1.png b/refs/pull/405/merge/_images/slab-detailed-arch1.png new file mode 100644 index 00000000..77a0cc81 Binary files /dev/null and b/refs/pull/405/merge/_images/slab-detailed-arch1.png differ diff --git a/refs/pull/405/merge/_images/slab-object-descriptors.png b/refs/pull/405/merge/_images/slab-object-descriptors.png new file mode 100644 index 00000000..dbeab55b Binary files /dev/null and b/refs/pull/405/merge/_images/slab-object-descriptors.png differ diff --git a/refs/pull/405/merge/_images/slab-object-descriptors1.png b/refs/pull/405/merge/_images/slab-object-descriptors1.png new file mode 100644 index 00000000..dbeab55b Binary files /dev/null and b/refs/pull/405/merge/_images/slab-object-descriptors1.png differ diff --git a/refs/pull/405/merge/_images/slab-overview.png b/refs/pull/405/merge/_images/slab-overview.png new file mode 100644 index 00000000..90086d4b Binary files /dev/null and b/refs/pull/405/merge/_images/slab-overview.png differ diff --git a/refs/pull/405/merge/_images/slab-overview1.png b/refs/pull/405/merge/_images/slab-overview1.png new file mode 100644 index 00000000..90086d4b Binary files /dev/null and b/refs/pull/405/merge/_images/slab-overview1.png differ diff --git a/refs/pull/405/merge/_images/syscalls-inspection.cast b/refs/pull/405/merge/_images/syscalls-inspection.cast new file mode 100644 index 00000000..ca749a42 --- /dev/null +++ b/refs/pull/405/merge/_images/syscalls-inspection.cast @@ -0,0 +1,1389 @@ +{"title": "System Call Inspection", "height": 24, "idle_time_limit": 1.0, "version": 2, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}, "width": 80, "timestamp": 1519682642} +[0.02593, "o", "\u001b]0;tavi@lktp: ~/src/linux/tools/labs\u0007\u001b[01;32mtavi@lktp\u001b[00m:\u001b[01;34m~/src/linux/tools/labs\u001b[00m$ "] +[2.585046, "o", "#"] +[2.812131, "o", " "] +[2.94729, "o", "a"] +[3.187178, "o", "t"] +[3.308689, "o", "t"] +[3.380836, "o", "a"] +[3.587609, "o", "c"] +[3.660319, "o", "h"] +[3.74021, "o", " "] +[3.935004, "o", "g"] +[4.157892, "o", "d"] +[4.34303, "o", "b"] +[4.527084, "o", " "] +[4.711204, "o", "t"] +[4.768411, "o", "o"] +[4.85479, "o", " "] +[5.081524, "o", "V"] +[5.193867, "o", "M"] +[5.366551, "o", "\r\n"] +[5.367316, "o", "\u001b]0;tavi@lktp: ~/src/linux/tools/labs\u0007\u001b[01;32mtavi@lktp\u001b[00m:\u001b[01;34m~/src/linux/tools/labs\u001b[00m$ "] +[6.562559, "o", "m"] +[6.655394, "o", "a"] +[6.702303, "o", "k"] +[6.826912, "o", "e"] +[6.898232, "o", " "] +[7.081019, "o", "g"] +[7.184305, "o", "d"] +[7.250501, "o", "b"] +[7.464891, "o", "\r\n"] +[7.487695, "o", "gdb -ex \"target remote localhost:1234\" /home/tavi/src/linux/vmlinux\r\n"] +[7.552276, "o", "GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1\r\nCopyright (C) 2016 Free Software Foundation, Inc.\r\nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\r\nThis is free software: you are free to change and redistribute it.\r\nThere is NO WARRANTY, to the extent permitted by law. Type \"show copying\"\r\nand \"show warranty\" for details.\r\nThis GDB was configured as \"x86_64-linux-gnu\".\r\nType \"show configuration\" for configuration details.\r\nFor bug reporting instructions, please see:\r\n<http://www.gnu.org/software/gdb/bugs/>.\r\nFind the GDB manual and other documentation resources online at:\r\n<http://www.gnu.org/software/gdb/documentation/>.\r\nFor help, type \"help\".\r\nType \"apropos word\" to search for commands related to \"word\"...\r\n"] +[7.552711, "o", "Reading symbols from /home/tavi/src/linux/vmlinux..."] +[8.0237, "o", "done.\r\n"] +[8.040804, "o", "Remote debugging using localhost:1234\r\n"] +[8.049686, "o", "default_idle () at arch/x86/kernel/process.c:357\r\n"] +[8.049841, "o", "357\t}\r\n"] +[8.049944, "o", "(gdb) "] +[8.617598, "o", "b"] +[8.712276, "o", "t"] +[8.906112, "o", "\r\n"] +[8.907612, "o", "#0 default_idle () at arch/x86/kernel/process.c:357\r\n#1 0xc101fcfd in arch_cpu_idle () at arch/x86/kernel/process.c:346\r\n"] +[8.916461, "o", "#2 0xc14639f9 in default_idle_call () at kernel/sched/idle.c:98\r\n"] +[8.916818, "o", "#3 0xc107b2a5 in cpuidle_idle_call () at kernel/sched/idle.c:156\r\n#4 do_idle () at kernel/sched/idle.c:246\r\n"] +[8.923466, "o", "#5 0xc107b5b5 in cpu_startup_entry (state=<optimized out>)\r\n at kernel/sched/idle.c:351\r\n#6 0xc145d643 in rest_init () at init/main.c:436\r\n"] +[8.923757, "o", "#7 0xc1614acb in start_kernel () at init/main.c:716\r\n"] +[8.926458, "o", "#8 0xc161424a in i386_start_kernel () at arch/x86/kernel/head32.c:56\r\n"] +[8.926871, "o", "#9 0xc10001d3 in startup_32_smp () at arch/x86/kernel/head_32.S:363\r\n"] +[8.927813, "o", "#10 0x00000000 in ?? ()\r\n"] +[8.928515, "o", "(gdb) "] +[9.441926, "o", "#"] +[9.610515, "o", " "] +[10.164044, "o", "V"] +[10.268664, "o", "M"] +[10.453102, "o", " "] +[10.592012, "o", "i"] +[10.687218, "o", "s"] +[10.769038, "o", " "] +[10.88914, "o", "i"] +[11.031982, "o", "d"] +[11.171022, "o", "l"] +[11.339681, "o", "e"] +[11.541285, "o", "\r\n"] +[11.541408, "o", "(gdb) "] +[13.459643, "o", "#"] +[13.604705, "o", " "] +[13.787454, "o", "l"] +[13.867483, "o", "e"] +[14.028803, "o", "t"] +[14.196721, "o", "s"] +[14.299574, "o", " "] +[14.400587, "o", "a"] +[14.678709, "o", "t"] +[15.297907, "o", "\b\u001b[K"] +[15.474776, "o", "\b\u001b[K"] +[17.314512, "o", "a"] +[17.493688, "o", "d"] +[17.640039, "o", "d"] +[17.734576, "o", " "] +[17.836868, "o", "a"] +[17.94166, "o", " "] +[18.172955, "o", "b"] +[18.231003, "o", "r"] +[18.338597, "o", "e"] +[18.389443, "o", "a"] +[18.493356, "o", "k"] +[18.697004, "o", "p"] +[18.791969, "o", "o"] +[19.002137, "o", "i"] +[19.076693, "o", "n"] +[19.247079, "o", "t"] +[19.682963, "o", " "] +[19.920143, "o", "t"] +[20.019301, "o", "o"] +[20.13914, "o", " "] +[20.298365, "o", "a"] +[20.399756, "o", " "] +[20.543224, "o", "s"] +[20.654014, "o", "y"] +[20.722395, "o", "s"] +[20.875473, "o", "t"] +[20.949965, "o", "e"] +[21.03673, "o", "m"] +[21.105939, "o", " "] +[21.199805, "o", "c"] +[21.248673, "o", "a"] +[21.33164, "o", "l"] +[21.457598, "o", "l"] +[21.662139, "o", "\r\n"] +[21.662437, "o", "(gdb) "] +[23.558939, "o", "b"] +[23.610705, "o", "r"] +[23.671647, "o", "e"] +[23.830052, "o", "\u0007ak"] +[24.613391, "o", " "] +[25.766837, "o", "s"] +[25.878063, "o", "y"] +[25.959348, "o", "s"] +[26.26539, "o", "_"] +[26.884977, "o", "d"] +[26.936127, "o", "u"] +[27.021843, "o", "p"] +[27.318277, "o", "2"] +[27.598228, "o", "\r\n"] +[27.640182, "o", "Breakpoint 1 at 0xc1139210: file fs/file.c, line 912.\r\n"] +[27.64023, "o", "(gdb) "] +[28.770631, "o", "c"] +[29.000408, "o", "\r\nContinuing.\r\n"] +[29.585196, "o", "^Z"] +[29.585536, "o", "\r\n[1]+ Stopped make gdb\r\n"] +[29.586221, "o", "\u001b]0;tavi@lktp: ~/src/linux/tools/labs\u0007\u001b[01;32mtavi@lktp\u001b[00m:\u001b[01;34m~/src/linux/tools/labs\u001b[00m$ "] +[30.715625, "o", "#"] +[30.828185, "o", " "] +[30.978622, "o", "c"] +[31.038514, "o", "o"] +[31.18384, "o", "n"] +[31.28793, "o", "n"] +[31.34898, "o", "e"] +[31.392867, "o", "c"] +[31.690793, "o", " "] +[32.237691, "o", "\b\u001b[K"] +[32.355048, "o", "t"] +[32.442939, "o", " "] +[32.588287, "o", "t"] +[32.918417, "o", "o"] +[33.039158, "o", " "] +[33.167914, "o", "t"] +[33.2546, "o", "h"] +[33.340674, "o", "e"] +[33.395216, "o", " "] +[33.6407, "o", "V"] +[33.72697, "o", "M"] +[33.917668, "o", "\r\n"] +[33.918502, "o", "\u001b]0;tavi@lktp: ~/src/linux/tools/labs\u0007\u001b[01;32mtavi@lktp\u001b[00m:\u001b[01;34m~/src/linux/tools/labs\u001b[00m$ "] +[37.546829, "o", "m"] +[37.637743, "o", "i"] +[37.761726, "o", "n"] +[37.837263, "o", "i"] +[37.938906, "o", "c"] +[38.022622, "o", "o"] +[38.113482, "o", "m"] +[38.172694, "o", " "] +[38.308186, "o", "-"] +[38.54722, "o", "D"] +[38.6566, "o", " "] +[39.13904, "o", "s"] +[39.277557, "o", "e"] +[39.337429, "o", "r"] +[39.459585, "o", "ial.pts "] +[39.776685, "o", "\r\n"] +[39.780118, "o", "\u001b[!p\u001b[?3;4l\u001b[4l\u001b>\u001b[0m\u001b(B"] +[39.780371, "o", "\u001b[?1h\u001b=\u001b[H\u001b[2J"] +[39.781975, "o", "\u001b[?12l\u001b[?25h"] +[39.782204, "o", "\nWelcome to minicom 2.7\r\n\nOPTIONS: I18n \r\n"] +[39.782381, "o", "Compiled on Feb 7 2016, 13:37:27.\r\nPort serial.pts, 23:03:56\r\n\nPress CTRL-A Z for help on special keys\r\n\n"] +[40.619769, "o", "\n"] +[40.622796, "o", "root@qemux86:~# "] +[41.981219, "o", "#"] +[42.161306, "o", " "] +[42.413334, "o", "t"] +[42.58837, "o", "r"] +[42.674525, "o", "i"] +[43.334665, "o", "g"] +[43.464242, "o", "g"] +[43.537786, "o", "e"] +[43.650717, "o", "r"] +[43.838322, "o", " "] +[44.718033, "o", "d"] +[44.842141, "o", "u"] +[44.914998, "o", "p"] +[45.233999, "o", "2"] +[45.931475, "o", " "] +[46.078743, "o", "s"] +[46.175471, "o", "y"] +[46.248864, "o", "s"] +[46.892927, "o", "t"] +[46.987556, "o", "e"] +[47.185408, "o", "m"] +[47.28593, "o", " "] +[47.444084, "o", "c"] +[47.49419, "o", "a"] +[47.548442, "o", "l"] +[47.661648, "o", "l"] +[47.793085, "o", "\r\n"] +[47.79407, "o", "root@qemux86:~# "] +[48.389908, "o", "e"] +[48.469687, "o", "c"] +[48.566341, "o", "h"] +[48.637507, "o", "o"] +[48.761749, "o", " "] +[49.620761, "o", "a"] +[49.796805, "o", " "] +[50.159016, "o", ">"] +[50.287746, "o", " "] +[50.407382, "o", "/"] +[50.591362, "o", "t"] +[50.702265, "o", "m"] +[50.775619, "o", "p"] +[51.05656, "o", "/"] +[51.245617, "o", "x"] +[51.460523, "o", "\r\n"] +[52.650063, "o", "\u001b[0m\u001b(B\u001b[7m\u001b[24;1H\u001b[K\u001b[?12l\u001b[?25h"] +[52.650349, "o", "\u001b[?25lCTRL-A Z for help | 115200 8N1 | NOR | Minicom 2.7 | VT102 | Offline | rial.pts\u001b[?12l\u001b[?25h\u001b[13;1H"] +[52.886767, "o", "\u001b[24;1H\u001b[0m\u001b(B\u001b[?12l\u001b[?25h\u001b[H\u001b[2J\u001b[?1l\u001b>"] +[52.88713, "o", "Suspended. Type \"fg\" to resume.\r\n\r\n[2]+ Stopped minicom -D serial.pts\r\n"] +[52.887817, "o", "\u001b]0;tavi@lktp: ~/src/linux/tools/labs\u0007\u001b[01;32mtavi@lktp\u001b[00m:\u001b[01;34m~/src/linux/tools/labs\u001b[00m$ "] +[53.689978, "o", "f"] +[53.888551, "o", "g"] +[53.990684, "o", " "] +[54.462791, "o", "1"] +[54.54925, "o", "\r\n"] +[54.549574, "o", "make gdb\r\n"] +[54.550655, "o", "\r\n"] +[54.558163, "o", "Breakpoint 1, SyS_dup2 (oldfd=3, newfd=1) at fs/file.c:912\r\n"] +[54.558198, "o", "912\tSYSCALL_DEFINE2(dup2, unsigned int, oldfd, unsigned int, newfd)\r\n"] +[54.558292, "o", "(gdb) "] +[68.972448, "o", "#"] +[69.215133, "o", " "] +[70.145897, "o", "l"] +[70.226727, "o", "e"] +[70.397696, "o", "t"] +[70.589752, "o", "s"] +[70.722316, "o", " "] +[71.095534, "o", "e"] +[71.198966, "o", "x"] +[71.299745, "o", "a"] +[71.960882, "o", "m"] +[72.431415, "o", "\b\u001b[K"] +[72.541534, "o", "\b\u001b[K"] +[72.657555, "o", "\b\u001b[K"] +[72.763229, "o", "\b\u001b[K"] +[72.955358, "o", "b"] +[72.995208, "o", "a"] +[73.09843, "o", "c"] +[73.230889, "o", "k"] +[73.48259, "o", "t"] +[73.625035, "o", "r"] +[73.716815, "o", "a"] +[73.931987, "o", "c"] +[74.00581, "o", "e"] +[74.151293, "o", " "] +[74.244418, "o", "t"] +[74.36868, "o", "h"] +[74.435091, "o", "e"] +[74.852494, "o", " "] +[74.998958, "o", "s"] +[75.146618, "o", "y"] +[75.18531, "o", "s"] +[75.40006, "o", "t"] +[75.507571, "o", "e"] +[75.878345, "o", "m"] +[76.021645, "o", " "] +[76.139759, "o", "c"] +[76.199716, "o", "a"] +[76.298113, "o", "l"] +[76.406879, "o", "l"] +[76.499901, "o", " "] +[76.624196, "o", "f"] +[76.714473, "o", "l"] +[76.863719, "o", "o"] +[76.936706, "o", "w"] +[77.285863, "o", "\r\n"] +[77.286167, "o", "(gdb) "] +[77.609834, "o", "b"] +[77.67291, "o", "t"] +[77.908684, "o", "\r\n"] +[77.909971, "o", "#0 SyS_dup2 (oldfd=3, newfd=1) at fs/file.c:912\r\n"] +[77.910076, "o", "#1 0xc1001361 in do_syscall_32_irqs_on (regs=<optimized out>)\r\n at arch/x86/entry/common.c:327\r\n"] +[77.912731, "o", "#2 do_int80_syscall_32 (regs=0xc7235fb4) at arch/x86/entry/common.c:341\r\n#3 0xc14645d3 in entry_INT80_32 () at arch/x86/entry/entry_32.S:544\r\n"] +[77.91529, "o", "#4 0x00000003 in ?? ()\r\n"] +[77.917663, "o", "#5 0x00000003 in ?? ()\r\n"] +[77.92062, "o", "#6 0x0a09e224 in ?? ()\r\n"] +[77.920927, "o", "Backtrace stopped: previous frame inner to this frame (corrupt stack?)\r\n(gdb) "] +[82.733885, "o", "f"] +[82.805597, "o", "r"] +[82.943042, "o", " "] +[83.158856, "o", "1"] +[83.338543, "o", "\r\n"] +[83.338863, "o", "#1 0xc1001361 in do_syscall_32_irqs_on (regs=<optimized out>)\r\n at arch/x86/entry/common.c:327\r\n"] +[83.339111, "o", "327\t\t\tregs->ax = ia32_sys_call_table[nr](\r\n(gdb) "] +[84.302882, "o", "l"] +[84.466961, "o", "i"] +[84.573508, "o", "s"] +[84.805097, "o", "t"] +[86.197885, "o", " "] +[87.456892, "o", "\r\n"] +[87.457044, "o", "322\t\t\t * It's possible that a 32-bit syscall implementation\r\n323\t\t\t * takes a 64-bit parameter but nonetheless assumes that\r\n324\t\t\t * the high bits are zero. Make sure we zero-extend all\r\n325\t\t\t * of the args.\r\n326\t\t\t */\r\n327\t\t\tregs->ax = ia32_sys_call_table[nr]("] +[87.457116, "o", "\r\n328\t\t\t\t(unsigned int)regs->bx, (unsigned int)regs->cx,\r\n329\t\t\t\t(unsigned int)regs->dx, (unsigned int)regs->si,\r\n330\t\t\t\t(unsigned int)regs->di, (unsigned int)regs->bp);\r\n331\t\t}\r\n"] +[87.457622, "o", "(gdb) "] +[90.858059, "o", "#"] +[90.97271, "o", " "] +[91.144448, "o", "t"] +[91.217524, "o", "h"] +[91.269411, "o", "i"] +[91.456193, "o", "s"] +[91.63016, "o", " "] +[91.782525, "o", "l"] +[91.948946, "o", "o"] +[92.056737, "o", "o"] +[92.152544, "o", "k"] +[92.246961, "o", "s"] +[92.353698, "o", " "] +[92.444179, "o", "l"] +[92.631606, "o", "i"] +[92.770763, "o", "k"] +[92.861851, "o", "e"] +[92.969579, "o", " "] +[93.109459, "o", "t"] +[93.210131, "o", "h"] +[93.324771, "o", "e"] +[93.466555, "o", " "] +[93.619111, "o", "s"] +[93.715197, "o", "y"] +[93.795165, "o", "s"] +[93.949435, "o", "t"] +[94.027965, "o", "e"] +[94.184473, "o", " "] +[94.3008, "o", "c"] +[94.342823, "o", "a"] +[94.445488, "o", "l"] +[94.568218, "o", "l"] +[94.656948, "o", " "] +[94.839902, "o", "d"] +[94.957893, "o", "i"] +[95.075175, "o", "s"] +[95.230277, "o", "p"] +[95.339237, "o", "a"] +[95.543096, "o", "t"] +[95.751003, "o", "c"] +[95.854341, "o", "h"] +[95.943425, "o", "e"] +[96.023733, "o", "r"] +[96.172254, "o", "\r\n"] +[96.172374, "o", "(gdb) "] +[101.058686, "o", "#"] +[101.204849, "o", " "] +[101.545024, "o", "n"] +[101.645855, "o", "r"] +[101.798058, "o", " "] +[101.950607, "o", "i"] +[102.056996, "o", "s"] +[102.134187, "o", " "] +[102.342601, "o", "t"] +[102.416898, "o", "h"] +[102.533298, "o", "e"] +[102.593287, "o", " "] +[102.719888, "o", "s"] +[102.900423, "o", "y"] +[102.94586, "o", "s"] +[103.162384, "o", "t"] +[103.241973, "o", "e"] +[103.574398, "o", "m"] +[103.675272, "o", " "] +[103.802496, "o", "c"] +[103.849596, "o", "a"] +[103.955005, "o", "l"] +[104.090651, "o", "l"] +[104.1248, "o", " "] +[104.318767, "o", "n"] +[104.403953, "o", "u"] +[104.607057, "o", "m"] +[104.809716, "o", "b"] +[104.882333, "o", "e"] +[104.945321, "o", "r"] +[105.169779, "o", "\r\n"] +[105.170195, "o", "(gdb) "] +[120.867099, "o", "l"] +[121.049682, "o", "i"] +[121.155454, "o", "s"] +[121.359302, "o", "t"] +[121.479029, "o", " "] +[121.619056, "o", "3"] +[121.715251, "o", "0"] +[121.836342, "o", "0"] +[122.442593, "o", "\r\n"] +[122.447014, "o", "295\t/*\r\n296\t * Does a 32-bit syscall. Called with IRQs on in CONTEXT_KERNEL. Does\r\n297\t * all entry and exit work and returns with IRQs off. This function is\r\n298\t * extremely hot in workloads that use it, and it's usually called from\r\n299\t * do_fast_syscall_32, so forcibly inline it to improve performance.\r\n300\t */\r\n"] +[122.447378, "o", "301\tstatic __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs)\r\n302\t{\r\n303\t\tstruct thread_info *ti = current_thread_info();\r\n304\t\tunsigned int nr = (unsigned int)regs->orig_ax;\r\n(gdb) "] +[124.092652, "o", "#"] +[124.554034, "o", " "] +[124.797533, "o", "i"] +[124.905822, "o", "t"] +[125.030417, "o", " "] +[125.160131, "o", "i"] +[125.259278, "o", "s"] +[125.37996, "o", " "] +[125.517546, "o", "p"] +[125.669394, "o", "i"] +[125.760003, "o", "c"] +[125.875741, "o", "k"] +[125.996377, "o", "e"] +[126.076136, "o", "d"] +[126.247928, "o", " "] +[126.466909, "o", "u"] +[126.53385, "o", "p"] +[126.664159, "o", " "] +[127.47466, "o", "f"] +[127.507676, "o", "r"] +[127.594243, "o", "o"] +[127.686369, "o", "m"] +[127.793519, "o", " "] +[127.867138, "o", "t"] +[127.990397, "o", "h"] +[128.119207, "o", " "] +[128.507492, "o", "\b\u001b[K"] +[128.590147, "o", "e"] +[128.692867, "o", " "] +[128.889331, "o", "s"] +[129.214909, "o", "a"] +[129.981084, "o", "m"] +[130.065029, "o", "e"] +[130.186849, "o", " "] +[130.540104, "o", "s"] +[130.732803, "o", "t"] +[130.793955, "o", "r"] +[131.422146, "o", "c"] +[131.696522, "o", "t"] +[131.853467, "o", "u"] +[132.034292, "o", "r"] +[132.08244, "o", "e"] +[132.324049, "o", "\b\u001b[K"] +[132.443772, "o", "\b\u001b[K"] +[132.573348, "o", "\b\u001b[K"] +[132.694863, "o", "\b\u001b[K"] +[132.81051, "o", "\b\u001b[K"] +[132.997241, "o", "u"] +[133.088819, "o", "c"] +[133.337918, "o", "t"] +[133.454541, "o", "u"] +[133.569818, "o", "r"] +[133.609841, "o", "e"] +[133.711729, "o", " "] +[134.021296, "o", "("] +[134.244295, "o", "p"] +[134.364747, "o", "t"] +[134.518463, "o", "_"] +[134.694346, "o", "r"] +[134.756482, "o", "e"] +[135.004436, "o", "g"] +[135.409283, "o", "s"] +[135.67484, "o", ")"] +[136.719996, "o", "\r\n"] +[136.720311, "o", "(gdb) "] +[159.587179, "o", "#"] +[159.767425, "o", " "] +[159.943861, "o", "l"] +[160.036363, "o", "e"] +[160.198006, "o", "t"] +[160.366941, "o", "s"] +[160.481441, "o", " "] +[160.690788, "o", "i"] +[161.019933, "o", "n"] +[161.265835, "o", "p"] +[161.435021, "o", "s"] +[161.821488, "o", "\b\u001b[K"] +[161.951302, "o", "\b\u001b[K"] +[162.226603, "o", "s"] +[162.36373, "o", "p"] +[162.498729, "o", "e"] +[162.574127, "o", "c"] +[162.821589, "o", "t"] +[162.945206, "o", " "] +[163.051945, "o", "t"] +[163.219025, "o", "h"] +[163.276168, "o", "e"] +[163.387915, "o", " "] +[163.856566, "o", "r"] +[163.947525, "o", "e"] +[164.54179, "o", "g"] +[164.735443, "o", "s"] +[164.860377, "o", " "] +[164.983243, "o", "c"] +[165.068139, "o", "o"] +[165.142719, "o", "n"] +[165.325774, "o", "t"] +[165.347382, "o", "e"] +[165.53939, "o", "n"] +[165.632312, "o", "t"] +[165.845555, "o", "s"] +[166.537455, "o", "\r\n"] +[166.537632, "o", "(gdb) "] +[166.819034, "o", "p"] +[166.958081, "o", "r"] +[167.052344, "o", "i"] +[167.133431, "o", "n"] +[167.213977, "o", "t"] +[167.322155, "o", " "] +[167.662143, "o", "*"] +[167.894034, "o", "r"] +[167.957716, "o", "e"] +[168.123891, "o", "g"] +[168.275607, "o", "s"] +[168.368704, "o", "\r\n"] +[168.369137, "o", "value has been optimized out\r\n(gdb) "] +[169.223841, "o", "#"] +[169.68196, "o", " "] +[170.473422, "o", "o"] +[170.562498, "o", "p"] +[170.754795, "o", "t"] +[170.780246, "o", "i"] +[170.985415, "o", "m"] +[171.06, "o", "i"] +[171.118702, "o", "z"] +[171.326175, "o", "e"] +[171.422983, "o", "d"] +[171.566281, "o", " "] +[171.82724, "o", "b"] +[171.902983, "o", "y"] +[172.056031, "o", " "] +[172.291054, "o", "c"] +[172.382563, "o", "i"] +[172.439382, "o", "m"] +[172.571587, "o", "p"] +[172.870082, "o", "\b\u001b[K"] +[172.987523, "o", "\b\u001b[K"] +[173.101322, "o", "\b\u001b[K"] +[173.254872, "o", "o"] +[173.322597, "o", "m"] +[173.44459, "o", "p"] +[173.603123, "o", "i"] +[173.779322, "o", "l"] +[173.905269, "o", "e"] +[174.000955, "o", "r"] +[174.086025, "o", "."] +[174.209714, "o", "."] +[174.349851, "o", "."] +[174.538669, "o", " "] +[179.50067, "o", "g"] +[179.580322, "o", "o"] +[179.763011, "o", " "] +[179.903828, "o", "a"] +[180.013494, "o", " "] +[180.236946, "o", "f"] +[180.467494, "o", "r"] +[180.568763, "o", "a"] +[180.697886, "o", "m"] +[180.82554, "o", "e"] +[180.907141, "o", " "] +[181.169606, "o", "d"] +[181.262241, "o", "e"] +[181.42098, "o", "e"] +[181.616856, "o", "p"] +[181.793458, "o", "e"] +[181.910212, "o", "r"] +[182.544419, "o", "\r\n"] +[182.54482, "o", "(gdb) "] +[183.073511, "o", "f"] +[183.168588, "o", "r"] +[183.669953, "o", " "] +[191.37133, "o", "2"] +[191.540642, "o", "\r\n"] +[191.541499, "o", "#2 do_int80_syscall_32 (regs=0xc7235fb4) at arch/x86/entry/common.c:341\r\n"] +[191.541856, "o", "341\t\tdo_syscall_32_irqs_on(regs);\r\n(gdb) "] +[192.917131, "o", "p"] +[193.062137, "o", "r"] +[193.147118, "o", "i"] +[193.231132, "o", "n"] +[193.304903, "o", "t"] +[193.385087, "o", " "] +[193.915946, "o", "*"] +[194.135248, "o", "r"] +[194.23597, "o", "e"] +[194.394568, "o", "g"] +[194.566658, "o", "s"] +[194.653019, "o", "\r\n"] +[194.653763, "o", "$1 = {bx = 3, cx = 1, "] +[194.654076, "o", "dx = 3, si = 168423920, di = 168419876, bp = 168419336, \r\n ax = 4294967258, ds = 123, __dsh = 0, es = 123, __esh = 0, fs = 0, \r\n __fsh = 0, "] +[194.654371, "o", "gs = 0, __gsh = 0, orig_ax = 63, ip = 1150252833, cs = 115, \r\n __csh = 0, flags = 514, "] +[194.65463, "o", "sp = 3218117628, ss = 123, __ssh = 0}\r\n(gdb) "] +[198.397833, "o", "#"] +[198.589958, "o", " "] +[199.416287, "o", "\b\u001b[K"] +[199.54844, "o", "\b\u001b[K"] +[199.789439, "o", "p"] +[199.910455, "o", "r"] +[200.013253, "o", "i"] +[200.081967, "o", "n"] +[200.172051, "o", "t"] +[200.23888, "o", " "] +[200.344988, "o", "r"] +[200.443063, "o", "e"] +[200.636653, "o", "g"] +[200.903926, "o", "s"] +[201.297424, "o", "\b\u001b[K"] +[201.555797, "o", "s"] +[201.70675, "o", "\r\n"] +[201.718736, "o", "$2 = (struct pt_regs *) 0xc7235fb4\r\n(gdb) "] +[202.762192, "o", "#"] +[202.96906, "o", " "] +[203.200172, "o", "t"] +[203.335914, "o", "h"] +[203.397287, "o", "i"] +[203.509368, "o", "s"] +[203.663251, "o", " "] +[204.186121, "o", "i"] +[204.277979, "o", "s"] +[204.37577, "o", " "] +[204.575364, "o", "a"] +[204.681527, "o", " "] +[205.432843, "o", "s"] +[205.577435, "o", "a"] +[205.84148, "o", "v"] +[205.901931, "o", "e"] +[206.142056, "o", " "] +[206.48041, "o", "\b\u001b[K"] +[206.576791, "o", "d"] +[206.650202, "o", " "] +[206.846523, "o", "o"] +[207.147206, "o", " "] +[207.497795, "o", "\b\u001b[K"] +[207.682557, "o", "n"] +[207.773982, "o", " "] +[207.873402, "o", "s"] +[208.081623, "o", "t"] +[208.158662, "o", "a"] +[208.370015, "o", "c"] +[208.494404, "o", "k"] +[210.422713, "o", " "] +[212.637105, "o", "s"] +[212.787177, "o", "t"] +[212.851629, "o", "r"] +[212.997138, "o", "u"] +[213.10568, "o", "c"] +[213.316927, "o", "t"] +[213.4249, "o", "u"] +[213.518001, "o", "r"] +[213.568409, "o", "e"] +[213.68215, "o", " "] +[214.147557, "o", "w"] +[214.236414, "o", "h"] +[214.292857, "o", "i"] +[214.384715, "o", "c"] +[214.448337, "o", "h"] +[214.52596, "o", " "] +[214.62955, "o", "s"] +[214.810601, "o", "t"] +[214.922436, "o", "o"] +[215.0038, "o", "r"] +[215.075964, "o", "e"] +[215.264322, "o", "s"] +[215.370649, "o", " "] +[215.800702, "o", "u"] +[215.868643, "o", "s"] +[215.977376, "o", "e"] +[216.044684, "o", "r"] +[216.169163, "o", "s"] +[216.284503, "o", "p"] +[216.34314, "o", "a"] +[216.450213, "o", "c"] +[216.550799, "o", "e"] +[216.722203, "o", " "] +[219.131447, "o", "r"] +[219.195644, "o", "e"] +[219.377234, "o", "g"] +[219.486582, "o", "i"] +[219.520092, "o", "s"] +[219.685879, "o", "t"] +[219.754728, "o", "e"] +[219.874287, "o", "r"] +[220.02845, "o", "s"] +[221.002656, "o", " "] +[221.144104, "o", "v"] +[221.201385, "o", "a"] +[221.300797, "o", "l"] +[221.517941, "o", "u \r"] +[221.655037, "o", "e"] +[221.819353, "o", "s"] +[222.291958, "o", "\r\n"] +[222.292213, "o", "(gdb) "] +[228.409682, "o", "i"] +[228.551388, "o", "n"] +[229.037434, "o", "f"] +[229.139332, "o", "o"] +[229.400686, "o", " "] +[230.375475, "o", "r"] +[230.455225, "o", "e"] +[230.615513, "o", "\u0007"] +[231.367524, "o", "g"] +[231.608532, "o", "s"] +[231.985991, "o", "\b\u001b[K"] +[232.17368, "o", "i"] +[232.244238, "o", "s"] +[232.453164, "o", "t"] +[232.55645, "o", "e"] +[232.688874, "o", "r"] +[232.95895, "o", " "] +[233.83154, "o", "e"] +[233.978035, "o", "s"] +[234.047244, "o", "p"] +[234.168937, "o", "\r\n"] +[234.169348, "o", "esp 0xc7235f8c"] +[234.169649, "o", "\t0xc7235f8c\r\n"] +[234.16976, "o", "(gdb) "] +[250.775201, "o", "#"] +[251.106842, "o", " "] +[251.346477, "o", "h"] +[251.418165, "o", "o"] +[251.501715, "o", "w"] +[251.664792, "o", " "] +[252.067964, "o", "d"] +[252.208144, "o", "i"] +[252.87959, "o", "d"] +[253.06756, "o", " "] +[253.393168, "o", "t"] +[253.533434, "o", "h"] +[253.601184, "o", "o"] +[253.76566, "o", "s"] +[253.959997, "o", "e"] +[254.157286, "o", " "] +[254.898526, "o", "u"] +[254.999925, "o", "s"] +[255.096884, "o", "e"] +[255.171001, "o", "r"] +[255.315978, "o", "s"] +[255.418223, "o", "p"] +[255.516375, "o", "a"] +[255.651774, "o", "c"] +[255.762584, "o", "e"] +[255.92294, "o", " "] +[256.104238, "o", "r"] +[256.165681, "o", "e"] +[256.623148, "o", "g"] +[256.761757, "o", "i"] +[256.823147, "o", "s"] +[257.031872, "o", "t"] +[257.103524, "o", "e"] +[257.561344, "o", "r"] +[258.279258, "o", " "] +[258.447006, "o", "v"] +[258.502906, "o", "a"] +[258.608216, "o", "l"] +[258.786735, "o", "u"] +[258.86697, "o", "e"] +[258.972944, "o", "s"] +[259.099576, "o", " "] +[259.319621, "o", "g"] +[259.43755, "o", "o"] +[259.566479, "o", "t"] +[259.670838, "o", " "] +[259.795132, "o", "s"] +[259.867977, "o", "a"] +[260.067483, "o", "v"] +[260.107313, "o", "e"] +[260.330451, "o", "d"] +[260.681612, "o", " "] +[262.446506, "o", "o"] +[262.637035, "o", "n"] +[262.71973, "o", " "] +[262.816535, "o", "s"] +[262.986307, "o", "t"] +[263.060635, "o", "a"] +[263.228155, "o", "c"] +[263.277514, "o", "k"] +[263.566323, "o", "?"] +[263.893074, "o", "\r\n"] +[263.893184, "o", "(gdb) "] +[264.675148, "o", "#"] +[265.174988, "o", " "] +[265.776336, "o", "g"] +[265.893763, "o", "o"] +[266.031976, "o", " "] +[266.147399, "o", "a"] +[266.278558, "o", " "] +[266.768307, "o", "f"] +[266.949187, "o", "r"] +[267.030231, "o", "a"] +[267.15945, "o", "m"] +[267.376536, "o", " "] +[267.847105, "o", "\b\u001b[K"] +[267.91339, "o", "e"] +[268.015642, "o", " "] +[268.317662, "o", "d"] +[268.428077, "o", "e"] +[268.589581, "o", "e"] +[268.699983, "o", "p"] +[268.795125, "o", "e"] +[268.886986, "o", "r"] +[268.983051, "o", "."] +[269.133065, "o", "."] +[269.275845, "o", "."] +[269.70994, "o", "\r\n"] +[269.71023, "o", "(gdb) "] +[269.989964, "o", "f"] +[270.057684, "o", "r"] +[270.124032, "o", "e"] +[270.338379, "o", " "] +[272.954739, "o", "3"] +[273.342331, "o", "\r\n"] +[273.342463, "o", "Undefined command: \"fre\". Try \"help\".\r\n(gdb) "] +[274.537938, "o", "f"] +[274.591956, "o", "r"] +[274.794531, "o", " "] +[275.013426, "o", "3"] +[275.213151, "o", "\r\n"] +[275.213508, "o", "#3 0xc14645d3 in entry_INT80_32 () at arch/x86/entry/entry_32.S:544\r\n"] +[275.213876, "o", "544\t\tcall\tdo_int80_syscall_32\r\n(gdb) "] +[280.62674, "o", "l"] +[280.794815, "o", "i"] +[280.926434, "o", "s"] +[281.156915, "o", "t"] +[281.246634, "o", " "] +[281.604719, "o", "5"] +[281.88764, "o", "3"] +[281.986378, "o", "2"] +[282.314826, "o", "\r\n"] +[282.319103, "o", "527\t * edx arg3\r\n528\t * esi arg4\r\n529\t * edi arg5\r\n530\t * ebp arg6\r\n531\t */\r\n532\tENTRY(entry_INT80_32)\r\n533\t\tASM_CLAC\r\n534\t\tpushl\t%eax\t\t\t/* pt_regs->orig_ax */\r\n535\t\tSAVE_ALL pt_regs_ax=$-ENOSYS\t/* save rest */\r\n536\t\r\n"] +[282.319396, "o", "(gdb) "] +[287.032723, "o", "$"] +[287.628779, "o", "\b\u001b[K"] +[287.896648, "o", "#"] +[288.026461, "o", " "] +[288.213827, "o", "l"] +[288.286875, "o", "e"] +[288.488417, "o", "t"] +[288.672395, "o", "s"] +[289.171884, "o", " "] +[289.288632, "o", "s"] +[289.468608, "o", "e"] +[289.602164, "o", "e"] +[289.762666, "o", " "] +[289.952819, "o", "w"] +[290.078185, "o", "h"] +[290.119588, "o", "a"] +[290.337222, "o", "t"] +[290.411464, "o", " "] +[291.504878, "o", "S"] +[291.584952, "o", "A"] +[291.754893, "o", "V"] +[291.802071, "o", "E"] +[291.96154, "o", "_"] +[292.14258, "o", "A"] +[292.21097, "o", "L"] +[292.344666, "o", "L"] +[292.56581, "o", " "] +[292.756512, "o", "d"] +[292.852271, "o", "o"] +[292.933196, "o", "e"] +[293.021413, "o", "s"] +[294.080447, "o", "\r\n"] +[294.080887, "o", "(gdb) "] +[295.025805, "o", "d"] +[295.136476, "o", "i"] +[295.271217, "o", "s"] +[295.37067, "o", "a"] +[295.527332, "o", "s"] +[295.898488, "o", "s"] +[296.085096, "o", "emble "] +[297.455021, "o", "\r\n"] +[297.455375, "o", "Dump of assembler code for function entry_INT80_32:\r\n 0xc14645a4 <+0>:\tlea 0x0(%esi),%esi\r\n 0xc14645a7 <+3>:\tpush %eax\r\n 0xc14645a8 <+4>:\tcld \r\n 0xc14645a9 <+5>:\tpush $0x0\r\n 0xc14645ab <+7>:\tpush %fs\r\n 0xc14645ad <+9>:\tpush %es\r\n 0xc14645ae <+10>:\tpush %ds\r\n 0xc14645af <+11>:\tpush $0xffffffda\r\n 0xc14645b1 <+13>:\tpush %ebp\r\n"] +[297.455523, "o", " 0xc14645b2 <+14>:\tpush %edi\r\n 0xc14645b3 <+15>:\tpush %esi\r\n 0xc14645b4 <+16>:\tpush %edx\r\n 0xc14645b5 <+17>:\tpush %ecx\r\n 0xc14645b6 <+18>:\tpush %ebx\r\n"] +[297.455959, "o", " 0xc14645b7 <+19>:\tmov $0x7b,%edx\r\n 0xc14645bc <+24>:\tmov %edx,%ds\r\n 0xc14645be <+26>:\tmov %edx,%es\r\n"] +[297.456273, "o", " 0xc14645c0 <+28>:\tmov $0xd8,%edx\r\n 0xc14645c5 <+33>:\tmov %edx,%fs\r\n"] +[297.456519, "o", " 0xc14645c7 <+35>:\tcall 0xc1000ed3 <trace_hardirqs_off_thunk>\r\n 0xc14645cc <+40>:\tmov %esp,%eax\r\n 0xc14645ce <+42>:\tcall 0xc1001300 <do_int80_syscall_32>\r\n"] +[297.456787, "o", "---Type <return> to continue, or q <return> to quit---"] +[300.037654, "o", "q"] +[300.474906, "o", "\r\nQuit\r\n"] +[300.475028, "o", "(gdb) "] +[301.222036, "o", "#"] +[301.344949, "o", " "] +[301.53983, "o", "a"] +[301.639062, "o", "s"] +[301.804905, "o", " "] +[301.932574, "o", "e"] +[302.019082, "o", "x"] +[302.205597, "o", "p"] +[302.282764, "o", "e"] +[302.353223, "o", "c"] +[302.577703, "o", "t"] +[302.659955, "o", "e"] +[302.829647, "o", "d"] +[302.916048, "o", ","] +[302.988029, "o", " "] +[303.195687, "o", "i"] +[303.309352, "o", "t"] +[303.425016, "o", " "] +[304.041744, "o", "p"] +[304.269832, "o", "u"] +[304.428141, "o", "s"] +[304.641784, "o", "h"] +[304.756462, "o", "e"] +[304.840521, "o", "s"] +[305.137798, "o", " "] +[306.996152, "o", "r"] +[307.053783, "o", "e"] +[307.293212, "o", "s"] +[307.493748, "o", "i"] +[308.526057, "o", "\b\u001b[K"] +[308.651061, "o", "\b\u001b[K"] +[308.813776, "o", "\b\u001b[K"] +[309.52065, "o", "u"] +[309.734069, "o", "\b\u001b[K"] +[309.866326, "o", "\b\u001b[K"] +[310.014799, "o", "u"] +[310.293887, "o", "e"] +[310.409052, "o", "r"] +[310.764658, "o", "\b\u001b[K"] +[310.889594, "o", "\b\u001b[K"] +[311.047137, "o", "s"] +[311.173052, "o", "e"] +[311.228372, "o", "r"] +[311.711761, "o", "s"] +[311.809911, "o", "p"] +[311.873173, "o", "a"] +[311.988731, "o", "c"] +[312.077428, "o", "e"] +[312.161123, "o", " "] +[312.281191, "o", "r"] +[312.349935, "o", "e"] +[312.547146, "o", "g"] +[312.667304, "o", "s"] +[312.936388, "o", " "] +[313.086964, "o", "t"] +[313.154591, "o", "o"] +[313.232086, "o", " "] +[314.351931, "o", "s"] +[314.549992, "o", "t"] +[314.60986, "o", "a"] +[314.792887, "o", "c"] +[314.864733, "o", "k"] +[314.991827, "o", "\r\n"] +[314.992256, "o", "(gdb) "] +[327.831401, "o", "#"] +[328.116647, "o", " "] +[328.304643, "o", "l"] +[328.403419, "o", "e"] +[328.643693, "o", "t"] +[328.881425, "o", "s"] +[329.012271, "o", " "] +[329.350209, "o", "o"] +[329.675607, "o", "\b\u001b[K"] +[329.746522, "o", "g"] +[329.894035, "o", "o"] +[329.960528, "o", " "] +[330.265508, "o", "d"] +[330.454674, "o", "e"] +[330.61252, "o", "e"] +[330.767734, "o", "p"] +[331.017861, "o", "e"] +[331.105343, "o", "r"] +[331.193089, "o", ","] +[331.291487, "o", " "] +[331.421255, "o", "t"] +[331.499907, "o", "o"] +[331.589935, "o", " "] +[331.800311, "o", "u"] +[332.05827, "o", "s"] +[332.210451, "o", "e"] +[332.270701, "o", "r"] +[332.420355, "o", "s"] +[332.533886, "o", "p"] +[332.598023, "o", "a"] +[332.679367, "o", "c"] +[332.768566, "o", "e"] +[332.92981, "o", "\r\n"] +[332.929919, "o", "(gdb) "] +[333.474291, "o", "f"] +[333.512483, "o", "r"] +[333.670863, "o", " "] +[334.214986, "o", "2"] +[334.409422, "o", "\r\n"] +[334.410165, "o", "#2 do_int80_syscall_32 (regs=0xc7235fb4) at arch/x86/entry/common.c:341\r\n"] +[334.410451, "o", "341\t\tdo_syscall_32_irqs_on(regs);\r\n(gdb) "] +[334.795034, "o", "p"] +[334.935707, "o", "r"] +[335.041764, "o", "i"] +[335.125845, "o", "n"] +[335.256727, "o", "t"] +[335.436358, "o", " "] +[336.398283, "o", "*"] +[336.683485, "o", "r"] +[336.751145, "o", "e"] +[336.914056, "o", "g"] +[337.129438, "o", "s"] +[337.326378, "o", "\r\n"] +[337.327037, "o", "$3 = {bx = 3, cx = 1, dx = 3, "] +[337.327271, "o", "si = 168423920, di = 168419876, bp = 168419336, \r\n ax = 4294967258, ds = 123, __dsh = 0, es = 123, __esh = 0, fs = 0, \r\n"] +[337.327484, "o", " __fsh = 0, gs = 0, __gsh = 0, orig_ax = 63, ip = 1150252833, cs = 115, \r\n __csh = 0, flags = 514, sp = 3218117628, "] +[337.327641, "o", "ss = 123, __ssh = 0}\r\n(gdb) "] +[338.677993, "o", "#"] +[338.93667, "o", " "] +[339.41632, "o", "t"] +[339.584092, "o", "h"] +[340.119744, "o", "e"] +[340.257132, "o", " "] +[340.430186, "o", "p"] +[340.531965, "o", "t"] +[340.720155, "o", "_"] +[340.823874, "o", "r"] +[340.878238, "o", "e"] +[341.092385, "o", "g"] +[341.261419, "o", "s"] +[341.410487, "o", " "] +[341.687741, "o", "s"] +[341.898318, "o", "t"] +[341.974712, "o", "r"] +[342.103508, "o", "u"] +[342.220027, "o", "c"] +[342.426521, "o", "t"] +[342.533294, "o", "u"] +[342.643383, "o", "r"] +[342.706116, "o", "e"] +[342.969115, "o", " "] +[343.424403, "o", "s"] +[343.831852, "o", "a"] +[344.073427, "o", "v"] +[344.124191, "o", "e"] +[344.307738, "o", "s"] +[344.41903, "o", " "] +[344.562734, "o", "t"] +[344.695776, "o", "h"] +[344.763893, "o", "e"] +[344.926178, "o", " "] +[345.788445, "o", "E"] +[346.04075, "o", "S"] +[346.167767, "o", "P"] +[346.367919, "o", " "] +[346.480742, "o", "a"] +[346.612524, "o", "n"] +[346.708959, "o", "d"] +[346.772221, "o", " "] +[347.04116, "o", "E"] +[347.27069, "o", "I"] +[347.41795, "o", "P"] +[347.620023, "o", " "] +[348.267947, "o", "v"] +[348.310577, "o", "a"] +[348.389535, "o", "l"] +[348.583187, "o", "u"] +[348.626281, "o", "e"] +[348.75411, "o", "s"] +[349.152128, "o", " "] +[350.062966, "o", "\b\b\b\b\b\b\b"] +[350.505726, "o", "\u001b[1@r"] +[350.581222, "o", "\u001b[1@e"] +[350.733489, "o", "\u001b[1@g"] +[350.860972, "o", "\u001b[1@s"] +[351.063679, "o", "\u001b[1@ "] +[351.403168, "o", "\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C"] +[351.723396, "o", "a"] +[351.796061, "o", "s"] +[351.924873, "o", " "] +[352.127877, "o", "w"] +[352.258955, "o", "e"] +[352.359039, "o", "l"] +[352.480885, "o", "l"] +[352.581941, "o", "\r\n"] +[352.582063, "o", "(gdb) "] +[354.291356, "o", "p"] +[354.434906, "o", "r"] +[354.548164, "o", "i"] +[354.623451, "o", "n"] +[354.677168, "o", "t"] +[354.835361, "o", " "] +[355.104827, "o", "/"] +[355.285227, "o", "x"] +[355.434379, "o", " "] +[355.814288, "o", "r"] +[355.884763, "o", "e"] +[356.044765, "o", "g"] +[356.169825, "o", "-"] +[356.229667, "o", "s"] +[356.715904, "o", ">"] +[356.92396, "o", "\b\u001b[K"] +[357.049325, "o", "\b\u001b[K"] +[357.20555, "o", "\b\u001b[K"] +[357.296469, "o", "s"] +[357.676925, "o", ">"] +[358.100747, "o", "i"] +[358.154056, "o", "p"] +[358.530121, "o", "\b\u001b[K"] +[358.650376, "o", "\b\u001b[K"] +[358.771888, "o", "\b\u001b[K"] +[358.830286, "o", "-"] +[359.096595, "o", ">"] +[359.399708, "o", "i"] +[359.471959, "o", "p"] +[359.66492, "o", "\r\n"] +[359.69065, "o", "$4 = 0x448f7721\r\n(gdb) "] +[362.750139, "o", "d"] +[362.873006, "o", "i"] +[363.70087, "o", "s"] +[364.005826, "o", "a"] +[364.154305, "o", "s"] +[364.534403, "o", "s"] +[364.638318, "o", "emble "] +[367.274254, "o", "0x"] +[367.274386, "o", "448f"] +[367.274769, "o", "7721"] +[368.070465, "o", "-"] +[368.275859, "o", "0"] +[368.34472, "o", "x"] +[368.717017, "o", "1"] +[368.721481, "o", "2"] +[368.831229, "o", ","] +[369.57988, "o", "+"] +[369.896806, "o", "0"] +[370.018088, "o", "x"] +[370.253572, "o", "1"] +[370.325077, "o", "2"] +[370.729392, "o", "\r\n"] +[370.729561, "o", "Dump of assembler code from 0x448f770f to 0x448f7721:\r\n"] +[370.730714, "o", " 0x448f770f:\tnop\r\n"] +[370.73105, "o", " 0x448f7710:\tmov %ebx,%edx\r\n"] +[370.731361, "o", " 0x448f7712:\tmov 0x8(%esp),%ecx\r\n"] +[370.731696, "o", " 0x448f7716:\tmov 0x4(%esp),%ebx\r\n"] +[370.732008, "o", " 0x448f771a:\tmov $0x3f,%eax\r\n"] +[370.732313, "o", " 0x448f771f:\tint $0x80\r\nEnd of assembler dump.\r\n"] +[370.732521, "o", "(gdb) "] +[374.541556, "o", "#"] +[374.783001, "o", " "] +[374.898373, "o", "t"] +[375.026925, "o", "h"] +[375.073567, "o", "i"] +[375.175876, "o", "s"] +[375.257213, "o", " "] +[375.437225, "o", "l"] +[375.612851, "o", "o"] +[375.726918, "o", "o"] +[375.811791, "o", "k"] +[375.914079, "o", "s"] +[375.991534, "o", " "] +[376.124911, "o", "l"] +[376.227571, "o", "i"] +[376.402924, "o", "k"] +[376.568604, "o", "e"] +[376.709076, "o", " "] +[376.892681, "o", "t"] +[377.0435, "o", "h"] +[377.153381, "o", "e"] +[377.255434, "o", " "] +[379.598554, "o", "d"] +[379.742728, "o", "u"] +[379.818192, "o", "p"] +[379.946914, "o", "2"] +[380.101209, "o", " "] +[381.094712, "o", "i"] +[381.254821, "o", "m"] +[381.448647, "o", "p"] +[381.516377, "o", "l"] +[381.632838, "o", "e"] +[381.733497, "o", "m"] +[381.821502, "o", "e"] +[381.939177, "o", "n"] +[382.061297, "o", "t"] +[382.126975, "o", "a"] +[382.263958, "o", "t"] +[382.355856, "o", "i"] +[382.39873, "o", "o"] +[382.625141, "o", "n"] +[382.785792, "o", " "] +[382.924201, "o", "i"] +[383.007739, "o", "n"] +[383.112653, "o", " "] +[383.344371, "o", "g"] +[383.528085, "o", "l"] +[383.818807, "o", "\b\u001b[K"] +[383.940934, "o", "\b\u001b[K"] +[384.549965, "o", "l"] +[384.699794, "o", "i"] +[384.893748, "o", "b"] +[384.958022, "o", "c"] +[385.106737, "o", "\r\n"] +[385.106862, "o", "(gdb) "] +[390.638525, "o", "#"] +[390.745393, "o", " "] +[390.899618, "o", "l"] +[390.932654, "o", "e"] +[391.101789, "o", "t"] +[391.253114, "o", "s"] +[391.385379, "o", " "] +[391.507941, "o", "c"] +[391.609023, "o", "h"] +[391.674385, "o", "e"] +[391.751088, "o", "c"] +[391.811, "o", "k"] +[391.917497, "o", " "] +[392.061073, "o", "t"] +[392.14249, "o", "h"] +[392.235203, "o", "e"] +[392.357752, "o", " "] +[392.997036, "o", "s"] +[393.16912, "o", "t"] +[393.264152, "o", "a"] +[393.476405, "o", "c"] +[393.623273, "o", "k"] +[393.735766, "o", " "] +[393.886348, "o", "v"] +[393.956001, "o", "a"] +[394.095124, "o", "l"] +[394.297637, "o", "u"] +[394.373537, "o", "e"] +[394.864079, "o", "s"] +[396.020466, "o", " "] +[396.544499, "o", "a"] +[397.19223, "o", "\b\u001b[K"] +[397.516516, "o", "("] +[397.757745, "o", "d"] +[397.840435, "o", "a"] +[398.021342, "o", "r"] +[398.083794, "o", "a"] +[398.395255, "o", "\b\u001b[K"] +[398.527905, "o", "\b\u001b[K"] +[398.655121, "o", "\b\u001b[K"] +[398.791444, "o", "\b\u001b[K"] +[400.259196, "o", "\b\u001b[K"] +[400.381224, "o", "\b\u001b[K"] +[400.705872, "o", "\r\n"] +[400.705994, "o", "(gdb) "] +[405.090136, "o", "p"] +[405.250017, "o", "r"] +[405.339117, "o", "i"] +[405.408649, "o", "n"] +[405.48463, "o", "t"] +[405.598488, "o", " "] +[406.982799, "o", "/"] +[407.074314, "o", "x"] +[407.190834, "o", " "] +[407.406215, "o", "r"] +[407.477829, "o", "e"] +[407.621752, "o", "g"] +[407.761064, "o", "s"] +[407.848706, "o", "-"] +[408.12336, "o", ">"] +[409.034397, "o", "s"] +[409.101141, "o", "p"] +[409.237828, "o", "\r\n"] +[409.250562, "o", "$5 = 0xbfd093fc\r\n(gdb) "] +[410.588712, "o", "x"] +[410.779534, "o", " "] +[410.929273, "o", "/"] +[411.084678, "o", "x"] +[411.282106, "o", " "] +[412.846629, "o", "0xb"] +[412.84701, "o", "fd093fc"] +[413.495368, "o", "\r\n"] +[413.495801, "o", "0xbfd093fc:\t0x08068b46\r\n"] +[413.495927, "o", "(gdb) "] +[413.970708, "o", "\r\n"] +[413.971563, "o", "0xbfd09400:\t0x00000003\r\n"] +[413.971895, "o", "(gdb) "] +[414.429768, "o", "\r\n"] +[414.430693, "o", "0xbfd09404:\t0x00000001\r\n"] +[414.430996, "o", "(gdb) "] +[416.367425, "o", "#"] +[416.600327, "o", " "] +[417.126384, "o", "f"] +[417.206421, "o", "i"] +[417.315777, "o", "r"] +[417.716293, "o", "s"] +[418.11331, "o", "t"] +[418.641803, "o", " "] +[419.136181, "o", "s"] +[419.31382, "o", "e"] +[419.466617, "o", "e"] +[420.57146, "o", "m"] +[421.230979, "o", "\b\u001b[K"] +[421.365032, "o", "\b\u001b[K"] +[421.493488, "o", "\b\u001b[K"] +[421.621835, "o", "\b\u001b[K"] +[421.857413, "o", "i"] +[421.945647, "o", "s"] +[422.057603, "o", " "] +[422.199844, "o", "t"] +[422.257072, "o", "h"] +[422.36931, "o", "e"] +[422.432441, "o", " "] +[423.25473, "o", "r"] +[423.329204, "o", "e"] +[423.486095, "o", "t"] +[423.556503, "o", "u"] +[423.658879, "o", "r"] +[423.740909, "o", "n"] +[423.811235, "o", " "] +[423.941111, "o", "a"] +[424.030245, "o", "d"] +[424.169883, "o", "d"] +[424.362463, "o", "r"] +[424.436531, "o", "e"] +[424.621395, "o", "s"] +[424.763605, "o", "s"] +[425.22778, "o", "\r\n"] +[425.228074, "o", "(gdb) "] +[426.180565, "o", "#"] +[426.329978, "o", " "] +[426.674846, "o", "s"] +[427.644279, "o", "e"] +[427.832117, "o", "c"] +[427.945399, "o", "o"] +[428.050368, "o", "n"] +[428.1215, "o", "d"] +[428.252667, "o", " "] +[428.383049, "o", "a"] +[428.500148, "o", "n"] +[428.596744, "o", "d"] +[428.698814, "o", " "] +[428.945383, "o", "r"] +[429.106316, "o", "i"] +[429.645192, "o", "\b\u001b[K"] +[429.767912, "o", "\b\u001b[K"] +[429.845124, "o", "t"] +[430.003863, "o", "h"] +[430.107219, "o", "i"] +[430.255689, "o", "r"] +[430.487167, "o", "d"] +[430.667477, "o", " "] +[431.006023, "o", "a"] +[431.211805, "o", "r"] +[431.292319, "o", "e"] +[431.437362, "o", " "] +[431.56393, "o", "t"] +[431.683208, "o", "h"] +[431.728348, "o", "e"] +[431.865432, "o", " "] +[432.888452, "o", "p"] +[432.977097, "o", "a"] +[433.175822, "o", "r"] +[433.258553, "o", "a"] +[433.531527, "o", "m"] +[434.072679, "o", "e"] +[434.235626, "o", "t"] +[434.331498, "o", "e"] +[434.456163, "o", "r"] +[434.694781, "o", "s"] +[434.879649, "o", " "] +[435.461291, "o", "("] +[435.855804, "o", "f"] +[435.932997, "o", "d"] +[436.744873, "o", "s"] +[436.988719, "o", " "] +[438.082246, "o", "3"] +[438.216148, "o", " "] +[438.350139, "o", "a"] +[438.461137, "o", "n"] +[438.546648, "o", "d"] +[438.645921, "o", " "] +[438.899168, "o", "1"] +[439.219735, "o", ")"] +[439.481293, "o", "\r\n"] +[439.481613, "o", "(gdb) "] +[450.102183, "o", "quit\r\n"] +[450.102822, "o", "A debugging session is active.\r\n\r\n\tInferior 1 [Remote target] will be detached.\r\n\r\nQuit anyway? (y or n) "] +[451.119252, "o", "y"] +[451.379225, "o", "\r\nDetaching from program: /home/tavi/src/linux/vmlinux, Remote target\r\n"] +[451.379742, "o", "Ending remote debugging.\r\n"] +[451.390975, "o", "\u001b]0;tavi@lktp: ~/src/linux/tools/labs\u0007\u001b[01;32mtavi@lktp\u001b[00m:\u001b[01;34m~/src/linux/tools/labs\u001b[00m$ "] +[451.925851, "o", "f"] +[452.122079, "o", "g"] +[452.20423, "o", "\r\n"] +[452.2046, "o", "minicom -D serial.pts\r\n"] +[452.204924, "o", "\u001b[!p\u001b[?3;4l\u001b[4l\u001b>\u001b[?1h\u001b=\u001b[1;1H\u001b[?12l\u001b[?25h\u001b[0m\u001b(B \u001b[2;1HWelcome to minicom 2.7 \u001b[3;1H \u001b[4;1HOPTIONS: I18n \u001b[5;1HCompiled on Feb 7 2016, 13:37:27. \u001b[6;1HPort serial.pts, 23:03:56 \u001b[7;1H \u001b[8;1HPress CTRL-A Z for help on special keys \u001b[9;1H \u001b[10;1H \u001b[11;1Hroot@qemux86:~# # trigger dup2 system call \u001b[12;1Hroot@qemux86:~# echo a > /"] +[452.205008, "o", "tmp/x \u001b[13;1H \u001b[14;1H \u001b[15;1H \u001b[16;1H \u001b[17;1H \u001b[18;1H \u001b[19;1H \u001b[20;1H \u001b[21;1H \u001b[22;1H \u001b[23;1H \u001b[24;1H\u001b[0m\u001b("] +[452.205404, "o", "B\u001b[7mCTRL-A Z for help | 115200 8N1 | NOR | Minicom 2.7 | VT102 | Offline | rial.pts\u001b[13;1H\u001b[?12l\u001b[?25h\u001b[24;1H\u001b[0m\u001b(B \u001b[13;1Hroot@qemux86:~# "] +[453.066691, "o", "\u001b[0m\u001b(B\u001b[7m\u001b[24;1H\u001b[K\u001b[?12l\u001b[?25h\u001b[?25lCTRL-A Z for help | 115200 8N1 | NOR | Minicom 2.7 | VT102 | Offline | rial.pts\u001b[?12l\u001b[?25h\u001b[13;17H"] +[453.274675, "o", "\u001b[8;30H\u001b[?25l\u001b[0m\u001b(B+----------------------+\u001b[9;30H| Leave Minicom? |\u001b[10;30H| No |\u001b[11;30H+----------------------+\u001b[10;51H\u001b[?25l\u001b[10;33H\u001b[0m\u001b(B\u001b[7m Yes "] +[453.425761, "o", "\u001b[?12l\u001b[?25h\u001b[8;1H\u001b[0m\u001b(BPress CTRL-A Z for help on special keys \u001b[9;1H \u001b[10;1H \u001b[11;1Hroot@qemux86:~# # trigger dup2 system call \u001b[13;17H\u001b[0m\u001b(B\u001b[7m\u001b[?12l\u001b[?25h"] +[453.426136, "o", "\u001b[?12l\u001b[?25h\u001b[0m\u001b(B\u001b[H\u001b[2J\u001b[?12l\u001b[?25h\u001b[?1l\u001b>\u001b[!p\u001b[?3;4l\u001b[4l\u001b>"] +[453.42742, "o", "\u001b]0;tavi@lktp: ~/src/linux/tools/labs\u0007\u001b[01;32mtavi@lktp\u001b[00m:\u001b[01;34m~/src/linux/tools/labs\u001b[00m$ "] +[453.929041, "o", "#"] +[454.48124, "o", " "] +[454.772523, "o", "t"] +[454.877335, "o", "h"] +[454.967191, "o", "e"] +[455.064771, "o", " "] +[455.221252, "o", "e"] +[455.36275, "o", "n"] +[455.48508, "o", "d"] +[456.337409, "o", "\r\n"] +[456.3382, "o", "\u001b]0;tavi@lktp: ~/src/linux/tools/labs\u0007\u001b[01;32mtavi@lktp\u001b[00m:\u001b[01;34m~/src/linux/tools/labs\u001b[00m$ "] +[457.092602, "o", "exit\r\n"] diff --git a/refs/pull/405/merge/_images/syscalls-vdso.cast b/refs/pull/405/merge/_images/syscalls-vdso.cast new file mode 100644 index 00000000..08d11b8f --- /dev/null +++ b/refs/pull/405/merge/_images/syscalls-vdso.cast @@ -0,0 +1,299 @@ +{"title": "VDSO", "width": 80, "height": 24, "env": {"TERM": "xterm-256color", "SHELL": "/bin/bash"}, "timestamp": 1519704037, "version": 2, "idle_time_limit": 1.0} +[0.025954, "o", "\u001b]0;tavi@lktp: ~/src/linux/tools/labs\u0007\u001b[01;32mtavi@lktp\u001b[00m:\u001b[01;34m~/src/linux/tools/labs\u001b[00m$ "] +[0.778357, "o", "\r\u001b[12P(reverse-i-search)`':\u001b[C"] +[1.32861, "o", "\b\b\b\u001b[23@m': minicom -D serial.pts\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"] +[1.448449, "o", "\b\b\b\b\b\b\b\b\b\u001b[1@i\u001b[C\u001b[C\u001b[C"] +[1.765225, "o", "\r\u001b]0;tavi@lktp: ~/src/linux/tools/labs\u0007\u001b[01;32mtavi@lktp\u001b[00m:\u001b[01;34m~/src/linux/tools/labs\u001b[00m$ minicom -D serial.pts \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\n"] +[1.769204, "o", "\u001b[!p\u001b[?3;4l\u001b[4l\u001b>\u001b[0m\u001b(B"] +[1.769319, "o", "\u001b[?1h\u001b=\u001b[H\u001b[2J"] +[1.770766, "o", "\u001b[?12l\u001b[?25h"] +[1.770874, "o", "\nWelcome to minicom 2.7\r\n\nOPTIONS: I18n \r\nCompiled on Feb 7 2016, 13:37:27.\r\nPort serial.pts, 05:00:24\r\n\nPress CTRL-A Z for help on special keys\r\n\n"] +[2.416093, "o", "\n"] +[2.418403, "o", "root@qemux86:~# "] +[3.828624, "o", "\r(reverse-i-search)`': "] +[4.158346, "o", "\b\b\bc': cat /proc/$$/maps | grep vdso\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"] +[4.248967, "o", "\b\b\b\b\b\b\b\b\b\b\b ': cat /proc/$$/maps | grep vdso \u001b[11;21Ha': "] +[4.827489, "o", "\r\u001b[P\u001b[P\u001b[P\u001b[P\u001b[P\u001b[P\u001b[P\u001b[Proot@qemux86:~# "] +[4.82862, "o", "\r\n"] +[4.879844, "o", "b7fe1000-b7fe2000 r-xp 00000000 00:00 0 [vdso]"] +[4.880004, "o", "\r\n"] +[4.881875, "o", "root@qemux86:~# "] +[6.142231, "o", "d"] +[6.284442, "o", "d"] +[6.458279, "o", " "] +[6.621989, "o", "i"] +[6.739944, "o", "f"] +[6.869664, "o", " "] +[7.493448, "o", "\b \b"] +[7.874738, "o", "="] +[8.588815, "o", "/"] +[8.637697, "o", "d"] +[8.738769, "o", "e"] +[8.938278, "o", "v"] +[8.984739, "o", "/"] +[9.500486, "o", "$"] +[9.669718, "o", "$"] +[9.933013, "o", "/"] +[10.500669, "o", "m"] +[10.616163, "o", "e"] +[10.693377, "o", "m"] +[10.978277, "o", " "] +[11.216909, "o", "o"] +[11.376459, "o", "f"] +[11.551348, "o", "="] +[12.560851, "o", "v"] +[12.764026, "o", "d"] +[12.85403, "o", "."] +[13.112242, "o", "s"] +[13.185422, "o", "o"] +[13.657544, "o", " "] +[15.232911, "o", "s"] +[15.352051, "o", "k"] +[15.564274, "o", "i"] +[15.669058, "o", "p"] +[16.316486, "o", "="] +[17.003593, "o", "$"] +[18.445474, "o", "("] +[18.601053, "o", "("] +[19.54437, "o", "0"] +[19.660685, "o", "x"] +[20.138912, "o", "b"] +[20.616486, "o", "f"] +[21.48522, "o", "\b \b"] +[22.515307, "o", "7"] +[23.508009, "o", "f"] +[23.790619, "o", "e"] +[24.400251, "o", "1"] +[25.248207, "o", ")"] +[25.375563, "o", ")"] +[26.327645, "o", " "] +[26.726994, "o", "c"] +[26.847455, "o", "o"] +[27.02857, "o", "u"] +[27.276381, "o", "n"] +[27.383646, "o", "t"] +[27.625756, "o", "="] +[27.920608, "o", "1"] +[28.521296, "o", " "] +[29.112339, "o", "b"] +[29.222891, "o", "s"] +[29.743661, "o", "="] +[30.384493, "o", "4"] +[30.485127, "o", "0"] +[30.695845, "o", "9"] +[31.075003, "o", "6"] +[32.188246, "o", "\r\n"] +[32.199355, "o", "dd: "] +[32.19954, "o", "failed to open '/dev/885/mem'"] +[32.199693, "o", ": No such file or directory"] +[32.199842, "o", "\r\n"] +[32.201711, "o", "root@qemux86:~# "] +[33.598384, "o", "dd if=/dev/$$/mem of=vd.so skip=$((0xb7fe1)) count=1 bs=4096"] +[34.061345, "o", "\b"] +[34.562175, "o", "\b"] +[34.593086, "o", "\b"] +[34.624228, "o", "\b"] +[34.655779, "o", "\b"] +[34.686158, "o", "\b"] +[34.718106, "o", "\b"] +[34.747207, "o", "\b"] +[34.777381, "o", "\b"] +[34.808345, "o", "\b"] +[34.838882, "o", "\b"] +[34.87023, "o", "\b"] +[34.901235, "o", "\b"] +[34.931911, "o", "\b"] +[34.962706, "o", "\b"] +[34.994145, "o", "\b"] +[35.025857, "o", "\b"] +[35.055689, "o", "\b"] +[35.086722, "o", "\b"] +[35.117042, "o", "\b"] +[35.148358, "o", "\b"] +[35.179121, "o", "\b"] +[35.210605, "o", "\b"] +[35.240516, "o", "\b"] +[35.271948, "o", "\b"] +[35.30293, "o", "\b"] +[35.334901, "o", "\b"] +[35.364321, "o", "\b"] +[35.396241, "o", "\b"] +[35.426037, "o", "\b"] +[35.456994, "o", "\b"] +[35.488153, "o", "\b"] +[35.519142, "o", "\b"] +[35.550182, "o", "\b"] +[35.581047, "o", "\b"] +[35.611116, "o", "\b"] +[35.641763, "o", "\b"] +[35.672908, "o", "\b"] +[35.703498, "o", "\b"] +[35.734998, "o", "\b"] +[35.766411, "o", "\b"] +[35.796549, "o", "\b"] +[35.82753, "o", "\b"] +[36.601742, "o", "\b"] +[37.09839, "o", "\b"] +[37.128155, "o", "\b"] +[37.163111, "o", "\b"] +[37.192346, "o", "\b"] +[37.223703, "o", "\b"] +[37.253359, "o", "\b"] +[37.284626, "o", "\b"] +[37.608855, "o", "v"] +[37.939538, "o", "\b\u001b[P"] +[38.087974, "o", "\b\u001b[P"] +[38.254754, "o", "\b\u001b[P"] +[38.440987, "o", " /$$/mem of=vd.so skip=$((0xb7fe1)) count=1 bs=4096 \u001b[15;24Hp"] +[38.558039, "o", " /$$/mem of=vd.so skip=$((0xb7fe1)) count=1 bs=4096 \u001b[15;25Hr"] +[38.691276, "o", " /$$/mem of=vd.so skip=$((0xb7fe1)) count=1 bs=4096 \u001b[15;26Ho"] +[38.847178, "o", " /$$/mem of=vd.so skip=$((0xb7fe1)) count=1 bs=4096 \u001b[15;27Hc"] +[39.508168, "o", "\r\n"] +[39.523093, "o", "dd: "] +[39.52328, "o", "/proc/885/mem: cannot skip to specified offset"] +[39.523317, "o", "\r\n"] +[39.52466, "o", "1+0 records in"] +[39.524744, "o", "\r\n"] +[39.524825, "o", "1+0 records out"] +[39.525076, "o", "\r\n"] +[39.525484, "o", "4096 bytes (4.1 kB, 4.0 KiB) copied, 0.00261601 s, 1.6 MB/s"] +[39.525575, "o", "\r\n"] +[39.527474, "o", "root@qemux86:~# "] +[41.610174, "o", "n"] +[41.732264, "o", "m"] +[41.988107, "o", " "] +[42.33858, "o", "-"] +[42.79556, "o", "D"] +[43.104068, "o", " "] +[43.291478, "o", "v"] +[43.55666, "o", "d"] +[43.843116, "o", "."] +[44.185221, "o", "s"] +[44.542652, "o", "o"] +[45.448387, "o", "\r\n"] +[45.491518, "o", "00000000 A LINUX_2.5\r\n"] +[45.49171, "o", "00000000 A LINUX_2.6"] +[45.491843, "o", "\r\n"] +[45.491964, "o", "00000b4c T __kernel_rt_sigreturn"] +[45.492082, "o", "\r\n"] +[45.492159, "o", "00000b40 T __kernel_sigreturn"] +[45.492224, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[45.492353, "o", "00000b2c T __kernel_vsyscall"] +[45.492598, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[45.49281, "o", "00000710 T __vdso_clock_gettime"] +[45.492887, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[45.493019, "o", "000009a0 T __vdso_gettimeofday"] +[45.493104, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[45.493252, "o", "00000b00 T __vdso_time"] +[45.493323, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[45.495654, "o", "root@qemux86:~# "] +[47.899977, "o", "o"] +[48.346053, "o", "b"] +[48.401345, "o", "j"] +[48.663622, "o", "d"] +[48.966338, "o", "u"] +[49.273586, "o", "m"] +[49.392373, "o", "p"] +[49.52031, "o", " "] +[49.715854, "o", "-"] +[50.017434, "o", "d"] +[50.916108, "o", "r"] +[51.076094, "o", " "] +[51.470914, "o", ">"] +[51.659245, "o", " "] +[52.330585, "o", "v"] +[52.682659, "o", "d"] +[53.100659, "o", "s"] +[53.21442, "o", "o"] +[53.522123, "o", "."] +[55.809864, "o", "s"] +[57.590678, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[57.633021, "o", "objdump: "] +[57.633213, "o", "'a.out': No such file"] +[57.633325, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[57.635624, "o", "root@qemux86:~# "] +[59.8835, "o", "objdump -dr > vdso.s"] +[60.157193, "o", "\b"] +[60.660172, "o", "\b"] +[60.689762, "o", "\b"] +[60.722033, "o", "\b"] +[60.752467, "o", "\b"] +[60.783825, "o", "\b"] +[60.813211, "o", "\b"] +[60.845191, "o", "\b"] +[60.875427, "o", "\b"] +[60.905546, "o", "\b"] +[61.100984, "o", "r"] +[61.244992, "o", " "] +[61.660944, "o", " > vdso.s \u001b[24;29Hv"] +[61.996232, "o", " > vdso.s \u001b[24;30Hd"] +[62.139048, "o", " > vdso.s \u001b[24;31H."] +[62.350791, "o", " > vdso.s \u001b[24;32Hs"] +[62.450021, "o", " > vdso.s \u001b[24;33Ho"] +[62.598679, "o", " > vdso.s \u001b[24;34H "] +[62.933485, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[62.974853, "o", "root@qemux86:~# "] +[66.634044, "o", "v"] +[66.745211, "o", "i"] +[66.942786, "o", " "] +[67.232609, "o", "v"] +[67.824023, "o", "d"] +[68.377726, "o", "s"] +[68.437403, "o", "o"] +[68.723205, "o", "."] +[69.712646, "o", "s"] +[69.919804, "o", "\r\n\u001b[23;80H \u001b[24;1H"] +[69.956533, "o", "\u001b[1;1H\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\n\u001b[K\u001b[1;1H\u001b[K\nvd.so: file format elf32-i386\u001b[5;1HDisassembly of section .text:\u001b[7;1H000006d0 <__vdso_clock_gettime@@LINUX_2.6-0x40>:\u001b[8;2H6d0: 55 push %ebp\u001b[9;2H6d1: 89 e5 mov %esp,%ebp\u001b[10;2H6"] +[69.956753, "o", "d3: 53 push %ebx\u001b[11;2H6d4: e8 49 04 00 00 call b22 <__vdso_time@@LINUX_2.6+0x22>\u001b[12;2H6d9: 81 c3 6b fc ff ff add $0xfffffc6b,%ebx\u001b[13;2H6df: 0f ae e8 lfence\u001b[14;2H6e2: 0f 31 rdtsc\u001b[15;2H6e4: 89 c1 mov %eax,%ecx\u001b[16;2H6e6: 8b 83 44 cd ff ff mov -0x32bc(%ebx),%eax\u001b[17;2H6ec: 8b 9b 48 cd ff ff mov -0x32b8(%ebx),%ebx\u001b[18;2H6f2: 39 d3 cmp %edx,%ebx\u001b[19;2H6f4: 72 0e jb 704 <LINUX_2.5@@LINUX_2.5+0x704>\u001b[20;2H6f6: 76 08 jbe 700 <LINUX_2.5@@LINUX_2.5+0x700>\u001b[21;2H6f8: 89 da mov %ebx,%edx\u001b[22;2H6fa: 5b pop %ebx\u001b[23;2H6fb: 5d pop %ebp\u001b[1;1H\u001b[24;1H\u001b[K- vdso.s 1/413 0%\u001b[1;1H"] +[70.48049, "o", "\u001b[24;1H\u001b[K/"] +[71.703477, "o", "v"] +[71.956563, "o", "s"] +[72.061476, "o", "y"] +[72.151126, "o", "s"] +[72.345804, "o", "c"] +[72.43538, "o", "a"] +[72.532243, "o", "l"] +[72.655082, "o", "l"] +[72.868018, "o", "\u001b[1;1H\u001b[1;2H82e: 3d ff c9 9a 3b cmp $0x3b9ac9ff,%eax\u001b[2;1H 833: 77 eb ja 820 <__vdso_cloc"] +[72.868164, "o", "k_gettime@@LINUX_2.6+0x11\u001b[2;80H\u001b[3;2H835: 8b 75 f0 mov -0x10(%ebp),%esi\u001b[4;2H838: 01 0f add %ecx,(%edi)\u001b[5;1H 83a: 89 47 04 mov %eax,0x4(%edi)\u001b[6;2H83d: 85 f6 test %esi,%esi"] +[72.868249, "o", "\u001b[7;1H 83f: 0f 85 24 ff ff ff jne 769 <__vdso_clock_gettime@@LINUX_2.6+0x59\u001b[7;80H\u001b[8;2H845: 89 f9 mov "] +[72.86854, "o", " %edi,%ecx\u001b[9;2H847: b8 09 01 00 00 mov $0x109,%eax\u001b[10;2H84c: 89 da mov %ebx,%edx\u001b[11;2H84e: 8b 5d 08 mov 0x8(%ebp),%ebx \u001b[12;2H851: e8 d6 02 00 00 call b2c <__kernel_vsyscall@@LINUX_2.5>\u001b[13;2H856: 89 d3 mov %edx,%ebx\u001b[14;2H858: 83 c4 10 add $0x10,%esp\u001b[15;2H85b: 5b pop %ebx \u001b[16;2H85c: 5e pop %esi "] +[72.868973, "o", "\u001b[17;2H85d: 5f pop %edi \u001b[18;2H85e: 5d pop %ebp \u001b[19;2H85f: c3 ret \u001b[20;2H860: 8b 45 08 mov 0x8(%ebp),%eax \u001b[21;2H863: 85 c0 test %eax,%ea\u001b[22;2H865: 75 de jne 845 <__vdso_clock_gettime@@LINUX_2.6+0x13\u001b[22;80H\u001b[23;2H867: 89 7d 0c mov %edi,0xc(%ebp)\u001b[12;54H\u001b[24;1H\u001b[K- vdso.s 135/413 32%\u001b[12;54H"] +[73.659739, "o", "\u001b[24;1H\u001b[K/"] +[73.751232, "o", "\u001b[12;54H\u001b[1;2Hac2: e9 fe fe ff ff jmp 9c5 <__vdso_gettimeofday@@LINUX_2.6+0x25>\u001b[1;80H\u001b[2;2Hac7: 8b 97 84 cd ff ff mov -0x327c(%edi),%edx \u001b[2;80H\u001b[3;2Hacd: 8b 5d 0c mov 0xc(%ebp),%ebx \u001b[4;2Had0: 89 13 mov %edx,(%ebx\u001b[5;2Had2: 8b 97 88 cd ff ff mov -0x3278(%edi),%edx\u001b[6;2Had8: 89 53 04 "] +[73.751392, "o", " mov %edx,0x4(%ebx)\u001b[7;2Hadb: eb 95 jmp a72 <__vdso_gettimeofday@@LINUX_2.6+0xd2>\u001b[7;80H\u001b[8;2Hadd: b8 4e 00 00 00 mov $0x4e,%eax\u001b[9;2Hae2: 8b 4d 0c mov 0xc(%ebp),%ecx\u001b[10;2Hae5\u001b[11;2Hae7: 89 f3 mov %esi,%ebx \u001b[12;2Hae9: e8 3e 00\u001b[13;2Haee\u001b[14;2Haf0: e9 7d ff ff ff jmp a72 <__vdso_gettimeofday@@LINUX_2.6+0xd2>\u001b[14;80H\u001b[15;2Haf5: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi\u001b[16;2Haf9: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi\u001b[17;2H \u001b[18;1H00000b00 <__vdso_time@@LINUX_2.6>: \u001b[19;2Hb00: 55 push %ebp\u001b[20;2Hb01: e8 18 00 00 00 call b1e <__vdso_time@@LINUX_2.6+0x1e>\u001b[21;2Hb06: 05 3e f8 ff ff add $0xfffff83e,%eax\u001b[22;2Hb0b: 89 e5 mov %esp,%ebp \u001b[22;80H\u001b[23;2Hb0d: 8b 55 08 mov 0x8(%ebp),%edx\u001b[12;54H\u001b[24;1H\u001b[K- vd"] +[73.751422, "o", "so.s 351/413 84%\u001b[12;54H"] +[74.638384, "o", "\u001b[24;1H\u001b[K/"] +[74.706985, "o", "\u001b[12;54H\u001b[1;2Hb1c: 5d pop %ebp \u001b[1;80H\u001b[2;2Hb1d: c3 ret \u001b[3;2Hb1e: 8b 04 24 mov (%esp),%eax \u001b[4;2Hb21: c3 ret "] +[74.707435, "o", " \u001b[5;2Hb22: 8b 1c 24 mov (%esp),%ebx \u001b[6;2Hb25: c3 ret \u001b[7;2Hb26: 8b 3c 24 mov (%esp),%edi \u001b[7;80H\u001b[8;2Hb29: c3 ret \u001b[9;2Hb2a: 90 nop \u001b[10;2Hb2b: 90 nop \u001b[11;2H \u001b[12;1H00000b2c <__kernel_vsyscall@@LINUX_2.5>: \u001b[13;2Hb2c: 51 push %ecx \u001b[14;2Hb2d: 52 push %edx \u001b[14;80H\u001b[15;2Hb2e: 55 push %ebp \u001b[16;2Hb2f: 89 e5 mov %esp,%ebp \u001b[17;2Hb31: 0f 34 sysenter\u001b[18;1H b33: cd 80 int $0x80"] +[74.707709, "o", "\u001b[19;3H35: 5d pop \u001b[20;3H36: 5a pop %edx \u001b[21;3H37: 59 pop %ecx \u001b[22;3H38: c3 ret \u001b[23;3H39: 90 nop \u001b[12;20H\u001b[24;1H\u001b[K- vdso.s 378/413 91%\u001b[12;20H"] +[75.741371, "o", "\u001b[13;20H\u001b[24;1H\u001b[K- vdso.s 379/413 91%\u001b[13;20H"] +[76.240657, "o", "\u001b[14;20H\u001b[24;1H\u001b[K- vdso.s 380/413 92%\u001b[14;20H"] +[76.271822, "o", "\u001b[15;20H\u001b[24;1H\u001b[K- vdso.s 381/413 92%\u001b[15;20H"] +[76.303272, "o", "\u001b[16;20H\u001b[24;1H\u001b[K- vdso.s 382/413 92%\u001b[16;20H"] +[76.335376, "o", "\u001b[17;20H\u001b[24;1H\u001b[K- vdso.s 383/413 92%\u001b[17;20H"] +[76.365685, "o", "\u001b[18;20H\u001b[24;1H\u001b[K- vdso.s 384/413 92%\u001b[18;20H"] +[76.396024, "o", "\u001b[19;20H\u001b[24;1H\u001b[K- vdso.s 385/413 93%\u001b[19;20H"] +[76.426024, "o", "\u001b[20;20H\u001b[24;1H\u001b[K- vdso.s 386/413 93%\u001b[20;20H"] +[76.633377, "o", "\u001b[21;20H\u001b[24;1H\u001b[K- vdso.s 387/413 93%\u001b[21;20H"] +[76.801144, "o", "\u001b[22;20H\u001b[24;1H\u001b[K- vdso.s 388/413 93%\u001b[22;20H"] +[76.95044, "o", "\u001b[23;20H\u001b[24;1H\u001b[K- vdso.s 389/413 94%\u001b[23;20H"] +[77.101372, "o", "\u001b[1;4Hd: c3 ret \u001b[2;4He: 8b 04 24 mov (%esp),%eax\u001b[3;3H21: c3 ret \u001b[4;4H2: 8b 1c 24 mov (%esp),%ebx\u001b[5;4H5: c3 ret "] +[77.10181, "o", " \u001b[6;4H6: 8b 3c 24 mov (%esp),%edi\u001b[7;4H9: c3 ret \u001b[8;4Ha: 90 nop\u001b[9;4Hb\u001b[10;2H \u001b[11;1H00000b2c <__kernel_vsyscall@@LINUX_2.5>:\u001b[12;1H b2c: 51 push %ecx\u001b[13;4Hd: 52 push %ed\u001b[14;4He: 55 push %ebp\u001b[15;4Hf: 89 e5 mov %esp,%ebp\u001b[16;3H31: 0f 34 sysenter \u001b[17;4H3: cd 80 int $0x80\u001b[18;4H5: 5d pop %ebp \u001b[19;4H6: 5a pop %edx\u001b[20;4H7: 59 pop %ec\u001b[21;4H8: c3 ret \u001b[22;4H9: 90 nop\u001b[23;4Ha\u001b[23;20H\u001b[24;1H\u001b[K- vdso.s 390/413 94%\u001b[23;20H"] +[77.455803, "o", "\u001b[1;4He: 8b 04 24 mov (%esp),%eax\u001b[2;3H21: c3 ret \u001b[3;4H2: 8b 1c 24 mov (%esp),%ebx\u001b[4;4H5: c3 ret \u001b[5;4H6: 8b 3c 24 mov (%esp),%edi\u001b[6;4H9: c3 ret \u001b[7;4Ha: 90 nop\u001b[8;4Hb\u001b[9;2H \u001b[10;1H00000b2c <__kernel_vsyscall@@LINUX_2.5>:\u001b[11;1H b2c: 51 push %ecx\u001b[12;4H"] +[77.455926, "o", "d: 52 push %ed\u001b[13;4He: 55 push %ebp\u001b[14;4Hf: 89 e5 mov %esp,%ebp\u001b[15;3H31: 0f 34 sysenter \u001b[16;4H3: cd 80 int $0x80\u001b[17;4H5: 5d pop %ebp \u001b[18;4H6: 5a pop %edx\u001b[19;4H7: 59 pop %ec\u001b[20;4H8: c3 ret \u001b[21;4H9: 90 nop\u001b[22;4Ha\u001b[23;4Hb\u001b[23;20H\u001b[24;1H\u001b[K- vdso.s 391/413 94%\u001b[23;20H"] +[85.076246, "o", "\u0007\u001b[24;1H\u001b[K- vdso.s 391/413 94%\u001b[23;20H"] +[85.088716, "o", "\u001b[24;1H\u001b[K:"] +[85.733973, "o", "q"] +[86.200246, "o", "!"] +[86.579774, "o", "\u001b[23;20H\u001b[24;1H\u001b[K- vdso.s 391/413 94%\u001b[23;20H"] +[86.580204, "o", "\u001b[24;1H\u001b[K"] +[86.586893, "o", "root@qemux86:~# "] +[87.180212, "o", "\u001b[0m\u001b(B\u001b[7m\r\u001b[K\u001b[?12l\u001b[?25h"] +[87.180527, "o", "\u001b[?25lCTRL-A Z for help | 115200 8N1 | NOR | Minicom 2.7 | VT102 | Offline | rial.pts\u001b[?12l\u001b[?25h\u001b[24;17H"] +[87.375774, "o", "\u001b[8;30H\u001b[?25l\u001b[0m\u001b(B+----------------------+\u001b[9;30H| Leave Minicom? |\u001b[10;30H| No |\u001b[11;30H+----------------------+\u001b[10;51H\u001b[?25l\u001b[10;33H\u001b[0m\u001b(B\u001b[7m Yes "] +[87.691546, "o", "\u001b[?12l\u001b[?25h\u001b[8;1H\u001b[0m\u001b(B b2b: 90 nop \u001b[9;1H \u001b[10;1H00000b2c <__kernel_vsyscall@@LINUX_2.5>: \u001b[11;1H b2c: 51 push %ecx \u001b[24;17H\u001b[0m\u001b(B\u001b[7m"] +[87.691675, "o", "\u001b[?12l\u001b[?25h"] +[87.691981, "o", "\u001b[?12l\u001b[?25h\u001b[0m\u001b(B\u001b[H\u001b[2J\u001b[?12l\u001b[?25h\u001b[?1l\u001b>\u001b[!p\u001b[?3;4l\u001b[4l\u001b>"] +[87.69329, "o", "\u001b]0;tavi@lktp: ~/src/linux/tools/labs\u0007\u001b[01;32mtavi@lktp\u001b[00m:\u001b[01;34m~/src/linux/tools/labs\u001b[00m$ "] +[88.615113, "o", "exit\r\n"] diff --git a/refs/pull/405/merge/_images/tso.png b/refs/pull/405/merge/_images/tso.png new file mode 100644 index 00000000..a43f230d Binary files /dev/null and b/refs/pull/405/merge/_images/tso.png differ diff --git a/refs/pull/405/merge/_images/tso1.png b/refs/pull/405/merge/_images/tso1.png new file mode 100644 index 00000000..a43f230d Binary files /dev/null and b/refs/pull/405/merge/_images/tso1.png differ diff --git a/refs/pull/405/merge/_images/write.png b/refs/pull/405/merge/_images/write.png new file mode 100644 index 00000000..d87abc99 Binary files /dev/null and b/refs/pull/405/merge/_images/write.png differ diff --git a/refs/pull/405/merge/_images/write1.png b/refs/pull/405/merge/_images/write1.png new file mode 100644 index 00000000..d87abc99 Binary files /dev/null and b/refs/pull/405/merge/_images/write1.png differ diff --git a/refs/pull/405/merge/_images/write2.png b/refs/pull/405/merge/_images/write2.png new file mode 100644 index 00000000..e533a36a Binary files /dev/null and b/refs/pull/405/merge/_images/write2.png differ diff --git a/refs/pull/405/merge/_images/write21.png b/refs/pull/405/merge/_images/write21.png new file mode 100644 index 00000000..e533a36a Binary files /dev/null and b/refs/pull/405/merge/_images/write21.png differ diff --git a/refs/pull/405/merge/_images/xen-overview.png b/refs/pull/405/merge/_images/xen-overview.png new file mode 100644 index 00000000..9294dfba Binary files /dev/null and b/refs/pull/405/merge/_images/xen-overview.png differ diff --git a/refs/pull/405/merge/_images/xen-overview1.png b/refs/pull/405/merge/_images/xen-overview1.png new file mode 100644 index 00000000..9294dfba Binary files /dev/null and b/refs/pull/405/merge/_images/xen-overview1.png differ diff --git a/refs/pull/405/merge/_sources/index.rst.txt b/refs/pull/405/merge/_sources/index.rst.txt new file mode 100644 index 00000000..e81a9a0c --- /dev/null +++ b/refs/pull/405/merge/_sources/index.rst.txt @@ -0,0 +1,88 @@ +===================== +Linux Kernel Teaching +===================== + +This is a collection of lectures and labs Linux kernel topics. The +lectures focus on theoretical and Linux kernel exploration. + + +The labs focus on device drivers topics and they resemble "howto" +style documentation. Each topic has two parts: + +* a walk-through the topic which contains an overview, the main + abstractions, simple examples and pointers to APIs + +* a hands-on part which contains a few exercises that should be + resolved by the student; to focus on the topic at hand, the student + is presented with a starting coding skeleton and with in-depth tips + on how to solve the exercises + +This content is based on the `Operatings Systems 2 +<http://ocw.cs.pub.ro/courses/so2>`_ course from the Computer Science +and Engineering Department, the Faculty of Automatic Control and +Computers, University POLITEHNICA of Bucharest. + +You can get the latest version at http://github.com/linux-kernel-labs. + +To get started build the documentation from the sources after +installing docker-compose on you host: + +.. code-block:: c + + cd tools/labs && make docker-docs + +then point your browser at **Documentation/output/labs/index.html**. + +Alternatively, you can build directly on the host (see +tools/labs/docs/Dockerfile for dependencies): + +.. code-block:: c + + cd tools/labs && make docs + +.. toctree:: + + so2/index.rst + +.. toctree:: + :caption: Lectures + + lectures/intro.rst + lectures/syscalls.rst + lectures/processes.rst + lectures/interrupts.rst + lectures/smp.rst + lectures/address-space.rst + lectures/memory-management.rst + lectures/fs.rst + lectures/debugging.rst + lectures/networking.rst + lectures/arch.rst + lectures/virt.rst + +.. toctree:: + :caption: Labs + + labs/infrastructure.rst + labs/introduction.rst + labs/kernel_modules.rst + labs/kernel_api.rst + labs/device_drivers.rst + labs/interrupts.rst + labs/deferred_work.rst + labs/block_device_drivers.rst + labs/filesystems_part1.rst + labs/filesystems_part2.rst + labs/networking.rst + labs/arm_kernel_development.rst + labs/memory_mapping.rst + labs/device_model.rst + labs/kernel_profiling.rst + +.. toctree:: + :caption: Useful info + + info/vm.rst + info/extra-vm.rst + info/contributing.rst + diff --git a/refs/pull/405/merge/_sources/info/contributing.rst.txt b/refs/pull/405/merge/_sources/info/contributing.rst.txt new file mode 100644 index 00000000..d18c5ae1 --- /dev/null +++ b/refs/pull/405/merge/_sources/info/contributing.rst.txt @@ -0,0 +1,206 @@ +================================= +Contributing to linux-kernel-labs +================================= + +``linux-kernel-labs`` is an open platform. +You can help it get better by contributing to the documentation, exercises or +the infrastructure. +All contributions are welcome, no matter if they are just fixes for typos or +new sections in the documentation. + +All information required for making a contribution can be found in the +`linux-kernel-labs Linux repo <https://github.com/linux-kernel-labs/linux>`_. +In order to change anything, you need to create a Pull Request (``PR``) +from your own fork to this repository. +The PR will be reviewed by the members of the team and will be merged once +any potential issue is fixed. + +******************** +Repository structure +******************** + +The `linux-kernel-labs repo <https://github.com/linux-kernel-labs/linux>`_ is +a fork of the Linux kernel repo, with the following additions: + + * ``/tools/labs``: contains the labs and the :ref:`virtual machine (VM) infrastructure<vm_link>` + + * ``tools/labs/templates``: contains the skeletons sources + * ``tools/labs/qemu``: contains the qemu VM configuration + + * ``/Documentation/teaching``: contains the sources used to generate this + documentation + +************************** +Building the documentation +************************** + +To build the documentation, navigate to ``tools/labs`` and run the following +command: + +.. code-block:: bash + + make docs + +.. note:: + The command should install all the required packages. + In some cases, installing the packages or building the documentation might + fail, because of broken dependencies versions. + + Instead of struggling to fix the dependencies, the simplest way to build + the documentation is using a `Docker <https://www.docker.com/>`_. + First, install ``docker`` and ``docker-compose`` on your host, and then run: + + .. code-block:: bash + + make docker-docs + + The first run might take some time, but subsequent builds will be faster. + +*********************** +Creating a contribution +*********************** + +Forking the repository +====================== + +1. If you haven't done it already, clone the + `linux-kernel-labs repo <https://github.com/linux-kernel-labs/linux>`_ + repository locally: + + .. code-block:: bash + + $ mkdir -p ~/src + $ git clone git@github.com:linux-kernel-labs/linux.git ~/src/linux + +2. Go to https://github.com/linux-kernel-labs/linux, make sure you are logged + in and click ``Fork`` in the top right of the page. + +3. Add the forked repo as a new remote to the local repo: + + .. code-block:: bash + + $ git remote add my_fork git@github.com:<your_username>/linux.git + +Now, you can push to your fork by using ``my_fork`` instead of ``origin`` +(e.g. ``git push my_fork master``). + +Creating a pull request +======================= + +.. warning:: + + Pull requests must be created from their own branches, which are started from + ``master``. + +1. Go to the master branch and make sure you have no local changes: + + .. code-block:: bash + + student@eg106:~/src/linux$ git checkout master + student@eg106:~/src/linux$ git status + On branch master + Your branch is up-to-date with 'origin/master'. + nothing to commit, working directory clean + + +2. Make sure the local master branch is up-to-date with linux-kernel-labs: + + .. code-block:: bash + + student@eg106:~/src/linux$ git pull origin master + + .. note:: + + You can also push the latest master to your forked repo: + + .. code-block:: bash + + student@eg106:~/src/linux$ git push my_fork master + +3. Create a new branch for your change: + + .. code-block:: bash + + student@eg106:~/src/linux$ git checkout -b <your_branch_name> + +4. Make some changes and commit them. In this example, we are going to change + ``Documentation/teaching/index.rst``: + + .. code-block:: bash + + student@eg106:~/src/linux$ vim Documentation/teaching/index.rst + student@eg106:~/src/linux$ git add Documentation/teaching/index.rst + student@eg106:~/src/linux$ git commit -m "<commit message>" + + .. warning:: + + The commit message must include a relevant description of your change + and the location of the changed component. + + Examples: + + * ``documentation: index: Fix typo in the first section`` + * ``labs: block_devices: Change printk log level`` + +5. Push the local branch to your forked repository: + + .. code-block:: bash + + student@eg106:~/src/linux$ git push my_fork <your_branch_name> + +6. Open the Pull Request + + * Go to https://github.com and open your forked repository page + * Click ``New pull request``. + * Make sure base repository (left side) is ``linux-kernel-labs/linux`` and the + base is master. + * Make sure the head repository (right side) is your forked repo and the + compare branch is your pushed branch. + * Click ``Create pull request``. + +Making changes to a Pull Request +================================ + +After receiving feedback for your changes, you might need to update the Pull +Request. +Your goal is to do a new push on the same branch. For this, follow the next steps: + +1. Make sure your branch is still up to date with the ``linux-kernel-labs`` repo + ``master`` branch. + + .. code-block:: bash + + student@eg106:~/src/linux$ git fetch origin master + student@eg106:~/src/linux$ git rebase FETCH_HEAD + + .. note:: + + If you are getting conflicts, it means that someone else modified the same + files/lines as you and already merged the changes since you opened the + Pull Request. + + In this case, you will need to fix the conflicts by editing the + conflicting files manually (run ``git status`` to see these files). + After fixing the conflicts, add them using ``git add`` and then run + ``git rebase --continue``. + + +2. Apply the changes to your local files +3. Commit the changes. We want all the changes to be in the same commit, so + we will amend the changes to the initial commit. + + .. code-block:: bash + + student@eg106:~/src/linux$ git add Documentation/teaching/index.rst + student@eg106:~/src/linux$ git commit --amend + +4. Force-push the updated commit: + + .. code-block:: bash + + student@eg106:~/src/linux$ git push my_fork <your_branch_name> -f + + After this step, the Pull Request is updated. It is now up to the + linux-kernel-labs team to review the pull request and integrate your + contributions in the main project. + diff --git a/refs/pull/405/merge/_sources/info/extra-vm.rst.txt b/refs/pull/405/merge/_sources/info/extra-vm.rst.txt new file mode 100644 index 00000000..bd3b997c --- /dev/null +++ b/refs/pull/405/merge/_sources/info/extra-vm.rst.txt @@ -0,0 +1,166 @@ +===================================== +Customizing the Virtual Machine Setup +===================================== + +Connect to the Virtual Machine via SSH +-------------------------------------- + +The default Yocto image for the QEMU virtual machine +(``core-image-minimal-qemu``) provides the minimal functionality to run the +kernel and kernel modules. For extra features, such as an SSH connection, +a more complete image is required, such as ``core-image-sato-dev-qemu``. + +To use the new image, update the ``YOCTO_IMAGE`` variable in +``tools/labs/qemu/Makefile``: + +.. code-block:: shell + + YOCTO_IMAGE = core-image-sato-qemu$(ARCH).ext4 + +When you start the virtual machine the first time using ``make boot`` with the +new image configuration, it will download the image and then boot the virtual +machine. The image is larger (around 400MB) than the minimal image so expect +some time for the download. + +You then enter the virtual machine via ``minicom``, determine the IP address of +the ``eth0`` interface an then you can connect to the virtual machine via SSH: + +.. code-block:: shell + + $ minicom -D serial.pts + Poky (Yocto Project Reference Distro) 2.3 qemux86 /dev/hvc0 + + qemux86 login: root + root@qemux86:~# ip a s + 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 + inet 127.0.0.1/8 scope host lo + valid_lft forever preferred_lft forever + inet6 ::1/128 scope host + valid_lft forever preferred_lft forever + 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000 + link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff + inet 172.213.0.18/24 brd 172.213.0.255 scope global eth0 + valid_lft forever preferred_lft forever + inet6 fe80::5054:ff:fe12:3456/64 scope link + valid_lft forever preferred_lft forever + 3: sit0@NONE: <NOARP> mtu 1480 qdisc noop qlen 1000 + link/sit 0.0.0.0 brd 0.0.0.0 + + $ ssh -l root 172.213.0.18 + The authenticity of host '172.213.0.18 (172.213.0.18)' can't be established. + RSA key fingerprint is SHA256:JUWUcD7LdvURNcamoPePMhqEjFFtUNLAqO+TtzUiv5k. + Are you sure you want to continue connecting (yes/no)? yes + Warning: Permanently added '172.213.0.18' (RSA) to the list of known hosts. + root@qemux86:~# uname -a + Linux qemux86 4.19.0+ #3 SMP Sat Apr 4 22:45:18 EEST 2020 i686 GNU/Linux + +Connecting a Debugger to the Virtual Machine Kernel +--------------------------------------------------- + +You can use GDB to connect to the running virtual machine kernel and inspect +the state of the kernel. You run ``make gdb`` in ``tools/labs/``: + +.. code-block:: shell + + .../linux/tools/labs$ make gdb + ln -fs /home/tavi/src/linux/vmlinux vmlinux + gdb -ex "target remote localhost:1234" vmlinux + GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1 + Copyright (C) 2016 Free Software Foundation, Inc. + License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> + This is free software: you are free to change and redistribute it. + There is NO WARRANTY, to the extent permitted by law. Type "show copying" + and "show warranty" for details. + This GDB was configured as "x86_64-linux-gnu". + Type "show configuration" for configuration details. + For bug reporting instructions, please see: + <http://www.gnu.org/software/gdb/bugs/>. + Find the GDB manual and other documentation resources online at: + <http://www.gnu.org/software/gdb/documentation/>. + For help, type "help". + Type "apropos word" to search for commands related to "word"... + Reading symbols from vmlinux...done. + Remote debugging using localhost:1234 + 0xc13cf2f2 in native_safe_halt () at ./arch/x86/include/asm/irqflags.h:53 + 53asm volatile("sti; hlt": : :"memory"); + (gdb) bt + #0 0xc13cf2f2 in native_safe_halt () at ./arch/x86/include/asm/irqflags.h:53 + #1 arch_safe_halt () at ./arch/x86/include/asm/irqflags.h:95 + #2 default_idle () at arch/x86/kernel/process.c:341 + #3 0xc101f136 in arch_cpu_idle () at arch/x86/kernel/process.c:332 + #4 0xc106a6dd in cpuidle_idle_call () at kernel/sched/idle.c:156 + #5 do_idle () at kernel/sched/idle.c:245 + #6 0xc106a8c5 in cpu_startup_entry (state=<optimized out>) + at kernel/sched/idle.c:350 + #7 0xc13cb14a in rest_init () at init/main.c:415 + #8 0xc1507a7a in start_kernel () at init/main.c:679 + #9 0xc10001da in startup_32_smp () at arch/x86/kernel/head_32.S:368 + #10 0x00000000 in ?? () + (gdb) + +Rebuild the Kernel Image +------------------------ + +The kernel image is built the first time the VM is started. To rebuild the +kernel remove the kernel image file defined by the ``ZIMAGE`` variable in +``tools/labs/qemu/Makefile``: + +.. code-block:: shell + + ZIMAGE = $(KDIR)/arch/$(ARCH)/boot/$(b)zImage + +Typically the full path of the kernel is ``arch/x86/boot/bzImage``. + +Once removed the kernel image is rebuild by using: + +.. code-block:: shell + + ~/src/linux/tools/labs$ make zImage + +or simply starting the virtual machine + +.. code-block:: shell + + ~/src/linux/tools/labs$ make boot + +Using Docker containers +----------------------- + +If your setup doesn't allow the installation of the packages required for the +laboratory setup, you can build and run a container that has all the setup +already prepared for the virtual machine environment. + +In order to run the containerized setup, you need to install the following +packages: + +* ``docker`` +* ``docker-compose`` + +In order to run the container infrastructure run the following command in the +``tools/labs/`` directory: + +.. code-block:: shell + + sergiu@local:~/src/linux/tools/labs$ make docker-kernel + ... + ubuntu@so2:~$ + +The first time you run the command above, it will take a long time, because you +will have to build the container environment and install the required +applications. + +Every time you run the ``make docker-kernel`` command, another shell will +connect to the container. This will allow you to work with multiple tabs. + +All the commands that you would use in the regular environment can be used in +the containerized environment. + +The linux repository is mounted in the ``/linux`` directory. All changes +you will make here will also be seen on your local instance. + +In order to stop the container use the following command: + +.. code-block:: shell + + make stop-docker-kernel diff --git a/refs/pull/405/merge/_sources/info/vm.rst.txt b/refs/pull/405/merge/_sources/info/vm.rst.txt new file mode 100644 index 00000000..7d3be932 --- /dev/null +++ b/refs/pull/405/merge/_sources/info/vm.rst.txt @@ -0,0 +1,130 @@ +.. _vm_link: + +===================== +Recommended Setup +===================== +The simplest way to achieve a functional setup is to follow the steps listed in `this repo <https://gitlab.cs.pub.ro/so2/so2-labs>`__. + +===================== +Virtual Machine Setup +===================== + +Practice work is designed to run on a QEMU based virtual machine. Kernel code +is developed and built on the host machine and then deployed and run on the +virtual machine. + +In order to run and use the virtual machine the following packages are required +on a Debian/Ubuntu system: + +* ``flex`` +* ``bison`` +* ``build-essential`` +* ``gcc-multilib`` +* ``libncurses5-dev`` +* ``qemu-system-x86`` +* ``qemu-system-arm`` +* ``python3`` +* ``minicom`` + +The ``kvm`` package is not strictly required, but will make the virtual machine +faster by using KVM support (with the ``-enable-kvm`` option to QEMU). If ``kvm`` +is absent, the virtual machine will still run (albeit slower) using emulation. + +The virtual machine setup uses prebuild Yocto images that it downloads and a +kernel image that it builds itself. The following images are supported: + +* ``core-image-minimal-qemu`` +* ``core-image-minimal-dev-qemu`` +* ``core-image-sato-dev-qemu`` +* ``core-image-sato-qemu`` +* ``core-image-sato-sdk-qemu`` + +By default, ``core-image-minimal-qemu`` it used. This setting can be changed by +updating the ``YOCTO_IMAGE`` variable in ``tools/labs/qemu/Makefile``. + +Starting the Virtual Machine +---------------------------- + +You start the virtual machine in the ``tools/labs/`` folder by running ``make +boot``: + +.. code-block:: shell + + .../linux/tools/labs$ make boot + +The first run of the ``make boot`` command will compile the kernel image and it +will take longer. Subsequent runs will only start the QEMU virtual machine, +with verbose output provided: + +.. code-block:: shell + + .../linux/tools/labs$ make boot + mkdir /tmp/tmp.7rWv63E9Wf + sudo mount -t ext4 -o loop core-image-minimal-qemux86.ext4 /tmp/tmp.7rWv63E9Wf + sudo make -C /home/razvan/school/so2/linux.git modules_install INSTALL_MOD_PATH=/tmp/tmp.7rWv63E9Wf + make: Entering directory '/home/razvan/school/so2/linux.git' + INSTALL crypto/crypto_engine.ko + INSTALL drivers/crypto/virtio/virtio_crypto.ko + INSTALL drivers/net/netconsole.ko + DEPMOD 4.19.0+ + make: Leaving directory '/home/razvan/school/so2/linux.git' + sudo umount /tmp/tmp.7rWv63E9Wf + rmdir /tmp/tmp.7rWv63E9Wf + sleep 1 && touch .modinst + qemu/create_net.sh tap0 + + dnsmasq: failed to create listening socket for 172.213.0.1: Address already in use + qemu/create_net.sh tap1 + + dnsmasq: failed to create listening socket for 127.0.0.1: Address already in use + /home/razvan/school/so2/linux.git/tools/labs/templates/assignments/6-e100/nttcp -v -i & + nttcp-l: nttcp, version 1.47 + nttcp-l: running in inetd mode on port 5037 - ignoring options beside -v and -p + bind: Address already in use + nttcp-l: service-socket: bind:: Address already in use, errno=98 + ARCH=x86 qemu/qemu.sh -kernel /home/razvan/school/so2/linux.git/arch/x86/boot/bzImage -device virtio-serial -chardev pty,id=virtiocon0 -device virtconsole,chardev=virtiocon0 -serial pipe:pipe1 -serial pipe:pipe2 -netdev tap,id=tap0,ifname=tap0,script=no,downscript=no -net nic,netdev=tap0,model=virtio -netdev tap,id=tap1,ifname=tap1,script=no,downscript=no -net nic,netdev=tap1,model=i82559er -drive file=core-image-minimal-qemux86.ext4,if=virtio,format=raw -drive file=disk1.img,if=virtio,format=raw -drive file=disk2.img,if=virtio,format=raw --append "root=/dev/vda loglevel=15 console=hvc0" --display none -s + qemu-system-i386: -chardev pty,id=virtiocon0: char device redirected to /dev/pts/68 (label virtiocon0) + +.. note:: To show the QEMU console use + +.. code-block:: shell + + .../linux/tools/labs$ QEMU_DISPLAY=gtk make boot + + This will show the VGA output and will also give + access to the standard keyboard. + +.. note:: The virtual machine setup scripts and configuration files are located + in ``tools/labs/qemu/``. + +.. _vm_interaction_link: + +Connecting to the Virtual Machine +--------------------------------- + +Once the virtual machine is started you can connect to it on the serial port. A +symbolic link named ``serial.pts`` is created to the emulated serial port +device: + +.. code-block:: shell + + .../linux/tools/labs$ ls -l serial.pts + lrwxrwxrwx 1 razvan razvan 11 Apr 1 08:03 serial.pts -> /dev/pts/68 + +On the host you use the ``minicom`` command to connect to the virtual machine +via the ``serial.pts`` link: + +.. code-block:: shell + + .../linux/tools/labs$ minicom -D serial.pts + [...] + Poky (Yocto Project Reference Distro) 2.3 qemux86 /dev/hvc0 + + qemux86 login: root + root@qemux86:~# + +.. note:: When you connect to the virtual machine, simply enter ``root`` at the + login prompt and you will get a root console, no password required. + +.. note:: You exit ``minicom`` by pressing ``Ctrl+a`` and then ``x``. You will + get a confirmation prompt and then you will exit ``minicom``. diff --git a/refs/pull/405/merge/_sources/labs/arm_kernel_development.rst.txt b/refs/pull/405/merge/_sources/labs/arm_kernel_development.rst.txt new file mode 100644 index 00000000..ade020c4 --- /dev/null +++ b/refs/pull/405/merge/_sources/labs/arm_kernel_development.rst.txt @@ -0,0 +1,387 @@ +========================= +Kernel Development on ARM +========================= + +Lab objectives +============== + +* get a feeling of what System on a Chip (SoC) means +* get familiar with embedded world using ARM as a supported architecture +* understand what a Board Support Package means (BSP) +* compile and boot an ARM kernel with Qemu using i.MX6UL platform as an example +* get familiar with hardware description using Device Trees + +System on a Chip +================ + +A System on a Chip (**SoC**) is an integrated circuit (**IC**) that integrates an entire system onto it. The components +that can be usually found on an SoC include a central processing unit (**CPU**), memory, input/output ports, storage devices +together with more sophisticated modules like audio digital interfaces, neural processing units (**NPU**) or graphical +processing units (**GPU**). + +SoCs can be used in various applications most common are: + - consumer electronics (TV sets, mobile phones, video game consoles) + - industrial computers (medical imaging, etc) + - automotive + - home appliances + +The leading architecture for SoCs is **ARM**. Worth mentioning here is that there are also x86-based SoCs platforms. Another thing +we need to keep an eye on is **RISC-V** an open standard instruction set architecture. + +A simplified view of an **ARM** platform is shown in the image below: + +.. image:: ../res/schematic.png + :align: center + +We will refer as a reference platform at NXP's `i.MX6UL <imx6ul>`_ platform, but in general all SoC's contain the following building blocks: + + - one or more CPU cores + - a system bus + - clock and reset module + + - PLL + - OSC + - reset controller + + - interrupt controller + - timers + - memory controller + - peripheral controllers + + - `I2C <https://en.wikipedia.org/wiki/I%C2%B2C>`_ + - `SPI <https://en.wikipedia.org/wiki/Serial_Peripheral_Interface>`_ + - `GPIO <https://en.wikipedia.org/wiki/General-purpose_input/output>`_ + - `Ethernet <https://en.wikipedia.org/wiki/Network_interface_controller>`_ (for network) + - `uSDHC <https://en.wikipedia.org/wiki/MultiMediaCard>`_ (for storage) + - USB + - `UART <https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter>`_ + - `I2S <https://en.wikipedia.org/wiki/I%C2%B2S>`_ (for sound) + - eLCDIF (for LCD Panel) + +Here is the complete block diagram for i.MX6UL platform: + +.. image:: https://www.nxp.com/assets/images/en/block-diagrams/IMX6UL-BD.jpg + :alt: IMX6UL-BD + :width: 60 % + :align: center + +i.MX6UL Evaluation Kit board looks like this: + +.. image:: https://www.compulab.com/wp-content/gallery/sbc-imx6ul/compulab_sbc-imx6ul_single-board-computer.jpg + :alt: imx6ul-evk + :width: 60 % + :align: center + +Other popular SoC boards: + + * `Broadcom Raspberry Pi <https://en.wikipedia.org/wiki/Raspberry_Pi>`_ + * `Texas Instruments Beagle board <https://en.wikipedia.org/wiki/BeagleBoard>`_ + * `Odroid Xu4 <https://wiki.odroid.com/odroid-xu4/odroid-xu4>`_ + * `Nvidia Jetson Nano <https://developer.nvidia.com/embedded/jetson-nano-developer-kit>`_ + +Board Support package +===================== + +A board support package (**BSP**) is the minimal set of software packages that allow to demonstrate the capabilities of a certain hardware platform. This includes: + + - toolchain + - bootloader + - Linux kernel image, device tree files and drivers + - root filesystem + +Semiconductor manufacturers usually provide a **BSP** together with an evaluation board. BSP is typically bundled using `Yocto <https://www.yoctoproject.org/>`_ + +Toolchain +========= +Because our development machines are mostly x86-based we need a cross compiler that can produce executable +code for ARM platform. + +We can build our own cross compiler from scratch using https://crosstool-ng.github.io/ or we can install one + +.. code-block:: bash + + $ sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf # for arm32 + $ sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu # for arm64 + +There are several of toolchain binaries depending on the configuration: + + - With "arm-eabi-gcc" you have the Linux system C library which will make calls into the kernel IOCTLs, e.g. for allocating memory pages to the process. + - With "arm-eabi-none-gcc" you are running on platform which doesn't have an operating system at all - so the C library is different to cope with that. + +Compiling the Linux kernel on ARM +--------------------------------- + +Compile the kernel for 32bit ARM boards: + +.. code-block:: bash + + # select defconfig based on your platform + $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make imx_v6_v7_defconfig + # compile the kernel + $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make -j8 + +Compile the kernel for 64bit ARM boards: + +.. code-block:: bash + + # for 64bit ARM there is a single config for all supported boards + $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make defconfig + # compile the kernel + $ ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make -j8 + +Linux kernel image +================== + +The kernel image binary is named ``vmlinux`` and it can be found in the root of the kernel tree. Compressed image used for booting can be found under: + +- ``arch/arm/boot/Image``, for arm32 +- ``arch/arm64/boot/Image``, for arm64 + +.. code-block:: bash + + $ file vmlinux + vmlinux: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, not stripped + + $ file vmlinux + vmlinux: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), statically linked, not stripped + +Rootfs +====== + +The root filesystem (``rootfs``) is the filesystem mounted at the top of files hierarchy (``/``). It should contain at least +the critical files allowing the system to boot to a shell. + +.. code-block:: bash + + root@so2$ tree -d -L 2 + ├── bin + ├── boot + ├── dev + ├── etc + ├── home + │ └── root + ├── lib + │ └── udev + ├── mnt + ├── proc + ├── sbin + │ └── init + ├── sys + ├── usr + │ ├── bin + │ ├── include + │ ├── lib + └── var + +As for ``x86`` we will make use of Yocto rootfs images. In order to download an ``ext4`` rootfs image for ``arm32`` one needs to run: + +.. code-block:: bash + + $ cd tools/labs/ + $ ARCH=arm make core-image-minimal-qemuarm.ext4 + +Device tree +=========== + +Device tree (**DT**) is a tree structure used to describe the hardware devices in a system. Each node in the tree describes a device hence it is called **device node**. DT was introduced +to provide a way to discover non-discoverable hardware (e.g a device on an I2C bus). This information was previously stored inside the source code for the Linux kernel. This meant that +each time we needed to modify a node for a device the kernel needed to be recompiled. This no longer holds true as device tree and kernel image are separate binaries now. + +Device trees are stored inside device tree sources (*.dts*) and compiled into device tree blobs (*.dtb*). + +.. code-block:: bash + + # compile dtbs + $ make dtbs + + # location for DT sources on arm32 + $ ls arch/arm/boot/dts/ + imx6ul-14x14-evk.dtb imx6ull-14x14-evk.dtb bcm2835-rpi-a-plus.dts + + # location for DT source on arm64 + $ ls arch/arm64/boot/dts/<vendor> + imx8mm-evk.dts imx8mp-evk.dts + +The following image is a represantation of a simple device tree, describing board type, cpu and memory. + +.. image:: ../res/dts_node.png + :align: center + +Notice that a device tree node can be defined using ``label: name@address``: + + - ``label``, is an identifier used to reference the node from other places + - ``name``, node identifier + - ``address``, used to differentiate nodes with the same name. + +A node might contain several properties arranged in the ``name = value`` format. The name is a string +and the value can be bytes, strings, array of strings. + +Here is an example: + +.. code:: c + + / { + node@0 { + empty-property; + string-property = "string value"; + string-list-property = "string value 1", "string value 2"; + int-list-property = <value1 value2>; + + child-node@0 { + child-empty-property; + child-string-property = "string value"; + child-node-reference = <&child-node1>; + }; + + child-node1: child-node@1 { + child-empty-property; + child-string-property = "string value"; + }; + }; + }; + +Qemu +==== + +We will use ``qemu-system-arm`` to boot 32bit ARM platforms. Although, this can be installed from official distro repos, for example: + +.. code:: bash + + sudo apt-get install -y qemu-system-arm + +We strongly recommend using latest version of ``qemu-system-arm`` build from sources: + +.. code:: bash + + $ git clone https://gitlab.com/qemu-project/qemu.git + $ ./configure --target-list=arm-softmmu --disable-docs + $ make -j8 + $ ./build/qemu-system-arm + +Exercises +========= + +.. include:: ../labs/exercises-summary.hrst +.. |LAB_NAME| replace:: arm_kernel_development + +.. warning:: + + The rules for working with the virtual machine for ``ARM`` are modified as follows + + .. code-block:: shell + + # modules build + tools/labs $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make build + # modules copy + tools/labs $ ARCH=arm make copy + # kernel build + $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make -j8 + +0. Intro +-------- + +Inspect the following locations in the Linux kernel code and identify platforms and vendors using +ARM architecture: + + - 32-bit: ``arch/arm/boot/dts`` + - 64-bit: ``arch/arm64/boot/dts`` + + +Use ``qemu`` and look at the supported platforms: + +.. code-block:: bash + + ../qemu/build/arm-softmmu/qemu-system-arm -M ? + +.. note:: We used our own compiled version of ``Qemu`` for ``arm32``. See `Qemu`_ section for more details. + +1. Boot +------- + +Use ``qemu`` to boot ``i.MX6UL`` platform. In order to boot, we first need to compile the kernel. +Review `Compiling the Linux kernel on ARM`_ section. + +Successful compilation will result in the following binaries: + + - ``arch/arm/boot/Image``, kernel image compiled for ARM + - ``arch/arm/boot/dts/imx6ul-14x14-evk.dtb``, device tree blob for ``i.MX6UL`` board + +Review `Rootfs`_ section and download ``core-image-minimal-qemuarm.ext4`` rootfs. +Run ``qemu`` using then following command: + +.. code-block:: bash + + ../qemu/build/arm-softmmu/qemu-system-arm -M mcimx6ul-evk -cpu cortex-a7 -m 512M \ + -kernel arch/arm/boot/zImage -nographic -dtb arch/arm/boot/dts/imx6ul-14x14-evk.dtb \ + -append "root=/dev/mmcblk0 rw console=ttymxc0 loglevel=8 earlycon printk" -sd tools/labs/core-image-minimal-qemuarm.ext4 + +.. note:: LCDIF and ASRC devices are not well supported with ``Qemu``. Remove them from compilation. + +.. code-block:: bash + + $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make menuconfig + # set FSL_ASRC=n and DRM_MXSFB=n + $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make -j8 + +Once the kernel is booted check kernel version and cpu info: + +.. code-block:: bash + + $ cat /proc/cpuinfo + $ cat /proc/version + +2. CPU information +------------------ + +Inspect the CPU configuration for ``NXP i.MX6UL`` board. Start with ``arch/arm/boot/dts/imx6ul-14x14-evk.dts``. + + - find ``cpu@0`` device tree node and look for ``operating-points`` property. + - read the maximum and minimum operating frequency the processor can run + + .. code:: bash + + $ cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq + $ cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq + +3. I/O memory +------------- +Inspect I/O space configuration for ``NXP i.MX6UL`` board. Start with ``arch/arm/boot/dts/imx6ul-14x14-evk.dts`` and identify each device mentioned below. + +.. code:: bash + + $ cat /proc/iomem + 00900000-0091ffff : 900000.sram sram@900000 + 0209c000-0209ffff : 209c000.gpio gpio@209c000 + 021a0000-021a3fff : 21a0000.i2c i2c@21a0000 + 80000000-9fffffff : System RAM + +Identify device tree nodes corresponding to: + + - ``System RAM``, look for ``memory@80000000`` node in ``arch/arm/boot/dts/imx6ul-14x14-evk.dtsi``. What's the size of the System RAM? + - ``GPIO1``, look for ``gpio@209c000`` node in ``arch/arm/boot/dts/imx6ul.dtsi``. What's the size of the I/O space for this device? + - ``I2C1``, look for ``i2c@21a0000`` node in ``arch/arm/boot/dts/imx6ul.dtsi``. What's the size of the I/O spaces for this device? + +4. Hello World +-------------- + +Implement a simple kernel module that prints a message at load/unload time. Compile it and load it on ``i.MX6UL`` emulated platform. + +.. code-block:: shell + + # modules build + tools/labs $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make build + # modules copy + tools/labs $ ARCH=arm make copy + # kernel build + $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make -j8 + +5. Simple device +---------------- + +Implement a driver for a simple platform device. Find ``TODO 1`` and notice how ``simple_driver`` is declared and register as a platform driver. +Follow ``TODO 2`` and add the ``so2,simple-device-v1`` and ``so2,simple-device-v2`` compatible strings in the simple_device_ids array. + +Create two device tree nodes in ``arch/arm/boot/dts/imx6ul.dtsi`` under ``soc`` node with compatible strings ``so2,simple-device-v1`` and +``so2,simple-device-v2`` respectively. Then notice the behavior when loading ``simple_driver`` module. + +.. _imx6ul: https://www.nxp.com/products/processors-and-microcontrollers/arm-processors/i-mx-applications-processors/i-mx-6-processors/i-mx-6ultralite-processor-low-power-secure-arm-cortex-a7-core:i.MX6UL diff --git a/refs/pull/405/merge/_sources/labs/block_device_drivers.rst.txt b/refs/pull/405/merge/_sources/labs/block_device_drivers.rst.txt new file mode 100644 index 00000000..3b6efca7 --- /dev/null +++ b/refs/pull/405/merge/_sources/labs/block_device_drivers.rst.txt @@ -0,0 +1,1210 @@ +==================== +Block Device Drivers +==================== + +Lab objectives +============== + + * acquiring knowledge about the behavior of the I/O subsystem on Linux + * hands-on activities in structures and functions of block devices + * acquiring basic skills for utilizing the API for block devices, by solving + exercises + +Overview +======== + +Block devices are characterized by random access to data organized in fixed-size +blocks. Examples of such devices are hard drives, CD-ROM drives, RAM disks, etc. +The speed of block devices is generally much higher than the speed of character +devices, and their performance is also important. This is why the Linux kernel +handles differently these 2 types of devices (it uses a specialized API). + +Working with block devices is therefore more complicated than working with +character devices. Character devices have a single current position, while block +devices must be able to move to any position in the device to provide random +access to data. To simplify work with block devices, the Linux kernel provides +an entire subsystem called the block I/O (or block layer) subsystem. + +From the kernel perspective, the smallest logical unit of addressing is the +block. Although the physical device can be addressed at sector level, the kernel +performs all disk operations using blocks. Since the smallest unit of physical +addressing is the sector, the size of the block must be a multiple of the size +of the sector. Additionally, the block size must be a power of 2 and can not +exceed the size of a page. The size of the block may vary depending on the file +system used, the most common values being 512 bytes, 1 kilobytes and 4 +kilobytes. + + +Register a block I/O device +=========================== + +To register a block I/O device, function :c:func:`register_blkdev` is used. +To deregister a block I/O device, function :c:func:`unregister_blkdev` is +used. + +Starting with version 4.9 of the Linux kernel, the call to +:c:func:`register_blkdev` is optional. The only operations performed by this +function are the dynamic allocation of a major (if the major argument is 0 when +calling the function) and creating an entry in :file:`/proc/devices`. In +future kernel versions it may be removed; however, most drivers still call it. + +Usually, the call to the register function is performed in the module +initialization function, and the call to the deregister function is performed in +the module exit function. A typical scenario is presented below: + + +.. code-block:: c + + #include <linux/fs.h> + + #define MY_BLOCK_MAJOR 240 + #define MY_BLKDEV_NAME "mybdev" + + static int my_block_init(void) + { + int status; + + status = register_blkdev(MY_BLOCK_MAJOR, MY_BLKDEV_NAME); + if (status < 0) { + printk(KERN_ERR "unable to register mybdev block device\n"); + return -EBUSY; + } + //... + } + + static void my_block_exit(void) + { + //... + unregister_blkdev(MY_BLOCK_MAJOR, MY_BLKDEV_NAME); + } + + +Register a disk +=============== + +Although the :c:func:`register_blkdev` function obtains a major, it does not +provide a device (disk) to the system. For creating and using block devices +(disks), a specialized interface defined in :file:`linux/genhd.h` is used. + +The useful functions defined in :file:`linux/genhd.h` are to register /allocate +a disk, add it to the system, and de-register /unmount the disk. + +The :c:func:`alloc_disk` function is used to allocate a disk, and the +:c:func:`del_gendisk` function is used to deallocate it. Adding the disk to the +system is done using the :c:func:`add_disk` function. + +The :c:func:`alloc_disk` and :c:func:`add_disk` functions are typically used in +the module initialization function, and the :c:func:`del_gendisk` function in +the module exit function. + +.. code-block:: c + + #include <linux/fs.h> + #include <linux/genhd.h> + + #define MY_BLOCK_MINORS 1 + + static struct my_block_dev { + struct gendisk *gd; + //... + } dev; + + static int create_block_device(struct my_block_dev *dev) + { + dev->gd = alloc_disk(MY_BLOCK_MINORS); + //... + add_disk(dev->gd); + } + + static int my_block_init(void) + { + //... + create_block_device(&dev); + } + + static void delete_block_device(struct my_block_dev *dev) + { + if (dev->gd) + del_gendisk(dev->gd); + //... + } + + static void my_block_exit(void) + { + delete_block_device(&dev); + //... + } + +As with character devices, it is recommended to use :c:type:`my_block_dev` +structure to store important elements describing the block device. + +Note that immediately after calling the :c:func:`add_disk` function (actually +even during the call), the disk is active and its methods can be called at any +time. As a result, this function should not be called before the driver is fully +initialized and ready to respond to requests for the registered disk. + + +It can be noticed that the basic structure in working with block devices (disks) +is the :c:type:`struct gendisk` structure. + +After a call to :c:func:`del_gendisk`, the :c:type:`struct gendisk` structure +may continue to exist (and the device operations may still be called) if there +are still users (an open operation was called on the device but the associated +release operation has not been called). One solution is to keep the number of +users of the device and call the :c:func:`del_gendisk` function only when there +are no users left of the device. + +:c:type:`struct gendisk` structure +================================== + +The :c:type:`struct gendisk` structure stores information about a disk. As +stated above, such a structure is obtained from the :c:func:`alloc_disk` call +and its fields must be filled before it is sent to the :c:func:`add_disk` +function. + +The :c:type:`struct gendisk` structure has the following important fields: + + * :c:member:`major`, :c:member:`first_minor`, :c:member:`minor`, describing + the identifiers used by the disk; a disk must have at least one minor; if + the disk allows the partitioning operation, a minor must be allocated for + each possible partition + * :c:member:`disk_name`, which represents the disk name as it appears in + :file:`/proc/partitions` and in sysfs (:file:`/sys/block`) + * :c:member:`fops`, representing operations associated with the disk + * :c:member:`queue`, which represents the queue of requests + * :c:member:`capacity`, which is disk capacity in 512 byte sectors; + it is initialized using the :c:func:`set_capacity` function + * :c:member:`private_data`, which is a pointer to private data + +An example of filling a :c:type:`struct gendisk` structure is presented below: + +.. code-block:: c + + #include <linux/genhd.h> + #include <linux/fs.h> + #include <linux/blkdev.h> + + #define NR_SECTORS 1024 + + #define KERNEL_SECTOR_SIZE 512 + + static struct my_block_dev { + //... + spinlock_t lock; /* For mutual exclusion */ + struct request_queue *queue; /* The device request queue */ + struct gendisk *gd; /* The gendisk structure */ + //... + } dev; + + static int create_block_device(struct my_block_dev *dev) + { + ... + /* Initialize the gendisk structure */ + dev->gd = alloc_disk(MY_BLOCK_MINORS); + if (!dev->gd) { + printk (KERN_NOTICE "alloc_disk failure\n"); + return -ENOMEM; + } + + dev->gd->major = MY_BLOCK_MAJOR; + dev->gd->first_minor = 0; + dev->gd->fops = &my_block_ops; + dev->gd->queue = dev->queue; + dev->gd->private_data = dev; + snprintf (dev->gd->disk_name, 32, "myblock"); + set_capacity(dev->gd, NR_SECTORS); + + add_disk(dev->gd); + + return 0; + } + + static int my_block_init(void) + { + int status; + //... + status = create_block_device(&dev); + if (status < 0) + return status; + //... + } + + static void delete_block_device(struct my_block_dev *dev) + { + if (dev->gd) { + del_gendisk(dev->gd); + } + //... + } + + static void my_block_exit(void) + { + delete_block_device(&dev); + //... + } + +As stated before, the kernel considers a disk as a vector of 512 byte sectors. +In reality, the devices may have a different size of the sector. To work with +these devices, the kernel needs to be informed about the real size of a sector, +and for all operations the necessary conversions must be made. + +To inform the kernel about the device sector size, a parameter of the request +queue must be set just after the request queue is allocated, using the +:c:func:`blk_queue_logical_block_size` function. All requests generated by the +kernel will be multiple of this sector size and will be aligned accordingly. +However, communication between the device and the driver will still be performed +in sectors of 512 bytes in size, so conversion should be done each time (an +example of such conversion is when calling the :c:func:`set_capacity` function +in the code above). + +:c:type:`struct block_device_operations` structure +================================================== + +Just as for a character device, operations in :c:type:`struct file_operations` +should be completed, so for a block device, the operations in +:c:type:`struct block_device_operations` should be completed. The association +of operations is done through the :c:member:`fops` field in the +:c:type:`struct gendisk` +structure. + +Some of the fields of the :c:type:`struct block_device_operations` structure +are presented below: + +.. code-block:: c + + struct block_device_operations { + int (*open) (struct block_device *, fmode_t); + int (*release) (struct gendisk *, fmode_t); + int (*locked_ioctl) (struct block_device *, fmode_t, unsigned, + unsigned long); + int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long); + int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, + unsigned long); + int (*direct_access) (struct block_device *, sector_t, + void **, unsigned long *); + int (*media_changed) (struct gendisk *); + int (*revalidate_disk) (struct gendisk *); + int (*getgeo)(struct block_device *, struct hd_geometry *); + blk_qc_t (*submit_bio) (struct bio *bio); + struct module *owner; + } + +:c:func:`open` and :c:func:`release` operations are called directly from user +space by utilities that may perform the following tasks: partitioning, file +system creation, file system verification. In a :c:func:`mount` operation, the +:c:func:`open` function is called directly from the kernel space, the file +descriptor being stored by the kernel. A driver for a block device can not +differentiate between :c:func:`open` calls performed from user space and kernel +space. + +An example of how to use these two functions is given below: + +.. code-block:: c + + #include <linux/fs.h> + #include <linux/genhd.h> + + static struct my_block_dev { + //... + struct gendisk * gd; + //... + } dev; + + static int my_block_open(struct block_device *bdev, fmode_t mode) + { + //... + + return 0; + } + + static int my_block_release(struct gendisk *gd, fmode_t mode) + { + //... + + return 0; + } + + struct block_device_operations my_block_ops = { + .owner = THIS_MODULE, + .open = my_block_open, + .release = my_block_release + }; + + static int create_block_device(struct my_block_dev *dev) + { + //.... + dev->gd->fops = &my_block_ops; + dev->gd->private_data = dev; + //... + } + +Please notice that there are no read or write operations. These operations are +performed by the :c:func:`request` function associated with the request queue +of the disk. + +Request Queues - Multi-Queue Block Layer +======================================== + +Drivers for block devices use queues to store the block I/O requests that will +be processed. A request queue is represented by the +:c:type:`struct request_queue` structure. The request queue is made up of a +double-linked list of requests and their associated control information. The +requests are added to the queue by higher-level kernel code (for example, file +systems). + +The block device driver associates each queue with a handling function, which +will be called for each request in the queue +(the :c:type:`struct request` structure). + +In earlier version of the Linux kernel, each device driver had associated one or +more request queues (:c:type:`struct request_queue`), where any client could add +requests, while also being able to reorder them. +The problem with this approach is that it requires a per-queue lock, making it +inefficient in distributed systems. + +The `Multi-Queue Block Queing Mechanism <https://www.kernel.org/doc/html/latest/block/blk-mq.html>`_ +solves this issue by splitting the device driver queue in two parts: + 1. Software staging queues + 2. Hardware dispatch queues + +Software staging queues +----------------------- + +The staging queues hold requests from the clients before sending them to the +block device driver. To prevent the waiting for a per-queue lock, a staging +queue is allocated for each CPU or node. A software queue is associated to +only one hardware queue. + +While in this queue, the requests can be merged or reordered, according to an +I/O Scheduler, in order to maximize performance. This means that only the +requests coming from the same CPU or node can be optimized. + +Staging queues are usually not used by the block device drivers, but only +internally by the I/O subsystem to optimize requests before sending them to the +device drivers. + +Hardware dispatch queues +------------------------ + +The hardware queues (:c:type:`struct blk_mq_hw_ctx`) are used to send the +requests from the staging queues to the block device driver. +Once in this queue, the requests can't be merged or reordered. + +Depending on the underlying hardware, a block device driver can create multiple +hardware queues in order to improve parallelism and maximize performance. + +Tag sets +-------- + +A block device driver can accept a request before the previous one is completed. +As a consequence, the upper layers need a way to know when a request is +completed. For this, a "tag" is added to each request upon submission and sent +back using a completion notification after the request is completed. + +The tags are part of a tag set (:c:type:`struct blk_mq_tag_set`), which is +unique to a device. +The tag set structure is allocated and initialized before the request queues +and also stores some of the queues properties. + +.. code-block:: c + + struct blk_mq_tag_set { + ... + const struct blk_mq_ops *ops; + unsigned int nr_hw_queues; + unsigned int queue_depth; + unsigned int cmd_size; + int numa_node; + void *driver_data; + struct blk_mq_tags **tags; + struct list_head tag_list; + ... + }; + +Some of the fields in :c:type:`struct blk_mq_tag_set` are: + + * ``ops`` - Queue operations, most notably the request handling function. + * ``nr_hw_queues`` - The number of hardware queues allocated for the device + * ``queue_depth`` - Hardware queues size + * ``cmd_size`` - Number of extra bytes allocated at the end of the device, to + be used by the block device driver, if needed. + * ``numa_node`` - In NUMA systems, the index of the node the storage device is + connected to. + * ``driver_data`` - Data private to the driver, if needed. + * ``tags`` - Pointer to an array of ``nr_hw_queues`` tag sets. + * ``tag_list`` - List of request queues using this tag set. + +Create and delete a request queue +--------------------------------- + +Request queues are created using the :c:func:`blk_mq_init_queue` function and +are deleted using :c:func:`blk_cleanup_queue`. The first function creates both +the hardware and the software queues and initializes their structures. + +Queue properties, including the number of hardware queues, their capacity and +request handling function are configured using the :c:type:`blk_mq_tag_set` +structure, as described above. + +An example of using these functions is as follows: + +.. code-block:: c + + #include <linux/fs.h> + #include <linux/genhd.h> + #include <linux/blkdev.h> + + static struct my_block_dev { + //... + struct blk_mq_tag_set tag_set; + struct request_queue *queue; + //... + } dev; + + static blk_status_t my_block_request(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) + //... + + static struct blk_mq_ops my_queue_ops = { + .queue_rq = my_block_request, + }; + + static int create_block_device(struct my_block_dev *dev) + { + /* Initialize tag set. */ + dev->tag_set.ops = &my_queue_ops; + dev->tag_set.nr_hw_queues = 1; + dev->tag_set.queue_depth = 128; + dev->tag_set.numa_node = NUMA_NO_NODE; + dev->tag_set.cmd_size = 0; + dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; + err = blk_mq_alloc_tag_set(&dev->tag_set); + if (err) { + goto out_err; + } + + /* Allocate queue. */ + dev->queue = blk_mq_init_queue(&dev->tag_set); + if (IS_ERR(dev->queue)) { + goto out_blk_init; + } + + blk_queue_logical_block_size(dev->queue, KERNEL_SECTOR_SIZE); + + /* Assign private data to queue structure. */ + dev->queue->queuedata = dev; + //... + + out_blk_init: + blk_mq_free_tag_set(&dev->tag_set); + out_err: + return -ENOMEM; + } + + static int my_block_init(void) + { + int status; + //... + status = create_block_device(&dev); + if (status < 0) + return status; + //... + } + + static void delete_block_device(struct block_dev *dev) + { + //... + blk_cleanup_queue(dev->queue); + blk_mq_free_tag_set(&dev->tag_set); + } + + static void my_block_exit(void) + { + delete_block_device(&dev); + //... + } + +After initializing the tag set structure, the tag lists are allocated using the +:c:func:`blk_mq_alloc_tag_set` function. +The pointer to the function which will process the requests +(:c:func:`my_block_request`) is filled in the ``my_queue_ops`` structure and +then the pointer to this structure is added to the tag set. + +The queue is created using the :c:func:`blk_mq_init_queue` function, based on +the information added in the tag set. + +As part of the request queue initialization, you can configure the +:c:member:`queuedata` field, which is equivalent to the :c:member:`private_data` +field in other structures. + +Useful functions for processing request queues +---------------------------------------------- + +The ``queue_rq`` function from :c:type:`struct blk_mq_ops` is used to handle +requests for working with the block device. +This function is the equivalent of read and write functions encountered on +character devices. The function receives the requests for the device as +arguments and can use various functions for processing them. + +The functions used to process the requests in the handler are described below: + + * :c:func:`blk_mq_start_request` - must be called before starting processing + a request; + * :c:func:`blk_mq_requeue_request` - to re-send the request in the queue; + * :c:func:`blk_mq_end_request` - to end request processing and notify the + upper layers. + +Requests for block devices +========================== + +A request for a block device is described by :c:type:`struct request` +structure. + +The fields of :c:type:`struct request` structure include: + + * :c:member:`cmd_flags`: a series of flags including direction (reading or + writing); to find out the direction, the macrodefinition + :c:macro:`rq_data_dir` is used, which returns 0 for a read request and 1 + for a write request on the device; + * :c:member:`__sector`: the first sector of the transfer request; if the + device sector has a different size, the appropriate conversion should be + done. To access this field, use the :c:macro:`blk_rq_pos` macro; + * :c:member:`__data_len`: the total number of bytes to be transferred; to + access this field the :c:macro:`blk_rq_bytes` macro is used; + * generally, data from the current :c:type:`struct bio` will be + transferred; the data size is obtained using the + :c:macro:`blk_rq_cur_bytes` macro; + * :c:member:`bio`, a dynamic list of :c:type:`struct bio` structures that + is a set of buffers associated to the request; this field is accessed by + macrodefinition :c:macro:`rq_for_each_segment` if there are multiple + buffers, or by :c:macro:`bio_data` macrodefinition in case there is only + one associated buffer; + +We will discuss more about the :c:type:`struct bio` structure and its +associated operations in the :ref:`bio_structure` section. + +Create a request +---------------- + +Read /write requests are created by code layers superior to the kernel I/O +subsystem. Typically, the subsystem that creates requests for block devices is +the file management subsystem. The I/O subsystem acts as an interface between +the file management subsystem and the block device driver. The main operations +under the responsibility of the I/O subsystem are adding requests to the queue +of the specific block device and sorting and merging requests according to +performance considerations. + +Process a request +----------------- + +The central part of a block device driver is the request handling function +(``queue_rq``). In previous examples, the function that fulfilled this role was +:c:func:`my_block_request`. As stated in the +`Create and delete a request queue`_ section, this function is associated to the +driver when creating the tag set structure. + +This function is called when the kernel considers that the driver should process +I/O requests. The function must start processing the requests from the queue, +but it is not mandatory to finish them, as requests may be finished by other +parts of the driver. + +The request function runs in an atomic context and must follow the rules for +atomic code (it does not need to call functions that can cause sleep, etc.). + +Calling the function that processes the requests is asynchronous relative +to the actions of any userspace process and no assumptions about the process +in which the respective function is running should be made. Also, it should not +be assumed that the buffer provided by a request is from kernel space or user +space, any operation that accesses the userspace being erroneous. + +One of the simplest request handling function is presented below: + +.. code-block:: c + + static blk_status_t my_block_request(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) + { + struct request *rq = bd->rq; + struct my_block_dev *dev = q->queuedata; + + blk_mq_start_request(rq); + + if (blk_rq_is_passthrough(rq)) { + printk (KERN_NOTICE "Skip non-fs request\n"); + blk_mq_end_request(rq, BLK_STS_IOERR); + goto out; + } + + /* do work */ + ... + + blk_mq_end_request(rq, BLK_STS_OK); + + out: + return BLK_STS_OK; + } + +The :c:func:`my_block_request` function performs the following operations: + + * Get a pointer to the request structure from the ``bd`` argument and start + its processing using the :c:func:`blk_mq_start_request` function. + * A block device can receive calls which do not transfer data blocks (e.g. + low level operations on the disk, instructions referring to special ways of + accessing the device). Most drivers do not know how to handle these + requests and return an error. + * To return an error, :c:func:`blk_mq_end_request` function is called, + ``BLK_STS_IOERR`` being the second argument. + * The request is processed according to the needs of the associated device. + * The request ends. In this case, :c:func:`blk_mq_end_request` function is + called in order to complete the request. + +.. bio_structure: + +:c:type:`struct bio` structure +============================== + +Each :c:type:`struct request` structure is an I/O block request, but may come +from combining more independent requests from a higher level. The sectors to be +transferred for a request can be scattered into the main memory but they always +correspond to a set of consecutive sectors on the device. The request is +represented as a series of segments, each corresponding to a buffer in memory. +The kernel can combine requests that refer to adjacent sectors but will not +combine write requests with read requests into a single +:c:type:`struct request` structure. + +A :c:type:`struct request` structure is implemented as a linked list of +:c:type:`struct bio` structures together with information that allows the +driver to retain its current position while processing the request. + +The :c:type:`struct bio` structure is a low-level description of a portion of +a block I/O request. + +.. code-block:: c + + struct bio { + //... + struct gendisk *bi_disk; + unsigned int bi_opf; /* bottom bits req flags, top bits REQ_OP. Use accessors. */ + //... + struct bio_vec *bi_io_vec; /* the actual vec list */ + //... + struct bvec_iter bi_iter; + /... + void *bi_private; + //... + }; + +In turn, the :c:type:`struct bio` structure contains a :c:member:`bi_io_vec` +vector of :c:type:`struct bio_vec` structures. It consists of the individual +pages in the physical memory to be transferred, the offset within the page and +the size of the buffer. To iterate through a :c:type:`struct bio` structure, +we need to iterate through the vector of :c:type:`struct bio_vec` and transfer +the data from every physical page. To simplify vector iteration, the +:c:type:`struct bvec_iter` structure is used. This structure maintains +information about how many buffers and sectors were consumed during the +iteration. The request type is encoded in the :c:member:`bi_opf` field; to +determine it, use the :c:func:`bio_data_dir` function. + +Create a :c:type:`struct bio` structure +--------------------------------------- + +Two functions can be used to create a :c:type:`struct bio` structure: + + * :c:func:`bio_alloc`: allocates space for a new structure; the structure + must be initialized; + * :c:func:`bio_clone`: makes a copy of an existing :c:type:`struct bio` + structure; the newly obtained structure is initialized with the values of + the cloned structure fields; the buffers are shared with the + :c:type:`struct bio` structure that has been cloned so that access to the + buffers has to be done carefully to avoid access to the same memory area + from the two clones; + +Both functions return a new :c:type:`struct bio` structure. + +Submit a :c:type:`struct bio` structure +--------------------------------------- + +Usually, a :c:type:`struct bio` structure is created by the higher levels of +the kernel (usually the file system). A structure thus created is then +transmitted to the I/O subsystem that gathers more :c:type:`struct bio` +structures into a request. + +For submitting a :c:type:`struct bio` structure to the associated I/O device +driver, the :c:func:`submit_bio` function is used. The function receives as +argument an initialized :c:type:`struct bio` structure that will be added to +a request from the request queue of an I/O device. From that queue, it can be +processed by the I/O device driver using a specialized function. + + +.. _bio_completion: + +Wait for the completion of a :c:type:`struct bio` structure +----------------------------------------------------------- + +Submitting a :c:type:`struct bio` structure to a driver has the effect of +adding it to a request from the request queue from where it will be further +processed. Thus, when the :c:func:`submit_bio` function returns, it is not +guaranteed that the processing of the structure has finished. If you want to +wait for the processing of the request to be finished, use the +:c:func:`submit_bio_wait` function. + +To be notified when the processing of a :c:type:`struct bio` structure ends +(when we do not use :c:func:`submit_bio_wait` function), the +:c:member:`bi_end_io` field of the structure should be used. This field +specifies the function that will be called at the end of the +:c:type:`struct bio` structure processing. You can use the +:c:member:`bi_private` field of the structure to pass information to the +function. + +Initialize a :c:type:`struct bio` structure +------------------------------------------- + +Once a :c:type:`struct bio` structure has been allocated and before being +transmitted, it must be initialized. + +Initializing the structure involves filling in its important fields. As +mentioned above, the :c:member:`bi_end_io` field is used to specify the function +called when the processing of the structure is finished. The +:c:member:`bi_private` field is used to store useful data that can be accessed +in the function pointed by :c:member:`bi_end_io`. + +The :c:member:`bi_opf` field specifies the type of operation. + +.. code-block:: c + + struct bio *bio = bio_alloc(GFP_NOIO, 1); + //... + bio->bi_disk = bdev->bd_disk; + bio->bi_iter.bi_sector = sector; + bio->bi_opf = REQ_OP_READ; + bio_add_page(bio, page, size, offset); + //... + +In the code snippet above we specified the block device to which we sent the +following: :c:type:`struct bio` structure, startup sector, operation +(:c:data:`REQ_OP_READ` or :c:data:`REQ_OP_WRITE`) and content. The content of a +:c:type:`struct bio` structure is a buffer described by: a physical page, +the offset in the page and the size of the bufer. A page can be assigned using +the :c:func:`alloc_page` call. + +.. note:: The :c:data:`size` field of the :c:func:`bio_add_page` call must be + a multiple of the device sector size. + +.. _bio_content: + +How to use the content of a :c:type:`struct bio` structure +---------------------------------------------------------- + +To use the content of a :c:type:`struct bio` structure, the structure's +support pages must be mapped to the kernel address space from where they can be +accessed. For mapping /unmapping, use the :c:macro:`kmap_atomic` and +the :c:macro:`kunmap_atomic` macros. + +A typical example of use is: + +.. code-block:: c + + static void my_block_transfer(struct my_block_dev *dev, size_t start, + size_t len, char *buffer, int dir); + + + static int my_xfer_bio(struct my_block_dev *dev, struct bio *bio) + { + struct bio_vec bvec; + struct bvec_iter i; + int dir = bio_data_dir(bio); + + /* Do each segment independently. */ + bio_for_each_segment(bvec, bio, i) { + sector_t sector = i.bi_sector; + char *buffer = kmap_atomic(bvec.bv_page); + unsigned long offset = bvec.bv_offset; + size_t len = bvec.bv_len; + + /* process mapped buffer */ + my_block_transfer(dev, sector, len, buffer + offset, dir); + + kunmap_atomic(buffer); + } + + return 0; + } + +As it can be seen from the example above, iterating through a +:c:type:`struct bio` requires iterating through all of its segments. A segment +(:c:type:`struct bio_vec`) is defined by the physical address page, the offset +in the page and its size. + +To simplify the processing of a :c:type:`struct bio`, use the +:c:macro:`bio_for_each_segment` macrodefinition. It will iterate through all +segments, and will also update global information stored in an iterator +(:c:type:`struct bvec_iter`) such as the current sector as well as other +internal information (segment vector index, number of bytes left to be +processed, etc.) . + +You can store information in the mapped buffer, or extract information. + +In case request queues are used and you needed to process the requests +at :c:type:`struct bio` level, use the :c:macro:`rq_for_each_segment` +macrodefinition instead of the :c:macro:`bio_for_each_segment` macrodefinition. +This macrodefinition iterates through each segment of each +:c:type:`struct bio` structure of a :c:type:`struct request` structure and +updates a :c:type:`struct req_iterator` structure. The +:c:type:`struct req_iterator` contains the current :c:type:`struct bio` +structure and the iterator that traverses its segments. + +A typical example of use is: + +.. code-block:: c + + struct bio_vec bvec; + struct req_iterator iter; + + rq_for_each_segment(bvec, req, iter) { + sector_t sector = iter.iter.bi_sector; + char *buffer = kmap_atomic(bvec.bv_page); + unsigned long offset = bvec.bv_offset; + size_t len = bvec.bv_len; + int dir = bio_data_dir(iter.bio); + + my_block_transfer(dev, sector, len, buffer + offset, dir); + + kunmap_atomic(buffer); + } + +Free a :c:type:`struct bio` structure +------------------------------------- + +Once a kernel subsystem uses a :c:type:`struct bio` structure, it will have to +release the reference to it. This is done by calling :c:func:`bio_put` function. + +Set up a request queue at :c:type:`struct bio` level +---------------------------------------------------- + +We have previously seen how we can specify a function to be used to process +requests sent to the driver. The function receives as argument the requests and +carries out processing at :c:type:`struct request` level. + +If, for flexibility reasons, we need to specify a function that carries +out processing at :c:type:`struct bio` structure level, we no longer +use request queues and we will need to fill the ``submit_bio`` field in the +:c:type:`struct block_device_operations` associated to the driver. + +Below is a typical example of initializing a function that carries out +processing at :c:type:`struct bio` structure level: + +.. code-block:: c + + // the declaration of the function that carries out processing + // :c:type:`struct bio` structures + static blk_qc_t my_submit_bio(struct bio *bio); + + struct block_device_operations my_block_ops = { + .owner = THIS_MODULE, + .submit_bio = my_submit_bio + ... + }; + +Further reading +=============== + +* `Linux Device Drivers 3rd Edition, Chapter 16. Block Drivers <http://static.lwn.net/images/pdf/LDD3/ch16.pdf>`_ +* Linux Kernel Development, Second Edition – Chapter 13. The Block I/O Layer +* `A simple block driver <https://lwn.net/Articles/58719/>`_ +* `The gendisk interface <https://lwn.net/Articles/25711/>`_ +* `The bio structure <https://lwn.net/Articles/26404/>`_ +* `Request queues <https://lwn.net/Articles/27055/>`_ +* `Documentation/block/request.txt - Struct request documentation <https://elixir.bootlin.com/linux/v4.15/source/Documentation/block/request.txt>`_ +* `Documentation/block/biodoc.txt - Notes on the Generic Block Layer <https://elixir.bootlin.com/linux/v4.15/source/Documentation/block/biodoc.txt>`_ +* `drivers/block/brd/c - RAM backed block disk driver <https://elixir.bootlin.com/linux/v4.15/source/drivers/block/brd.c>`_ +* `I/O Schedulers <https://www.linuxjournal.com/article/6931>`_ + + +Exercises +========= + +.. include:: ../labs/exercises-summary.hrst +.. |LAB_NAME| replace:: block_device_drivers + +0. Intro +-------- + +Using |LXR|_ find the definitions of the following symbols in the Linux kernel: + + * :c:type:`struct bio` + * :c:type:`struct bio_vec` + * :c:macro:`bio_for_each_segment` + * :c:type:`struct gendisk` + * :c:type:`struct block_device_operations` + * :c:type:`struct request` + +1. Block device +--------------- + +Create a kernel module that allows you to register or deregister a block device. +Start from the files in the :file:`1-2-3-6-ram-disk/kernel` directory in the +lab skeleton. + +Follow the comments marked with **TODO 1** in the laboratory skeleton. Use the +existing macrodefinitions (:c:macro:`MY_BLOCK_MAJOR`, +:c:macro:`MY_BLKDEV_NAME`). Check the value returned by the register function, +and in case of error, return the error code. + +Compile the module, copy it to the virtual machine and insert it into the +kernel. Verify that your device was successfully created inside the +:file:`/proc/devices`. +You will see a device with major 240. + +Unload the kernel module and check that the device was unregistered. + +.. hint:: Review the `Register a block I/O device`_ section. + +Change the :c:macro:`MY_BLOCK_MAJOR` value to 7. Compile the module, copy it to +the virtual machine, and insert it into the kernel. Notice that the insertion +fails because there is already another driver/device registered in the kernel +with the major 7. + +Restore the 240 value for the :c:macro:`MY_BLOCK_MAJOR` macro. + +2. Disk registration +-------------------- + +Modify the previous module to add a disk associated with the driver. Analyze the +macrodefinitions, :c:type:`my_block_dev` structure and existing functions from +the :file:`ram-disk.c` file. + +Follow the comments marked with **TODO 2**. Use the +:c:func:`create_block_device` and the :c:func:`delete_block_device` functions. + +.. hint:: Review the `Register a disk`_ and `Process a request`_ sections. + +Fill in the :c:func:`my_block_request` function to process the request +without actually processing your request: display the "request received" message +and the following information: start sector, total size, data size from the +current :c:type:`struct bio` structure, direction. To validate a request type, +use the :c:func:`blk_rq_is_passthrough` (the function returns 0 in the case in +which we are interested, i.e. when the request is generated by the file system). + +.. hint:: To find the needed info, review the `Requests for block devices`_ + section. + +Use the :c:func:`blk_mq_end_request` function to finish processing the +request. + +Insert the module into the kernel and inspect the messages printed +by the module. When a device is added, a request is sent to the device. Check +the presence of :file:`/dev/myblock` and if it doesn't exist, create the device +using the command: + +.. code-block:: shell + + mknod /dev/myblock b 240 0 + +To generate writing requests, use the command: + +.. code-block:: shell + + echo "abc"> /dev/myblock + +Notice that a write request is preceded by a read request. The request +is done to read the block from the disk and "update" its content with the +data provided by the user, without overwriting the rest. After reading and +updating, writing takes place. + +3. RAM disk +----------- + +Modify the previous module to create a RAM disk: requests to the device will +result in reads/writes in a memory area. + +The memory area :c:data:`dev->data` is already allocated in the source code of +the module using :c:func:`vmalloc` and deallocated using :c:func:`vfree`. + +.. note:: Review the `Process a request`_ section. + +Follow the comments marked with **TODO 3** to complete the +:c:func:`my_block_transfer` function to write/read the request information +in/from the memory area. The function will be called for each request within +the queue processing function: :c:func:`my_block_request`. To write/read +to/from the memory area, use :c:func:`memcpy`. To determine the write/read +information, use the fields of the :c:type:`struct request` structure. + +.. hint:: To find out the size of the request data, use the + :c:macro:`blk_rq_cur_bytes` macro. Do not use the + :c:macro:`blk_rq_bytes` macro. + +.. hint:: To find out the buffer associated to the request, use + :c:data:`bio_data`(:c:data:`rq->bio`). + +.. hint:: A description of useful macros is in the `Requests for block devices`_ + section. + +.. hint:: You can find useful information in the + `block device driver example + <https://github.com/martinezjavier/ldd3/blob/master/sbull/sbull.c>`_ + from `Linux Device Driver <http://lwn.net/Kernel/LDD3/>`_. + +For testing, use the test file :file:`user/ram-disk-test.c`. +The test program is compiled automatically at ``make build``, copied to the +virtual machine at ``make copy`` and can be run on the QEMU virtual machine +using the command: + +.. code-block:: shell + + ./ram-disk-test + +There is no need to insert the module into the kernel, it will be inserted by +the ``ram-disk-test`` command. + +Some tests may fail because of lack of synchronization between the transmitted +data (flush). + +4. Read data from the disk +-------------------------- + +The purpose of this exercise is to read data from the +:c:macro:`PHYSICAL_DISK_NAME` disk (:file:`/dev/vdb`) directly from the kernel. + +.. attention:: Before solving the exercise, we need to make sure the disk is + added to the virtual machine. + + Check the variable ``QEMU_OPTS`` from :file:`qemu/Makefile`. + There should already be two extra disks added using ``-drive ...``. + + If there are not, generate a file that we will use as + the disk image using the command: + :command:`dd if=/dev/zero of=qemu/mydisk.img bs=1024 count=1` + and add the following option: + :command:`-drive file=qemu/mydisk.img,if=virtio,format=raw` + to :file:`qemu/Makefile` (in the :c:data:`QEMU_OPTS` variable, + after the root disk). + +Follow the comments marked with **TODO 4** in the directory :file:`4-5-relay/` +and implement :c:func:`open_disk` and :c:func:`close_disk`. +Use the :c:func:`blkdev_get_by_path` and :c:func:`blkdev_put` functions. The +device must be opened in read-write mode exclusively +(:c:macro:`FMODE_READ` | :c:macro:`FMODE_WRITE` | :c:macro:`FMODE_EXCL`), and +as holder you must use the current module (:c:macro:`THIS_MODULE`). + +Implement the :c:func:`send_test_bio` function. You will have to create a new +:c:type:`struct bio` structure and fill it, submit it and wait for it. Read the +first sector of the disk. To wait, call the :c:func:`submit_bio_wait` function. + +.. hint:: The first sector of the disk is the sector with the index 0. + This value must be used to initialize the field + :c:member:`bi_iter.bi_sector` of the :c:type:`struct bio`. + + For the read operation, use the :c:macro:`REQ_OP_READ` macro to + initialize the :c:member:`bi_opf` field of the :c:type:`struct bio`. + +After finishing the operation, display the first 3 bytes of data read by +:c:type:`struct bio` structure. Use the format ``"% 02x"`` for :c:func:`printk` +to display the data and the :c:macro:`kmap_atomic` and :c:macro:`kunmap_atomic` +macros respectively. + +.. hint:: As an argument for the :c:func:`kmap_atomic` function, just use the + page which is allocated above in the code, in the :c:data:`page` + variable. + +.. hint:: Review the sections :ref:`bio_content` and :ref:`bio_completion`. + +For testing, use the :file:`test-relay-disk` script, which is copied on the +virtual machine when running :command:`make copy`. If it is not copied, make +sure it is executable: + +.. code-block:: shell + + chmod +x test-relay-disk + +There is no need to load the module into the kernel, it will be loaded by +:command:`test-relay-disk`. + +Use the command below to run the script: + +.. code-block:: shell + + ./test-relay-disk + +The script writes "abc" at the beginning of the disk indicated by +:c:macro:`PHYSICAL_DISK_NAME`. After running, the module will display 61 62 63 +(the corresponding hexadecimal values of letters "a", "b" and "c"). + +5. Write data to the disk +------------------------- + +Follow the comments marked with **TODO 5** to write a message +(:c:macro:`BIO_WRITE_MESSAGE`) on the disk. + +The :c:func:`send_test_bio` function receives as argument the operation type +(read or write). Call in the :c:func:`relay_init` function the function for +reading and in the :c:func:`relay_exit` function the function for writing. We +recommend using the :c:macro:`REQ_OP_READ` and the :c:macro:`REQ_OP_WRITE` +macros. + +Inside the :c:func:`send_test_bio` function, if the operation is write, fill in +the buffer associated to the :c:type:`struct bio` structure with the message +:c:macro:`BIO_WRITE_MESSAGE`. Use the :c:macro:`kmap_atomic` and the +:c:macro:`kunmap_atomic` macros to work with the buffer associated to the +:c:type:`struct bio` structure. + +.. hint:: You need to update the type of the operation associated to the + :c:type:`struct bio` structure by setting the :c:member:`bi_opf` field + accordingly. + +For testing, run the :file:`test-relay-disk` script using the command: + +.. code-block:: shell + + ./test-relay-disk + +The script will display the ``"read from /dev/sdb: 64 65 66"`` message at the +standard output. + +6. Processing requests from the request queue at :c:type:`struct bio` level +--------------------------------------------------------------------------- + +In the implementation from Exercise 3, we have only processed a +:c:type:`struct bio_vec` of the current :c:type:`struct bio` from the request. +We want to process all :c:type:`struct bio_vec` structures from all +:c:type:`struct bio` structures. +For this, we will iterate through all :c:type:`struct bio` requests and through +all :c:type:`struct bio_vec` structures (also called segments) of each +:c:type:`struct bio`. + +Add, within the ramdisk implementation (:file:`1-2-3-6-ram-disk/` directory), +support for processing the requests from the request queue at +:c:type:`struct bio` level. Follow the comments marked with **TODO 6**. + +Set the :c:macro:`USE_BIO_TRANSFER` macro to 1. + +Implement the :c:func:`my_xfer_request` function. Use the +:c:macro:`rq_for_each_segment` macro to iterate through the :c:type:`bio_vec` +structures of each :c:type:`struct bio` from the request. + +.. hint:: Review the indications and the code snippets from the + :ref:`bio_content` section. + +.. hint:: Use the :c:type:`struct bio` segment iterator to get the current + sector (:c:member:`iter.iter.bi_sector`). + +.. hint:: Use the request iterator to get the reference to the current + :c:type:`struct bio` (:c:member:`iter.bio`). + +.. hint:: Use the :c:macro:`bio_data_dir` macro to find the reading or writing + direction for a :c:type:`struct bio`. + +Use the :c:macro:`kmap_atomic` or the :c:macro:`kunmap_atomic` macros to map +the pages of each :c:type:`struct bio` structure and access its associated +buffers. For the actual transfer, call the :c:func:`my_block_transfer` function +implemented in the previous exercise. + +For testing, use the :file:`ram-disk-test.c` test file: + +.. code-block:: shell + + ./ram-disk-test + +There is no need to insert the module into the kernel, it will be inserted by +the :command:`ram-disk-test` executable. + +Some tests may crash because of lack of synchronization between the transmitted +data (flush). diff --git a/refs/pull/405/merge/_sources/labs/deferred_work.rst.txt b/refs/pull/405/merge/_sources/labs/deferred_work.rst.txt new file mode 100644 index 00000000..72cf9ac8 --- /dev/null +++ b/refs/pull/405/merge/_sources/labs/deferred_work.rst.txt @@ -0,0 +1,946 @@ +============= +Deferred work +============= + +Lab objectives +============== + +* Understanding deferred work (i.e. code scheduled to be executed at a + later time) +* Implementation of common tasks that uses deferred work +* Understanding the peculiarities of synchronization for deferred work + +Keywords: softirq, tasklet, struct tasklet_struct, bottom-half +handlers, jiffies, HZ, timer, struct timer_list, spin_lock_bh, +spin_unlock_bh, workqueue, struct work_struct, kernel thread, events/x + +Background information +====================== + +Deferred work is a class of kernel facilities that allows one to +schedule code to be executed at a later timer. This scheduled code can +run either in the process context or in interruption context depending +on the type of deferred work. Deferred work is used to complement the +interrupt handler functionality since interrupts have important +requirements and limitations: + +* The execution time of the interrupt handler must be as small as + possible +* In interrupt context we can not use blocking calls + +Using deferred work we can perform the minimum required work in the +interrupt handler and schedule an asynchronous action from the +interrupt handler to run at a later time and execute the rest of the +operations. + +Deferred work that runs in interrupt context is also known as +bottom-half, since its purpose is to execute the rest of the actions +from an interrupt handler (top-half). + +Timers are another type of deferred work that are used to schedule the +execution of future actions after a certain amount of time has passed. + +Kernel threads are not themselves deferred work, but can be used to +complement the deferred work mechanisms. In general, kernel threads +are used as "workers" to process events whose execution contains +blocking calls. + +There are three typical operations that are used with all types of +deferred work: + +1. **Initialization**. Each type is described by a structure whose + fields will have to be initialized. The handler to be scheduled is + also set at this time. +2. **Scheduling**. Schedules the execution of the handler as soon as + possible (or after expiry of a timeout). +3. **Masking** or **Canceling**. Disables the execution of the + handler. This action can be either synchronous (which guarantees + that the handler will not run after the completion of canceling) or + asynchronous. + +.. attention:: When doing deferred work cleanup, like freeing the + structures associated with the deferred work or + removing the module and thus the handler code from the + kernel, always use the synchronous type of canceling + the deferred work. + +The main types of deferred work are kernel threads and softirqs. Work +queues are implemented on top of kernel threads and tasklets and +timers on top of softirqs. Bottom-half handlers were the first +implementation of deferred work in Linux, but in the meantime it was +replaced by softirqs. That is why some functions presented +contain *bh* in their name. + +Softirqs +======== + +softirqs can not be used by device drivers, they are reserved for +various kernel subsystems. Because of this there is a fixed number of +softirqs defined at compile time. For the current kernel version we +have the following types defined: + +.. code-block:: c + + enum { + HI_SOFTIRQ = 0, + TIMER_SOFTIRQ, + NET_TX_SOFTIRQ, + NET_RX_SOFTIRQ, + BLOCK_SOFTIRQ, + IRQ_POLL_SOFTIRQ, + TASKLET_SOFTIRQ, + SCHED_SOFTIRQ, + HRTIMER_SOFTIRQ, + RCU_SOFTIRQ, + NR_SOFTIRQS + }; + + +Each type has a specific purpose: + +* *HI_SOFTIRQ* and *TASKLET_SOFTIRQ* - running tasklets +* *TIMER_SOFTIRQ* - running timers +* *NET_TX_SOFIRQ* and *NET_RX_SOFTIRQ* - used by the networking subsystem +* *BLOCK_SOFTIRQ* - used by the IO subsystem +* *BLOCK_IOPOLL_SOFTIRQ* - used by the IO subsystem to increase performance when the iopoll handler is invoked; +* *SCHED_SOFTIRQ* - load balancing +* *HRTIMER_SOFTIRQ* - implementation of high precision timers +* *RCU_SOFTIRQ* - implementation of RCU type mechanisms [1]_ + +.. [1] RCU is a mechanism by which destructive operations + (e.g. deleting an element from a chained list) are done in two + steps: (1) removing references to deleted data and (2) freeing + the memory of the element. The second setup is done only after + we are sure nobody uses the element anymore. The advantage of + this mechanism is that reading the data can be done without + synchronization. For more information see + Documentation/RCU/rcu.txt. + + +The highest priority is the *HI_SOFTIRQ* type softirqs, followed in +order by the other softirqs defined. *RCU_SOFTIRQ* has the lowest +priority. + +Softirqs are running in interrupt context which means that they can +not call blocking functions. If the sofitrq handler requires calls to +such functions, work queues can be scheduled to execute these blocking +calls. + +Tasklets +-------- + +A tasklet is a special form of deferred work that runs in interrupt +context, just like softirqs. The main difference between sofirqs and tasklets +is that tasklets can be allocated dynamically and thus they can be used +by device drivers. A tasklet is represented by :c:type:`struct +tasklet` and as many other kernel structures it needs to be +initialized before being used. A pre-initialized tasklet can be defined +as following: + +.. code-block:: c + + void handler(unsigned long data); + + DECLARE_TASKLET(tasklet, handler, data); + DECLARE_TASKLET_DISABLED(tasklet, handler, data); + + +If we want to initialize the tasklet manually we can use the following +approach: + +.. code-block:: c + + void handler(unsigned long data); + + struct tasklet_struct tasklet; + + tasklet_init(&tasklet, handler, data); + +The *data* parameter will be sent to the handler when it is executed. + +Programming tasklets for running is called scheduling. Tasklets are +running from softirqs. Tasklets scheduling is done with: + +.. code-block:: c + + void tasklet_schedule(struct tasklet_struct *tasklet); + + void tasklet_hi_schedule(struct tasklet_struct *tasklet); + +When using *tasklet_schedule*, a *TASKLET_SOFTIRQ* softirq is +scheduled and all tasklets scheduled are run. For +*tasklet_hi_schedule*, a *HI_SOFTIRQ* softirq is scheduled. + +If a tasklet was scheduled multiple times and it did not run between +schedules, it will run once. Once the tasklet has run, it can be +re-scheduled, and will run again at a later timer. Tasklets can be +re-scheduled from their handlers. + +Tasklets can be masked and the following functions can be used: + +.. code-block:: c + + void tasklet_enable(struct tasklet_struct * tasklet); + void tasklet_disable(struct tasklet_struct * tasklet); + +Remember that since tasklets are running from softirqs, blocking calls +can not be used in the handler function. + +Timers +------ + +A particular type of deferred work, very often used, are timers. They +are defined by :c:type:`struct timer_list`. They run in interrupt +context and are implemented on top of softirqs. + +To be used, a timer must first be initialized by calling :c:func:`timer_setup`: + +.. code-block:: c + + #include <linux/sched.h> + + void timer_setup(struct timer_list * timer, + void (*function)(struct timer_list *), + unsigned int flags); + +The above function initializes the internal fields of the structure +and associates *function* as the timer handler. Since timers are planned +over softirqs, blocking calls can not be used in the code associated +with the treatment function. + +Scheduling a timer is done with :c:func:`mod_timer`: + +.. code-block:: c + + int mod_timer(struct timer_list *timer, unsigned long expires); + +Where *expires* is the time (in the future) to run the handler +function. The function can be used to schedule or reschedule a timer. + +The time unit is *jiffie*. The absolute value of a jiffie +is dependent on the platform and it can be found using the +:c:type:`HZ` macro that defines the number of jiffies for 1 second. To +convert between jiffies (*jiffies_value*) and seconds (*seconds_value*), +the following formulas are used: + +.. code-block:: c + + jiffies_value = seconds_value * HZ ; + seconds_value = jiffies_value / HZ ; + +The kernel maintains a counter that contains the number of jiffies +since the last boot, which can be accessed via the :c:macro:`jiffies` +global variable or macro. We can use it to calculate a time in the +future for timers: + +.. code-block:: c + + #include <linux/jiffies.h> + + unsigned long current_jiffies, next_jiffies; + unsigned long seconds = 1; + + current_jiffies = jiffies; + next_jiffies = jiffies + seconds * HZ; + +To stop a timer, use :c:func:`del_timer` and :c:func:`del_timer_sync`: + +.. code-block:: c + + int del_timer(struct timer_list *timer); + int del_timer_sync(struct timer_list *timer); + +These functions can be called for both a scheduled timer and an +unplanned timer. :c:func:`del_timer_sync` is used to eliminate the +races that can occur on multiprocessor systems, since at the end of +the call it is guaranteed that the timer processing function does not +run on any processor. + +A frequent mistake in using timers is that we forget to turn off +timers. For example, before removing a module, we must stop the timers +because if a timer expires after the module is removed, the handler +function will no longer be loaded into the kernel and a kernel oops +will be generated. + +The usual sequence used to initialize and schedule a one-second +timeout is: + +.. code-block:: c + + #include <linux/sched.h> + + void timer_function(struct timer_list *); + + struct timer_list timer ; + unsigned long seconds = 1; + + timer_setup(&timer, timer_function, 0); + mod_timer(&timer, jiffies + seconds * HZ); + +And to stop it: + +.. code-block:: c + + del_timer_sync(&timer); + +Locking +------- + +For synchronization between code running in process context (A) and +code running in softirq context (B) we need to use special locking +primitives. We must use spinlock operations augmented with +deactivation of bottom-half handlers on the current processor in (A), +and in (B) only basic spinlock operations. Using spinlocks makes sure +that we don't have races between multiple CPUs while deactivating the +softirqs makes sure that we don't deadlock in the softirq is scheduled +on the same CPU where we already acquired a spinlock. + +We can use the :c:func:`local_bh_disable` and +:c:func:`local_bh_enable` to disable and enable softirqs handlers (and +since they run on top of softirqs also timers and tasklets): + +.. code-block:: c + + void local_bh_disable(void); + void local_bh_enable(void); + +Nested calls are allowed, the actual reactivation of the softirqs is +done only when all local_bh_disable() calls have been complemented by +local_bh_enable() calls: + +.. code-block:: c + + /* We assume that softirqs are enabled */ + local_bh_disable(); /* Softirqs are now disabled */ + local_bh_disable(); /* Softirqs remain disabled */ + + local_bh_enable(); /* Softirqs remain disabled */ + local_bh_enable(); /* Softirqs are now enabled */ + +.. attention:: These above calls will disable the softirqs only on the + local processor and they are usually not safe to use, they must be + complemented with spinlocks. + + +Most of the time device drivers will use special versions of spinlocks +calls for synchronization like :c:func:`spin_lock_bh` and +:c:func:`spin_unlock_bh`: + +.. code-block:: c + + void spin_lock_bh(spinlock_t *lock); + void spin_unlock_bh(spinlock_t *lock); + + +Workqueues +========== + +Workqueues are used to schedule actions to run in process context. The +base unit with which they work is called work. There are two types of +work: + +* :c:type:`struct work_struct` - it schedules a task to run at + a later time +* :c:type:`struct delayed_work` - it schedules a task to run after at + least a given time interval + +A delayed work uses a timer to run after the specified time +interval. The calls with this type of work are similar to those for +:c:type:`struct work_struct`, but has **_delayed** in the functions +names. + +Before using them a work item must be initialized. There are two types +of macros that can be used, one that declares and initializes the work +item at the same time and one that only initializes the work item (and +the declaration must be done separately): + +.. code-block:: c + + #include <linux/workqueue.h> + + DECLARE_WORK(name , void (*function)(struct work_struct *)); + DECLARE_DELAYED_WORK(name, void(*function)(struct work_struct *)); + + INIT_WORK(struct work_struct *work, void(*function)(struct work_struct *)); + INIT_DELAYED_WORK(struct delayed_work *work, void(*function)(struct work_struct *)); + +:c:func:`DECLARE_WORK` and :c:func:`DECLARE_DELAYED_WORK` declare and +initialize a work item, and :c:func:`INIT_WORK` and +:c:func:`INIT_DELAYED_WORK` initialize an already declared work item. + +The following sequence declares and initiates a work item: + +.. code-block:: c + + #include <linux/workqueue.h> + + void my_work_handler(struct work_struct *work); + + DECLARE_WORK(my_work, my_work_handler); + +Or, if we want to initialize the work item separately: + +.. code-block:: c + + void my_work_handler(struct work_struct * work); + + struct work_struct my_work; + + INIT_WORK(&my_work, my_work_handler); + +Once declared and initialized, we can schedule the task using +:c:func:`schedule_work` and :c:func:`schedule_delayed_work`: + +.. code-block:: c + + schedule_work(struct work_struct *work); + + schedule_delayed_work(struct delayed_work *work, unsigned long delay); + +:c:func:`schedule_delayed_work` can be used to plan a work item for +execution with a given delay. The delay time unit is jiffies. + +Work items can not be masked but they can be canceled by calling +:c:func:`cancel_delayed_work_sync` or :c:func:`cancel_work_sync`: + +.. code-block:: c + + int cancel_work_sync(struct delayed_work *work); + int cancel_delayed_work_sync(struct delayed_work *work); + +The call only stops the subsequent execution of the work item. If the +work item is already running at the time of the call, it will continue +to run. In any case, when these calls return, it is guaranteed that +the task will no longer run. + +.. attention:: While there are versions of these functions that are + not synchronous (.e.g. :c:func:`cancel_work`) do not + use them when you are performing cleanup work otherwise + race condition could occur. + +We can wait for a workqueue to complete running all of its work items by calling :c:func:`flush_scheduled_work`: + +.. code-block:: c + + void flush_scheduled_work(void); + +This function is blocking and, therefore, can not be used in interrupt +context. The function will wait for all work items to be completed. +For delayed work items, :c:type:`cancel_delayed_work` must be called +before :c:func:`flush_scheduled_work`. + +Finally, the following functions can be used to schedule work items on +a particular processor (:c:func:`schedule_delayed_work_on`), or on all +processors (:c:func:`schedule_on_each_cpu`): + +.. code-block:: c + + int schedule_delayed_work_on(int cpu, struct delayed_work *work, unsigned long delay); + int schedule_on_each_cpu(void(*function)(struct work_struct *)); + +A usual sequence to initialize and schedule a work item is the following: + +.. code-block:: c + + void my_work_handler(struct work_struct *work); + + struct work_struct my_work; + + INIT_WORK(&my_work, my_work_handler); + + schedule_work(&my_work); + +And for waiting for termination of a work item: + +.. code-block:: c + + flush_scheduled_work(); + +As you can see, the *my_work_handler* function receives the task as +the parameter. To be able to access the module's private data, you can +use :c:func:`container_of`: + +.. code-block:: c + + struct my_device_data { + struct work_struct my_work; + // ... + }; + + void my_work_handler(struct work_struct *work) + { + struct my_device_data * my_data; + + my_data = container_of(work, struct my_device_data, my_work); + // ... + } + +Scheduling work items with the functions above will run the handler in +the context of a kernel thread called *events/x*, where x is the +processor number. The kernel will initialize a kernel thread (or a +pool of workers) for each processor present in the system: + +.. code-block:: shell + + $ ps -e + PID TTY TIME CMD + 1? 00:00:00 init + 2 ? 00:00:00 ksoftirqd / 0 + 3 ? 00:00:00 events / 0 <--- kernel thread that runs work items + 4 ? 00:00:00 khelper + 5 ? 00:00:00 kthread + 7? 00:00:00 kblockd / 0 + 8? 00:00:00 kacpid + +The above functions use a predefined workqueue (called events), and +they run in the context of the *events/x* thread, as noted +above. Although this is sufficient in most cases, it is a shared +resource and large delays in work items handlers can cause delays for +other queue users. For this reason there are functions for creating +additional queues. + +A workqueue is represented by :c:type:`struct workqueue_struct`. A new +workqueue can be created with these functions: + +.. code-block:: c + + struct workqueue_struct *create_workqueue(const char *name); + struct workqueue_struct *create_singlethread_workqueue(const char *name); + +:c:func:`create_workqueue` uses one thread for each processor in the +system, and :c:func:`create_singlethread_workqueue` uses a single +thread. + +To add a task in the new queue, use :c:func:`queue_work` or +:c:func:`queue_delayed_work`: + +.. code-block:: c + + int queue_work(struct workqueue_struct * queue, struct work_struct *work); + + int queue_delayed_work(struct workqueue_struct *queue, + struct delayed_work * work , unsigned long delay); + +:c:func:`queue_delayed_work` can be used to plan a work for execution +with a given delay. The time unit for the delay is jiffies. + +To wait for all work items to finish call :c:func:`flush_workqueue`: + +.. code-block:: c + + void flush_workqueue(struct worksqueue_struct * queue); + +And to destroy the workqueue call :c:func:`destroy_workqueue` + +.. code-block:: c + + void destroy_workqueue(struct workqueue_struct *queue); + +The next sequence declares and initializes an additional workqueue, +declares and initializes a work item and adds it to the queue: + +.. code-block:: c + + void my_work_handler(struct work_struct *work); + + struct work_struct my_work; + struct workqueue_struct * my_workqueue; + + my_workqueue = create_singlethread_workqueue("my_workqueue"); + INIT_WORK(&my_work, my_work_handler); + + queue_work(my_workqueue, &my_work); + +And the next code sample shows how to remove the workqueue: + +.. code-block:: c + + flush_workqueue(my_workqueue); + destroy_workqueue(my_workqueue); + +The work items planned with these functions will run in the context of +a new kernel thread called *my_workqueue*, the name passed to +:c:func:`create_singlethread_workqueue`. + +Kernel threads +============== + +Kernel threads have emerged from the need to run kernel code in +process context. Kernel threads are the basis of the workqueue +mechanism. Essentially, a kernel thread is a thread that only runs in +kernel mode and has no user address space or other user attributes. + +To create a kernel thread, use :c:func:`kthread_create`: + +.. code-block:: c + + #include <linux/kthread.h> + + struct task_struct *kthread_create(int (*threadfn)(void *data), + void *data, const char namefmt[], ...); + +* *threadfn* is a function that will be run by the kernel thread +* *data* is a parameter to be sent to the function +* *namefmt* represents the kernel thread name, as it is displayed in + ps/top ; Can contain sequences %d , %s etc. Which will be replaced + according to the standard printf syntax. + +For example, the following call: + +.. code-block:: c + + kthread_create (f, NULL, "%skthread%d", "my", 0); + +Will create a kernel thread with the name mykthread0. + +The kernel thread created with this function will be stopped (in the +*TASK_INTERRUPTIBLE* state). To start the kernel thread, call the +:c:func:`wake_up_process`: + +.. code-block:: c + + #include <linux/sched.h> + + int wake_up_process(struct task_struct *p); + +Alternatively, you can use :c:func:`kthread_run` to create and run a +kernel thread: + +.. code-block:: c + + struct task_struct * kthread_run(int (*threadfn)(void *data) + void *data, const char namefmt[], ...); + +Even if the programming restrictions for the function running within +the kernel thread are more relaxed and scheduling is closer to +scheduling in userspace, there are, however, some limitations to be +taken into account. We will list below the actions that can or can not +be made from a kernel thread: + +* can't access the user address space (even with copy_from_user, + copy_to_user) because a kernel thread does not have a user address + space +* can't implement busy wait code that runs for a long time; if the + kernel is compiled without the preemptive option, that code will run + without being preempted by other kernel threads or user processes + thus hogging the system +* can call blocking operations +* can use spinlocks, but if the hold time of the lock is significant, + it is recommended to use mutexes + +The termination of a kernel thread is done voluntarily, within the +function running in the kernel thread, by calling :c:func:`do_exit`: + +.. code-block:: c + + fastcall NORET_TYPE void do_exit(long code); + +Most of the implementations of kernel threads handlers use the same +model and it is recommended to start using the same model to avoid +common mistakes: + +.. code-block:: c + + #include <linux/kthread.h> + + DECLARE_WAIT_QUEUE_HEAD(wq); + + // list events to be processed by kernel thread + struct list_head events_list; + struct spin_lock events_lock; + + + // structure describing the event to be processed + struct event { + struct list_head lh; + bool stop; + //... + }; + + struct event* get_next_event(void) + { + struct event *e; + + spin_lock(&events_lock); + e = list_first_entry(&events_list, struct event*, lh); + if (e) + list_del(&e->lh); + spin_unlock(&events_lock); + + return e + } + + int my_thread_f(void *data) + { + struct event *e; + + while (true) { + wait_event(wq, (e = get_next_event)); + + /* Event processing */ + + if (e->stop) + break; + } + + do_exit(0); + } + + /* start and start kthread */ + kthread_run(my_thread_f, NULL, "%skthread%d", "my", 0); + + +With the template above, the kernel thread requests can be issued +with: + +.. code-block:: c + + void send_event(struct event *ev) + { + spin_lock(&events_lock); + list_add(&ev->lh, &events_list); + spin_unlock(&events_lock); + wake_up(&wq); + } + +Further reading +=============== + +* `Linux Device Drivers, 3rd ed., Ch. 7: Time, Delays, and Deferred Work <http://lwn.net/images/pdf/LDD3/ch07.pdf>`_ +* `Scheduling Tasks <http://tldp.org/LDP/lkmpg/2.6/html/x1211.html>`_ +* `Driver porting: the workqueue interface <http://lwn.net/Articles/23634/>`_ +* `Workqueues get a rework <http://lwn.net/Articles/211279/>`_ +* `Kernel threads made easy <http://lwn.net/Articles/65178/>`_ +* `Unreliable Guide to Locking <http://www.kernel.org/pub/linux/kernel/people/rusty/kernel-locking/index.html>`_ + +Exercises +========= + +.. include:: ../labs/exercises-summary.hrst +.. |LAB_NAME| replace:: deferred_work + +0. Intro +-------- + +Using |LXR|_, find the definitions of the following symbols: + +* :c:macro:`jiffies` +* :c:type:`struct timer_list` +* :c:func:`spin_lock_bh function` + + +1.Timer +------- + +We're looking at creating a simple kernel module that displays a +message at *TIMER_TIMEOUT* seconds after the module's kernel load. + +Generate the skeleton for the task named **1-2-timer** and follow the +sections marked with **TODO 1** to complete the task. + +.. hint:: Use `pr_info(...)`. Messages will be displayed on the + console and can also be viewed using dmesg. When scheduling + the timer we need to use the absolute time of the system (in + the future) in number of ticks. The current time of the + system in the number of ticks is given by :c:type:`jiffies`. + Thus, the absolute time we need to pass to the timer is + ``jiffies + TIMER_TIMEOUT * HZ``. + + For more information review the `Timers`_ section. + + +2. Periodic timer +----------------- + +Modify the previous module to display the message in once every +TIMER_TIMEOUT seconds. Follow the section marked with **TODO 2** in the +skeleton. + +3. Timer control using ioctl +---------------------------- + +We plan to display information about the current process after N +seconds of receiving a ioctl call from user space. N is transmitted as +ioctl parameter. + +Generate the skeleton for the task named **3-4-5-deferred** and +follow the sections marked with **TODO 1** in the skeleton driver. + +You will need to implement the following ioctl operations. + +* MY_IOCTL_TIMER_SET to schedule a timer to run after a number of + seconds which is received as an argument to ioctl. The timer does + not run periodically. + * This command receives directly a value, not a pointer. + +* MY_IOCTL_TIMER_CANCEL to deactivate the timer. + +.. note:: Review :ref:`ioctl` for a way to access the ioctl argument. + +.. note:: Review the `Timers`_ section for information on enabling / + disabling a timer. In the timer handler, display the current + process identifier (PID) and the process executable image name. + +.. hint:: You can find the current process identifier using the *pid* + and *comm* fields of the current process. For details, + review :ref:`proc-info`. + +.. hint:: To use the device driver from userspace you must create the + device character file */dev/deferred* using the mknod + utility. Alternatively, you can run the + *3-4-5-deferred/kernel/makenode* script that performs this + operation. + +Enable and disable the timer by calling user-space ioctl +operations. Use the *3-4-5-deferred/user/test* program to test +planning and canceling of the timer. The program receives the ioctl +type operation and its parameters (if any) on the command line. + +.. hint:: Run the test executable without arguments to observe the + command line options it accepts. + + To enable the timer after 3 seconds use: + + .. code-block:: c + + ./test s 3 + + To disable the timer use: + + .. code-block:: c + + ./test c + + +Note that every time the current process the timer runs from is +*swapper/0* with PID 0. This process is the idle process. It is +running when there is nothing else to run on. Because the virtual +machine is very light and does not do much it is natural to see this +process most of the time. + +4. Blocking operations +---------------------- + +Next we want to see what happens when we perform blocking operations +in a timer routine. For this we try to call in the timer-handling +routines a function called alloc_io() that simulates a blocking +operation. + +Modify the module so that when you receive *MY_IOCTL_TIMER_ALLOC* +command the timer handler will call :c:func:`alloc_io`. Follow the +sections marked with **TODO 2** in the skeleton. + +Use the same timer. To differentiate functionality in the timer +handler, use a flag in the device structure. Use the +*TIMER_TYPE_ALLOC* and *TIMER_TYPE_SET* macros defined in the code +skeleton. For initialization, use TIMER_TYPE_NONE. + +Run the test program to verify the functionality of task 3. Run the +test program again to call :c:func:`alloc_io()`. + +.. note:: The driver causes an error because a blocking function is + called in the atomic context (the timer handler runs + interrupt context). + +5. Workqueues +------------- + +We will modify the module to prevent the error observed in the +previous task. + +To do so, lets call :c:func:`alloc_io` using workqueues. Schedule a +work item from the timer handler In the work handler (running in +process context) call the :c:func:`alloc_io`. Follow the sections +marked with **TODO 3** in the skeleton and review the `Workqueues`_ +section if needed. + +.. hint:: Add a new field with the type :c:type:`struct work_struct` + in your device structure. Initialize this field. Schedule + the work from the timer handler using :c:func:`schedule_work`. + Schedule the timer handler aften N seconds from the ioctl. + +6. Kernel thread +---------------- + +Implement a simple module that creates a kernel thread that shows the +current process identifier. + +Generate the skeleton for the task named **6-kthread** and follow the +TODOs from the skeleton. + + +.. note:: There are two options for creating and running a thread: + + * :c:func:`kthread_run` to create and run the thread + + * :c:func:`kthread_create` to create a suspended thread and + then start it running with :c:func:`wake_up_process`. + + Review the `Kernel Threads`_ section if needed. + +.. attention:: Synchronize the thread termination with module unloading: + + * The thread should finish when the module is unloaded + + * Wait for the kernel thread to exit before continuing + with unloading + + +.. hint:: For synchronization use two wait queues and two flags. + + Review :ref:`waiting-queues` on how to use waiting queue. + + Use atomic variables for flags. Review :ref:`atomic-variables`. + + +7. Buffer shared between timer and process +------------------------------------------ + +The purpose of this task is to exercise the synchronization between a +deferrable action (a timer) and process context. Set up a periodic +timer that monitors a list of processes. If one of the processes +terminate a message is printed. Processes can be dynamically added to +the list. Use the *3-4-5-deferred/kernel/* skeleton as a base and +follow the **TODO 4** markings to complete the task. + +When the *MY_IOCTL_TIMER_MON* command is received check that the given +process exists and if so add to the monitored list of +processes and then arm the timer after setting its type. + +.. hint:: Use :c:func:`get_proc` which checks the pid, finds the + associated :c:type:`struct task_struct` and allocates a + :c:type:`struct mon_proc` item you can add to your + list. Note that the function also increases the reference + counter of the task, so that its memory won't be free when + the task terminates. + +.. attention:: Use a spinlock to protect the access to the list. Note + that since we share data with the timer handler we need + to disable bottom-half handlers in addition to taking + the lock. Review the `Locking`_ section. + +.. hint:: Collect the information every second from a timer. Use the + existing timer and add new behaviour for it via the + TIMER_TYPE_ACCT. To set the flag, use the *t* argument of + the test program. + + +In the timer handler iterate over the list of monitored processes and +check if they have terminated. If so, print the process name and pid +then remove the process from the list, decrement the task usage +counter so that it's memory can be free and finally free the +:c:type:`struct mon_proc` structure. + +.. hint:: Use the *state* field of :c:func:`struct task_struct`. A + task has terminated if its state is *TASK_DEAD*. + +.. hint:: Use :c:func:`put_task_struct` to decrement the task usage + counter. + +.. attention:: Make sure you protect the list access with a + spinlock. The simple variant will suffice. + +.. attention:: Make sure to use the safe iteration over the list since + we may need to remove an item from the list. + +Rearm the timer after checking the list. diff --git a/refs/pull/405/merge/_sources/labs/device_drivers.rst.txt b/refs/pull/405/merge/_sources/labs/device_drivers.rst.txt new file mode 100644 index 00000000..f73121b5 --- /dev/null +++ b/refs/pull/405/merge/_sources/labs/device_drivers.rst.txt @@ -0,0 +1,1037 @@ +======================== +Character device drivers +======================== + +Laboratory objectives +===================== + + * understand the concepts behind character device driver + * understand the various operations that can be performed on character devices + * working with waiting queues + +Overview +======== + +In UNIX, hardware devices are accessed by the user through special device +files. These files are grouped into the /dev directory, and system calls +``open``, ``read``, ``write``, ``close``, ``lseek``, ``mmap`` etc. are +redirected by the operating system to the device driver associated with the +physical device. The device driver is a kernel component (usually a module) +that interacts with a hardware device. + +In the UNIX world there are two categories of device files and thus +device drivers: character and block. This division is done by the speed, +volume and way of organizing the data to be transferred from the device to the +system and vice versa. In the first category, there are slow devices, which +manage a small amount of data, and access to data does not require frequent +seek queries. Examples are devices such as keyboard, mouse, serial ports, +sound card, joystick. In general, operations with these devices (read, write) +are performed sequentially byte by byte. The second category includes devices +where data volume is large, data is organized on blocks, and search is common. +Examples of devices that fall into this category are hard drives, cdroms, ram +disks, magnetic tape drives. For these devices, reading and writing is done at +the data block level. + +For the two types of device drivers, the Linux kernel offers different APIs. +If for character devices system calls go directly to device drivers, in case of +block devices, the drivers do not work directly with system calls. In +the case of block devices, communication between the user-space and the block +device driver is mediated by the file management subsystem and the block device +subsystem. The role of these subsystems is to prepare the device driver's +necessary resources (buffers), to keep the recently read data in the cache +buffer, and to order the read and write operations for performance reasons. + +Majors and minors +================= + +In UNIX, the devices traditionally had a unique, fixed identifier associated +with them. This tradition is preserved in Linux, although identifiers can be +dynamically allocated (for compatibility reasons, most drivers still use static +identifiers). The identifier consists of two parts: major and minor. The first +part identifies the device type (IDE disk, SCSI disk, serial port, etc.) +and the second one identifies the device (first disk, second serial port, +etc.). Most times, the major identifies the driver, while the minor identifies +each physical device served by the driver. In general, a driver will have a +major associate and will be responsible for all minors associated with that +major. + +.. code-block:: bash + + $ ls -la /dev/hda? /dev/ttyS? + brw-rw---- 1 root disk 3, 1 2004-09-18 14:51 /dev/hda1 + brw-rw---- 1 root disk 3, 2 2004-09-18 14:51 /dev/hda2 + crw-rw---- 1 root dialout 4, 64 2004-09-18 14:52 /dev/ttyS0 + crw-rw---- 1 root dialout 4, 65 2004-09-18 14:52 /dev/ttyS1 + +As can be seen from the example above, device-type information can be found +using the ls command. The special character files are identified by the ``c`` +character in the first column of the command output, and the block type by the +character ``b``. In columns ``5`` and ``6`` of the result you can see the +major, respectively the minor for each device. + +Certain major identifiers are statically assigned to devices (in the +``Documentation/admin-guide/devices.txt`` file from the kernel sources). When choosing the +identifier for a new device, you can use two methods: static (choose a number +that does not seem to be used already) or dynamically. In /proc/devices are the +loaded devices, along with the major identifier. + +To create a device type file, use the ``mknod`` command; the command receives the +type (``block`` or ``character``), ``major`` and ``minor`` of the device +(``mknod name type major minor``). Thus, if you want to create a character device +named ``mycdev`` with the major ``42`` and minor ``0``, use the command: + +.. code-block:: bash + + # mknod /dev/mycdev c 42 0 + +To create the block device with the name ``mybdev`` with the major 240 and minor 0 +the command will be: + +.. code-block:: bash + + # mknod /dev/mybdev b 240 0 + +Next, we'll refer to character devices as drivers. + +Data structures for a character device +====================================== + +In the kernel, a character-type device is represented by +:c:type:`struct cdev <cdev>`, a structure used to register it in the +system. Most driver operations use three important structures: +``struct file_operations``, ``struct file`` and ``struct inode``. + +:c:type:`struct file_operations` +-------------------------------- + +As mentioned above, the character device drivers receive unaltered system calls +made by users over device-type files. Consequently, implementation of a character +device driver means implementing the system calls specific to files: ``open``, +``close``, ``read``, ``write``, ``lseek``, ``mmap``, etc. These operations are +described in the fields of the ``struct file_operations`` structure: + +.. code-block:: c + + #include <linux/fs.h> + + struct file_operations { + struct module *owner; + loff_t (*llseek) (struct file *, loff_t, int); + ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); + ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); + [...] + long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); + [...] + int (*open) (struct inode *, struct file *); + int (*flush) (struct file *, fl_owner_t id); + int (*release) (struct inode *, struct file *); + [...] + +.. ** + +It can be noticed that the signature of the function differs from the system +call that the user uses. The operating system sits between the user and +the device driver to simplify implementation in the device driver. + +``open`` does not receive the parameter path or the various parameters that control +the file opening mode. Similarly, ``read``, ``write``, ``release``, ``ioctl``, ``lseek`` +do not receive as a parameter a file descriptor. Instead, these routines receive as +parameters two structures: ``file`` and ``inode``. Both structures represent a file, +but from different perspectives. + +Most parameters for the presented operations have a direct meaning: + * ``file`` and ``inode`` identifies the device type file; + * ``size`` is the number of bytes to be read or written; + * ``offset`` is the displacement to be read or written (to be updated + accordingly); + * ``user_buffer`` user buffer from which it reads / writes; + * ``whence`` is the way to seek (the position where the search operation starts); + * ``cmd`` and ``arg`` are the parameters sent by the users to the ioctl call (IO + control). + +``inode`` and ``file`` structures +--------------------------------- + +An ``inode`` represents a file from the point of view of the file system. Attributes +of an inode are the size, rights, times associated with the file. An inode uniquely +identifies a file in a file system. + +The ``file`` structure is still a file, but closer to the user's point of view. +From the attributes of the file structure we list: the inode, the file name, +the file opening attributes, the file position. All open files at a given time +have associated a ``file`` structure. + +To understand the differences between inode and file, we will use an analogy +from object-oriented programming: if we consider a class inode, then the files +are objects, that is, instances of the inode class. Inode represents the static +image of the file (the inode has no state), while the file represents the +dynamic image of the file (the file has state). + +Returning to device drivers, the two entities have almost always standard ways +of using: the inode is used to determine the major and minor of the device on +which the operation is performed, and the file is used to determine the flags +with which the file was opened, but also to save and access (later) private +data. + +The file structure contains, among many fields: + + * ``f_mode``, which specifies read (``FMODE_READ``) or write + (``FMODE_WRITE``); + * ``f_flags``, which specifies the file opening flags (``O_RDONLY``, + ``O_NONBLOCK``, ``O_SYNC``, ``O_APPEND``, ``O_TRUNC``, etc.); + * ``f_op``, which specifies the operations associated with the file (pointer to + the ``file_operations`` structure ); + * ``private_data``, a pointer that can be used by the programmer to store + device-specific data; The pointer will be initialized to a memory location + assigned by the programmer. + * ``f_pos``, the offset within the file + +The inode structure contains, among much information, an ``i_cdev`` +field, which is a pointer to the structure that defines the character +device (when the inode corresponds to a character device). + +Implementation of operations +============================ + +To implement a device driver, it is recommended that you create a structure +that contains information about the device, information used in the module. In +the case of a driver for a character device, the structure will contain a cdev +structure field to refer to the device. The following example uses the struct +my_device_data: + +.. code-block:: c + + #include <linux/fs.h> + #include <linux/cdev.h> + + struct my_device_data { + struct cdev cdev; + /* my data starts here */ + //... + }; + + static int my_open(struct inode *inode, struct file *file) + { + struct my_device_data *my_data; + + my_data = container_of(inode->i_cdev, struct my_device_data, cdev); + + file->private_data = my_data; + //... + } + + static int my_read(struct file *file, char __user *user_buffer, size_t size, loff_t *offset) + { + struct my_device_data *my_data; + + my_data = (struct my_device_data *) file->private_data; + + //... + } + +.. ** + +A structure like ``my_device_data`` will contain the data associated with a device. +The ``cdev`` field (``cdev`` type) is a character-type device and is used to record it +in the system and identify the device. The pointer to the ``cdev`` member can be +found using the ``i_cdev`` field of the ``inode`` structure (using the ``container_of`` +macro). In the private_data field of the file structure, information can be +stored at open which is then available in the ``read``, ``write``, ``release``, etc. +routines. + +Registration and unregistration of character devices +==================================================== + +The registration/unregistration of a device is made by specifying the major and +minor. The ``dev_t`` type is used to keep the identifiers of a device (both major +and minor) and can be obtained using the ``MKDEV`` macro. + +For the static assignment and unallocation of device identifiers, the +``register_chrdev_region`` and ``unregister_chrdev_region`` functions are used: + +.. code-block:: c + + #include <linux/fs.h> + + int register_chrdev_region(dev_t first, unsigned int count, char *name); + void unregister_chrdev_region(dev_t first, unsigned int count); + +.. ** + +It is recommended that device identifiers be dynamically assigned to the +``alloc_chrdev_region`` function. + +Below sequence reserves ``my_minor_count`` devices, starting with ``my_major`` +major and ``my_first_minor`` minor (if the max value for minor is exceeded, +move to the next major): + +.. code-block:: c + + #include <linux/fs.h> + ... + + err = register_chrdev_region(MKDEV(my_major, my_first_minor), my_minor_count, + "my_device_driver"); + if (err != 0) { + /* report error */ + return err; + } + ... + +.. ** + +After assigning the identifiers, the character device will have to be +initialized (``cdev_init``) and the kernel will have to be notified(``cdev_add``). The +``cdev_add`` function must be called only after the device is ready to receive +calls. Removing a device is done using the ``cdev_del`` function. + +.. code-block:: c + + #include <linux/cdev.h> + + void cdev_init(struct cdev *cdev, struct file_operations *fops); + int cdev_add(struct cdev *dev, dev_t num, unsigned int count); + void cdev_del(struct cdev *dev); + +.. ** + +The following sequence registers and initializes MY_MAX_MINORS devices: + +.. code-block:: c + + #include <linux/fs.h> + #include <linux/cdev.h> + + #define MY_MAJOR 42 + #define MY_MAX_MINORS 5 + + struct my_device_data { + struct cdev cdev; + /* my data starts here */ + //... + }; + + struct my_device_data devs[MY_MAX_MINORS]; + + const struct file_operations my_fops = { + .owner = THIS_MODULE, + .open = my_open, + .read = my_read, + .write = my_write, + .release = my_release, + .unlocked_ioctl = my_ioctl + }; + + int init_module(void) + { + int i, err; + + err = register_chrdev_region(MKDEV(MY_MAJOR, 0), MY_MAX_MINORS, + "my_device_driver"); + if (err != 0) { + /* report error */ + return err; + } + + for(i = 0; i < MY_MAX_MINORS; i++) { + /* initialize devs[i] fields */ + cdev_init(&devs[i].cdev, &my_fops); + cdev_add(&devs[i].cdev, MKDEV(MY_MAJOR, i), 1); + } + + return 0; + } + +.. ** + +While the following sequence deletes and unregisters them: + +.. code-block:: c + + void cleanup_module(void) + { + int i; + + for(i = 0; i < MY_MAX_MINORS; i++) { + /* release devs[i] fields */ + cdev_del(&devs[i].cdev); + } + unregister_chrdev_region(MKDEV(MY_MAJOR, 0), MY_MAX_MINORS); + } + +.. ** + +.. note:: Initialization of the struct my_fops used the initialization + of members by name, defined in C99 standard (see designated + initializers and the file_operations structure). Structure + members who do not explicitly appear in this initialization + will be set to the default value for their type. For + example, after the initialization above, ``my_fops.mmap`` will + be NULL. + +.. _access_to_process_address_space: + +Access to the address space of the process +========================================== + +A driver for a device is the interface between an application and hardware. As +a result, we often have to access user-space data. Accessing it can not be done +directly (by dereferencing a user-space pointer). Direct access of a +user-space pointer can lead to incorrect behavior (depending on architecture, a +user-space pointer may not be valid or mapped to kernel-space), a kernel oops +(the user-mode pointer can refer to a non-resident memory area) or security +issues. Proper access to user-space data is done by calling the macros / +functions below: + +.. code-block:: c + + #include <asm/uaccess.h> + + put_user(type val, type *address); + get_user(type val, type *address); + unsigned long copy_to_user(void __user *to, const void *from, unsigned long n); + unsigned long copy_from_user(void *to, const void __user *from, unsigned long n); + +.. ** + +All macros / functions return 0 in case of success and another value in case of +error and have the following roles: + + * ``put_user`` store the value ``val`` to user-space address ``address``; + Type can be one on 8, 16, 32, 64 bit (the maximum supported type depends on the + hardware platform); + * ``get_user`` analogue to the previous function, only that val will be set to a + value identical to the value at the user-space address given by address; + * ``copy_to_user`` copies ``n`` bytes from the kernel-space, from the address + referenced by ``from`` in user-space to the address referenced by ``to``; + * ``copy_from_user`` copies ``n`` bytes from user-space from the address + referenced by ``from`` in kernel-space to the address referenced by ``to``. + +A common section of code that works with these functions is: + +.. code-block:: c + + #include <asm/uaccess.h> + + /* + * Copy at most size bytes to user space. + * Return ''0'' on success and some other value on error. + */ + if (copy_to_user(user_buffer, kernel_buffer, size)) + return -EFAULT; + else + return 0; + +Open and release +================ + +The ``open`` function performs the initialization of a device. In most cases, +these operations refer to initializing the device and filling in specific data +(if it is the first open call). The release function is about releasing +device-specific resources: unlocking specific data and closing the device if +the last call is close. + +In most cases, the open function will have the following structure: + +.. code-block:: c + + static int my_open(struct inode *inode, struct file *file) + { + struct my_device_data *my_data = + container_of(inode->i_cdev, struct my_device_data, cdev); + + /* validate access to device */ + file->private_data = my_data; + + /* initialize device */ + ... + + return 0; + } + +.. ** + +A problem that occurs when implementing the ``open`` function is access control. +Sometimes a device needs to be opened once at a time; More specifically, do not +allow the second open before the release. To implement this restriction, you +choose a way to handle an open call for an already open device: it can return +an error (``-EBUSY``), block open calls until a release operation, or shut down +the device before do the open. + +At the user-space call of the open and close functions on the device, call +my_open and my_release in the driver. An example of a user-space call: + +.. code-block:: c + + int fd = open("/dev/my_device", O_RDONLY); + if (fd < 0) { + /* handle error */ + } + + /* do work */ + //.. + + close(fd); + +.. ** + +Read and write +============== + +The read and write operations are reaching the device driver as a +result of an user-space program calling the read or write system calls: + +.. code-block:: c + + if (read(fd, buffer, size) < 0) { + /* handle error */ + } + + if (write(fd, buffer, size) < 0) { + /* handle error */ + } + +.. ** + +The ``read`` and ``write`` functions transfer data between the device and the +user-space: the read function reads the data from the device and transfers it +to the user-space, while writing reads the user-space data and writes it to the +device. The buffer received as a parameter is a user-space pointer, which is +why it is necessary to use the ``copy_to_user`` or ``copy_from_user`` functions. + +The value returned by read or write can be: + + * the number of bytes transferred; if the returned value is less than the size + parameter (the number of bytes requested), then it means that a partial + transfer was made. Most of the time, the user-space app calls the system call + (read or write) function until the required data number is transferred. + * 0 to mark the end of the file in the case of read ; if write returns the + value 0 then it means that no byte has been written and that no error has + occurred; In this case, the user-space application retries the write call. + * a negative value indicating an error code. + +To perform a data transfer consisting of several partial transfers, the +following operations should be performed: + + * transfer the maximum number of possible bytes between the buffer received + as a parameter and the device (writing to the device/reading from the device + will be done from the offset received as a parameter); + * update the offset received as a parameter to the position from which the + next read / write data will begin; + * return the number of bytes transferred. + +The sequence below shows an example for the read function that takes +into account the internal buffer size, user buffer size and the offset: + +.. code-block:: c + + static int my_read(struct file *file, char __user *user_buffer, + size_t size, loff_t *offset) + { + struct my_device_data *my_data = (struct my_device_data *) file->private_data; + ssize_t len = min(my_data->size - *offset, size); + + if (len <= 0) + return 0; + + /* read data from my_data->buffer to user buffer */ + if (copy_to_user(user_buffer, my_data->buffer + *offset, len)) + return -EFAULT; + + *offset += len; + return len; + } + +.. ** + +The images below illustrate the read operation and how data is +transferred between the user-space and the driver: + + 1. when the driver has enough data available (starting with the OFFSET + position) to accurately transfer the required size (SIZE) to the user. + 2. when a smaller amount is transferred than required. + +.. image:: ../res/read.png + :width: 49 % +.. image:: ../res/read2.png + :width: 49 % + +We can look at the read operation implemented by the driver as a response to a +user-space read request. In this case, the driver is responsible for advancing +the offset according to how much it reads and returning the read size (which +may be less than what is required). + +The structure of the write function is similar: + +.. code-block:: c + + static int my_write(struct file *file, const char __user *user_buffer, + size_t size, loff_t * offset) + { + struct my_device_data *my_data = (struct my_device_data *) file->private_data; + ssize_t len = min(my_data->size - *offset, size); + + if (len <= 0) + return 0; + + /* read data from user buffer to my_data->buffer */ + if (copy_from_user(my_data->buffer + *offset, user_buffer, len)) + return -EFAULT; + + *offset += len; + return len; + } + +.. ** + +The write operation will respond to a write request from user-space. In +this case, depending on the maximum driver capacity (MAXSIZ), it can +write more or less than the required size. + +.. image:: ../res/write.png + :width: 49 % +.. image:: ../res/write2.png + :width: 49 % + +.. _ioctl: + +ioctl +===== + +In addition to read and write operations, a driver needs the ability to perform +certain physical device control tasks. These operations are accomplished by +implementing a ``ioctl`` function. Initially, the ioctl system call used Big Kernel +Lock. That's why the call was gradually replaced with its unlocked version +called ``unlocked_ioctl``. You can read more on LWN: +http://lwn.net/Articles/119652/ + +.. code-block:: c + + static long my_ioctl (struct file *file, unsigned int cmd, unsigned long arg); + +.. ** + +``cmd`` is the command sent from user-space. If a value is being sent from the +user-space call, it can be accessed directly. If a buffer is fetched, the arg +value will be a pointer to it, and must be accessed through the ``copy_to_user`` +or ``copy_from_user``. + +Before implementing the ``ioctl`` function, the numbers corresponding to the +commands must be chosen. One method is to choose consecutive numbers starting +at 0, but it is recommended to use ``_IOC(dir, type, nr, size)`` macro definition +to generate ioctl codes. The macro definition parameters are as follows: + + * ``dir`` represents the data transfer (``_IOC_NONE`` , ``_IOC_READ``, + ``_IOC_WRITE``). + * ``type`` represents the magic number (``Documentation/ioctl/ioctl-number.txt``); + * ``nr`` is the ioctl code for the device; + * ``size`` is the size of the transferred data. + +The following example shows an implementation for a ``ioctl`` function: + +.. code-block:: c + + #include <asm/ioctl.h> + + #define MY_IOCTL_IN _IOC(_IOC_WRITE, 'k', 1, sizeof(my_ioctl_data)) + + static long my_ioctl (struct file *file, unsigned int cmd, unsigned long arg) + { + struct my_device_data *my_data = + (struct my_device_data*) file->private_data; + my_ioctl_data mid; + + switch(cmd) { + case MY_IOCTL_IN: + if( copy_from_user(&mid, (my_ioctl_data *) arg, + sizeof(my_ioctl_data)) ) + return -EFAULT; + + /* process data and execute command */ + + break; + default: + return -ENOTTY; + } + + return 0; + } + +.. ** + +At the user-space call for the ioctl function, the my_ioctl function of the +driver will be called. An example of such a user-space call: + +.. code-block:: c + + if (ioctl(fd, MY_IOCTL_IN, buffer) < 0) { + /* handle error */ + } + +.. ** + +Waiting queues +============== + +It is often necessary for a thread to wait for an operation to finish, +but it is desirable that this wait is not busy-waiting. Using waiting +queues we can block a thread until an event occurs. When the condition +is satisfied, elsewhere in the kernel, in another process, in an +interrupt or deferrable work, we will wake up the process. + +A waiting queue is a list of processes that are waiting for a specific +event. A queue is defined with the ``wait_queue_head_t`` type and can +be used by the functions/macros: + +.. code-block:: c + + #include <linux/wait.h> + + DECLARE_WAIT_QUEUE_HEAD(wq_name); + + void init_waitqueue_head(wait_queue_head_t *q); + + int wait_event(wait_queue_head_t q, int condition); + + int wait_event_interruptible(wait_queue_head_t q, int condition); + + int wait_event_timeout(wait_queue_head_t q, int condition, int timeout); + + int wait_event_interruptible_timeout(wait_queue_head_t q, int condition, int timeout); + + void wake_up(wait_queue_head_t *q); + + void wake_up_interruptible(wait_queue_head_t *q); + +.. ** + +The roles of the macros / functions above are: + + * :c:func:`init_waitqueue_head` initializes the queue; to initialize the + queue at compile time, you can use the :c:macro:`DECLARE_WAIT_QUEUE_HEAD` macro; + * :c:func:`wait_event` and :c:func:`wait_event_interruptible` adds the current thread to the + queue while the condition is false, sets it to TASK_UNINTERRUPTIBLE or + TASK_INTERRUPTIBLE and calls the scheduler to schedule a new thread; Waiting + will be interrupted when another thread will call the wake_up function; + * :c:func:`wait_event_timeout` and :c:func:`wait_event_interruptible_timeout` have the same + effect as the above functions, only waiting can be interrupted at the end of + the timeout received as a parameter; + * :c:func:`wake_up` puts all threads off from state TASK_INTERRUPTIBLE and + TASK_UNINTERRUPTIBLE in TASK_RUNNING status; Remove these threads from the + queue; + * :c:func:`wake_up_interruptible` same action, but only threads with TASK_INTERRUPTIBLE + status are woken up. + +A simple example is that of a thread waiting to change the value of a flag. The +initializations are done by the sequence: + +.. code-block:: c + + #include <linux/sched.h> + + wait_queue_head_t wq; + int flag = 0; + + init_waitqueue_head(&wq); + +.. ** + +A thread will wait for the flag to be changed to a value other than zero: + +.. code-block:: c + + wait_event_interruptible(wq, flag != 0); + +.. ** + +While another thread will change the flag value and wake up the waiting threads: + +.. code-block:: c + + flag = 1 ; + wake_up_interruptible (&wq); + +.. ** + +Exercises +========= + +.. include:: ../labs/exercises-summary.hrst +.. |LAB_NAME| replace:: device_drivers + +0. Intro +-------- + +Using `LXR <http://elixir.free-electrons.com/linux/latest/source>`_ find the definitions +of the following symbols in the Linux kernel: + + * :c:type:`struct file` + * :c:type:`struct file_operations` + * :c:type:`generic_ro_fops` + * :c:func:`vfs_read` + + +1. Register/unregister +---------------------- + +The driver will control a single device with the ``MY_MAJOR`` major and +``MY_MINOR`` minor (the macros defined in the kernel/so2_cdev.c file). + + 1. Create **/dev/so2_cdev** character device node using **mknod**. + + .. hint:: Read `Majors and minors`_ section in the lab. + + 2. Implement the registration and deregistration of the device with the name + ``so2_cdev``, respectively in the init and exit module functions. Implement **TODO 1**. + + .. hint:: Read the section `Registration and unregistration of character devices`_ + + 3. Display, using ``pr_info``, a message after the registration and unregistration + operations to confirm that they were successful. Then load the module into the kernel: + + .. code-block:: bash + + $ insmod so2_cdev.ko + + And see character devices in ``/proc/devices``: + + .. code-block:: bash + + $ cat /proc/devices | less + + Identify the device type registered with major 42 . Note that ``/proc/devices`` + contains only the device types (major) but not the actual devices (i.e. minors). + + .. note:: Entries in /dev are not created by loading the module. These can be created + in two ways: + + * manually, using the ``mknod`` command as we did above. + * automatically using udev daemon + + 4. Unload the kernel module + + .. code-block:: bash + + rmmod so2_cdev + +2. Register an already registered major +--------------------------------------- + +Modify **MY_MAJOR** so that it points to an already used major number. + +.. hint:: See ``/proc/devices`` to get an already assigned major. + +See `errno-base.h <http://elixir.free-electrons.com/linux/v4.9/source/include/uapi/asm-generic/errno-base.h>`_ +and figure out what does the error code mean. +Return to the initial configuration of the module. + +3. Open and close +----------------- + +Run ``cat /dev/so2_cdev`` to read data from our char device. +Reading does not work because the driver does not have the open function implemented. +Follow comments marked with TODO 2 and implement them. + + 1. Initialize your device + + * add a cdev struct field to ``so2_device_data`` structure. + * Read the section `Registration and unregistration of character devices`_ in the lab. + + 2. Implement the open and release functions in the driver. + 3. Display a message in the open and release functions. + 4. Read again ``/dev/so2_cdev`` file. Follow the messages displayed by the kernel. + We still get an error because ``read`` function is not yet implemented. + +.. note:: The prototype of a device driver's operations is in the ``file_operations`` + structure. Read `Open and release`_ section. + +4. Access restriction +--------------------- + +Restrict access to the device with atomic variables, so that a single process +can open the device at a time. The rest will receive the "device busy" error +(``-EBUSY``). Restricting access will be done in the open function displayed by +the driver. Follow comments marked with **TODO 3** and implement them. + + 1. Add an ``atomic_t`` variable to the device structure. + 2. Initialize the variable at module initialization. + 3. Use the variable in the open function to restrict access to the device. We + recommend using :c:func:`atomic_cmpxchg`. + 4. Reset the variable in the release function to retrieve access to the device. + 5. To test your deployment, you'll need to simulate a long-term use of your + device. To simulate a sleep, call the scheduler at the end of the device opening: + +.. code-block:: bash + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1000); + +.. ** + + 6. Test using ``cat /dev/so2_cdev`` & ``cat /dev/so2_cdev``. + + +.. note:: The advantage of the atomic_cmpxchg function is that it can check the + old value of the variable and set it up to a new value, all in one + atomic operation. Read more details about `atomic_cmpxchg <https://www.khronos.org/registry/OpenCL/sdk/1.1/docs/man/xhtml/atomic_cmpxchg.html>`_ + An example of use is `here <http://elixir.free-electrons.com/linux/v4.9/source/lib/dump_stack.c#L24>`_. + +5. Read operation +----------------- + +Implement the read function in the driver. Follow comments marked with ``TODO 4`` and implement them. + + 1. Keep a buffer in ``so2_device_data`` structure initialized with the value of ``MESSAGE`` macro. + Initializing this buffer will be done in module ``init`` function. + 2. At a read call, copy the contents of the kernel space buffer into the user + space buffer. + + * Use the :c:func:`copy_to_user` function to copy information from kernel space to + user space. + * Ignore the size and offset parameters at this time. You can assume that + the buffer in user space is large enough. You do not need to check the + validity of the size argument of the read function. + * The value returned by the read call is the number of bytes transmitted + from the kernel space buffer to the user space buffer. + + 3. After implementation, test using ``cat /dev/so2_cdev``. + +.. note:: The command ``cat /dev/so2_cdev`` does not end (use Ctrl+C). + Read the `read and write`_ sections and `Access to the address space of the process`_ + If you want to display the offset value use a construction of the form: + ``pr_info("Offset: %lld \n", *offset)``; The data type loff_t (used by offset ) is a typedef for long long int. + +The ``cat`` command reads to the end of the file, and the end of the file is +signaled by returning the value 0 in the read. Thus, for a correct implementation, +you will need to update and use the offset received as a parameter in the read +function and return the value 0 when the user has reached the end of the buffer. + +Modify the driver so that the ``cat`` commands ends: + + 1. Use the size parameter. + 2. For every read, update the offset parameter accordingly. + 3. Ensure that the read function returns the number of bytes that were copied + into the user buffer. + +.. note:: By dereferencing the offset parameter it is possible to read and move the current + position in the file. Its value needs to be updated every time a read is done + successfully. + +6. Write operation +------------------ + +Add the ability to write a message into kernel buffer to replace the predefined message. Implement +the write function in the driver. Follow comments marked with ``TODO 5`` + +Ignore the offset parameter at this time. You can assume that the driver buffer is +large enough. You do not need to check the validity of the write function size +argument. + +.. note:: The prototype of a device driver's operations is in the file_operations + structure. + Test using commands: + + .. code-block:: bash + + echo "arpeggio"> /dev/so2_cdev + cat /dev/so2_cdev + + Read the `read and write`_ sections and `Access to the address space of the process`_ + +7. ioctl operation +------------------ + +For this exercise, we want to add the ioctl ``MY_IOCTL_PRINT`` to display the +message from the ``IOCTL_MESSAGE`` macro in the driver. +Follow the comments marked with ``TODO 6`` + +For this: + + 1. Implement the ioctl function in the driver. + 2. We need to use ``user/so2_cdev_test.c`` to call the + ioctl function with the appropriate parameters. + 3. To test, we will use an user-space program (``user/so2_cdev_test.c``) + which will call the ``ioctl`` function with the required arguments. + +.. note:: The macro ``MY_IOCTL_PRINT`` is defined in the file ``include/so2_cdev.h``, + which is shared between the kernel module and the user-space program. + + Read the `ioctl`_ section in the lab. + +.. note:: The user-space code is compiled automatically at ``make build`` and + copied at ``make copy``. + + Because we need to compile the program for qemu machine which is 32 bit, + if your host is 64 bit then you need to install ``gcc-multilib`` package. + +Extra Exercises +=============== + +Ioctl with messaging +-------------------- + +Add two ioctl operations to modify the message associated with the +driver. Use fixed-length buffer ( BUFFER_SIZE ). + + 1. Add the ``ioctl`` function from the driver the following operations: + + * ``MY_IOCTL_SET_BUFFER`` for writing a message to the device; + * ``MY_IOCTL_GET_BUFFER`` to read a message from your device. + + 2. For testing, pass the required command line arguments to the + user-space program. + +.. note:: Read the `ioctl`_ and `Access to the address space of the process`_ + sections of the lab. + +Ioctl with waiting queues +------------------------- + +Add two ioctl operations to the device driver for queuing. + + 1. Add the ``ioctl`` function from the driver the following operations: + + * ``MY_IOCTL_DOWN`` to add the process to a queue; + * ``MY_IOCTL_UP`` to remove the process from a queue. + + 2. Fill the device structure with a ``wait_queue_head_t`` field and a flag. + 3. Do not forget to initialize the wait queue and flag. + 4. Remove exclusive access condition from previous exercise + 5. For testing, pass the required command line arguments to the + user-space program. + +When the process is added to the queue, it will remain blocked in execution; To +run the queue command open a new console in the virtual machine with Alt+F2 ; +You can return to the previous console with Alt+F1. If you're connected via +SSH to the virtual machine, open a new console. + +.. note:: Read the `ioctl`_ and `Waiting queues`_ sections in the lab. + +O_NONBLOCK implementation +------------------------- + +.. note:: If a file is open with the ``O_NONBLOCK`` flag, then its + operations will be non-blocking. + + In case data is not available when performing a read, the following + happens: + + * if the file has been open with ``O_NONBLOCK``, the read call + will return ``-EWOULDBLOCK``. + * otherwise, the current task (process) will be placed in a waiting + queue and will be unblocked as soon as data becomes available + (in our case, at write). + +* To allow unblocking the read operation, remove the exclusive access + condition from previous exercises. +* You can use the queue defined for the previous exercise. +* You can ignore the file offset. +* Modify the initial size of data to ``0``, to allow testing. +* For testing, pass the required command line arguments to the + user-space program. + + * when using the ``n`` option, the test program will change the open flags + to ``O_NONBLOCK`` and then perform a ``read``. + +* What are the flags used to open the file when running ``cat /dev/so2_dev``? + diff --git a/refs/pull/405/merge/_sources/labs/device_model.rst.txt b/refs/pull/405/merge/_sources/labs/device_model.rst.txt new file mode 100644 index 00000000..032990d6 --- /dev/null +++ b/refs/pull/405/merge/_sources/labs/device_model.rst.txt @@ -0,0 +1,1286 @@ +================== +Linux Device Model +================== + +Overview +======== + +Plug and Play is a technology that offers support for automatically adding and +removing devices to the system. This reduces conflicts with the resources they +use by automatically configuring them at system startup. In order to achieve +these goals, the following features are required: + + * Automatic detection of adding and removing devices in the system (the device + and its bus must notify the appropriate driver that a configuration change + occurred). + * Resource management (addresses, irq lines, DMA channels, memory areas), + including resource allocation to devices and solving conflicts that may arise. + * Devices must allow for software configuration (device resources - ports, + interrupts, DMA resources - must allow for driver assignment). + * The drivers required for new devices must be loaded automatically by the + operating system when needed. + * When the device and its bus allow, the system should be able to add or + remove the device from the system while it is running, without having to reboot + the system (hotplug). + +For a system to support plug and play, the BIOS, operating system and the device +must support this technology. The device must have an ID that will provide to the +driver for identification, and the operating system must be able to identify +these configuration changes as they appear. + +Plug and play devices are: PCI devices (network cards), USB (keyboard, mouse, +printer), etc. + +Prior to version 2.6, the kernel did not have a unified model to get +information about devices. +For this reason, a model for Linux devices, Linux Device Model, was developed. + +The primary purpose of this model is to maintain internal data structures that +reflect the state and structure of the system. Such information includes what +devices are in the system, how they are in terms of power management, what bus +they are attached to, what drivers they have, along with the structure of the +buses, devices, drivers in the system. + +To maintain this information, the kernel uses the following entities: + + * device - a physical device that is attached to a bus + * driver - a software entity that can be associated with a device and performs + operations with it + * bus - a device to which other devices can be attached + * class - a type of device that has a similar behavior; There is a class for + disks, partitions, serial ports, etc. + * subsystem - a view on the structure of the system; Kernel subsystems + include devices (hierarchical view of all devices in the system), buses (bus + view of devices according to how they are attached to buses), classes, etc. + +sysfs +===== + +The kernel provides a representation of its model in userspace through the +sysfs virtual file system. It is usually mounted in the /sys directory and +contains the following subdirectories: + + * block - all block devices available in the system (disks, partitions) + * bus - types of bus to which physical devices are connected (pci, ide, usb) + * class - drivers classes that are available in the system (net, sound, usb) + * devices - the hierarchical structure of devices connected to the system + * firmware - information from system firmware (ACPI) + * fs - information about mounted file systems + * kernel - kernel status information (logged-in users, hotplug) + * module - the list of modules currently loaded + * power - information related to the power management subsystem + +As you can see, there is a correlation between the kernel data structures +within the described model and the subdirectories in the sysfs virtual file +system. Although this likeness may lead to confusion between the two concepts, +they are different. The kernel device model can work without the sysfs file +system, but the reciprocal is not true. + +The sysfs information is found in files that contain an attribute. Some +standard attributes (represented by files or directories with the same name) +are as follows: + + * dev - Major and minor device identifier. It can be used to automatically + create entries in the /dev directory + * device - a symbolic link to the directory containing devices; It can be + used to discover the hardware devices that provide a particular service (for + example, the ethi PCI card) + * driver - a symbolic link to the driver directory (located in + /sys/bus/\*/drivers ) + +Other attributes are available, depending on the bus and driver used. + +.. ditaa:: + +------+ + | /sys | + +--+---+ + | + +----------------------------------------------------+-------------------------------------+-----------------------------------------+ + | | | | + v v v v + +-----+ +-------+ +---------+ +--------+ + | bus | | class | | devices | | module | + +--+--+ +---+---+ +----+----+ +---+----+ + | | | | + | | | +-------------+-----------------+ + | | | | | + v v v v v + +------------------------+ +-----------------------+ +-------------------------+ +----------------------+ +-------------------------+ + | mybus: struct bus_type | | myclass: struct class | | mybus0: struct device | | mybus: struct module | | mydriver: struct module | + +-------------+----------+ +----------+------------+ +-----------+-------------+ +----------------------+ +-------------------------+ + | | | + +--------+--------------+ v v + | | +-------------------------------+ +----------------------+ + v v | myclass0: struct class_device | | mydev: struct device | + +---------+ +---------+ +-------------------------------+ +----------------------+ + | devices | | drivers | + +---------+ +---+-----+ + | + v + +--------------------------------+ + | mydriver: struct device_driver | + +--------------------------------+ + + +Basic Structures in Linux Devices +================================= + +Linux Device Model provides a number of structures to ensure the interaction +between a hardware device and a device driver. The whole model is based on +kobject structure. Hierarchies are built using this structure and the following +structures are implemented: + + * struct bus_type + * struct device + * struct device_driver + + +.. ditaa:: + :--no-separation: + + +--+ +--+ +--+ + mydriver.c | | mybus.c | | bus/driver/device core | | kobject core + | | | | | | + | | | | | | + | | | | | | + | | +-----------------------------+ | | +-----------------------------+ | | + | | | my_bus_type +------=>+ struct bus_type | | | + | | +-----------------------------+ | | +-----------------------------+ | | + | | |name | | | |name | | | + | | |uevent() = my_uevent() | | | |uevent() | | | + | | |match() = my_match() | | | |match() | | | + | | +-----------------------------+ | | +-----------------------------+ | | + | | | | | | | | + | | | | +-----------------------------+ | | + | | | | | | + +----------------+ | | +-----------------------------+ | | +-----------------------------+ | | +-------------------+ + | mydriver +------=>+ struct my_driver +------->+ struct device_driver +-------+---->| struct kobject | + +----------------+ | | +-----------------------------+ | | +-----------------------------+ | | | +-------------------+ + | | | | | | | | | name | | | | | k_name | + +----------------+ | | +-----------------------------+ | | +-----------------------------+ | | | +-------------------+ + | | | my_register_driver() | | | | driver_register() | | | | | kobject_add() | + | | | my_unregister_driver() | | | | driver_unregister() | | | | | kobject_delete() | + | | +-----------------------------+ | | +-----------------------------+ | | | +-------------------+ + | | | | | | | + | | | | | | | + +----------------+ | | +-----------------------------+ | | +-----------------------------+ | | | + | mydevice +------=>+ struct my_device +------->+ struct device +-------+ + +----------------+ | | +-----------------------------+ | | +-----------------------------+ | | + | | | | | | | | | bus_id | | | + +----------------+ | | +-----------------------------+ | | +-----------------------------+ | | + | | | my_register_device() | | | | device_register() | | | + | | | my_unregister_device() | | | | device_unregister() | | | + | | +-----------------------------+ | | +-----------------------------+ | | + | | | | | | + +--+ +--+ +--+ + + +The kobject structure +--------------------- + +A kobject structure does not perform a single function. This structure is +usually integrated into a larger one. A kobject structure actually +incorporates a set of features that will be offered to a higher abstraction +object in the Linux Device Model hierarchy. + +For example, the cdev structure has the following definition: + +.. code-block:: c + + struct cdev { + struct kobject kob; + struct module *owner; + const struct file_operations *ops; + struct list_head list; + dev_t dev; + unsigned int count; + }; + + +Note that this structure includes a ``kobject`` structure field. + +A kobject structure is defined as follows: + +.. code-block:: c + + struct kobject { + const char *name; + struct list_head entry; + struct kobject *parent; + struct kset *kset; + struct kobj_type *ktype; + struct sysfs_dirent *sd; + struct kref kref; + unsigned int state_initialized:1; + unsigned int state_in_sysfs:1; + unsigned int state_add_uevent_sent:1; + unsigned int state_remove_uevent_sent:1; + unsigned int uevent_suppress:1; + }; + +As we can see, the kobject structures are in a hierarchy: an object has a +parent and holds a kset member, which contains objects on the same level. + +Working with the structure involves initializing it with the +:c:func:`kobject_init` function. +Also in the initialization process it is necessary to set the name of the +``kobject`` structure, which will appear in sysfs, using the +:c:func:`kobject_set_name` function. + +Any operation on a kobject is done by incrementing its internal counter using +:c:func:`kobject_get`, or decrementing if it is no longer used using +:c:func:`kobject_put`. +Thus, a kobject object will only be released when its internal counter reaches 0. +A method of notifying this is needed so that the resources associated with the +device structure which included the kobject structure are released +(for example, cdev). +The method is called ``release`` and is associated with the object via the ktype +field (:c:type:`struct kobj_type`). + +The kobject structure is the basic structure of the Linux Device Model. +The structures in the higher levels of the model are :c:type:`struct bus_type`, +:c:type:`struct device` and :c:type:`struct device_driver`. + +Buses +----- + +A bus is a communication channel between the processor and an input/output +device. To ensure that the model is generic, all input/output devices are +connected to the processor via such a bus (even if it can be a virtual one +without a physical hardware correspondent). + +When adding a system bus, it will appear in the sysfs file system in +``/sys/bus``. +As with kobjects, buses can be organized into hierarchies and will be represented +in sysfs. + +In the Linux Device Model, a bus is represented by the structure +:c:type:`struct bus_type`: + +.. code-block:: c + + struct bus_type { + const char *name; + const char *dev_name; + struct device *dev_root; + struct bus_attribute *bus_attrs; + struct device_attribute *dev_attrs; + struct driver_attribute *drv_attrs; + struct subsys_private *p; + + int (*match)(struct device *dev, struct device_driver *drv); + int (*uevent)(struct device *dev, struct kobj_uevent_env *env); + int (*probe)(struct device *dev); + int (*remove)(struct device *dev); + //... + }; + +It can be noticed that a bus has a name, lists of default attributes, a number +of specific functions, and the driver's private data. +The ``uevent`` function (formerly ``hotplug``) is used with hotplug devices. + +Bus operations are the registration, the implementation of the operations +described in the :c:type:`struct bus_type` structure and the iteration and +inspection of the devices connected to the bus. + +A bus is registered using :c:func:`bus_register`, and unregistered using +:c:func:`bus_unregister`. + +Implementation example: + +.. code-block:: c + + #include <linux/device.h> + /* mybus.c */ + + //bus type + struct bus_type my_bus_type = { + .name = "mybus", + .match = my_match, + .uevent = my_uevent, + }; + + static int __init my_bus_init(void) + { + int err; + + //... + err = bus_register(&my_bus_type); + if (err) + return err; + //... + } + + static void __exit my_bus_exit(void) + { + //... + bus_unregister(&my_bus_type); + //... + } + + +The functions that will normally be initialized within a bus_type structure are +``match`` and ``uevent``: + +.. code-block:: c + + #include <linux/device.h> + #include <linux/string.h> + /* mybus.c */ + + // match devices to drivers; just do a simple name test + static int my_match(struct device *dev, struct device_driver *driver) + { + return !strncmp(dev_name(dev), driver->name, strlen(driver->name)); + } + + // respond to hotplug user events; add environment variable DEV_NAME + static int my_uevent(struct device *dev, struct kobj_uevent_env *env) + { + add_uevent_var(env, "DEV_NAME=%s", dev_name(dev)); + return 0; + } + +The ``match`` function is used when a new device or a new driver is added to the +bus. Its role is to make a comparison between the device ID and the driver ID. +The ``uevent`` function is called before generating a hotplug in user-space and +has the role of adding environment variables. + +Other possible operations on a bus are iterating over the drivers or devices +attached to it. +Although we can not directly access them (lists of drivers and devices +being stored in the private data of the driver, the ``subsys_private *p`` field), +these can be iterated using the :c:macro:`bus_for_each_dev` and +:c:macro:`bus_for_each_drv` macros. + +The Linux Device Model interface allows you to create attributes for the +associated objects. These attributes will have a corresponding file in the +bus subdirectory in sysfs. The attributes associated with a bus are +described by the bus_attribute structure : + +.. code-block:: c + + struct bus_attribute { + struct attribute attr; + ssize_t (*show)(struct bus_type *, char *buf); + ssize_t (*store)(struct bus_type *, const char *buf, size_t count); + }; + +Typically, an attribute is defined by the :c:macro:`BUS_ATTR` macro. +The :c:func:`bus_create_file` and :c:func:`bus_remove_file` functions can be +used to add/delete an attribute within the bus structure. + +An example of defining an attribute for ``my_bus`` is shown below: + +.. code-block:: c + + /* mybus.c */ + + #define MY_BUS_DESCR "SO2 rules forever" + + // export a simple bus attribute + static ssize_t my_show_bus_descr(struct bus_type *bus, char *buf) + { + return snprintf(buf, PAGE_SIZE, "%s\n", MY_BUS_DESCR); + } + + /* + * define attribute - attribute name is descr; + * full name is bus_attr_descr; + * sysfs entry should be /sys/bus/mybus/descr + */ + BUS_ATTR(descr, 0444, my_show_bus_descr, NULL); + + // specify attribute - in module init function + static int __init my_bus_init(void) + { + int err; + //... + err = bus_create_file(&my_bus_type, &bus_attr_descr); + if (err) { + /* handle error */ + } + //... + } + + static void __exit my_bus_exit(void) + { + //... + bus_remove_file(&my_bus_type, &bus_attr_descr); + //... + } + +The bus is represented by both a ``bus_type`` object and a ``device`` object, +as we will see later (the bus is also a device). + + +Devices +------- + +Any device in the system has a :c:type:`struct device` structure associated +with it. +Devices are discovered by different kernel methods (hotplug, device drivers, +system initialization) and are registered in the system. Each device present in +the kernel has an entry in ``/sys/devices``. + +At the lowest level, a device in Linux Device Model is represented by a +:c:type:`struct device` structure: + +.. code-block:: c + + struct device { + //... + struct device *parent; + struct device_private *p; + struct kobject kobj; + + const char *init_name; /* initial name of the device */ + //... + struct bus_type *bus; /* type of bus device is on */ + struct device_driver *driver; /* which driver has allocated this + device */ + //... + void (*release)(struct device *dev); + }; + +Structure fields include the parent device that is usually a controller, the +associated ``kobject``, the bus it is connected to, the device driver, and a +function called when the device counter reaches 0 (``release``). + +As usual, we have the registration/unregistration functions +:c:func:`device_register` and :c:func:`device_unregister`. + +To work with attributes, we have structure :c:type:`struct device_attribute`, +the macro :c:macro:`DEVICE_ATTR` for definition, and the functions +:c:func:`device_create_file` and :c:func:`device_remove_file` for adding/removing +the attribute to/from the device. + +One important thing to note is that the :c:type:`struct device` structure is +usually not used directly, but it is added to another structure. For example: + +.. code-block:: c + + // my device type + struct my_device { + char *name; + struct my_driver *driver; + struct device dev; + }; + +Typically, a bus driver will export functions to add or remove such a +device, as shown below: + +.. code-block:: c + + /* mybus.c */ + + /* BUS DEVICE (parent) */ + + // parent device release + static void my_bus_device_release(struct device *dev) + { + } + + // parent device + static struct device my_bus_device = { + .init_name = "mybus0", + .release = my_bus_device_release + }; + + /* DEVICE */ + + /* + * as we are not using the reference count, we use a no-op + * release function + */ + static void my_dev_release(struct device *dev) + { + } + + int my_register_device(struct my_device *mydev) + { + mydev->dev.bus = &my_bus_type; + mydev->dev.parent = &my_bus_device; + mydev->dev.release = my_dev_release; + dev_set_name(&mydev->dev, mydev->name); + + return device_register(&mydev->dev); + } + + void my_unregister_device(struct my_device *mydev) + { + device_unregister(&mydev->dev); + } + + /* export register/unregister device functions */ + EXPORT_SYMBOL(my_register_device); + EXPORT_SYMBOL(my_unregister_device); + +As seen, the functions ``my_register_device`` and ``my_unregister_device``, used +to add/remove a device to/from a bus, are defined in the same file where the +bus is defined. Device structures are not initialized; they will be initialized +when the devices are discovered by the system (by hotplug or direct registration +from driver) and the function ``my_register_device`` will be called to add a +device to the bus. + +To use the bus defined above in the driver implementation, we must define a +structure of type ``my_device``, initialize it and register it using the function +exported by the bus (``my_register_device``). + +.. code-block:: c + + /* mydriver.c */ + + static struct my_device mydev; + char devname[NAME_SIZE]; + //... + + //register + int err; + + sprintf(devname, "mydev0"); + mydev.name = devname; + mydev.driver = &mydriver; + dev_set_drvdata(&mydev.dev, &mydev); + err = my_register_device(&mydev); + if (err < 0) { + /*handle error */ + } + + //.. + + //unregister + my_unregister_device(&mydev); + +Drivers +------- + +Linux Device Model is used to allow simple association between system +devices and drivers. Drivers can export information independent of the physical +device. + +In sysfs, driver information has no single subdirectory associated; They can be +found in the directory structure in different places: the loaded module is in +``/sys/module``, in ``/sys/devices`` you can find the driver associated with +each device, in ``/sys/class`` the drivers belonging to a class, in +``/sys/bus`` the drivers associated to each bus. + +A device driver is identified by the structure :c:type:`struct device_driver`: + +.. code-block:: c + + struct device_driver { + const char *name; + struct bus_type *bus; + + struct driver_private *p; + + struct module *owner; + const char *mod_name; /* used for built-in modules */ + + int (*probe) (struct device *dev); + int (*remove) (struct device *dev); + void (*shutdown) (struct device *dev); + int (*suspend) (struct device *dev, pm_message_t state); + int (*resume) (struct device *dev); + }; + +Among the structure fields we find the name of the driver (appears in ``sysfs``), +the bus with which the driver works, and functions called at various times in a +device's operation. + +As before, we have the functions :c:func:`driver_register` and +:c:func:`driver_unregister` to register/unregister a driver. + +To work with attributes, we have the :c:type:`struct driver_attribute` structure, +the macro :c:type:`DRIVER_ATTR` for definition, and the functions +:c:func:`driver_create_file` and :c:func:`driver_remove_file` functions for +adding the attribute to the device. + +As with devices, the structure :c:type:`struct device_driver` is usually +incorporated into another structure specific to a particular bus (PCI, USB, etc.): + +.. code-block:: c + + /* mybus.c */ + + // my driver type + struct my_driver { + struct module *module; + struct device_driver driver; + }; + + #define to_my_driver(drv) container_of(drv, struct my_driver, driver); + + int my_register_driver(struct my_driver *driver) + { + int err; + + driver->driver.bus = &my_bus_type; + err= driver_register(&driver->driver); + if (err) + return err; + return 0; + } + + void my_unregister_driver(struct my_driver *driver) + { + driver_unregister(&driver->driver); + } + + /* export register/unregister driver functions */ + EXPORT_SYMBOL(my_register_driver); + EXPORT_SYMBOL(my_unregister_driver); + +Driver registration/unregistration operations are exported for use in +other modules. + +As for devices, the operations for drivers are defined when the bus is +initialized and they are exported to be used by drivers. When implementing a +driver that works with devices attached to the bus, we will call the functions +``my_register_driver`` and ``my_unregister_driver`` to associate with the bus. + +To use the functions (in the driver implementation), we must declare a structure +of type ``my_driver``, initialize it and register using the function exported +by the bus. + +.. code-block:: c + + /* mydriver.c */ + + static struct my_driver mydriver = { + .module = THIS_MODULE, + .driver = { + .name = "mydriver", + }, + }; + //... + + //register + int err; + err = my_register_driver(&mydriver); + if (err < 0) { + /*handle error */ + } + //.. + + //unregister + my_unregister_driver(&mydriver); + + +Classes +------- + +A class is a high-level view of the Linux Device Model, which abstracts +implementation details. For example, there are drivers for SCSI and ATA +drivers, but all belong to the class of disks. Classes provide a grouping of +devices based on functionality, not how they are connected or how they work. +Classes have a correspondent in ``/sys/classes``. + +There are two main structures that describe the classes: :c:type:`struct class` +and :c:type:`struct device`. +The class structure describes a generic class, while the structure +:c:type:`struct device` describes a class associated with a device. +There are functions for initializing/deinitiating and adding attributes for each +of these, described in ``include/linux/device.h``. + +The advantage of using classes is that the ``udev`` program in userspace, which we +will discuss later, allows the automatic creation of devices in the ``/dev`` +directory based on class information. + +For this reason, we will continue to present a small set of functions that work +with classes to simplify the use of the plug and play mechanism. + +A generic class is described by structure class structure: + +.. code-block:: c + + struct class { + const char *name; + struct module *owner; + struct kobject *dev_kobj; + + struct subsys_private *p; + + struct class_attribute *class_attrs; + struct class_device_attribute *class_dev_attrs; + struct device_attribute *dev_attrs; + + int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); + void (*class_release)(struct class *class); + void (*dev_release)(struct device *dev); + //... + }; + +The :c:func:`class_register` and :c:func:`class_unregister` functions can be +used for initialization/deinitialization. + +.. code-block:: c + + static struct class my_class = { + .name = "myclass", + }; + + static int __init my_init(void) + { + int err; + //... + err = class_register(&my_class); + if (err < 0) { + /* handle error */ + } + //... + } + + static void __exit my_cleanup(void) + { + //... + class_unregister(&my_class); + //... + } + +A class associated with a device is described by the :c:type:`struct device` +structure. +The :c:func:`device_create` and :c:func:`device_destroy` functions can be used +for initialization/deinitialization. +The :c:func:`device_create` function initializes the ``device`` structure, +and assigns the generic ``class`` structure and the device received as a +parameter to it; +In addition, it will create an attribute of the class, ``dev``, which contains +the minor and major of the device (``minor:major``). +Thus, udev utility in usermode can read the necessary data from this attribute +file to create a node in the ``/dev`` directory by calling ``makenod``. + +An example of initialization: + +.. code-block:: c + + struct device* my_classdev; + struct cdev cdev; + struct device dev; + + //init class for device cdev.dev + my_classdev = device_create(&my_class, NULL, cdev.dev, &dev, "myclass0"); + + //destroy class for device cdev.dev + device_destroy(&my_class, cdev.dev); + +When a new device is discovered, a class and a node will be assigned to it and +a node will be created in the ``/dev`` directory. +For the example above, the node ``/dev/myclass0`` will be generated. + +Hotplug +------- + +``Hotplug`` describes the mechanism for adding or removing a device from the +system while it is running without having to reboot the system. + +A hotplug event is a notification from the kernel to the user-space when something +changes in the system configuration. These events are generated when creating +or removing a kobject from the kernel. Since these objects are the basis of the +Linux Device Model, being included in all structures (``struct bus_type``, +``struct device``, ``struct device_driver``, ``struct class``, etc.), a hotplug event +will be generated when any of these structures is created or removed (``uevent``). + +When a device is discovered in the system, an event is generated. Depending on +the point where it resides in Linux Device Model, the functions corresponding +to the event will be called (usually, the ``uevent`` function associated to the +bus or the class). Using these functions, the driver has the ability to set +system variables for the user-space. +The generated event then reaches the user-space. Here is the ``udev`` +utility that captures these events. There are configuration files for this +utility in the ``/etc/udev/`` directory. Different rules can be specified to +capture only certain events and perform certain actions, depending on the +system variables set in the kernel or in ``uevent`` functions. + +An important consequence is that in this way the plug and play mechanism can be +achieved; with the help of ``udev`` and the classes (described above), entries +in the ``/dev/`` directories can be automatically created for devices, and using +``udev`` drivers can be automatically loaded for a device. + +Rules for ``udev`` are located ``/etc/udev/rules.d``. +Any file that ends with ``.rules`` in this directory will be parsed when an +event occurs. For more details on how to write rules in these files see +`Writing udev rules <http://www.reactivated.net/writing_udev_rules.html>`_. +For testing, there are utilities such as ``udevmonitor``, ``udevinfo`` and +``udevtest``. + +For a quick example, consider the situation where we want to automatically load +a driver for a device when an event occurs. We can create a new file +/etc/udev/rules.d/myrules.rules, we will have the following line: + +.. code-block:: bash + + SUBSYSTEM=="pnp", ATTRS{id}=="PNP0400", RUN+="/sbin/insmod /root/mydriver.ko" + +This will choose from the events generated only those belonging to the ``pnp`` +subsystem (connected to ``PNP`` bus) and having an id attribute with the value +``PNP0400``. + +When this rule will be found, the command specified under ``RUN`` will be +executed to insert the appropriate driver in the kernel. + + +Plug and Play +============= + +As noted above, in Linux Device Model all devices are connected by a bus, even if +it has a corresponding physical hardware or it is virtual. + +The kernel already has implemented most buses using a ``bus_type`` structure +and functions to register/unregister drivers and devices. +To implement a driver, we must first determine the bus to which the supported +devices are connected and use the structures and functions exported by this bus. +The main buses are ``PCI``, ``USB``, ``PNP``, ``IDE``, ``SCSI``, ``platform``, +``ACPI``, etc. + +PNP bus +------- + +The plug and play mechanism provides a means of detecting and setting the resources +for legacy driver that may not be configured or otherwise. All plug and play +drivers, protocols, services are based on Plug and Play level. It is responsible +for the exchange of information between drivers and protocols. The following +protocols are available: + + * ``PNPBIOS`` - used for systems such as serial and parallel ports + * ``ISAPNP`` - offers support for the ISA bus + * ``ACPI`` - offering, among other things, information about system-level devices + +The kernel contains a bus, called ``pnp_bus``, that is used for connecting by +many drivers. +The implementation and working with the bus follow the Linux Device Model and +is very similar to what we discussed above. + +The main functions and structures exported by the bus, which can be used by +drivers, are: + + * :c:type:`struct pnp_driver` - driver type associated to the bus + * :c:func:`pnp_register_driver` - function used to register a PNP driver in the system + * :c:func:`pnp_unregister_driver` - function used to unregister a PNP driver from the system + +As noted in previous sections, the bus has a function called ``match`` used to +associate the devices with the appropriate drivers. +For example, when discovering a new device, a driver which meets the condition +given by the ``match`` function regarding to the new device. Usually, this +condition is a comparation of IDs (driver id and device id). +A common approach is using a static table in each driver, which holds information +about the devices supported by the driver, which will be used by the bus +when verifying the condition. For example, for a parallel port device we have +the table ``parport_pc_pnp_tbl``: + +.. code-block:: c + + static const struct pnp_device_id parport_pc_pnp_tbl[] = { + /* Standard LPT Printer Port */ + {.id = "PNP0400", .driver_data = 0}, + /* ECP Printer Port */ + {.id = "PNP0401", .driver_data = 0}, + }; + + MODULE_DEVICE_TABLE(pnp, parport_pc_pnp_tbl); + +Each driver declares and initializes a structure ``pnp_driver``, such as +``parport_pc_pnp_driver``: + +.. code-block:: c + + static int parport_pc_pnp_probe(struct pnp_dev *dev, const struct pnp_id *card_id, + const struct pnp_id *dev_id); + static void parport_pc_pnp_remove(struct pnp_dev* dev); + + static struct pnp_driver parport_pc_pnp_driver = { + .name = "parport_pc", + .id_table = parport_pc_pnp_tbl, + .probe = parport_pc_pnp_probe, + .remove = parport_pc_pnp_remove, + }; + +We can notice that the structure has as fields a pointer to the table declared +above and two functions, which are called when a new device is detected and when +it is removed from the system. +As all the structures presented above, the driver must be registered to the +system: + +.. code-block:: c + + static int __init parport_pc_init(void) + { + err = pnp_register_driver(&parport_pc_pnp_driver); + if (err < 0) { + /* handle error */ + } + } + + static void __exit parport_pc_exit(void) + { + pnp_unregister_driver(&parport_pc_pnp_driver); + } + +PNP operations +-------------- + +So far we have discussed the Linux Device Model and its API. To +implement a plug and play driver, we must respect the Linux Device Model model. + +Most often, adding a bus in the kernel is not necessary, as most of the existing +buses are already implemented (PCI, USB, etc.). Thus, we must first identify the +bus to which the device is attached. +In the examples below, we will consider that this bus is bus PNP and we will +use the structures and functions described above. + +.. ditaa:: + + + Kernel space | User space + | + | + +-------------+ +-------------+ +---------------+ | +--------+ + | | | | | | | | | + | my_device | | my_driver | | my_bus_type | | | udev | + | | | | | | | | | + +-----+-------+ +------+------+ +-------+-------+ | +---+----+ + | | | | | + : : : | : + | | 1.my_register_driver() | 2.call_usermodehelper() | + | +-+------------------------->+-+------------------------->+-+ + | | | | | | | | + | | | | | | | | + | | | | | | | | + | 3.my_uevent() | | | | 4.call_usermodehelper() | | + +++-------------------------| |--------------------------> +------------------------->| | + | | | | | | | | | + | | | | 6.my_probe() | | 5.my_match() | | + | | | |<=------------------------| |<=------------------------| | + | | | | | | | | | + | | | | | | | | | + | | | | | | | | | + | | 7.my_remove() | | 8.my_uevent() | | 9.call_usermodehelper() | | +---------------------------+ + +-+------------------------>| |------------------------->| |------------------------->| | | | + | | | | | | | | | 1 - 2 -> add driver | + | | | | | | | | | 3 - 6 -> add device | + | | | | | | | | | 7 - 9 -> remove device | + | | | 10.my_unregister_driver()| | 11.call_usermodehelper() | | | 10 - 11 -> remove driver | + | +-+------------------------->+-+------------------------->+-+ | | + | | | | | +---------------------------+ + : : : | : + + +Adding a driver +--------------- + +In addition to the usual operations, a driver must follow the Linux Device Model. +Thus, it will be registered in the system using the functions provided by +the bus for this purpose. +Usually, the bus provides a particular driver structure containing a +:c:type:`struct device_driver` structure, that the driver must initialize and +register using a function ``*_register_driver``. +For example, for the ``PNP`` bus, the driver must declare and initialize a +structure of type :c:type:`struct pnp_driver` and register it using +``pnp_register_drvier``: + +.. code-block:: c + + static struct pnp_driver my_pnp_driver = { + .name = "mydriver", + .id_table = my_pnp_tbl, + .probe = my_pnp_probe, + .remove = my_pnp_remove, + }; + + static int __init my_init(void) + { + err = pnp_register_driver(&my_pnp_driver); + } + +Unlike legacy drivers, plug and play drivers don't register devices at +initialization in the init function (``my_init`` in the example above) using +:c:func:`register_device`. + +As described above, each bus has a `match` function which is called when a new +device is detected in the system to determine the associated driver. +Thus, there must be a way for each driver to export information about the +devices it supports, to allow this check to pass and have its functions further +called. +In the examples presented in this lab, the match function does a simple +comparison between the device name and the driver name. Most drivers use a table +containing information devices and store a pointer to this table in the +driver structure. +For example, a driver associated to a ``PNP`` bus defines a table of type +:c:type:`struct pnp_device_id` and initializes the field ``id_table`` from the +structure ``pnp_driver my_pnp_driver`` with a pointer to it: + +.. code-block:: c + + static const struct pnp_device_id my_pnp_tbl[] = { + /* Standard LPT Printer Port */ + {.id = "PNP0400", .driver_data = 0}, + /* ECP Printer Port */ + {.id = "PNP0401", .driver_data = 0}, + { } + }; + + MODULE_DEVICE_TABLE(pnp,my_pnp_tbl); + + static struct pnp_driver my_pnp_driver = { + //... + .id_table = my_pnp_tbl, + //... + }; + +In the example above, the driver supports multiple parallel port devices, +defined in the table ``my_pnp_tbl``. This information is used by the bus in +the ``match_device`` function. +When adding a driver, the bus driver will be associated to it and new entires +in ``sysfs`` will be created based on the driver name. +Then the bus ``match`` function will be called for every supported device, +to associate the driver with any connected device that it supports. + +Removing a driver +----------------- + +To remove a driver from the kernel, in addition to operations required for a +legacy driver, we must unregister the ``device_driver`` structure. +For a driver associated with the ``PNP`` bus, we must unregister the ``pnp_driver`` +structure using the :c:func:`pnp_unregister_driver` function: + +.. code-block:: c + + static struct pnp_driver my_pnp_driver; + + static void __exit my_exit(void) + { + pnp_unregister_driver(&my_pnp_driver); + } + +Unlike legacy drivers, plug and play drivers don't unregister devices in the +module unload function (``my_exit``). When a driver is removed, all the +references to it will be removed for all the devices it supports, and entries +from ``sysfs`` will also be removed. + +Adding a new device +------------------- + +As we saw above, plug and play drivers do not register devices at initialization. +This operation will take place in the ``probe`` function, which is called when +a new device is detected. A device attached to the ``PNP`` bus will be added to +the system by the function ``probe`` from the ``pnp_driver`` structure: + +.. code-block:: c + + static int my_pnp_probe(struct pnp_dev *dev, const struct pnp_id *card_id, + const struct pnp_id *dev_id) { + int err, iobase, nr_ports, irq; + + //get irq & ports + if (pnp_irq_valid(dev, 0)) + irq = pnp_irq(dev, 0); + if (pnp_port_valid(dev, 0)) { + iobase = pnp_port_start(dev, 0); + } else + return -ENODEV; + nr_ports = pnp_port_len(dev, 0); + + /* register device dev */ + } + + static struct pnp_driver my_pnp_driver = { + //... + .probe = my_pnp_probe, + //... + }; + +Upon detection of a device in the kernel (at boot or by the insertion of the +device through ``hotplug``), an interrupt is generated and reaches the bus +driver. +The device is registered using the function :c:func:`device_register` and it is +attached to the bus. A call to the user space will also be generated, and the +event can be treated by ``udev``. Then, the list of drivers associated with the +bus is iterated and the ``match`` function is called for each of them. +The ``match`` function tries to find a driver for the new device. After a +suitable driver is found for the device, the ``probe`` function of the driver +is called. If the function ends successfully, the device is added to the driver's +list of devices and new entries are created in ``sysfs`` based on the device name. + +Removing a device +----------------- + +As we saw above, the plug and play drivers don't unregister devices when the +driver is unloaded. This operation is done in the ``remove`` function, which +is called when a device is removed from the system. +In case of a device attached to the ``PNP`` bus, the unregister will be done +in the ``remove`` function specified in the ``pnp_driver`` structure: + +.. code-block:: c + + static void my_pnp_remove(struct pnp_dev *dev) { + /* unregister device dev */ + } + + static struct pnp_driver my_pnp_driver = { + //... + .remove = my_pnp_remove, + }; + +As seen in the example above, when the removal of a device is detected, the +``my_pnp_remove`` function is called. A user-space call is also generated, which +can be detected by ``udev``, and entries are removed from ``sysfs``. + +Exercises +========= + +.. include:: ../labs/exercises-summary.hrst +.. |LAB_NAME| replace:: device_model + +0. Intro +--------- + +Find the definitions of the following symbols in the Linux kernel: + + * functions ``dev_name``, ``dev_set_name``. + * functions ``pnp_device_probe``, ``pnp_bus_match``, ``pnp_register_driver`` + and the ``pnp_bus_type`` variable. + +1. Bus implementation +--------------------- + +Analyze the contents of the ``bex.c``, a module that implements a bus +driver. Follow the comments marked with **TODO 1** and implement the missing +functionality: register the bus driver and add a new device named ``root`` +with type ``none`` and version 1. + +.. hint:: See :c:func:`bex_add_dev`. + +.. hint:: The register and unregister must be done using :c:func:`bus_register` + and :c:func:`bus_unregister`. + +Load the module and verify that the bus is visible in ``/sys/bus``. Verify +that the device is visible in ``/sys/bus/bex/devices``. + +Remove the module and notice that the ``sysfs`` entries are removed. + +2. Add type and version device attributes +----------------------------------------- + +Add two read-only device attributes, ``type`` and ``version``. Follow the +**TODO 2** markings. + +.. hint:: You will need to add the two attributes in the structure + ``bex_dev_attrs``, as follows: + + ``&dev_attr_<insert-attribute-type-here>.attr,`` + +.. hint:: + + A possible implementation for the show function is the following: + + .. code-block:: c + + static ssize_t + type_show(struct device *dev, struct device_attribute *attr, char *buf) + { + struct bex_device *bex_dev = to_bex_device(dev); + + return sprintf(buf, "%s\n", bex_dev->type); + } + DEVICE_ATTR_RO(type); + +Observe that two new attributes are visible in +/sys/bus/bex/devices/root. Check the contents of these attributes. + +3. Add del and add bus attributes +--------------------------------- + +Add two write-only bus attributes, ``del`` and ``add``. del expects the name +of a device to delete, while add expects the name, type and version to +create a new device. Follow the **TODO 3** markings and review +`Buses`_. + +.. hint:: Use :c:func:`sscanf` to parse the input from sysfs and + :c:func:`bex_del_dev` and :c:func:`bex_add_dev` to delete + and create a new device. + +An example for the store function is the following: + +.. code-block:: c + + static ssize_t add_store(struct bus_type *bt, const char *buf, size_t count) + { + char name[32]; + int ret; + + ret = sscanf(buf, "%31s", name); + if (ret != 1) + return -EINVAL; + + ... + } + BUS_ATTR(add, S_IWUSR, NULL, add_store); + +.. hint:: The store functions should return ``0`` if + ``bex_add_dev``/``bex_del_dev`` fail and ``count`` otherwise. + +Create a new device and observe that is visible in +``/sys/bus/devices``. Delete it and observe it disapears from ``sysfs``. + +.. hint:: Use echo to write into the bus attributes: + + .. code-block:: shell + + $ echo "name type 1" > /sys/bus/bex/add + $ echo "name" > /sys/bus/bex/del + +4. Register the bex misc driver +------------------------------- + +Modify **bex-misc.c** so that it registers the driver with the bex +bus. Insert the ``bmx_misc.ko`` module and create a new bex device from +sysfs with the name "test", type "misc", version 2. Follow the **TODO +4** markings. + +Observe that the driver is visible in ``/sys/bus/bex/drivers``. + +Why isn't the probe function called? + +.. hint:: Notice that the bus match function in **bex.c** is not + implemented. + +Implement the bus matching function in **bex.c**. Follow the **TODO 5** +markings. Try again to create a new bex device and observe that this +time the ``probe`` function from the ``bex_misc`` driver is called. + +5. Register misc device in the bex_misc probe function +------------------------------------------------------ + +Modify **bex_misc.c** to refuse probing if ``version > 1``. Also, register the +defined misc device in ``bex_misc_probe`` and deregister it in +``bex_misc_remove``. Follow the **TODO 6** markings. + +.. hint:: Use :c:func:`misc_register` and :c:func:`misc_deregister`. + +Create a new device with the name "test", type "misc" and version 2 +and observe that the probe fails. Create a new device with the name +"test2", type "misc" and version 1 and observe that the probe is +successful. + +Inspect ``/sys/bus/bex/devices/test2`` and observe that we have a new +entry. Identify the major and minor for the misc device, create a +character device file and try to read and write from the misc device +buffer. + +.. hint:: The major and minor should be visible in the dev attribute + of the misc device + +6. Monitor uevent notifications +------------------------------- + +Use the ``udevadm monitor`` command and observe what happens when: + +* the ``bex.ko`` and ``bex_misc.ko`` modules are inserted + +* a new device with the type "type" is created + +* a new device with the type "misc" and version 2 is created + +* a new device with the type "misc" and version 1 is created + +* all of the above are removed diff --git a/refs/pull/405/merge/_sources/labs/filesystems_part1.rst.txt b/refs/pull/405/merge/_sources/labs/filesystems_part1.rst.txt new file mode 100644 index 00000000..0fd3efa2 --- /dev/null +++ b/refs/pull/405/merge/_sources/labs/filesystems_part1.rst.txt @@ -0,0 +1,796 @@ +============================ +File system drivers (Part 1) +============================ + +Lab objectives +============== + + * acquiring knowledge about the Virtual Filesystem (VFS) in Linux and understanding concepts regarding 'inode', 'dentry', 'file', superblock and data block. + * understanding the process of mounting a file system inside VFS. + * knowledge regarding various file system types and understanding differences between file systems with physical support (on disk) and the ones without physical support. + +Virtual Filesystem (VFS) +======================== + +The Virtual Filesystem (also known as VFS) is a component of the kernel that handles all system calls related to files and file systems. +VFS is a generic interface between the user and a particular file system. +This abstraction simplifies the implementation of file systems and provides an easier integration of multiple file systems. This way, the implementation of a file system is accomplished by using the API provided by the VFS, and the generic hardware and I/O subsystem communication parts are handled by VFS. + +From a functional point of view, file systems can be grouped into: + + * disk file systems (ext3, ext4, xfs, fat, ntfs, etc.) + * network file systems (nfs, smbfs/cifs, ncp, etc.) + * virtual filesystems (procfs, sysfs, sockfs, pipefs, etc.) + +A Linux kernel instance will use VFS for the hierarchy (a tree) of directories and files. +A new file system will be added as a VFS subtree using the mount operation. +A file system is usually mounted from the environment for which it was built (from a block type device, from network, etc.). +In particular, however, the VFS can use a normal file as a virtual block device, so it is possible to mount disk file systems over normal files. This way, stacks of file systems can be created. + +The basic idea of VFS is to provide a single file model that can represent files from any file system. +The file system driver is responsible for bringing to the common denominator. +This way the kernel can create a single directory structure that contains the entire system. +There will be a file system that will be the root, the rest being mounted in its various directories. + +The general file system model +============================= + +The general file system model, to which any implemented file system needs to be reduced, consists of several well-defined entities: :c:type:`superblock`, :c:type:`inode`, :c:type:`file`, and :c:type:`dentry`. +These entities are file system metadata (they contain information about data or other metadata). + +Model entities interact using some VFS or kernel subsystems: dentry cache, inode cache, buffer cache. +Each entity is treated as an object: it has a associated data structure and a pointer to a table of methods. The induction of particular behavior for each component is done by replacing the associated methods. + +superblock +---------- + +The superblock stores the information needed for a mounted file system: + + * inode and blocks locations + * file system block size + * maximum filename length + * maximum file size + * the location of the root inode + +Localization: +~~~~~~~~~~~~~ + + * In the case of disk file systems, the superblock has a correspondent in the first block of the disk. (Filesystem Control Block). + * In VFS, all superblocks of filesystems are retained in a list of structures of type :c:type:`struct super_block` and the methods in structures of type :c:type:`struct super_operations`. + +inode +----- + +The inode (index node) keeps information about a file in the general sense (abstraction): regular file, directory, special file (pipe, fifo), block device, character device, link, or anything that can be abstracted as a file. + +An inode stores information like: + + * file type; + * file size; + * access rights; + * access or modify time; + * location of data on the disk (pointers to disk blocks containing data). + +.. note:: + Usually, the inode does not contain the file name. The name is stored by the :c:type:`dentry` entity. This way, an inode can have multiple names (hardlinks). + +Localization: +~~~~~~~~~~~~~ + +Like the superblock, the :c:type:`inode` has a disk correspondent. +The inodes on disk are generally grouped into a specialized area (inode area) separated from the data blocks area; In some file systems, the equivalents of the inodes are spread in the file system structure (FAT); +As a VFS entity, an inode is represented by the structure :c:type:`struct inode` and by the operations with it defined in the structure :c:type:`struct inode_operations`. + +Each inode is generally identified by a number. On Linux, the ``-i`` argument of the ``ls`` command shows the inode number associated with each file: + +.. code-block:: console + + razvan@valhalla:~/school/so2/wiki$ ls -i + 1277956 lab10.wiki 1277962 lab9.wikibak 1277964 replace_lxr.sh + 1277954 lab9.wiki 1277958 link.txt 1277955 homework.wiki + +file +---- + +File is the component of the file system model that is closest to the user. +The structure exists only as a VFS entity in memory and has no physical correspondent on disk. + +While the inode abstracts a file on the disk, the file structure abstracts an open file. +From the point of view of the process, the file entity abstracts the file. From the point of view of the file system implementation, however, the inode is the entity that abstracts the file. + +The file structure maintains information such as: + + * file cursor position; + * file opening rights; + * pointer to the associated inode (eventually its index). + +Localization: +~~~~~~~~~~~~~ + + * The structure :c:type:`struct file` is the associated VFS entity, and the structure :c:type:`struct file_operations` represents the operations associated with it. + +dentry +------ + +The dentry (directory entry) associates an inode with a file name. + +Generally, a dentry structure contains two fields: + + * an integer that identifies the inode; + * a string representing its name. + +The dentry is a specific part of a path that can be a directory or a file. For example, for the path ``/bin/vi``, dentry objects will be created for ``/``, ``bin``, and ``vi`` (a total of 3 dentry objects). + + * the dentry has a correspondent on the disk, but the correspondence is not direct because each file system keeps the dentries in a specific way + * in VFS, the dentry entity is represented by the structure :c:type:`struct dentry` and the operations with it are defined in the :c:type:`struct dentry_operations` structure. + +.. _RegisterUnregisterSection: + +Register and unregister filesystems +=================================== + +In the current version, the Linux kernel supports about 50 file systems, including: + + * ext2/ ext4 + * reiserfs + * xfs + * fat + * ntfs + * iso9660 + * udf for CDs and DVDs + * hpfs + +On a single system, however, it is unlikely that there will be more than 5-6 file systems. For this reason, file systems (or, more correctly, file system types) are implemented as modules and can be loaded or unloaded at any time. + +In order to be able to dynamically load / unload a file system module, a file system registration / deregistration API is required. The structure describing a particular file system is :c:type:`struct file_system_type`: + + .. code-block:: c + + #include <linux/fs.h> + + struct file_system_type { + const char *name; + int fs_flags; + struct dentry *(*mount) (struct file_system_type *, int, + const char *, void *); + void (*kill_sb) (struct super_block *); + struct module *owner; + struct file_system_type * next; + struct hlist_head fs_supers; + struct lock_class_key s_lock_key; + struct lock_class_key s_umount_key; + //... + }; + + * ``name`` is a string representing the name that will identify a file system (the argument passed to ``mount -t``). + * ``owner`` is ``THIS_MODULE`` for file systems implemented in modules, and ``NULL`` if they are written directly into the kernel. + * The ``mount`` function reads the superblock from the disk in memory when loading the file system. The function is unique to each file system. + * The ``kill_sb`` function releases the super-block from memory. + * ``fs_flags`` specifies the flags with which the file system must be mounted. An example of such flag is ``FS_REQUIRES_DEV`` that specifies to VFS that the file system needs a disk (it is not a virtual file system). + * ``fs_supers`` is a list containing all the superblocks associated with this file system. Since the same file system can be mounted multiple times, there will be a separate superblock for each mount. + +The *registration of a file system* into the kernel is generally performed in the module initialization function. For registration, the programmer will have to + + #. initialize a structure of type :c:type:`struct file_system_type` with the name, the flags, the function that implements the superblock reading operation and the reference to the structure that identifies the current module + #. call the :c:func:`register_filesystem` function. + +When unloading the module, you must unregister the file system by calling the :c:func:`unregister_filesystem` function. + +An example of registering a virtual file system is found in the code for ``ramfs``: + +.. code-block:: c + + static struct file_system_type ramfs_fs_type = { + .name = "ramfs", + .mount = ramfs_mount, + .kill_sb = ramfs_kill_sb, + .fs_flags = FS_USERNS_MOUNT, + }; + + static int __init init_ramfs_fs(void) + { + if (test_and_set_bit(0, &once)) + return 0; + return register_filesystem(&ramfs_fs_type); + } + +.. _FunctionsMountKillSBSection: + +Functions mount, kill_sb +------------------------ + +When mounting the file system, the kernel calls the mount function defined within the structure :c:type:`file_system_type`. The function makes a set of initializations and returns a dentry (the structure :c:type:`struct dentry`) that represents the mount point directory. Usually :c:func:`mount` is a simple function that calls one of the functions: + + * :c:func:`mount_bdev`, which mounts a file system stored on a block device + * :c:func:`mount_single`, which mounts a file system that shares an instance between all mount operations + * :c:func:`mount_nodev`, which mounts a file system that is not on a physical device + * :c:func:`mount_pseudo`, a helper function for pseudo-file systems (``sockfs``, ``pipefs``, generally file systems that can not be mounted) + +These functions get as parameter a pointer to a function :c:func:`fill_super` that will be called after the superblock initialization to finish its initialization by the driver. An example of such a function can be found in the ``fill_super`` section. + +When unmounting the file system, the kernel calls :c:func:`kill_sb`, which performs cleanup operations and invokes one of the functions: + + * :c:func:`kill_block_super`, which unmounts a file system on a block device + * :c:func:`kill_anon_super`, which unmounts a virtual file system (information is generated when requested) + * :c:func:`kill_litter_super`, which unmounts a file system that is not on a physical device (the information is kept in memory) + +An example for a file system without disk support is the :c:func:`ramfs_mount` function in the ``ramfs`` file system: + +.. code-block:: c + + struct dentry *ramfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) + { + return mount_nodev(fs_type, flags, data, ramfs_fill_super); + } + +An example for a file system from disk is the :c:func:`minix_mount` function in the ``minix`` file system: + +.. code-block:: c + + struct dentry *minix_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) + { + return mount_bdev(fs_type, flags, dev_name, data, minix_fill_super); + } + +Superblock in VFS +================= + +The superblock exists both as a physical entity (entity on disk) and as a VFS entity (within the :c:type:`struct super_block` structure). +The superblock contains only metainformation and is used to write and read metadata from the disk (inodes, directory entries). +A superblock (and implicitly the :c:type:`struct super_block` structure) will contain information about the block device used, the list of inodes, a pointer to the inode of the file system root directory, and a pointer to the superblock operations. + +The :c:type:`struct super_block` structure +------------------------------------------ + +Part of the :c:type:`struct super_block` structure definition is presented below: + +.. code-block:: c + + struct super_block { + //... + dev_t s_dev; /* identifier */ + unsigned char s_blocksize_bits; /* block size in bits */ + unsigned long s_blocksize; /* block size in bytes */ + unsigned char s_dirt; /* dirty flag */ + loff_t s_maxbytes; /* max file size */ + struct file_system_type *s_type; /* filesystem type */ + struct super_operations *s_op; /* superblock methods */ + //... + unsigned long s_flags; /* mount flags */ + unsigned long s_magic; /* filesystem’s magic number */ + struct dentry *s_root; /* directory mount point */ + //... + char s_id[32]; /* informational name */ + void *s_fs_info; /* filesystem private info */ + }; + +The superblock stores global information for an instance of a file system: + * the physical device on which it resides + * block size + * the maximum size of a file + * file system type + * the operations it supports + * magic number (identifies the file system) + * the root directory ``dentry`` + +Additionally, a generic pointer (``void *``) stores the private data of the file system. +The superblock can be viewed as an abstract object to which its own data is added when there is a concrete implementation. + +.. _SuperblockSection: + +Superblock operations +--------------------- + +The superblock operations are described by the :c:type:`struct super_operations` structure: + +.. code-block:: c + + struct super_operations { + //... + int (*write_inode) (struct inode *, struct writeback_control *wbc); + struct inode *(*alloc_inode)(struct super_block *sb); + void (*destroy_inode)(struct inode *); + + void (*put_super) (struct super_block *); + int (*statfs) (struct dentry *, struct kstatfs *); + int (*remount_fs) (struct super_block *, int *, char *); + //... + }; + +The fields of the structure are function pointers with the following meanings: + + * ``write_inode``, ``alloc_inode``, ``destroy_inode`` write, allocate, respectively release resources associated with an inode and are described in the next lab + * ``put_super`` is called when the superblock is released at ``umount``; within this function, any resources (generally memory) from the file system's private data must be released; + * ``remount_fs`` is called when the kernel detects a remount attempt (mount flag ``MS_REMOUNTM``); most of the time here must be detected if a switch from read-only to read-write or vice versa is attempted; this can be done simply because both the old flags (in ``sb->s_flags``) and the new flags (the ``flags`` argument) can be accessed; ``data`` is a pointer to the data sent by :c:func:`mount` that represent file system specific options; + * ``statfs`` is called when a ``statfs`` system call is done (try ``stat –f`` or ``df``); this call must fill the fields of the :c:type:`struct kstatfs` structure, as it is done, for example, in the :c:func:`ext4_statfs` function. + +.. _FillSuperSection: + +The :c:func:`fill_super` function +===================================== + +As specified, the :c:func:`fill_super` function is called to terminate the superblock initialization. This initialization involves filling the :c:type:`struct super_block` structure fields and the initialization of the root directory inode. + +An example of implementation is the :c:func:`ramfs_fill_super` function which is called to initialize the remaining fields in the superblock: + +.. code-block:: c + + #include <linux/pagemap.h> + + #define RAMFS_MAGIC 0x858458f6 + + static const struct super_operations ramfs_ops = { + .statfs = simple_statfs, + .drop_inode = generic_delete_inode, + .show_options = ramfs_show_options, + }; + + static int ramfs_fill_super(struct super_block *sb, void *data, int silent) + { + struct ramfs_fs_info *fsi; + struct inode *inode; + int err; + + save_mount_options(sb, data); + + fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL); + sb->s_fs_info = fsi; + if (!fsi) + return -ENOMEM; + + err = ramfs_parse_options(data, &fsi->mount_opts); + if (err) + return err; + + sb->s_maxbytes = MAX_LFS_FILESIZE; + sb->s_blocksize = PAGE_SIZE; + sb->s_blocksize_bits = PAGE_SHIFT; + sb->s_magic = RAMFS_MAGIC; + sb->s_op = &ramfs_ops; + sb->s_time_gran = 1; + + inode = ramfs_get_inode(sb, NULL, S_IFDIR | fsi->mount_opts.mode, 0); + sb->s_root = d_make_root(inode); + if (!sb->s_root) + return -ENOMEM; + + return 0; + } + + +The kernel provides generic function to implement operations with file system structures. +The :c:func:`generic_delete_inode` and :c:func:`simple_statfs` functions used in the above code are such functions and can be used to implement the drivers if their functionality is sufficient. + +The :c:func:`ramfs_fill_super` function in the above code fills some fields in the superblock, then reads the root inode and allocates the root dentry. +Reading the root inode is done in the :c:func:`ramfs_get_inode` function, and consists of allocating a new inode using :c:func:`new_inode` and initializing it. In order to free the inode, :c:func:`iput` is used, and :c:func:`d_make_root` is used to allocate the root dentry. + +An example implementation for a disk file system is the :c:func:`minix_fill_super` function in the minix file system. +The functionality for the disk file system is similar to that of the virtual file system, with the exception of using the buffer cache. +Also, the minix file system keeps private data using the :c:type:`struct minix_sb_info` structure. +A large part of this function deals with the initialization of these private data. +The private data is allocated using the :c:func:`kzalloc` function and stored in the ``s_fs_info`` field of the superblock structure. + +VFS functions typically get as arguments the superblock, an inode and/or a dentry that contain a pointer to the superblock so that these private data can be easily accessed. + +.. _BufferCacheSection: + +Buffer cache +============ + +Buffer cache is a kernel subsystem that handles caching (both read and write) blocks from block devices. +The base entity used by buffer cache is the :c:type:`struct buffer_head` structure. +The most important fields in this structure are: + + * ``b_data``, pointer to a memory area where the data was read from or where the data must be written to + * ``b_size``, buffer size + * ``b_bdev``, the block device + * ``b_blocknr``, the number of block on the device that has been loaded or needs to be saved on the disk + * ``b_state``, the status of the buffer + +There are some important functions that work with these structures: + + * :c:func:`__bread`: reads a block with the given number and given size in a ``buffer_head`` structure; in case of success returns a pointer to the ``buffer_head`` structure, otherwise it returns ``NULL``; + * :c:func:`sb_bread`: does the same thing as the previous function, but the size of the read block is taken from the superblock, as well as the device from which the read is done; + * :c:func:`mark_buffer_dirty`: marks the buffer as dirty (sets the ``BH_Dirty`` bit); the buffer will be written to the disk at a later time (from time to time the ``bdflush`` kernel thread wakes up and writes the buffers to disk); + * :c:func:`brelse`: frees up the memory used by the buffer, after it has previously written the buffer on disk if needed; + * :c:func:`map_bh`: associates the buffer-head with the corresponding sector. + +Functions and useful macros +=========================== + +The super block typically contains a map of occupied blocks (by inodes, dentries, data) in the form of a bitmap (vector of bits). To work with such maps, it is recommend to use the following features: + + * :c:func:`find_first_zero_bit`, to find the first zero bit in a memory area. The size parameter means the number of bits in the search area; + * :c:func:`test_and_set_bit`, to set a bit and get the old value; + * :c:func:`test_and_clear_bit`, to delete a bit and get the old value; + * :c:func:`test_and_change_bit`, to invert the value of a bit and get the old value. + +The following macrodefinitions can be used to verify the type of an inode: + + * ``S_ISDIR`` (``inode->i_mode``) to check if the inode is a directory; + * ``S_ISREG`` (``inode->i_mode``) to check if the inode is a regular file (not a link or device file). + +Further reading +=============== + +#. Robert Love -- Linux Kernel Development, Second Edition -- Chapter + 12. The Virtual Filesystem +#. Understanding the Linux Kernel, 3rd edition - Chapter 12. The Virtual + Filesystem +#. `Linux Virtual File System (presentation)`_ +#. `Understanding Unix/Linux Filesystem`_ +#. `Creating Linux virtual filesystems`_ +#. `The Linux Documentation Project - VFS`_ +#. `The "Virtual File System" in Linux`_ +#. `A Linux Filesystem Tutorial`_ +#. `The Linux Virtual File System`_ +#. `Documentation/filesystems/vfs.txt`_ +#. `File systems sources`_ + +.. _Linux Virtual File System (presentation): http://www.coda.cs.cmu.edu/doc/talks/linuxvfs/ +.. _Understanding Unix/Linux Filesystem: http://www.cyberciti.biz/tips/understanding-unixlinux-file-system-part-i.html +.. _Creating Linux virtual filesystems: http://lwn.net/Articles/57369/ +.. _The Linux Documentation Project - VFS: http://www.tldp.org/LDP/tlk/fs/filesystem.html +.. _The "Virtual File System" in Linux: http://www.linux.it/~rubini/docs/vfs/vfs.html +.. _A Linux Filesystem Tutorial: http://inglorion.net/documents/tutorials/tutorfs/ +.. _The Linux Virtual File System: http://www.win.tue.nl/~aeb/linux/lk/lk-8.html +.. _Documentation/filesystems/vfs.txt: http://lxr.free-electrons.com/source/Documentation/filesystems/vfs.txt +.. _File systems sources: http://lxr.free-electrons.com/source/fs/ + +Exercises +========= + +.. include:: ../labs/exercises-summary.hrst +.. |LAB_NAME| replace:: filesystems + +.. + _[SURVEY-LABEL] + +myfs +---- + +To begin, we plan to get familiar with the interface exposed by the Linux kernel and the Virtual File System (VFS) component. That is why, for the beginning, we will work with a simple, virtual file system (i.e. without physical disk support). The file system is called ``myfs``. + +For this we will access the ``myfs/`` subdirectory in the laboratory skeleton. We will implement the superblock operations within this lab, and the next lab will continue with the inode operations. + +1. Register and unregister the myfs file system +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The first step in working with the file system is to register and unregister it. We want to do this for the file system described in ``myfs.c``. Check the file contents and follow the directions marked with ``TODO 1``. + +The steps you need to take are described in the section :ref:`RegisterUnregisterSection`. Use the ``"myfs"`` string for the file system name. + +.. note:: + Within the file system structure, use the ``myfs_mount`` function present in the code skeleton to fill the superblock (done when mounting). In ``myfs_mount`` call the function specific to a file system without disk support. As an argument for the specific mount function, use the function of type ``fill_super`` defined in the code skeleton. You can review the :ref:`FunctionsMountKillSBSection` section. + + To destroy the superblock (done at unmounting) use ``kill_litter_super``, also a function specific to a file system without disk support. The function is already implemented, you need to fill it in the :c:type:`struct file_system_type` structure. + + +After completing the sections marked with ``TODO 1`` , compile the module, copy it to the QEMU virtual machine, and start the virtual machine. Load the kernel module and then check the presence of the ``myfs`` file system within the ``/proc/filesystems`` file. + +At the moment, the file system is only registered, it does not expose operations to use it. If we try to mount it, the operation will fail. To try mounting, we create mount point ``/mnt/myfs/``. + +.. code-block:: console + + # mkdir -p /mnt/myfs + +and then we use the ``mount`` command: + +.. code-block:: console + + # mount -t myfs none /mnt/myfs + +The error message we get shows that we have not implemented the operations that work on the superblock. We will have to implement the operations on the superblock and initialize the root inode. We will do this further. + +.. note:: + + The ``none`` argument sent to the ``mount`` command indicates that we do not have a device from which to mount, the file system being a virtual one. Similarly, this is how the ``procfs`` or ``sysfs`` filesystems are mounted on Linux systems. + + +2. Completing myfs superblock +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To be able to mount the file system, we need to fill its superblock's fields, that is, a generic VFS structure of type :c:type:`struct super_block`. +We will fill out the structure within the :c:func:`myfs_fill_super` function; the superblock is represented by the variable ``sb`` passed as an argument to the function. +Follow the hints marked with ``TODO 2``. + +.. note:: + + To fill the ``myfs_fill_super`` function, you can start from the example in the section :ref:`FillSuperSection`. + + For the superblock structure fields, use the macros defined within the code skeleton wherever possible. + + +The ``s_op`` field in the superblock structure must be initialized to the superblock operations structures (type :c:type:`struct super_operations`). You need to define such a structure. + +For information on defining the :c:type:`struct super_operations` structure and filling the superblock, see the section :ref:`SuperblockSection`. + +.. note:: + + Initialize the ``drop_inode`` and ``statfs`` fields of :c:type:`struct super_operations` structure. + + +Although the superblock will be properly initialized at this time, the mount operation will continue to fail. +In order for the operation to be successfully completed, the root inode will have to be initialized, which we will do for the next exercise. + + +3. Initialize myfs root inode +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The root inode is the inode of the file system root directory (i.e. ``/``). +Initialization is done when the file system is mounted. +The ``myfs_fill_super`` function, called at mount, is the one that calls the ``myfs_get_inode`` function that creates and initializes an inode. +Typically, this function is used to create and initialize all inodes; In this exercise, however, we will only create the root inode. + +The :c:type:`inode` is allocated inside the ``myfs_get_inode`` function (local variable ``inode``, allocated using the :c:func:`new_inode` function call). + +To successfully complete mounting the file system, you will need to fill the ``myfs_get_inode`` function. Follow directions marked with ``TODO 3``. A starting point is the `ramfs_get_inode <https://elixir.bootlin.com/linux/latest/source/fs/ramfs/inode.c#L63>`_ function. + +.. note:: + + To initialize ``uid``, ``gid`` and ``mode`` , you can use the :c:func:`inode_init_owner` function as it is used in :c:func:`ramfs_get_inode`. + When you call :c:func:`inode_init_owner`, use ``NULL`` as the second parameter because there is no parent directory for the created inode. + + Initialize the ``i_atime``, ``i_ctime``, and ``i_mtime`` of the VFS inode to the value returned by the :c:func:`current_time` function. + + You will need to initialize the operations for the inode of type directory. To do this, follow the steps: + + #. Check if this is a directory type inode using the ``S_ISDIR`` macro. + #. For the ``i_op`` and ``i_fop`` fields, use kernel functions that are already implemented: + + * for ``i_op``: :c:type:`simple_dir_inode_operations`. + * for ``i_fop``: :c:type:`simple_dir_operations` + + #. Increase the number of links for the directory using the :c:func:`inc_nlink` function. + +4. Test myfs mount and unmount +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Now we can mount the filesystem. +Follow the steps above to compile the kernel module, copy to the virtual machine, and start the virtual machine, then insert the kernel module, create the mount point ``/mnt/myfs/``, and mount the file system. +We verify that the file system was mounted by inspecting the ``/proc/mounts`` file. + +What inode number does the ``/mnt/myfs`` directory have? Why? + +.. note:: + + To display the inode number of a directory, use the command: + + .. code-block:: console + + ls -di /path/to/directory + + where ``/path/to/directory/`` is the path to the directory whose inode number we want to display. + +We check myfs file system statistics using the following command: + +.. code-block:: console + + stat -f /mnt/myfs + +We want to see what the mount point ``/mnt/myfs`` contains and if we can create files. +For this we run the commands: + +.. code-block:: console + + # ls -la /mnt/myfs + # touch /mnt/myfs/a.txt + +We can see that we can not create the ``a.txt`` file on the file system. +This is because we have not implemented the operations to work with inodes in the :c:type:`struct super_operations` structure. +We will implement these operations within the next lab. + +Unmount the file system using the command + +.. code-block:: console + + umount /mnt/myfs + +Unload the kernel module corresponding to the file system as well. + +.. note:: + + To test the entire functionality, you can use the ``test-myfs.sh`` script: + + .. code-block:: console + + ./test-myfs.sh + + The script is copied to the virtual machine using ``make copy`` only if it is executable: + + .. code-block:: console + + student@workstation:~/linux/tools/labs$ chmod +x skels/filesystems/myfs/test-myfs.sh + + +.. note:: + + The statistics displayed for the file system are minimal because the information is provided by the simple_statfs function. + +minfs +----- + +Next, we will implement the basics of a very simple file system, called ``minfs``, with disk support. +We will use a disk in the virtual machine that we will format and mount with the ``minfs`` filesystem. + +For this we will access the ``minfs/kernel`` directory from the laboratory skeleton and work with the code in ``minfs.c``. +Just like ``myfs`` we will not implement the operations for working with inodes. We will just limit to working with the superblock and, therefore, mounting. +The rest of the operations will be implemented in the next lab. + +Follow the diagram below to clarify the role of structures within the ``minfs`` file system. + +.. image:: ../res/minfs.png + +1. Registering and unregistering the minfs file system +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + + Before solving the exercise, we need to add a disk to the virtual machine. To do this, generate a file that we will use as the disk image using the following command: + + .. code-block:: console + + dd if=/dev/zero of=mydisk.img bs=1M count=100 + + and add the ``-drive file=mydisk.img,if=virtio,format=raw`` argument to the ``qemu`` command in ``qemu/Makefile`` (in the ``QEMU_OPTS`` variable). + The new argument for the ``qemu`` command must be added after the one for the existing disk (``YOCTO_IMAGE``). + +To register and unregister the file system, you will need to fill the ``minfs_fs_type`` and ``minfs_mount`` functions in ``minfs.c``. Follow the directions marked with ``TODO 1``. + +.. note:: + + In the file system structure, for mount, use the ``minfs_mount`` function from in the code skeleton. + In this function, call the function to mount a file system with disk support (See the :ref:`FunctionsMountKillSBSection` section. Use :c:func:`mount_bdev`). + Choose the most suitable function for destroying the superblock (done at unmount); keep in mind that it is a file system with disk support. Use the :c:func:`kill_block_super` function. + + Initialize the ``fs_flags`` field of the :c:type:`minfs_fs_type` structure with the appropriate value for a file system with disk support. See the section :ref:`RegisterUnregisterSection`. + + The function for filling the superblock is ``minfs_fill_super``. + +After completing the sections marked with ``TODO 1``, compile the module, copy it into the QEMU virtual machine, and start the virtual machine. +Load the kernel module and then check the presence of the ``minfs`` file system within the ``/proc/filesystems`` file. + +To test the mounting of the ``minfs`` file system we will need to format the disk with its structure. Formatting requires the ``mkfs.minfs`` formatting tool from the ``minfs/user`` directory. The utility is automatically compiled when running ``make build`` and copied to the virtual machine at ``make copy``. + +After compiling, copying, and starting the virtual machine, format the ``/dev/vdd`` using the formatting utility: + +.. code-block:: console + + # ./mkfs.minfs /dev/vdd + +Load the kernel module: + +.. code-block:: console + + # insmod minfs.ko + +Create mount point ``/mnt/minfs/``: + +.. code-block:: console + + # mkdir -p /mnt/minfs/ + +and mount the filesystem + +.. code-block:: console + + # mount -t minfs /dev/vdd /mnt/minfs/ + +The operation fails because the root inode is not initialized. + +2. Completing minfs superblock +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To be able to mount the file system, you will need to fill the superblock (i.e a structure with type :c:type:`struct super_block`) within the ``minfs_fill_super`` function; it is the ``s`` argument of the function. +The structure of operations on the superblock is already defined: ``minfs_ops``. +Follow the directions marked with ``TODO 2``. You can also follow the implementation of the `minix_fill_super <https://elixir.bootlin.com/linux/latest/source/fs/minix/inode.c#L153>`_ function. + +.. note:: + + Some structures are found in the header file ``minfs.h``. + + For information on working with buffers, go to the :ref:`BufferCacheSection` section. + + Read the first block on the disk (block with index 0). + To read the block, use the :c:func:`sb_bread` function. + Cast the read data (the ``b_data`` field in the :c:type:`struct buffer_head` structure) to the structure storing the ``minfs`` superblock information on the disk: :c:type:`struct minfs_super_block`, defined in the source code file. + + Structure :c:type:`struct minfs_super_block` holds file system-specific information that is not found in the :c:type:`struct super_block` generic structure (in this case only version). + Those additional information (found in :c:type:`struct minfs_super_block` (on disk) but not in :c:type:`struct super_block` (VFS)) will be stored in the :c:type:`struct minfs_sb_info` structure. + +To check the functionality, we need a function for reading the root inode. +For the time being, use the ``myfs_get_inode`` function from ``myfs`` file system exercises. +Copy the function into the source code and call it the same as you did for myfs. +The third argument when calling the ``myfs_get_inode`` function is the inode creation permissions, similar to the virtual file system exercise (myfs). + +Validate the implementation by executing the commands from the previous exercise. + +3. Creating and destroying minfs inodes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For mounting, we need to initialize the root inode, and to get the root inode, we need to implement the functions to work with inodes. +That is, you need to implement the ``minfs_alloc_inode`` and ``minfs_destroy_inode`` functions. +Follow the directions marked with ``TODO 3``. You can use the :c:func:`minix_alloc_inode` and :c:func:`minix_destroy_inode` functions as a model. + +For the implementation, look at the macros and structures in the ``minfs.h`` header file. + +.. note:: + + For memory allocation/deallocation in ``minfs_alloc_inode`` and ``minfs_destroy_inode``, we recommend using :c:func:`kzalloc` and :c:func:`kfree`. + + In ``minfs_alloc_inode`` allocate structures with type :c:type:`struct minfs_inode_info`, but only return structures with type :c:type:`struct inode`, i.e. return those given by the ``vfs_inode`` field. + + In the ``minfs_alloc_inode`` function, call :c:func:`inode_init_once` to initialize the inode. + + In the ``destroy_inode`` function, you can access the structure with type :c:type:`struct minfs_inode_info` using the ``container_of`` macro. + +.. note:: + + In this exercise, you have implemented the ``minfs_alloc_inode`` and ``minfs_destroy_inode`` functions, but they are not yet called. The correctness of the implementation will be checked at the end of the next exercise. + +4. Initialize minfs root inode +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Initializing the root inode is required in order to mount the file system. +For this, you will need to complete the ``minfs_ops`` structure with the ``minfs_alloc_inode`` and ``minfs_destroy_inode`` functions and fill the ``minfs_iget`` function. + +The ``minfs_iget`` function is the function called to allocate a VFS inode (i.e. :c:type:`struct inode`) and fill it with minfs inode-specific information from the disk (i.e. ``struct minfs_inode``). + +Follow the directions marked with ``TODO 4``. +Fill out the ``alloc_inode`` and ``destroy_inode`` fields of :c:type:`struct super_operations` structure with the functions implemented in the previous step. + +The information about the root inode is found in the second block on the disk (the inode with index 1). +Make ``minfs_iget`` read the root minfs inode from the disk (:c:type:`struct minfs_inode`) and fill in the VFS inode (:c:type:`struct inode`). + +In the ``minfs_fill_super`` function, replace the ``myfs_get_inode`` call with the ``minfs_iget`` function call. + +.. note:: + To implement the ``minfs_iget`` function, follow the implementation of `V1_minix_iget <https://elixir.bootlin.com/linux/v4.15/source/fs/minix/inode.c#L460>`_. + To read a block, use the :c:func:`sb_bread` function. + Cast the read data (the ``b_data`` field of the :c:type:`struct buffer_head` structure) to the minfs inode from the disk (:c:type:`struct minfs_inode`). + + The ``i_uid``, ``i_gid``, ``i_mode``, ``i_size`` must be filled in the VFS inode with the values in the minfs inode structure read from disk. + To initialize the ``i_uid`` and ``i_gid fields``, use the functions :c:func:`i_uid_write` , and :c:func:`i_gid_write`. + + Initialize the ``i_atime`` , ``i_ctime``, and ``i_mtime`` fields of the VFS inode to the value returned by the :c:func:`current_time` function. + + You will need to initialize the operations for the inode with type directory. To do this, follow the steps: + + #. Check if this is a directory type inode using the ``S_ISDIR`` macro. + #. For the ``i_op`` and ``i_fop`` fields, use kernel functions already implemented: + + * for ``i_op``: :c:func:`simple_dir_inode_operations` . + * for ``i_fop``: :c:func:`simple_dir_operations` + + #. Increment the number of links for the directory using the :c:func:`inc_nlink` function. + +5. Testing of minfs mount and unmount +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Now we can mount the filesystem. +Follow the steps above to compile the kernel module, copy to the virtual machine, start the virtual machine, and then insert the kernel module, create mount point ``/mnt/minfs/`` and mount the file system. +We verify that the file system was mounted by investigating the ``/proc/mounts`` file. + +We check that everything is fine by listing the mount point contents ``/mnt/minfs/``: + +.. code-block:: console + + # ls /mnt/minfs/ + +After mount and verification, unmount the file system and unload the module from the kernel. + +.. note:: + Alternatively, to test the entire functionality, you can use the ``test-minfs.sh`` script: + + .. code-block:: console + + # ./test-minfs.sh + + The script is copied to the virtual machine when running the ``make copy`` command only if is executable. + + .. code-block:: console + + student@workstation:~/linux/tools/labs$ chmod +x skels/filesystems/minfs/user/test-minfs.sh + diff --git a/refs/pull/405/merge/_sources/labs/filesystems_part2.rst.txt b/refs/pull/405/merge/_sources/labs/filesystems_part2.rst.txt new file mode 100644 index 00000000..9217cdbe --- /dev/null +++ b/refs/pull/405/merge/_sources/labs/filesystems_part2.rst.txt @@ -0,0 +1,1076 @@ +============================ +File system drivers (Part 2) +============================ + +Lab objectives +============== + + * Improving the knowledge about inode, file and dentry. + * Acquiring knowledge about adding support for working with regular files and directories in VFS (*Virtual File System*). + * Acquiring knowledge about the internal implementation of a file system. + +Inode +===== + +The inode is an essential component of a UNIX file system and, at the same time, an important component of VFS. An inode is a metadata (it has information about information). +An inode uniquely identifies a file on disk and holds information about it (uid, gid, access rights, access times, pointers to data blocks, etc.). +An important aspect is that an inode does not have information about the file name (it is retained by the associated :c:type:`struct dentry` structure). + +The inode refers to a file on the disk. To refer an open file (associated with a file descriptor within a process), the :c:type:`struct file` structure is used. +An inode can have any number of (zero or more) ``file`` structures associated (multiple processes can open the same file, or a process can open the same file several times). + +Inode exists both as a VFS entity (in memory) and as a disk entity (for UNIX, HFS, NTFS, etc.). +The inode in VFS is represented by the structure :c:type:`struct inode`. +Like the other structures in VFS, :c:type:`struct inode` is a generic structure that covers the options for all supported file types, even those that do not have an associated disk entity (such as FAT). + +The inode structure +------------------- + +The inode structure is the same for all file systems. In general, file systems also have private information. These are referenced through the ``i_private`` field of the structure. +Conventionally, the structure that keeps that particular information is called ``<fsname>_inode_info``, where ``fsname`` represents the file system name. For example, minix and ext4 filesystems store particular information in structures :c:type:`struct minix_inode_info`, or :c:type:`struct ext4_inode_info`. + +Some of the important fields of :c:type:`struct inode` are: + + * ``i_sb`` : The superblock structure of the file system the inode belongs to. + * ``i_rdev``: the device on which this file system is mounted + * ``i_ino`` : the number of the inode (uniquely identifies the inode within the file system) + * ``i_blkbits``: number of bits used for the block size == log\ :sub:`2`\ (block size) + * ``i_mode``, ``i_uid``, ``i_gid``: access rights, uid, gid + + * ``i_size``: file/directory/etc. size in bytes + * ``i_mtime``, ``i_atime``, ``i_ctime``: change, access, and creation time + * ``i_nlink``: the number of names entries (dentries) that use this inode; for file systems without links (either hard or symbolic) this is always set to 1 + * ``i_blocks``: the number of blocks used by the file (all blocks, not just data); this is only used by the quota subsystem + * ``i_op``, ``i_fop``: pointers to operations structures: :c:type:`struct inode_operations` and :c:type:`struct file_operations`; ``i_mapping->a_ops`` contains a pointer to :c:type:`struct address_space_operations`. + * ``i_count``: the inode counter indicating how many kernel components use it. + +Some functions that can be used to work with inodes: + + * :c:func:`new_inode`: creates a new inode, sets the ``i_nlink`` field to 1 and initializes ``i_blkbits``, ``i_sb`` and ``i_dev``; + * :c:func:`insert_inode_hash`: adds the inode to the hash table of inodes; an interesting effect of this call is that the inode will be written to the disk if it is marked as dirty; + + .. warning:: + + An inode created with :c:func:`new_inode` is not in the hash table, and unless you have serious reasons not to, you must enter it in the hash table; + + * :c:func:`mark_inode_dirty`: marks the inode as dirty; at a later moment, it will be written on the disc; + * :c:func:`iget_locked`: loads the inode with the given number from the disk, if it is not already loaded; + * :c:func:`unlock_new_inode`: used in conjunction with :c:func:`iget_locked`, releases the lock on the inode; + * :c:func:`iput`: tells the kernel that the work on the inode is finished; if no one else uses it, it will be destroyed (after being written on the disk if it is maked as dirty); + * :c:func:`make_bad_inode`: tells the kernel that the inode can not be used; It is generally used from the function that reads the inode when the inode could not be read from the disk, being invalid. + +Inode operations +---------------- + +Getting an inode +^^^^^^^^^^^^^^^^ + +One of the main inode operations is obtaining an inode (the :c:type:`struct inode` in VFS). +Until version ``2.6.24`` of the Linux kernel, the developer defined a ``read_inode`` function. +Starting with version ``2.6.25``, the developer must define a ``<fsname>_iget`` where ``<fsname>`` is the name of the file system. +This function is responsible with finding the VFS inode if it exists or creating a new one and filling it with the information from the disk. + +Generally, this function will call :c:func:`iget_locked` to get the inode structure from VFS. If the inode is newly created then it will need to read the inode from the disk (using :c:func:`sb_bread`) and fill in the useful information. + +An example of such a function is :c:func:`minix_iget`: + +.. code-block:: c + + static struct inode *V1_minix_iget(struct inode *inode) + { + struct buffer_head * bh; + struct minix_inode * raw_inode; + struct minix_inode_info *minix_inode = minix_i(inode); + int i; + + raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh); + if (!raw_inode) { + iget_failed(inode); + return ERR_PTR(-EIO); + ... + } + + struct inode *minix_iget(struct super_block *sb, unsigned long ino) + { + struct inode *inode; + + inode = iget_locked(sb, ino); + if (!inode) + return ERR_PTR(-ENOMEM); + if (!(inode->i_state & I_NEW)) + return inode; + + if (INODE_VERSION(inode) == MINIX_V1) + return V1_minix_iget(inode); + ... + } + +The minix_iget function gets the VFS inode using :c:func:`iget_locked`. +If the inode is already existing (not new == the ``I_NEW`` flag is not set) the function returns. +Otherwise, the function calls the :c:func:`V1_minix_iget` function that will read the inode from the disk using :c:func:`minix_V1_raw_inode` and then complete the VFS inode with the read information. + +Superoperations +^^^^^^^^^^^^^^^ + +Many of the superoperations (components of the :c:type:`struct super_operations` structure used by the superblock) are used when working with inodes. These operations are described next: + + * ``alloc_inode``: allocates an inode. + Usually, this funcion allocates a :c:type:`struct <fsname>_inode_info` structure and performs basic VFS inode initialization (using :c:func:`inode_init_once`); + minix uses for allocation the :c:func:`kmem_cache_alloc` function that interacts with the SLAB subsystem. + For each allocation, the cache construction is called, which in the case of minix is the :c:func:`init_once` function. + Alternatively, :c:func:`kmalloc` can be used, in which case the :c:func:`inode_init_once` function should be called. + The :c:func:`alloc_inode` function will be called by the :c:func:`new_inode` and :c:func:`iget_locked` functions. + * ``write_inode`` : saves/updates the inode received as a parameter on disk; to update the inode, though inefficient, for beginners it is recommended to use the following sequence of operations: + + * load the inode from the disk using the :c:func:`sb_bread` function; + * modify the buffer according to the saved inode; + * mark the buffer as dirty using :c:func:`mark_buffer_dirty`; the kernel will then handle its writing on the disk; + * an example is the :c:func:`minix_write_inode` function in the ``minix`` file system + + * ``evict_inode``: removes any information about the inode with the number received in the ``i_ino`` field from the disk and memory (both the inode on the disk and the associated data blocks). This involves performing the following operations: + + * delete the inode from the disk; + * updates disk bitmaps (if any); + * delete the inode from the page cache by calling :c:func:`truncate_inode_pages`; + * delete the inode from memory by calling :c:func:`clear_inode` ; + * an example is the :c:func:`minix_evict_inode` function from the minix file system. + + * ``destroy_inode`` releases the memory occupied by inode + +inode_operations +^^^^^^^^^^^^^^^^ + +The inode operations are described by the :c:type:`struct inode_operations` structure. + +Inodes are of several types: file, directory, special file (pipe, fifo), block device, character device, link etc. +For this reason, the operations that an inode needs to implement are different for each type of inode. +Below are detailed operations for a :ref:`file type inode <FileInodes>` and a :ref:`directory inode <DirectoryInodes>`. + +The operations of an inode are initialized and accessed using the ``i_op`` field of the structure :c:type:`struct inode`. + +The file structure +================== + +The ``file`` structure corresponds to a file open by a process and exists only in memory, being associated with an inode. +It is the closest VFS entity to user-space; the structure fields contain familiar information of a user-space file (access mode, file position, etc.) and the operations with it are performed by known system calls (``read``, ``write`` , etc.). + +The file operations are described by the :c:type:`struct file_operations` structure. + +The file operations for a file system are initialized using the ``i_fop`` field of the :c:type:`struct inode` structure. +When opening a file, the VFS initializes the ``f_op`` field of the :c:type:`struct file` structure with address of ``inode->i_fop``, such that subsequent system calls use the value stored in the ``file->f_op``. + +.. _FileInodes: + +Regular files inodes +==================== + +To work with the inode, the ``i_op`` and ``i_fop`` fields of the inode structure must be filled in. +The type of the inode determines the operations that it needs to implement. + +.. _FileOperations: + +Regular files inode operations +------------------------------ + +In the ``minix`` file system, the ``minix_file_inode_operations`` structure is defined for the operations on an inode and for the file operations the ``minix_file_operations`` structure is defined: + +.. code-block:: c + + const struct file_operations minix_file_operations = { + .llseek = generic_file_llseek, + .read_iter = generic_file_read_iter, + //... + .write_iter = generic_file_write_iter, + //... + .mmap = generic_file_mmap, + //... + }; + + const struct inode_operations minix_file_inode_operations = { + .setattr = minix_setattr, + .getattr = minix_getattr, + }; + + //... + if (S_ISREG(inode->i_mode)) { + inode->i_op = &minix_file_inode_operations; + inode->i_fop = &minix_file_operations; + } + //... + + + +The functions :c:func:`generic_file_llseek` , :c:func:`generic_file_mmap` , :c:func:`generic_file_read_iter` and :c:func:`generic_file_write_iter` are implemented in the kernel. + +For simple file systems, only the truncation operation (``truncate`` system call) must be implemented. +Although initially there was a dedicated operation, starting with 3.14 the operation was embedded in ``setattr``: if the paste size is different from the current size of the inode, then a truncate operation must be performed. +An example of implementing this verification is in the :c:func:`minix_setattr` function: + +.. code-block:: c + + static int minix_setattr(struct dentry *dentry, struct iattr *attr) + { + struct inode *inode = d_inode(dentry); + int error; + + error = setattr_prepare(dentry, attr); + if (error) + return error; + + if ((attr->ia_valid & ATTR_SIZE) && + attr->ia_size != i_size_read(inode)) { + error = inode_newsize_ok(inode, attr->ia_size); + if (error) + return error; + + truncate_setsize(inode, attr->ia_size); + minix_truncate(inode); + } + + setattr_copy(inode, attr); + mark_inode_dirty(inode); + return 0; + } + +The truncate operation involves: + + * freeing blocks of data on the disk that are now extra (if the new dimension is smaller than the old one) or allocating new blocks (for cases where the new dimension is larger) + * updating disk bit maps (if used); + * updating the inode; + * filling with zero the space that was left unused from the last block using the :c:func:`block_truncate_page` function. + +An example of the implementation of the cropping operation is the :c:func:`minix_truncate` function in the ``minix`` file system. + +.. _AddressSpaceOperations: + +Address space operations +------------------------ + +There is a close link between the address space of a process and files: the execution of the programs is done almost exclusively by mapping the file into the process address space. +Because this approach works very well and is quite general, it can also be used for regular system calls such as ``read`` and ``write``. + +The structure that describes the address space is :c:type:`struct address_space`, and the operations with it are described by the structure :c:type:`struct address_space_operations`. To initialize the address space operations, fill ``inode->i_mapping->a_ops`` of the file type inode. + +An example is the ``minix_aops`` structure in the minix file system: + +.. code-block:: c + + static const struct address_space_operations minix_aops = { + .readpage = minix_readpage, + .writepage = minix_writepage, + .write_begin = minix_write_begin, + .write_end = generic_write_end, + .bmap = minix_bmap + }; + + //... + if (S_ISREG(inode->i_mode)) { + inode->i_mapping->a_ops = &minix_aops; + } + //... + +The :c:func:`generic_write_end` function is already implemented. +Most of the specific functions are very easy to implement, as follows: + +.. code-block:: c + + static int minix_writepage(struct page *page, struct writeback_control *wbc) + { + return block_write_full_page(page, minix_get_block, wbc); + } + + static int minix_readpage(struct file *file, struct page *page) + { + return block_read_full_page(page, minix_get_block); + } + + static void minix_write_failed(struct address_space *mapping, loff_t to) + { + struct inode *inode = mapping->host; + + if (to > inode->i_size) { + truncate_pagecache(inode, inode->i_size); + minix_truncate(inode); + } + } + + static int minix_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) + { + int ret; + + ret = block_write_begin(mapping, pos, len, flags, pagep, + minix_get_block); + if (unlikely(ret)) + minix_write_failed(mapping, pos + len); + + return ret; + } + + static sector_t minix_bmap(struct address_space *mapping, sector_t block) + { + return generic_block_bmap(mapping, block, minix_get_block); + } + +All that needs to be done is to implement :c:type:`minix_get_block`, which has to translate a block of a file into a block on the device. +If the flag ``create`` received as a parameter is set, a new block must be allocated. +In case a new block is created, the bit map must be updated accordingly. +To notify the kernel not to read the block from the disk, ``bh`` must be marked with :c:func:`set_buffer_new`. The buffer must be associated with the block through :c:func:`map_bh`. + +Dentry structure +================ + +Directories operations use the :c:type:`struct dentry` structure. +Its main task is to make links between inodes and filenames. +The important fields of this structure are presented below: + +.. code-block:: c + + struct dentry { + //... + struct inode *d_inode; /* associated inode */ + //... + struct dentry *d_parent; /* dentry object of parent */ + struct qstr d_name; /* dentry name */ + //... + + struct dentry_operations *d_op; /* dentry operations table */ + struct super_block *d_sb; /* superblock of file */ + void *d_fsdata; /* filesystem-specific data */ + //... + }; + +Fields meaning: + + * ``d_inode``: the inode referenced by this dentry; + * ``d_parent``: the dentry associated with the parent directory; + * ``d_name``: a :c:type:`struct qstr` structure that contains the fields ``name`` and ``len`` (the name and the length of the name). + * ``d_op``: operations with dentries, represented by the :c:type:`struct dentry_operations` structure. + The kernel implements default operations so there is no need to (re)implement them. Some file systems can do optimizations based on the specific structure of the dentries. + * ``d_fsdata``: field reserved for the file system that implements dentry operations; + +Dentry operations +----------------- + +The most commonly operations applied to dentries are: + + * ``d_make_root``: allocates the root dentry. It is generally used in the function that is called to read the superblock (``fill_super``), which must initialize the root directory. + So the root inode is obtained from the superblock and is used as an argument to this function, to fill the ``s_root`` field from the :c:type:`struct super_block` structure. + * ``d_add``: associates a dentry with an inode; the dentry received as a parameter in the calls discussed above signifies the entry (name, length) that needs to be created. This function will be used when creating/loading a new inode that does not have a dentry associated with it and has not yet been introduced to the hash table of inodes (at ``lookup``); + * ``d_instantiate``: The lighter version of the previous call, in which the dentry was previously added in the hash table. + +.. warning:: + + ``d_instantiate`` must be used to implement create calls (``mkdir``, ``mknod``, ``rename``, ``symlink``) and NOT ``d_add``. + +.. _DirectoryInodes: + +Directory inodes operations +=========================== + +The operations for directory type inodes have a higher complexity level than the ones for files. +The developer must define operations for inodes and operations for files. +In ``minix``, these operations are defined in :c:type:`minix_dir_inode_operations` and :c:type:`minix_dir_operations`: + +.. code-block:: c + + struct inode_operations minix_dir_inode_operations = { + .create = minix_create, + .lookup = minix_lookup, + .link = minix_link, + .unlink = minix_unlink, + .symlink = minix_symlink, + .mkdir = minix_mkdir, + .rmdir = minix_rmdir, + .mknod = minix_mknod, + //... + }; + + struct file_operations minix_dir_operations = { + .llseek = generic_file_llseek, + .read = generic_read_dir, + .iterate = minix_readdir, + //... + }; + + //... + if (S_ISDIR(inode->i_mode)) { + inode->i_op = &minix_dir_inode_operations; + inode->i_fop = &minix_dir_operations; + inode->i_mapping->a_ops = &minix_aops; + } + //... + +The only function already implemented is :c:func:`generic_read_dir`. + +The functions that implement the operations on directory inodes are the ones described below. + +Creating an inode +----------------- + +The inode creation function is indicated by the field ``create`` in the ``inode_operations`` structure. +In the minix case, the function is :c:func:`minix_create`. +This function is called by the ``open`` and ``creat`` system calls. Such a function performs the following operations: + + #. Introduces a new entry into the physical structure on the disk; the update of the bit maps on the disk must not be forgotten. + #. Configures access rights to those received as a parameter. + #. Marks the inode as dirty with the :c:func:`mark_inode_dirty` function. + #. Instantiates the directory entry (``dentry``) with the ``d_instantiate`` function. + +Creating a directory +-------------------- + +The directory creation function is indicated by the ``mkdir`` field in the ``inode_operations`` structure. +In the minix case, the function is :c:func:`minix_mkdir`. +This function is called by the ``mkdir`` system call. Such a function performs the following operations: + + #. Calls :c:func:`minix_create`. + #. Allocates a data block for the directory. + #. Creates the ``"."`` and ``".."`` entries. + +Creating a link +--------------- + +The link creation function (hard link) is indicated by the ``link`` field in the ``inode_operations`` structure. +In the minix case, the function is :c:func:`minix_link`. +This function is called by the ``link`` system call. Such a function performs the following operations: + + * Binds the new dentry to the inode. + * Increments the ``i_nlink`` field of the inode. + * Marks the inode as dirty using the :c:func:`mark_inode_dirty` function. + +Creating a symbolic link +------------------------ + +The symbolic link creation function is indicated by the ``symlink`` field in the ``inode_operations`` structure. +In the minix case, the function is :c:func:`minix_symlink`. +The operations to be performed are similar to ``minix_link`` with the differences being given by the fact that a symbolic link is created. + +Deleting a link +--------------- + +The link delete function (hard link) is indicated by the ``unlink`` field in the ``inode_operations`` structure. +In the minix case, the function is :c:func:`minix_unlink`. +This function is called by the ``unlink`` system call. Such a function performs the following operations: + + #. Deletes the directory entry given as a parameter from the physical disk structure. + #. Decrements the ``i_nlink`` counter of the inode to which the entry points (otherwise the inode will never be deleted). + +Deleting a directory +-------------------- + +The directory delete function is indicated by the ``rmdir`` field in the ``inode_operations`` structure. +In the minix case, the function is :c:func:`minix_rmdir`. +This function is called by the ``rmdir`` system call. +Such a function performs the following operations: + + #. Performs the operations done by ``minix_unlink``. + #. Ensures that the directory is empty; otherwise, returns ``ENOTEMPTY``. + #. Also deletes the data blocks. + +Searching for an inode in a directory +------------------------------------- + +The function that searches for an entry in a directory and extracts the inode is indicated by the ``lookup`` field in the ``inode_operations`` structure. +In the minix case, the function is ``minix_lookup``. +This function is called indirectly when information about the inode associated with an entry in a directory is needed. +Such a function performs the following operations: + + #. Searches in the directory indicated by ``dir`` the entry having the name ``dentry->d_name.name``. + #. If the entry is found, it will return ``NULL`` and associate the inode with the name using the :c:func:`d_add` function. + #. Otherwise, returns ``ERR_PTR``. + +Iterating through entries in a directory +---------------------------------------- + +The function which iterates through the entries in a directory (lists the directory contents) is indicated by the field ``iterate`` in the ``struct file_operations`` structure. +In the minix case, the function is ``minix_readdir``. +This function is called by the ``readdir`` system call. + +The function returns either all entries in the directory or just a part when the buffer allocated for it is not available. +A call of this function can return: + + * a number equal to the existing number of entries if there is enough space in the corresponding user space buffer; + * a number smaller than the actual number of entries, as much as there was space in the corresponding user space buffer; + * ``0``, where there are no more entries to read. + +The function will be called consecutively until all available entries are read. The function is called at least twice. + + * It is only called twice if: + + * the first call reads all entries and returns their number; + * the second call returns 0, having no other entries to read. + + * It is called more than twice if the first call does not return the total number of entries. + +The function performs the following operations: + + #. Iterates over the entries (the dentries) from the current directory. + #. For each dentry found, increments ``ctx->pos``. + #. For each valid dentry (an inode other than ``0``, for example), calls the :c:func:`dir_emit` function. + #. If the :c:func:`dir_emit` function returns a value other than zero, it means that the buffer in the user space is full and the function returns. + +The arguments of the ``dir_emit`` function are: + + * ``ctx`` is the directory iteration context, passed as an argument to the ``iterate`` function; + * ``name`` is the name of the entry (a string of characters); + * ``name_len`` is the length of the entry name; + * ``ino`` is the inode number associated with the entry; + * ``type`` identifies the entry type: ``DT_REG`` (file), ``DT_DIR`` (directory), ``DT_UNKNOWN`` etc. ``DT_UNKNOWN`` can be used when the entry type is unknown. + +.. _BitmapOperations: + +Bitmap operations +================= + +When working with the file systems, management information (what block is free or busy, what inode is free or busy) is stored using bitmaps. +For this we often need to use bit operations. Such operations are: + + * searching the first 0 bit: representing a free block or inode + * marking a bit as 1: marking a busy block or inode + +The bitmap operations are found in headers from ``include/asm-generic/bitops``, especially in ``find.h`` and ``atomic.h``. Usual functions, with names indicating their role, are: + + * :c:func:`find_first_zero_bit` + * :c:func:`find_first_bit` + * :c:func:`set_bit` + * :c:func:`clear_bit` + * :c:func:`test_and_set_bit` + * :c:func:`test_and_clear_bit` + +These functions usually receive the address of the bitmap, possibly its size (in bytes) and, if necessary, the index of the bit that needs to be activated (set) or deactivated (clear). + +Some usage examples are listed below: + +.. code-block:: c + + unsigned int map; + unsigned char array_map[NUM_BYTES]; + size_t idx; + int changed; + + /* Find first zero bit in 32 bit integer. */ + idx = find_first_zero_bit(&map, 32); + printk (KERN_ALERT "The %zu-th bit is the first zero bit.\n", idx); + + /* Find first one bit in NUM_BYTES bytes array. */ + idx = find_first_bit(array_map, NUM_BYTES * 8); + printk (KERN_ALERT "The %zu-th bit is the first one bit.\n", idx); + + /* + * Clear the idx-th bit in integer. + * It is assumed idx is less the number of bits in integer. + */ + clear_bit(idx, &map); + + /* + * Test and set the idx-th bit in array. + * It is assumed idx is less the number of bits in array. + */ + changed = __test_and_set_bit(idx, &sbi->imap); + if (changed) + printk(KERN_ALERT "%zu-th bit changed\n", idx); + +Further reading +=============== + +#. Robert Love -- Linux Kernel Development, Second Edition -- Chapter + 12. The Virtual Filesystem +#. Understanding the Linux Kernel, 3rd edition - Chapter 12. The Virtual + Filesystem +#. `Linux Virtual File System (presentation)`_ +#. `Understanding Unix/Linux Filesystem`_ +#. `Creating Linux virtual filesystems`_ +#. `The Linux Documentation Project - VFS`_ +#. `The "Virtual File System" in Linux`_ +#. `A Linux Filesystem Tutorial`_ +#. `The Linux Virtual File System`_ +#. `Documentation/filesystems/vfs.txt`_ +#. `File systems sources`_ + +.. _Linux Virtual File System (presentation): http://www.coda.cs.cmu.edu/doc/talks/linuxvfs/ +.. _Understanding Unix/Linux Filesystem: http://www.cyberciti.biz/tips/understanding-unixlinux-file-system-part-i.html +.. _Creating Linux virtual filesystems: http://lwn.net/Articles/57369/ +.. _The Linux Documentation Project - VFS: http://www.tldp.org/LDP/tlk/fs/filesystem.html +.. _The "Virtual File System" in Linux: http://www.linux.it/~rubini/docs/vfs/vfs.html +.. _A Linux Filesystem Tutorial: http://inglorion.net/documents/tutorials/tutorfs/ +.. _The Linux Virtual File System: http://www.win.tue.nl/~aeb/linux/lk/lk-8.html +.. _Documentation/filesystems/vfs.txt: http://lxr.free-electrons.com/source/Documentation/filesystems/vfs.txt +.. _File systems sources: http://lxr.free-electrons.com/source/fs/ + +Exercises +========= + +.. include:: ../labs/exercises-summary.hrst +.. |LAB_NAME| replace:: filesystems + +.. important:: + + In this lab, we will continue the implementation of the file systems started in the previous one. + For this, we will generate the laboratory skeleton using the following command: + + .. code-block:: console + + TODO=5 LABS=filesystems make skels + + After this, we will start the implementation from ``TODO 5``. + +myfs +---- + +For the exercises below, we will use the ``myfs`` file system whose implementation we started with the previous lab. +We stopped after mounting the file system and now we will continue with the operations for regular files and directories. +At the end of these exercises, we will be able to create, modify and delete regular directories and files. + +We will mostly use the ``inode`` and ``dentry`` VFS structures. +The ``inode`` structure defines a file (of any type: regular, directory, link), while the ``dentry`` structure defines a name, which is an entry in a directory. + +For this we will access the ``myfs`` directory in the lab skeleton. +The previously generated skeleton contains the solution for the previous lab; we will start from this. As in the previous lab, we will use the ``ramfs`` file system as a starting point. + +1. Directory operations +^^^^^^^^^^^^^^^^^^^^^^^ + +To begin with, we will implement the operations for working with directories. +The operations of creating a file or deleting a file are also directory operations; these operations result in adding or deleting a directory entry (*dentry*). + +At the end of this exercise we will be able to create and delete entries in the file system. We will not be able to read and write to regular files; we will do so in the next exercise. + +Follow directions marked with ``TODO 5`` which will guide you through the steps you need to take. + +You will need to specify the following directory operations: + + * create a file (``create`` function) + * search (``lookup`` function) + * link (``link`` function) + * create directory (``mkdir`` function) + * deletion (``rmdir`` and ``unlink`` functions) + * create node (``mknod``) + * rename (``rename`` function) + +For this, define the ``myfs_dir_inode_operations`` structure in the code, where marked with ``TODO 5``. +To begin, just define the structure ``myfs_dir_inode_operations``; you will define the structures ``myfs_file_operations``, ``myfs_file_inode_operations`` , and ``myfs_aops`` in the next exercise. + +.. tip:: + + Read the section :ref:`DirectoryInodes` + + As a model, you are following the ``ramfs_dir_inode_operations`` structure. + +Implement the ``mkdir``, ``mknod`` and ``create`` operations inside ``myfs_mkdir``, ``myfs_mknod`` and ``myfs_create``. +These operations will allow you to create directories and files in the file system. + +.. tip:: + + We recommend making the code modular using a ``mknod`` function, which you can also use for the next exercise. + For inode reading and allocation, use ``myfs_get_inode``, which is already implemented. + + As a model, follow the next functions implemented in the ``ramfs`` file system: + + * :c:func:`ramfs_mknod` + * :c:func:`ramfs_mkdir` + * :c:func:`ramfs_create` + +For the other functions, use generic calls (``simple_*``) already defined in VFS. + +In the ``myfs_get_inode`` function, initialize the operations fields of the directory inodes: + + * ``i_op`` must be initialized to the address of the structure ``myfs_dir_inode_operations``; + * ``i_fop`` must be initialized to the address of the structure ``simple_dir_operations``, defined in VFS. + +.. note:: + + ``i_op`` is a pointer to a structure of type :c:type:`struct inode_operations` containing operations that have to do with the inode, which are, for a directory, creating a new entry, listing entries, deleting entries, etc. + + ``i_fop`` is a pointer to a structure of type :c:type:`struct file_operations` containing operations that have to do with the ``file`` structure associated with the inode, such as ``read``, ``write``, and ``lseek``. + +Testing +""""""" + +Once the module is done, we can test the creation of files and directories. +To do this, we compile the kernel module (using ``make build``) and copy the resulting file (``myfs.ko``) and the test scripts (``test-myfs-{1,2}.sh``) in the virtual machine directory (using ``make copy``). + +.. note:: + + The test scripts are copied to the virtual machine using ``make copy`` only if they are executable: + + .. code-block:: console + + student@workstation:~/linux/tools/labs$ chmod +x skels/filesystems/myfs/test-myfs-*.sh + +After starting the virtual machine, insert the module, create the mount point and mount the file system: + +.. code-block:: console + + # insmod myfs.ko + # mkdir -p /mnt/myfs + # mount -t myfs none /mnt/myfs + +Now we can create file hierarchies and subdirectories in the mounted directory (``/mnt/myfs``). +We use commands like the ones below: + +.. code-block:: console + + # touch /mnt/myfs/peanuts.txt + # mkdir -p /mnt/myfs/mountain/forest + # touch /mnt/myfs/mountain/forest/tree.txt + # rm /mnt/myfs/mountain/forest/tree.txt + # rmdir /mnt/myfs/mountain/forest + +At this time we can not read or write files. When running commands such as the following ones we will get errors. + +.. code-block:: console + + # echo "chocolate" > /mnt/myfs/peanuts.txt + # cat /mnt/myfs/peanuts.txt + +This happens because we have not implemented the operations for working with files; we will do so further. + +To unload the kernel module, use the command + +.. code-block:: console + + umount /mnt/myfs + rmmod myfs + +To test the functionality provided by the kernel module, we can use the dedicated script ``test-myfs-1.sh``. +If the implementation is correct, no error messages will be displayed. + +2. File operations +^^^^^^^^^^^^^^^^^^ + +We want to implement the operations for working with files, which are used for accessing a file's content: read, write, truncate, etc. +For this you will specify the operations described in the structures :c:type:`struct inode_operations`, :c:type:`struct file_operations` and :c:type:`struct address_space_operations`. + +Follow the locations marked with ``TODO`` 6 which will guide you through the steps you need to take. + +Start by defining ``myfs_file_inode_operations`` and ``myfs_file_operations``. + +.. tip:: + + Read the section :ref:`FileOperations`. + + Use the generic function provided by VFS. + + An example of implementation is the ``ramfs`` file system. + Follow the implementation of ``ramfs_file_inode_operations`` and ``ramfs_file_operations``. + +Inside the function ``myfs_get_inode``, initialize the operations fields for the regular file inodes: + + * ``i_op`` must be initialized to ``myfs_file_inode_operations``; + * ``i_fop`` msust be initialized to ``myfs_file_operations``. + +Continue with defining the structure ``myfs_aops``. + +.. tip:: + + Read the section :ref:`AddressSpaceOperations`. + + Use the generic functions provided by VFS. + + An implementation example is the ``ramfs`` file system: the ``ramfs_aops`` structure. + + You do not need to define the function of type ``set_page_dirty``. + +Initialize the ``i_mapping->a_ops`` field of the inode structure to ``myfs_aops``. + +Testing +""""""" + +For testing, we use the steps described in the previous exercise. +In addition to those steps, we will now be able to read, write and modify a file using commands like the ones below: + +.. code-block:: console + + # echo "chocolate" > /mnt/myfs/peanuts.txt + # cat /mnt/myfs/peanuts.txt + +To test the functionality provided by the module, we can use the dedicated script: + +.. code-block:: console + + # ./test-myfs-2.sh + +If the implementation is correct, no error messages will be displayed when running the above script. + +minfs +----- + +For the exercises below, we will use the minfs file system whose development started in the previous lab. +This is a file system with disk support. +We stopped after mounting the file system and now we will continue with the operations on regular files and directories. +At the end of these exercises we will be able to create and delete entries in the file system. + +We will mainly use the :c:type:`inode` and :c:type:`dentry` VFS structures. +The inode structure defines a file (of any type: regular, directory, link), while the dentry structure defines a name, which is a directory entry. + +For this we will access the ``minfs/kernel`` directory from the laboratory skeleton. +The generated skeleton contains the solution from the previous lab; we will start from this. +As in the previous lab, we will use the ``minix`` file system as a starting point. + +We will use the formatting tool ``mkfs.minfs`` in the ``minfs/user`` directory which is automatically compiled when running ``make build`` and copied to the virtual machine at ``make copy``. + +The formatting tool prepares a virtual machine disk using a command like + +.. code-block:: console + + # ./mkfs.minfs /dev/vdb + +After formatting, the disk has a structure like the one in the diagram below: + +.. image:: ../res/minfs_arch.png + +As shown in the diagram, ``minfs`` is a minimalist file system. +``minfs`` contains a maximum of 32 inodes, each inode having a single data block (the file size is limited to block size). +The super block contains a 32-bit map (``imap``), each bit indicating the use of an inode. + +.. note:: + + Before you start working, go through the ``minfs/kernel/minfs.h`` header file. + This file contains the structures and macros that will be used in these exercises. + These structures and macros define the file system as described in the diagram above. + +1. Iterate operation +^^^^^^^^^^^^^^^^^^^^ + +At first we want to be able to list the contents of the root directory. +For this we must be able to read the entries in the root directory, which means implementing the ``iterate`` operation. +The ``iterate`` operation is a field within the ``minfs_dir_operations`` structure (of type ``file_operations``) and is implemented by the function ``minfs_readdir``. We need to implement this function. + +Follow directions marked with ``TODO 5`` which will guide you through the steps you need to take. + +.. tip:: + + Read the section :ref:`DirectoryInodes` + + As a starting point, follow the :c:func:`minix_readdir` function. + The function is rather complicated, but it gives you an insight into the steps you have to do. + + Follow, in ``minfs.c`` and ``minfs.h``, the definitions of structures ``struct minfs_inode_info``, ``struct minfs_inode`` and ``struct minfs_dir_entry``. + You will use them in the ``minfs_readdir`` implementation. + +Obtain the inode and the structure ``struct minfs_inode_info`` associated with the directory. +The structure ``struct minfs_inode_info`` is useful to find out the directory's data block. +From this structure you get the ``data_block`` field, representing the data block index on the disk. + +.. tip:: + + To get the structure ``struct minfs_inode_info`` structure, use :c:func:`list_entry` or :c:func:`container_of`. + +Use :c:func:`sb_bread` to read the directory data block. + +.. tip:: + + The data block of the directory is indicated by the ``data_block`` field of the structure ``struct minfs_inode_info`` corresponding to the directory. + + The data in the block is referenced by the ``b_data`` field of the ``buffer_head`` structure (the usual code will be ``bh->b_data``). + This block (being the data block of a directory) contains an array of at most ``MINFS_NUM_ENTRIES`` entries of type ``struct minfs_dir_entry`` (directory entries specific to ``minfs``). + Use casting to ``struct minfs_dir_entry *`` to work with the data in the block. + +Iterate over all the entries in the data block and fill the user space buffer inside the ``for`` loop. + +.. tip:: + + For each index, get the corresponding entry of the ``struct minfs_dir_entry`` by using pointer arithmetics on the ``bh->b_data`` field. + Ignore dentries that have an ``ino`` field equal to 0. Such a dentry is a free slot in the director's dentry list. + + For each valid entry, there is an existing call :c:func:`dir_emit` with the appropriate parameters. This is the call that sends the dentries to the caller (and then to user space). + + Check the call examples in :c:func:`qnx6_readdir` and :c:func:`minix_readdir`. + +Testing +""""""" + +Once the module is done, we can test the listing of the root directory contents. +To do this, we compile the kernel module (``make build``) and copy the result to the virtual machine together with the test scripts (``minfs/user/test-minfs-{0,1}.sh``) and the formatting utility (``minfs/user/mkfs.minfs``) using ``make copy``, then start the machine. + +.. note:: + + The test scripts are copied to the virtual machine only if they are executable: + + .. code-block:: console + + student@eg106:~/src/linux/tools/labs$ chmod +x skels/filesystems/minfs/user/test-minfs*.sh + +After we start the virtual machine, we format the ``/dev/vdb`` disk, create the mount point and mount the file system: + +.. code-block:: console + + # ./mkfs.minfs /dev/vdb + # mkdir -p /mnt/minfs + # mount -t minfs /dev/vdb /mnt/minfs + +Now we can list the contents of the root directory: + +.. code-block:: console + + # ls -l /mnt/minfs + +We notice that there is already a file (``a.txt``); it is created by the formatting utility. + +We also notice that we are not allowed to display information for a file using the ``ls`` command. +This is because we have not implemented the ``lookup`` function. We will implement it in the next exercise. + +To test the functionality provided by the module, we can use the dedicated script: + +.. code-block:: console + + # ./test-minfs-0.sh + # ./test-minfs-1.sh + +2. Lookup operation +^^^^^^^^^^^^^^^^^^^ + +To properly list the contents of a directory, we need to implement the search functionality, ie the ``lookup`` operation. +The ``lookup`` operation is a field within the ``minfs_dir_inode_operations`` structure (of type ``inode_operations``) and is implemented by the ``minfs_lookup`` function. +This function (``minfs_lookup``) needs to be implemented. +We will actually implement the ``minfs_find_entry`` function called by ``minfs_lookup`` . + +Follow directions marked with ``TODO 6`` which will tell you the steps you need to take. + +.. tip:: + + Read the section :ref:`DirectoryInodes` + + As a starting point, read the functions :c:func:`qnx6_find_entry` and :c:func:`minix_find_entry`. + +In the ``minfs_find_entry`` function, iterate over the directory where the dentry is: ``dentry->d_parent->d_inode``. +Iterating means going through the entries in the directory's data block (of type ``struct minfs_dir_entry``) and locate, if it exists, the requested entry. + +.. tip:: + + From the structure of type ``struct minfs_inode_info`` corresponding to the directory, find out the data block index and read it (``sb_read``). + You will access the block contents using ``bh->b_data``. + The directory data block contains an array of at most ``MINFS_NUM_ENTRIES`` entries of type ``struct minfs_dir_entry``. + Use pointer arithmetics to get entries of type ``struct minfs_dir_entry`` from the data block (``bh->b_data``). + + Check the presence of the name (stored in the local variable ``name``) in the directory (if there is an entry in the data block whose name is a string equal to the given name). Use :c:func:`strcmp` to verify. + + Ignore dentries that have an ``ino`` field equal to ``0``. Those dentries are free slots in the directory dentry list. + + Store in the ``final_de`` variable the dentry found. + If you do not find any dentry, then the ``final_de`` variable will have the value ``NULL``, the value with which it was initialized. + +Comment the ``simple_lookup`` call in the ``minfs_lookup`` function to invoke the implementation of ``minfs_readdir``. + +Testing +""""""" + +For testing, we use the steps described in the previous exercise. +The long file listing (``ls -l``) of the contents of a directory (root directory) will display permissions and other file-specific information: + +.. code-block:: console + + # ls -l /mnt/minfs + +To test the functionality provided by the module, we can use the dedicated scripts: + +.. code-block:: console + + # ./test-minfs-0.sh + # ./test-minfs-1.sh + +If the implementation is correct, no error messages will be displayed when running the scripts above. + +.. note:: + + After mounting the file system using the command + + .. code-block:: console + + # mount -t minfs /dev/vdb /mnt/minfs + + we try to create a file using the command + + .. code-block:: console + + # touch /mnt/minfs/peanuts.txt + + We notice that we get an error because we did not implement the directory operations that allow us to create a file. + We will do this for the next exercise. + +3. Create operation +^^^^^^^^^^^^^^^^^^^ + +In order to allow the creation of a file in a directory, we must implement the ``create`` operation. +The ``create`` operation is a field in the ``minfs_dir_inode_operations`` structure (of type :c:type:`inode_operations`) and is implemented by the ``minfs_create`` function. We need to implement this function. +In fact, we will implement the ``minfs_new_inode`` (which creates and initializes an inode) and ``minfs_add_link`` which adds a link (or name or *dentry*) for the created inode. + +Follow directions marked with ``TODO 7`` which will guide you through the steps you need to take. + +.. tip:: + + Read the section :ref:`DirectoryInodes` + + Inspect the code in the ``minfs_create`` and the skeleton of functions ``minfs_new_inode`` and ``minfs_add_link``. + +Implement the function ``minfs_new_inode``. Inside this function you will create (using :c:func:`new_inode`) and initialize an inode. The initialization is done using the data from disk. + +.. tip:: + + Use the :c:func:`minix_new_inode` function as a model. + Find the first free inode in imap (``sbi->imap``). + Use bitwise operations (``find_first_zero_bit`` and ``set_bit``). + Read the :ref:`BitmapOperations` section. + + The buffer for the superblock (``sbi->sbh``) must be marked as dirty . + + You must initialize the usual fields as it is done for the ``myfs`` file system. + Initialize the ``i_mode`` field to ``0`` in the call to ``inode_init_owner``. It will be initialized in the caller later. + +Implement the ``minfs_add_link`` function. The function adds a new dentry (``struct minfs_dir_entry``) to the parent directory data block (``dentry->d_parent->d_inode``). + +.. tip:: + + Use the function ``minix_add_link`` function as a model. + +In ``minfs_add_link`` we want to find the first free place for the dentry. +For this, you will iterate over the directory data block and you will find the first free entry. A free dentry has the ``ino`` field equal to ``0``. + +.. tip:: + + In order to work with the directory, get the inode of type ``struct minfs_inode_info`` corresponding to the parent directory (the **dir** inode). + Do not use the variable ``inode`` to get ``struct minfs_inode_info``; that inode belongs to the file, not to the parent directory inside which you want to add the link/dentry. + To get the ``struct minfs_inode_info`` structure, use :c:func:`container_of`. + + The structure ``struct minfs_inode_info`` is useful for finding the directory data block (the one indicated by the ``dentry->d_parent->d_inode``, which is the ``dir`` variable). + From this structure, get the ``data_block`` field, representing index of the data block on the disk. + This block contains the entries in the directory. Use :c:func:`sb_bread` to read the block and then ``bh->b_data`` to refer to the data. + The block contains at most ``MINFS_NUM_ENTRIES`` entries of type ``struct minfs_dir_entry``. + + If all entries are occupied, return ``-ENOSPC``. + + Iterate over the entries in the data block using the variable ``de`` and extract the first free entry (for which the ``ino`` field is ``0``). + + When you have found a free place, fill in the corresponding entry: + + * the ``inode->i_ino`` field in ``de->ino`` + * the ``dentry->d_name.name`` field in ``de->name`` + + Then mark the buffer dirty. + + +Testing +""""""" + +For testing, we use the steps described in the previous exercise. +Now we can create files within the file system: + +.. code-block:: console + + # touch /mnt/minfs/peanuts.txt + +To test the functionality provided by the module, we can use the dedicated script: + +.. code-block:: console + + # ./test-minfs-2.sh + +If the deployment is valid, no error messages will be displayed following the above script run. + +.. note:: + + The current implementation of the ``minfs`` file system is not definitive. + To be complete, the implementations needs function to delete files, create and delete directories, rename entries, and modify the contents of a file. + diff --git a/refs/pull/405/merge/_sources/labs/infrastructure.rst.txt b/refs/pull/405/merge/_sources/labs/infrastructure.rst.txt new file mode 100644 index 00000000..b3b4873c --- /dev/null +++ b/refs/pull/405/merge/_sources/labs/infrastructure.rst.txt @@ -0,0 +1,82 @@ +Infrastructure +============== + +In order to facilitate learning each topic has a hands-on exercises +section which will contain in-depth, incremental clues on how to solve +one or multiple tasks. To focus on a particular issue most of the +tasks will be performed on existing skeleton drivers. Each skeleton +driver has clearly marked sections that needs to be filled in order to +complete the tasks. + +The skeleton drivers are generated from full source examples located +in tools/labs/templates. To solve tasks you start by generating the +skeleton drivers, running the **skels** target in *tools/labs*. To +keep the workspace clean it is recommended to generate the skeletons +for one lab only and clean the workspace before start working on a new +lab. Labs can be selected by using the **LABS** variable: + +.. code-block:: shell + + tools/labs $ make clean + tools/labs $ LABS=kernel_modules make skels + + tools/labs $ ls skels/kernel_modules/ + 1-2-test-mod 3-error-mod 4-multi-mod 5-oops-mod 6-cmd-mod \ + 7-list-proc 8-kprobes 9-kdb + +You can also use the same variable to generate skeletons for specific +tasks: + +.. code-block:: shell + + tools/labs $ LABS="kernel_modules/6-cmd-mod kernel_modules/8-kprobes" make skels + + tools/labs$ ls skels/kernel_modules + 6-cmd-mod 8-kprobes + + +For each task you may have multiple steps to perform, usually +incremental. These steps are marked in the source code as well as in +the lab exercises with the keyword *TODO*. If we have multiple steps +to perform they will be prefixed by a number, like *TODO1*, *TODO2*, +etc. If no number is used it is assumed to be the one and only +step. If you want to resume a task from a certain step, you can using +the **TODO** variable. The following example will generate the +skeleton with the first *TODO* step resolved: + +.. code-block:: shell + + tools/labs $ TODO=2 LABS="kernel_modules/8-kprobes" skels + +Once the skelton drivers are generated you can build them with the +**build** make target: + +.. code-block:: shell + + tools/labs $ make build + echo "# autogenerated, do not edit " > skels/Kbuild + for i in ./kernel_modules/8-kprobes; do echo "obj-m += $i/" >> skels/Kbuild; done + make -C /home/tavi/src/linux M=/home/tavi/src/linux/tools/labs/skels ARCH=x86 modules + make[1]: Entering directory '/home/tavi/src/linux' + CC [M] /home/tavi/src/linux/tools/labs/skels/./kernel_modules/8-kprobes/kprobes.o + Building modules, stage 2. + MODPOST 1 modules + CC /home/tavi/src/linux/tools/labs/skels/./kernel_modules/8-kprobes/kprobes.mod.o + LD [M] /home/tavi/src/linux/tools/labs/skels/./kernel_modules/8-kprobes/kprobes.ko + make[1]: Leaving directory '/home/tavi/src/linux' + + +To copy the drivers to the VM you can use either use ssh or update the +VM image directly using the **copy** target: + +.. code-block:: shell + + tools/labs $ make copy + ... + 'skels/kernel_modules/8-kprobes/kprobes.ko' -> '/tmp/tmp.4UMKcISmQM/home/root/skels/kernel_modules/8-kprobes/kprobes.ko' + +.. attention:: The **copy** target will fail if the VM is + running. This is intentional so that we avoid corrupting the + filesystem. + + diff --git a/refs/pull/405/merge/_sources/labs/interrupts.rst.txt b/refs/pull/405/merge/_sources/labs/interrupts.rst.txt new file mode 100644 index 00000000..f5772846 --- /dev/null +++ b/refs/pull/405/merge/_sources/labs/interrupts.rst.txt @@ -0,0 +1,1120 @@ +========================== +I/O access and Interrupts +========================== + +Lab objectives +============== + +* communication with peripheral devices +* implement interrupt handlers +* synchronizing interrupts with process context + +Keywords: IRQ, I/O port, I/O address, base address, UART, request_region, release_region, inb, outb + +Background information +====================== + +A peripheral device is controlled by writing and reading its +registers. Often, a device has multiple registers that can be accessed +at consecutive addresses either in the memory address space or in the +I/O address space. Each device connected to the I/O bus has a set of +I/O addresses, called I/O ports. I/O ports can be mapped to physical +memory addresses so that the processor can communicate with the device +through instructions that work directly with the memory. For +simplicity, we will directly use I/O ports (without mapping to physical +memory addresses) to communicate with physical devices. + +The I/O ports of each device are structured into a set of specialized +registers to provide a uniform programming interface. Thus, most +devices will have the following types of registers: + +* **Control** registers that receive device commands +* **Status** registers, which contain information about the device's + internal status +* **Input** registers from which data is taken from the device +* **Output** registers in which the data is written to transmit it to the + device + +Physical ports are differentiated by the number of bits: they can be +8, 16 or 32-bit ports. + +For example, the parallel port has 8 8-bit I/O ports starting at base +address 0x378. The data log is found at base address (0x378), status +register at base + 1 (0x379), and control at base address + 2 +(0x37a). The data log is both an entry and exit log. + +Although there are devices that can be fully controlled using I/O +ports or special memory areas, there are situations where this is +insufficient. The main problem that needs to be addressed is that +certain events occur at undefined moments in time and it is +inefficient for the processor (CPU) to interrogate the status of the +device repeatedly (polling). The way to solve this problem is using an +Interrupt ReQuest (IRQ) which is a hardware notification by which the +processor is announced that a particular external event happened. + +For IRQs to be useful device drivers must implement handlers, i.e. a +particular sequence of code that handles the interrupt. Because in +many situations the number of interrupts available is limited, a +device driver must behave in an orderly fashion with interruptions: +interrupts must be requested before being used and released when they +are no longer needed. In addition, in some situations, device drivers +must share an interrupt or synchronize with interrupts. All of these will be +discussed further. + +When we need to access shared resources between an interrupt +routine (A) and code running in process context or in bottom-half +context (B), we must use a special synchronization technique. In (A) +we need to use a spinlock primitive, and in (B) we must disable +interrupts AND use a spinlock primitive. Disabling interrupts is not +enough because the interrupt routine can run on a processor other than +the one running (B). + +Using only a spinlock can lead to a deadlock. The classic example of +deadlock in this case is: + +1. We run a process on the X processor, and we acquire the lock +2. Before releasing the lock, an interrupt is generated on the X processor +3. The interrupt handling routine will try to acquire the lock and it + will go into an infinite loop + + +Accessing the hardware +====================== + +In Linux, the I/O ports access is implemented on all architectures and +there are several APIs that can be used. + +Request access to I/O ports +--------------------------- + +Before accessing I/O ports we first must request access to them, to +make sure there is only one user. In order to do so, one must use the +:c:func:`request_region` function: + +.. code-block:: c + + #include <linux/ioport.h> + + struct resource *request_region(unsigned long first, unsigned long n, + const char *name); + +To release a reserved region one must use the :c:func:`release_region` function: + +.. code-block:: c + + void release_region(unsigned long start, unsigned long n); + + +For example, the serial port COM1 has the base address 0x3F8 and it +has 8 ports and this is a code snippet of how to request access to +these ports: + +.. code-block:: c + + #include <linux/ioport.h> + + #define MY_BASEPORT 0x3F8 + #define MY_NR_PORTS 8 + + if (!request_region(MY_BASEPORT, MY_NR_PORTS, "com1")) { + /* handle error */ + return -ENODEV; + } + +To release the ports one would use something like: + +.. code-block:: c + + release_region(MY_BASEPORT, MY_NR_PORTS); + +Most of the time, port requests are done at the driver initialization +or probe time and the port releasing is done at the removal of the +device or module. + +All of the port requests can be seen from userspace via the +:file:`/proc/ioports` file: + +.. code-block:: shell + + $ cat /proc/ioports + 0000-001f : dma1 + 0020-0021 : pic1 + 0040-005f : timer + 0060-006f : keyboard + 0070-0077 : rtc + 0080-008f : dma page reg + 00a0-00a1 : pic2 + 00c0-00df : dma2 + 00f0-00ff : fpu + 0170-0177 : ide1 + 01f0-01f7 : ide0 + 0376-0376 : ide1 + 0378-037a : parport0 + 037b-037f : parport0 + 03c0-03df : vga+ + 03f6-03f6 : ide0 + 03f8-03ff : serial + ... + + +Accessing I/O ports +------------------- + +After a driver has obtained the desired I/O port range, one can +perform read or write operations on these ports. Since physical ports +are differentiated by the number of bits (8, 16, or 32 bits), there +are different port access functions depending on their size. The +following port access functions are defined in asm/io.h: + + +* *unsigned inb(int port)*, reads one byte (8 bits) from port +* *void outb(unsigned char byte, int port)*, writes one byte (8 bits) to port +* *unsigned inw(int port)*, reads two bytes (16-bit) ports +* *void outw(unsigned short word, int port)*, writes two bytes (16-bits) to port +* *unsigned inl (int port)*, reads four bytes (32-bits) from port +* *void outl(unsigned long word, int port)*, writes four bytes (32-bits) to port + +The port argument specifies the address of the port where the reads or +writes are done, and its type is platform dependent (may be unsigned +long or unsigned short). + +Some devices may have problems when the processor is trying to +transfer data too fast to and from the device. To avoid this issue we +may need to insert a delay after an I/O operation and there are functions +you can use that introduce this delay. Their names are similar to +those described above, with the exception that it ends in _p: inb_p, +outb_p, etc. + +For example, the following sequence writes a byte on COM1 serial port +and then reads it: + +.. code-block:: c + + #include <asm/io.h> + #define MY_BASEPORT 0x3F8 + + unsigned char value = 0xFF; + outb(value, MY_BASEPORT); + value = inb(MY_BASEPORT); + +5. Accessing I/O ports from userspace +------------------------------------- + +Although the functions described above are defined for device drivers, +they can also be used in user space by including the <sys/io.h> +header. In order to be used, ioperm or iopl must first be called to +get permission to perform port operations. The ioperm function obtains +permission for individual ports, while iopl for the entire I/O address +space. To use these features, the user must be root. + +The following sequence used in user space gets permission for the +first 3 ports of the serial port, and then releases them: + +.. code-block:: c + + #include <sys/io.h> + #define MY_BASEPORT 0x3F8 + + if (ioperm(MY_BASEPORT, 3, 1)) { + /* handle error */ + } + + if (ioperm(MY_BASEPORT, 3, 0)) { + /* handle error */ + } + +The third parameter of the ioperm function is used to request or +release port permission: 1 to get permission and 0 to release. + +Interrupt handling +================== + +Requesting an interrupt +----------------------- + +As with other resources, a driver must gain access to an interrupt +line before it can use it and release it at the end of the execution. + +In Linux, the request to obtain and release an interrupt is done using +the :c:func:`requests_irq` and :c:func:`free_irq` functions: + +.. code-block:: c + + #include <linux/interrupt.h> + + typedef irqreturn_t (*irq_handler_t)(int, void *); + + int request_irq(unsigned int irq_no, irq_handler_t handler, + unsigned long flags, const char *dev_name, void *dev_id); + + void free_irq(unsigned int irq_no, void *dev_id); + +Note that to get an interrupt, the developer calls +:c:func:`request_irq`. When calling this function you must specify the +interrupt number (*irq_no*), a handler that will be called when the +interrupt is generated (*handler*), flags that will instruct the +kernel about the desired behaviour (*flags*), the name of the device +using this interrupt (*dev_name*), and a pointer that can be +configured by the user at any value, and that has no global +significance (*dev_id*). Most of the time, *dev_id* will be +pointer to the device driver's private data. When the interrupt is +released, using the :c:func:`free_irq` function, the developer must +send the same pointer value (*dev_id*) along with the same interrupt +number (*irq_no*). The device name (*dev_name*) is used to display +statistics in */proc/interrupts*. + +The value that :c:func:`request_irq` returns is 0 if the entry was +successful or a negative error code indicating the reason for the +failure. A typical value is *-EBUSY* which means that the interrupt +was already requested by another device driver. + +The *handler* function is executed in interrupt context which means +that we can't call blocking APIs such as :c:func:`mutex_lock` or +:c:func:`msleep`. We must also avoid doing a lot of work in the +interrupt handler and instead use deferred work if needed. The actions +performed in the interrupt handler include reading the device +registers to get the status of the device and acknowledge the +interrupt, operations that most of the time can be performed with +non-blocking calls. + +There are situations where although a device uses interrupts we can't +read the device's registers in a non-blocking mode (for example a +sensor connected to an I2C or SPI bus whose driver does not guarantee +that bus read / write operations are non-blocking ). In this +situation, in the interruption, we must plan a work-in-process action +(work queue, kernel thread) to access the device's registers. Because +such a situation is relatively common, the kernel provides the +:c:func:`request_threaded_irq` function to write interrupt handling +routines running in two phases: a process-phase and an interrupt +context phase: + +.. code-block:: c + + #include <linux/interrupt.h> + + int request_threaded_irq(unsigned int irq, irq_handler_t handler, + irq_handler_t thread_fn, + unsigned long flags, const char *name, void *dev); + +*handler* is the function running in interrupt context, and will +implement critical operations while the thread_fn function runs in +process context and implements the rest of the operations. + +The flags that can be transmitted when an interruption is made are: + +* *IRQF_SHARED* announces the kernel that the interrupt can be + shared with other devices. If this flag is not set, then if there is + already a handler associated with the requested interrupt, the + request for interrupt will fail. A shared interrupt is handled in a + special way by the kernel: all the associated interrupt handlers + will be executed until the device that generated the interrupt will + be identified. But how can a device driver know if the interrupt + handling routine was activated by an interrupt generated by the + device it manages? Virtually all devices that offer interrupt + support have a status register that can be interrogated in the + handling routine to see if the interrupt was or was not generated by + the device (for example, in the case of the 8250 serial port, this + status register is IIR - Interrupt Information Register). When + requesting a shared interrupt, the dev_id argument must be unique + and it must not be NULL. Usually it is set to module's private + data. + +* *IRQF_ONESHOT* interrupt will be reactivated after running the process + context routine; Without this flag, the interrupt will be + reactivated after running the handler routine in the context of + the interrupt + + +Requesting the interrupt can be done either at the initialization of +the driver (:c:func:`init_module`), when the device is probed, or when +the device is used (e.g. during *open*). + +The following example performs the interrupt request for the COM1 +serial port: + +.. code-block:: c + + #include <linux/interrupt.h> + + #define MY_BASEPORT 0x3F8 + #define MY_IRQ 4 + + static my_init(void) + { + [...] + struct my_device_data *my_data; + int err; + + err = request_irq(MY_IRQ, my_handler, IRQF_SHARED, + "com1", my_data); + if (err < 0) { + /* handle error*/ + return err; + } + [...] + } + +As you can see, the IRQ for serial port COM1 is 4, which is used in +shared mode (IRQF_SHARED). + +.. attention:: When requesting a shared interrupt (IRQF_SHARED) the + *dev_id* argument can not be NULL. + +To release the interrupt associated with the serial port, the +following operations will be executed: + +.. code-block:: c + + free_irq (MY_IRQ, my_data); + + +During the initialization function (:c:func:`init_module`), or in the +function that opens the device, interrupts must be activated for the +device. This operation is dependent on the device, but most often +involves setting a bit from the control register. + + +As an example, for the 8250 serial port, the following operations must +be performed to enable interrupts: + +.. code-block:: c + + #include <asm/io.h> + #define MY_BASEPORT 0x3F8 + + outb(0x08, MY_BASEPORT+4); + outb(0x01, MY_BASEPORT+1); + + +In the above example, two operations are performed: + +1. All interruptions are activated by setting bit 3 (Aux Output 2) in + the MCR register - Modem Control Register +2. The RDAI (Transmit Holding Register Empty Interrupt) is activated + by setting the appropriate bit in the IER - Interrupt Enable + Register. + + +Implementing an interrupt handler +--------------------------------- + +Lets take a look at the signature of the interrupt handler function: + +.. code-block:: c + + irqreturn_t (*handler)(int irq_no, void *dev_id); + +The function receives as parameters the number of the interrupt +(*irq_no*) and the pointer sent to :c:func:`request_irq` when the +interrupt was requested. The interrupt handling routine must return a +value with a type of :c:type:`typedef irqreturn_t`. For the current kernel +version, there are three valid values: *IRQ_NONE*, *IRQ_HANDLED*, +and *IRQ_WAKE_THREAD*. The device driver must return *IRQ_NONE* if +it notices that the interrupt has not been generated by the device it +is in charge. Otherwise, the device driver must return *IRQ_HANDLED* +if the interrupt can be handled directly from the interrupt context or +*IRQ_WAKE_THREAD* to schedule the running of the process context +processing function. + +The skeleton for an interrupt handler is: + +.. code-block:: c + + irqreturn_t my_handler(int irq_no, void *dev_id) + { + struct my_device_data *my_data = (struct my_device_data *) dev_id; + + /* if interrupt is not for this device (shared interrupts) */ + /* return IRQ_NONE;*/ + + /* clear interrupt-pending bit */ + /* read from device or write to device*/ + + return IRQ_HANDLED; + } + + +Typically, the first thing executed in the interrupt handler is to +determine whether the interrupt was generated by the device that the +driver ordered. This usually reads information from the device's +registers to indicate whether the device has generated an +interrupt. The second thing is to reset the interrupt pending bit on +the physical device as most devices will no longer generate +interruptions until this bit has been reset (e.g. for the 8250 +serial port bit 0 in the IIR register must be cleared). + + +Locking +------- + +Because the interrupt handlers run in interrupt context the actions +that can be performed are limited: unable to access user space memory, +can't call blocking functions. Also, synchronization using spinlocks is +tricky and can lead to deadlocks if the spinlock used is already +acquired by a process that has been interrupted by the running +handler. + +However, there are cases where device drivers have to synchronize +using interrupts, such as when data is shared between the interrupt +handler and process context or bottom-half handlers. In these +situations it is necessary to both deactivate the interrupt and use +spinlocks. + +There are two ways to disable interrupts: disabling all interrupts, at +the processor level, or disabling a particular interrupt at the device +or interrupt controller level. Processor disabling is faster and is +therefore preferred. For this purpose, there are locking functions +that disable and enable interrupts acquiring and release a spinlock at +the same time: :c:func:`spin_lock_irqsave`, +:c:func:`spin_unlock_irqrestore`, :c:func:`spin_lock_irq`, and +:c:func:`spin_unlock_irq`: + +.. code-block:: c + + #include <linux/spinlock.h> + + void spin_lock_irqsave (spinlock_t * lock, unsigned long flags); + void spin_unlock_irqrestore (spinlock_t * lock, unsigned long flags); + + void spin_lock_irq (spinlock_t * lock); + void spin_unlock_irq (spinlock_t * lock); + +The :c:func:`spin_lock_irqsave` function disables interrupts for the +local processor before it obtains the spinlock; The previous state of +the interrupts is saved in *flags*. + +If you are absolutely sure that the interrupts on the current +processor have not already been disabled by someone else and you are +sure you can activate the interrupts when you release the spinlock, +you can use :c:func:`spin_lock_irq`. + +For read / write spinlocks there are similar functions available: + +* :c:func:`read_lock_irqsave` +* :c:func:`read_unlock_irqrestore` +* :c:func:`read_lock_irq` +* :c:func:`read_unlock_irq` +* :c:func:`write_lock_irqsave` +* :c:func:`write_unlock_irqrestore` +* :c:func:`write_lock_irq` +* :c:func:`write_unlock_irq` + +If we want to disable interrupts at the interrupt controller level +(not recommended because disabling a particular interrupt is slower, +we can not disable shared interrupts) we can do this with +:c:func:`disable_irq`, :c:func:`disable_irq_nosync`, and +:c:func:`enable_irq`. Using these functions will disable the interrupts on +all processors. Calls can be nested: if disable_irq is called twice, +it will require as many calls enable_irq to enable it. The difference +between disable_irq and disable_irq_nosync is that the first one will +wait for the executed handlers to finish. Because of this, +:c:func:`disable_irq_nosync` is generally faster, but may lead to +races with the interrupts handler, so when not sure use +:c:func:`disable_irq`. + +The following sequence disables and then enables the interrupt for +the COM1 serial port: + +.. code-block:: c + + #define MY_IRQ 4 + + disable_irq (MY_IRQ); + enable_irq (MY_IRQ); + +It is also possible to disable interrupts at the device level. This +approach is also slower than disabling interrupts at the processor +level, but it works with shared interrupts. The way to accomplish this +is device specific and it usually means we have to clear a bit from +one of the control registers. + +It is also possible to disable all interrupts for the current +processor independent of taking locks. Disabling all interruptions by +device drivers for synchronization purposes is inappropriate because +races are still possible if the interrupt is handled on another +CPU. For reference, the functions that disable / enable interrupts on +the local processor are :c:func:`local_irq_disable` and +:c:func:`local_irq_enable`. + +In order to use a resource shared between process context and the +interrupt handling routine, the functions described above will be used +as follows: + +.. code-block:: c + + static spinlock_t lock; + + /* IRQ handling routine: interrupt context */ + irqreturn_t kbd_interrupt_handle(int irq_no, void * dev_id) + { + ... + spin_lock(&lock); + /* Critical region - access shared resource */ + spin_unlock (&lock); + ... + } + + /* Process context: Disable interrupts when locking */ + static void my_access(void) + { + unsigned long flags; + + spin_lock_irqsave(&lock, flags); + /* Critical region - access shared resource */ + spin_unlock_irqrestore(&lock, flags); + + ... + } + + void my_init (void) + { + ... + spin_lock_init (&lock); + ... + } + + +The *my_access function* above runs in process context. To +synchronize access to the shared data, we disable the interrupts and +use the spinlock *lock*, i.e. the :c:func:`spin_lock_irqsave` and +:c:func:`spin_unlock_irqrestore` functions. + +In the interrupt handling routine, we use the :c:func:`spin_lock` and +:c:func:`spin_unlock` functions to access the shared resource. + +.. note:: The *flags* argument for :c:func:`spin_lock_irqsave` and + :c:func:`spin_unlock_irqrestore` is a value and not a pointer but keep + in mind that :c:func:`spin_lock_irqsave` function changes the value of + the flag, since this is actually a macro. + +Interrupt statistics +-------------------- + +Information and statistics about system interrupts can be found in +*/proc/interrupts* or */proc/stat*. Only system interrupts with +associated interrupt handlers appear in */proc/interrupts*: + +.. code-block:: shell + + # cat /proc/interrupts + CPU0 + 0: 7514294 IO-APIC-edge timer + 1: 4528 IO-APIC-edge i8042 + 6: 2 IO-APIC-edge floppy + 8: 1 IO-APIC-edge rtc + 9: 0 IO-APIC-level acpi + 12: 2301 IO-APIC-edge i8042 + 15: 41 IO-APIC-edge ide1 + 16: 3230 IO-APIC-level ioc0 + 17: 1016 IO-APIC-level vmxnet ether + NMI: 0 + LOC: 7229438 + ERR: 0 + MIS: 0 + +The first column specifies the IRQ associated with the interrupt. The +following column shows the number of interrupts that were generated +for each processor in the system; The last two columns provide +information about the interrupt controller and the device name that +registered the handler for that interrupt. + +The */proc/state* file provides information about system activity, +including the number of interruptions generated since the last (re)boot +of the system: + +.. code-block:: shell + + # cat /proc/stat | grep in + intr 7765626 7754228 4620 0 0 0 0 2 0 1 0 0 0 2377 0 0 41 3259 1098 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +Each line in the */proc/state* file begins with a keyword that +specifies the meaning of the information on the line. For information +on interrupts, this keyword is intr. The first number on the line +represents the total number of interrupts, and the other numbers +represent the number of interrupts for each IRQ, starting at 0. The +counter includes the number of interrupts for all processors in the +system. + + +Further reading +=============== + +Serial Port +----------- + +* `Serial Port <http://en.wikipedia.org/wiki/Serial_port>`_ +* `Interfacing the Serial / RS232 Port <http://www.beyondlogic.org/serial/serial.htm>`_ + + +Parallel port +------------- + +* `Interfacing the Standard Parallel Port <http://www.beyondlogic.org/spp/parallel.htm>`_ +* `Parallel Port Central <http://www.lvr.com/parport.htm>`_ + +Keyboard controller +------------------- + +* `Intel 8042 <http://en.wikipedia.org/wiki/Intel_8042>`_ +* drivers/input/serio/i8042.c +* drivers/input/keyboard/atkbd.c + +Linux device drivers +-------------------- + +* `Linux Device Drivers, 3rd ed., Ch. 9 - Communicating with Hardware <http://lwn.net/images/pdf/LDD3/ch09.pdf>`_ +* `Linux Device Drivers, 3rd ed., Ch. 10 - Interrupt Handling <http://lwn.net/images/pdf/LDD3/ch10.pdf>`_ +* `Interrupt Handlers <http://tldp.org/LDP/lkmpg/2.6/html/x1256.html>`_ + + +Exercises +========= + +.. include:: ../labs/exercises-summary.hrst +.. |LAB_NAME| replace:: interrupts + +0. Intro +-------- + +Using |LXR|_, find the definitions of the following symbols in the Linux kernel: + +* :c:type:`struct resource` +* :c:func:`request_region` and :c:func:`__request_region` +* :c:func:`request_irq` and :c:func:`request_threaded_irq` +* :c:func:`inb` for the x86 architecture. + +Analyze the following Linux code: + +* Keyboard initialization function :c:func:`i8042_setup_kbd` +* The AT or PS/2 keyboard interrupt function :c:func:`atkbd_interrupt` + +Keyboard driver +------------------ + +The next exercise's objective is to create a driver that uses the +keyboard IRQ, inspect the incoming key codes and stores them in a +buffer. The buffer will be accessible from userspace via character +device driver. + +1. Request the I/O ports +------------------------ + +To start with, we aim to allocate memory in the I/O space for hardware +devices. We will see that we cannot allocate space for the keyboard +because the designated region is already allocated. Then we will allocate +I/O space for unused ports. + +The *kbd.c* file contains a skeleton for the keyboard driver. Browse +the source code and inspect :c:func:`kbd_init`. Notice that the I/O +ports we need are I8042_STATUS_REG and I8042_DATA_REG. + +Follow the sections maked with **TODO 1** in the skeleton. Request the I/O +ports in :c:func:`kbd_init` and make sure to check for errors and to properly +clean-up in case of errors. When requesting, set the reserving caller's ID +string (``name``) with ``MODULE_NAME`` macro. Also, add code to release the I/O +ports in :c:func:`kbd_exit`. + +.. note:: You can review the `Request access to I/O ports`_ section before + proceeding. + +Now build the module and copy it to the VM image: + +.. code-block:: shell + + tools/labs $ make build + tools/labs $ make copy + + +Now start the VM and insert the module: + +.. code-block:: shell + + root@qemux86:~# insmod skels/interrupts/kbd.ko + kbd: loading out-of-tree module taints kernel. + insmod: can't insert 'skels/interrupts/kbd.ko': Device or resource busy + +Notice that you get an error when trying to request the I/O +ports. This is because we already have a driver that has requested the +I/O ports. To validate check the :file:`/proc/ioports` file for the +``STATUS_REG`` and ``DATA_REG`` values: + +.. code-block:: shell + + root@qemux86:~# cat /proc/ioports | egrep "(0060|0064)" + 0060-0060 : keyboard + 0064-0064 : keyboard + + +Lets find out which driver register these ports and try to remove the +module associated with it. + +.. code-block:: shell + + $ find -name \*.c | xargs grep \"keyboard\" + + find -name \*.c | xargs grep \"keyboard\" | egrep '(0x60|0x64)' + ... + ./arch/x86/kernel/setup.c:{ .name = "keyboard", .start = 0x60, .end = 0x60, + ./arch/x86/kernel/setup.c:{ .name = "keyboard", .start = 0x64, .end = 0x64 + +It looks like the I/O ports are registered by the kernel during the +boot, and we won't be able to remove the associated module. Instead, +let's trick the kernel and register ports 0x61 and 0x65. + +Use the function :c:func:`request_region` (inside the :c:func:`kbd_init` +function) to allocate the ports and the function :c:func:`release_region` +(inside the :c:func:`kbd_exit` function) to release the allocated memory. + +This time we can load the module and */proc/ioports* shows that the +owner of these ports is our module: + +.. code-block:: shell + + root@qemux86:~# insmod skels/interrupts/kbd.ko + kbd: loading out-of-tree module taints kernel. + Driver kbd loaded + root@qemux86:~# cat /proc/ioports | grep kbd + 0061-0061 : kbd + 0065-0065 : kbd + +Let's remove the module and check that the I/O ports are released: + +.. code-block:: shell + + root@qemux86:~# rmmod kbd + Driver kbd unloaded + root@qemux86:~# cat /proc/ioports | grep kbd + root@qemux86:~# + +2. Interrupt handling routine +----------------------------- + +For this task we will implement and register an interrupt handler for +the keyboard interrupt. You can review the `Requesting an interrupt`_ +section before proceeding. + +Follow the sections marked with **TODO 2** in the skeleton. + +First, define an empty interrupt handling routine named +:c:func:`kbd_interrupt_handler`. + +.. note:: Since we already have a driver that uses this interrupt we + should report the interrupt as not handled (i.e. return + :c:type:`IRQ_NONE`) so that the original driver still has a + chance to process it. + +Then register the interrupt handler routine using +:c:type:`request_irq`. The interrupt number is defined by the +`I8042_KBD_IRQ` macro. The interrupt handling routine must be +requested with :c:type:`IRQF_SHARED` to share the interrupt line with +the keyboard driver (i8042). + +.. note:: For shared interrupts, *dev_id* can not be NULL . Use + ``&devs[0]``, that is pointer to :c:type:`struct kbd`. This + structure contains all the information needed for device + management. To see the interrupt in */proc/interrupts*, do + not use NULL for *dev_name* . You can use the MODULE_NAME + macro. + + If the interrupt requesting fails make sure to properly + cleanup by jumping to the right label, in this case the one + the releases the I/O ports and continues with unregistering + the character device driver. + +Compile, copy and load module in the kernel. Check that the interrupt +line has been registered by looking at */proc/interrupts* . Determine +the IRQ number from the source code (see `I8042_KBD_IRQ`) and verify +that there are two drivers registered at this interrupt line (which +means that we have a shared interrupt line): the i8042 initial driver +and our driver. + +.. note:: More details about the format of the */proc/interrupts* can + be found in the `Interrupt statistics`_ section. + +Print a message inside the routine to make sure it is called. Compile +and reload the module into the kernel. Check that the interrupt handling +routine is called when you press the keyboard on the virtual machine, +using :command:`dmesg`. Also note that when you use the serial port no +keyboard interrupt is generated. + +.. attention:: To get access to the keyboard on the virtual machine + boot with "QEMU_DISPLAY=gtk make boot". + +3. Store ASCII keys to buffer +----------------------------- + +Next, we want to collect the keystrokes in a buffer whose content we +will then send to the user space. For this routine we will add the +following in the interrupt handling: + +* capture the pressed keys (only pressed, ignore released) +* identify the ASCII characters. +* copy the ASCII characters corresponding to the keystrokes and store + them in the buffer of the device + +Follow the sections marked **TODO 3** in the skeleton. + +Reading the data register +......................... + +First, fill in the :c:func:`i8042_read_data` function to read the +``I8042_DATA_REG`` of the keyboard controller. The function +just needs to return the value of the register. The value of the +registry is also called scancode, which is what is generated at each +keystroke. + +.. hint:: Read the ``I8042_DATA_REG`` register using :c:func:`inb` and + store the value in the local variable :c:type:`val`. + Revisit the `Accessing I/O ports`_ section. + +Call the :c:func:`i8042_read_data` in the +:c:func:`kbd_interrupt_handler` and print the value read. + +Print information about the keystrokes in the following format: + +.. code-block:: c + + pr_info("IRQ:% d, scancode = 0x%x (%u,%c)\n", + irq_no, scancode, scancode, scancode); + + +Where scancode is the value of the read register using the +:c:func:`i8042_read_data` function. + +Notice that the scancode (reading of the read register) is not an ASCII +character of the pressed key. We'll have to understand the scancode. + +Interpreting the scancode +......................... + +Note that the registry value is a scancode, not the ASCII value of the +character pressed. Also note that an interrupt is sent both when the +key is pressed and when the key is released. We only need to select +the code when the key is pressed and then and decode the ASCII +character. + +.. note:: To check scancode, we can use the showkey command (showkey + -s). + + In this form, the command will display the key scancodes for + 10 seconds after the last pressed key end then it will + stop. If you press and release a key you will get two + scancodes: one for the pressed key and one for the released + key. E.g: + + * If you press the ENTER key, you will get the 0x1c ( 0x1c ) + and 0x9c (for the released key) + * If you press the key a you will get the 0x1e (key pressed) + and 0x9e (for the key release) + * If you press b you will get 0x30 (key pressed) and 0xb0 + (for the release key) + * If you press the c key, you will get the 0x2e (key + pressed) 0xae and 0xae (for the released key) + * If you press the Shift key you will get the 0x2a (key + pressed) 0xaa and 0xaa (for the released key) + * If you press the Ctrl key you will get the 0x1d (key + pressed) and 0x9d (for the release key) + + As also indicated in this `article + <http://www.linuxjournal.com/article/1080>`_, a key + release scancode is 128 (0x80) higher then a key press + scancode. This is how we can distinguish between a press + key scancode and a release scancode. + + A scancode is translated into a keycode that matches a + key. A pressed scanned keycode and a released scancode + have the same keycode. For the keys shown above we have + the following table: + + .. flat-table:: + + * - Key + - Key Press Scancode + - Key Release Scancode + - Keycode + + * - ENTER + - 0x1c + - 0x9c + - 0x1c (28) + + * - a + - 0x1e + - 0x9e + - 0x1e (30) + + * - b + - 0x30 + - 0xb0 + - 0x30 (48) + + * - c + - 0x2e + - 0xae + - 0x2e (46) + + * - Shift + - 0x2a + - 0xaa + - 0x2a (42) + + * - Ctrl + - 0x1d + - 0x9d + - 0x1d (29) + + The press / release key is performed in the is_key_press() + function and obtaining the ASCII character of a scancode + takes place in the get_ascii() function. + +In the interrupt handler check the scancode to see if the key is +pressed or released then determine the corresponding ASCII +character. + +.. hint:: To check for press / release, use :c:func:`is_key_press`. + Use :c:func:`get_ascii` function to get the corresponding + ASCII code. Both functions expect the scancode. + + +.. hint:: To display the received information use the following + format. + + .. code-block:: c + + pr_info("IRQ %d: scancode=0x%x (%u) pressed=%d ch=%c\n", + irq_no, scancode, scancode, pressed, ch); + + Where scancode is the value of the data register, and ch is + the value returned by the get_ascii() function. + +Store characters to the buffer +............................... + +We want to collect the pressed characters (not the other keys) into +a circular buffer that can be consumed from user space. + +Update the interrupt handler to add a pressed ASCII character to the +end of the device buffer. If the buffer is full, the character will be +discarded. + +.. hint:: The device buffer is the field :c:type:`buf` in the device's + :c:type:`struct kbd`. To get the device data from the interrupt handler + use the following construct: + + .. code-block:: c + + struct kbd *data = (struct kbd *) dev_id; + + The buffer's dimension is located in :c:type:`struct kbd`'s field, + :c:type:`count`. The :c:type:`put_idx` and :c:type:`get_idx` fields + specify the next writing and reading index. Take a look at the + :c:func:`put_char` function's implementation to observe how the data is + added to the circular buffer. + +.. attention:: Synchronize the access to the buffer and the helper + indexes with a spinlock. + Define the spinlock in the device struct :c:type:`struct kbd` + and initialize it in :c:func:`kbd_init`. + + Use the :c:func:`spin_lock` and :c:func:`spin_unlock` functions + to protect the buffer in the interrupt handler. + + Revisit the `Locking`_ section. + +4. Reading the buffer +---------------------- + +In order to have access to the keylogger's data, we have to send it to +the user space. We will do this using the */dev/kbd* character device. When +reading from this device, we will get the data from the buffer in the kernel +space, where we collected the keys pressed. + +For this step +follow the sections marked with **TODO 4** in the :c:func:`kbd_read` function. + +Implement :c:func:`get_char` in a similar way to :c:func:`put_char`. Be careful +when implementing the circular buffer. + +In the :c:func:`kbd_read` function copy the data from the buffer to the +userspace buffer. + +.. hint:: Use :c:func:`get_char` to read a character from the buffer + and :c:func:`put_user` to store it to the user buffer. + +.. attention:: In the read function, use :c:func:`spin_lock_irqsave` and + :c:func:`spin_unlock_irqrestore` for locking. + + Revisit the `Locking`_ section. + +.. attention:: We cannot use :c:func:`put_user` or :c:func:`copy_to_user` + while holding the lock, as userpace access is not permitted from + atomic contexts. + + For more info, read the :ref:`Access to the address space of the + process section <_access_to_process_address_space>` in the + previous lab. + +For testing, you will need to create the */dev/kbd* character device +driver using the mknod before reading from it. The device master and +minor are defined as ``KBD_MAJOR`` and ``KBD_MINOR``: + +.. code-block:: c + + mknod /dev/kbd c 42 0 + +Build, copy and boot the virtual machine and load the module. Test it +using the command: + +.. code-block:: c + + cat /dev/kbd + + +5. Reset the buffer +------------------- + +Reset the buffer if the device is written to. For this step follow the +sections marked with **TODO 5** in the skeleton. + +Implement :c:func:`reset_buffer` and add the write operation to *kbd_fops*. + +.. attention:: In the write function Use :c:func:`spin_lock_irqsave` and + :c:func:`spin_unlock_irqrestore` for locking when resetting the + buffer. + + Revisit the `Locking`_ section. + +For testing, you will need to create the */dev/kbd* character device +driver using the mknod before reading from it. The device master and +minor are defined as ``KBD_MAJOR`` and ``KBD_MINOR``: + +.. code-block:: c + + mknod /dev/kbd c 42 0 + +Build, copy and boot the virtual machine and load the module. +Test it using the command: + +.. code-block:: c + + cat /dev/kbd + +Press some keys, then run the command :command:`echo "clear" > /dev/kbd`. +Check the buffer's content again. It should be reset. + +Extra Exercises +=============== + +1. kfifo +--------- + +Implement a keylogger using the +`kfifo API <https://elixir.bootlin.com/linux/v4.15/source/include/linux/kfifo.h>`_. + +.. hint:: Follow the `API call examples from the kernel code <https://elixir.bootlin.com/linux/v4.15/source/samples/kfifo>`_. + For example, the file `bytestream-examples.c <https://elixir.bootlin.com/linux/v4.15/source/samples/kfifo/bytestream-example.c>`_. diff --git a/refs/pull/405/merge/_sources/labs/introduction.rst.txt b/refs/pull/405/merge/_sources/labs/introduction.rst.txt new file mode 100644 index 00000000..98e3a630 --- /dev/null +++ b/refs/pull/405/merge/_sources/labs/introduction.rst.txt @@ -0,0 +1,887 @@ +============ +Introduction +============ + +Lab objectives +============== + +* presenting the rules and objectives of the Operating Systems 2 lab +* introducing the lab documentation +* introducing the Linux kernel and related resources + +Keywords +======== + +* kernel, kernel programming +* Linux, vanilla, http://www.kernel.org +* cscope, LXR +* gdb, /proc/kcore, addr2line, dump\_stack + +.. + _[SECTION-ABOUT-BEGIN] + +About this laboratory +===================== + +The Operating Systems 2 lab is a kernel programming and driver development lab. +The objectives of the laboratory are: + +* deepening the notions presented in the course +* presentation of kernel programming interfaces (kernel API) +* gaining documenting, development and debugging skills on a freestanding + environment +* acquiring knowledge and skills for drivers development + +A laboratory will present a set of concepts, applications and commands +specific to a given problem. The lab will start with a presentation +(each lab will have a set of slides) (15 minutes) and the remaining +time will be allocated to the lab exercises (80 minutes). + +For best laboratory performance, we recommend that you read the related slides. +To fully understand a laboratory, we recommend going through the lab support. For +in-depth study, use the supporting documentation. + +.. + _[SECTION-ABOUT-END] + +.. + _[SECTION-REFERENCES-BEGIN] + +References +========== + +- Linux + + - `Linux Kernel Development, 3rd + Edition <http://www.amazon.com/Linux-Kernel-Development-Robert-Love/dp/0672329468/>`__ + - `Linux Device Drivers, 3rd + Edition <http://free-electrons.com/doc/books/ldd3.pdf>`__ + - `Essential Linux Device + Drivers <http://www.amazon.com/Essential-Device-Drivers-Sreekrishnan-Venkateswaran/dp/0132396556>`__ + +- General + + - `mailing list <http://cursuri.cs.pub.ro/cgi-bin/mailman/listinfo/pso>`__ + (`searching the mailing list <http://blog.gmane.org/gmane.education.region.romania.operating-systems-design>`__) + +.. + _[SECTION-REFERENCES-END] + +.. + _[SECTION-CODE-NAVIGATION-BEGIN] + +Source code navigation +====================== + +.. _cscope_intro: + +cscope +------ + +`Cscope <http://cscope.sourceforge.net/>`__ is a tool for +efficient navigation of C sources. To use it, a cscope database must +be generated from the existing sources. In a Linux tree, the command +:command:`make ARCH=x86 cscope` is sufficient. Specification of the +architecture through the ARCH variable is optional but recommended; +otherwise, some architecture dependent functions will appear multiple +times in the database. + +You can build the cscope database with the command :command:`make +ARCH=x86 COMPILED_SOURCE=1 cscope`. This way, the cscope database will +only contain symbols that have already been used in the compile +process before, thus resulting in better performance when searching +for symbols. + +Cscope can also be used as stand-alone, but it is more useful when +combined with an editor. To use cscope with :command:`vim`, it is necessary to +install both packages and add the following lines to the file +:file:`.vimrc` (the machine in the lab already has the settings): + +.. code-block:: vim + + if has("cscope") + " Look for a 'cscope.out' file starting from the current directory, + " going up to the root directory. + let s:dirs = split(getcwd(), "/") + while s:dirs != [] + let s:path = "/" . join(s:dirs, "/") + if (filereadable(s:path . "/cscope.out")) + execute "cs add " . s:path . "/cscope.out " . s:path . " -v" + break + endif + let s:dirs = s:dirs[:-2] + endwhile + + set csto=0 " Use cscope first, then ctags + set cst " Only search cscope + set csverb " Make cs verbose + + nmap `<C-\>`s :cs find s `<C-R>`=expand("`<cword>`")`<CR>``<CR>` + nmap `<C-\>`g :cs find g `<C-R>`=expand("`<cword>`")`<CR>``<CR>` + nmap `<C-\>`c :cs find c `<C-R>`=expand("`<cword>`")`<CR>``<CR>` + nmap `<C-\>`t :cs find t `<C-R>`=expand("`<cword>`")`<CR>``<CR>` + nmap `<C-\>`e :cs find e `<C-R>`=expand("`<cword>`")`<CR>``<CR>` + nmap `<C-\>`f :cs find f `<C-R>`=expand("`<cfile>`")`<CR>``<CR>` + nmap `<C-\>`i :cs find i ^`<C-R>`=expand("`<cfile>`")`<CR>`$`<CR>` + nmap `<C-\>`d :cs find d `<C-R>`=expand("`<cword>`")`<CR>``<CR>` + nmap <F6> :cnext <CR> + nmap <F5> :cprev <CR> + + " Open a quickfix window for the following queries. + set cscopequickfix=s-,c-,d-,i-,t-,e-,g- + endif + +The script searches for a file called :file:`cscope.out` in the current directory, or +in parent directories. If :command:`vim` finds this file, you can use the shortcut :code:`Ctrl +]` +or :code:`Ctrl+\ g` (the combination control-\\ followed by g) to jump directly to +the definition of the word under the cursor (function, variable, structure, etc.). +Similarly, you can use :code:`Ctrl+\ s` to go where the word under the cursor is used. + +You can take a cscope-enabled :file:`.vimrc` file (also contains other goodies) from +https://github.com/ddvlad/cfg/blob/master/\_vimrc. +The following guidelines are based on this file, but also show basic :command:`vim` commands +that have the same effect. + +If there are more than one results (usually there are) you can move between them +using :code:`F6` and :code:`F5` (:code:`:ccnext` and :code:`:cprev`). +You can also open a new panel showing the results using :code:`:copen`. To close +the panel, use the :code:`:cclose` command. + +To return to the previous location, use :code:`Ctrl+o` (o, not zero). +The command can be used multiple times and works even if cscope changed the +file you are currently editing. + +To go to a symbol definition directly when :command:`vim` starts, use :code:`vim -t <symbol_name>` +(for example :code:`vim -t task_struct`). Otherwise, if you started :command:`vim` and want +to search for a symbol by name, use :code:`cs find g <symbol_name>` (for example +:code:`cs find g task_struct`). + +If you found more than one results and opened a panel showing all the matches +(using :code:`:copen`) and you want to find a symbol of type structure, +it is recommended to search in the results panel (using :code:`/` -- slash) +the character :code:`{` (opening brace). + +.. important:: + You can get a summary of all the :command:`cscope` commands using :command:`:cs help`. + + For more info, use the :command:`vim` built-in help command: :command:`:h cscope` or :command:`:h copen`. + +If you use :command:`emacs`, install the :code:`xcscope-el` package and +add the following lines in :file:`~/.emacs`. + +.. code-block:: vim + + (require ‘xcscope) + (cscope-setup) + +These commands will activate cscope for the C and C++ modes automatically. +:code:`C-s s` is the key bindings prefix and :code:`C-s s s` is used to +search for a symbol (if you call it when the cursor is over a word, +it will use that). For more details, check `https://github.com/dkogan/xcscope.el` + +clangd +------ + +`Clangd <https://clangd.llvm.org/>`__ is a language server that provides tools +for navigating C and C++ code. +`Language Server Protocol <https://microsoft.github.io/language-server-protocol/>`__ +facilitates features like go-to-definition, find-references, hover, completion, etc., +using semantic whole project analysis. + +Clangd requires a compilation database to understand the kernel source code. +It can be generated with: + +.. code-block:: bash + + make defconfig + make + scripts/clang-tools/gen_compile_commands.py + +LSP clients: + +- Vim/Neovim (`coc.nvim <https://github.com/neoclide/coc.nvim>`__, `nvim-lsp <https://github.com/neovim/nvim-lspconfig>`__, `vim-lsc <https://github.com/natebosch/vim-lsc>`__, `vim-lsp <https://github.com/prabirshrestha/vim-lsp>`__) +- Emacs (`lsp-mode <https://github.com/emacs-lsp/lsp-mode>`__) +- VSCode (`clangd extension <https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd>`__) + +Kscope +------ + +For a simpler interface, `Kscope <http://sourceforge.net/projects/kscope/>`__ +is a cscope frontend which uses QT. It is lightweight, very fast and very +easy to use. It allows searching using regular expressions, call graphs, etc. +Kscope is no longer mantained. + +There is also a `port <https///opendesktop.org/content/show.php/Kscope4?content=156987>`__ +of version 1.6 for Qt4 and KDE 4 which keeps the integration of the text +editor Kate and is easier to use than the last version on SourceForge. + +LXR Cross-Reference +------------------- + +LXR (LXR Cross-Reference) is a tool that allows indexing and +referencing the symbols in the source code of a program using +a web interface. The web interface shows links to +locations in files where a symbol is defined or used. Development website +for LXR is http://sourceforge.net/projects/lxr. Similar tools +are `OpenGrok <http://oracle.github.io/opengrok/>`__ and +`Gonzui <http://en.wikipedia.org/wiki/Gonzui>`__. + +Although LXR was originally intended for the Linux kernel sources, it is +also used in the sources of `Mozilla <http://lxr.mozilla.org/>`__, +`Apache HTTP Server <http://apache.wirebrain.de/lxr/>`__ and +`FreeBSD <http://lxr.linux.no/freebsd/source>`__. + +There are a number of sites that use LXR for cross-referencing the +the sources of the Linux kernel, the main site being `the original site of +development <http://lxr.linux.no/linux/>`__ which does not work anymore. You can +use `https://elixir.bootlin.com/ <https://elixir.bootlin.com/>`__. + +LXR allows searching for an identifier (symbol), after a free text +or after a file name. The main feature and, at the same +time, the main advantage provided is the ease of finding the declaration +of any global identifier. This way, it facilitates quick access to function +declarations, variables, macro definitions and the code can be easily +navigated. Also, the fact that it can detect what code areas are affected +when a variable or function is changed is a real advantage in the development +and debugging phase. + +SourceWeb +--------- + +`SourceWeb <http://rprichard.github.io/sourceweb/>`__ is a source code indexer +for C and C++. It uses the +`framework <http://clang.llvm.org/docs/IntroductionToTheClangAST.html>`__ +provided by the Clang compiler to index the code. + +The main difference between cscope and SourceWeb is the fact that SourceWeb +is, in a way, a compiler pass. SourceWeb doesn't index all the code, but +only the code that was efectively compiled by the compiler. This way, some +problems are eliminated, such as ambiguities about which variant of a function +defined in multiple places is used. This also means that the indexing takes +more time, because the compiled files must pass one more time through +the indexer to generate the references. + +Usage example: + +.. code-block:: bash + + make oldconfig + sw-btrace make -j4 + sw-btrace-to-compile-db + sw-clang-indexer --index-project + sourceweb index + +:file:`sw-btrace` is a script that adds the :file:`libsw-btrace.so` +library to :code:`LD_PRELOAD`. This way, the library is loaded by +every process started by :code:`make` (basically, the compiler), +registers the commands used to start the processes and generates +a filed called :file:`btrace.log`. This file is then used by +:code:`sw-btrace-to-compile-db` which converts it to a format defined +by clang: `JSON Compilation Database <http://clang.llvm.org/docs/JSONCompilationDatabase.html>`__. +This JSON Compilation Database resulted from the above steps is then +used by the indexer, which makes one more pass through the compiled +source files and generates the index used by the GUI. + +Word of advice: don't index the sources you are working with, but use +a copy, because SourceWeb doesn't have, at this moment, the capability +to regenerate the index for a single file and you will have to regenerate +the complete index. + +.. + _[SECTION-CODE-NAVIGATION-END] + +.. + _[SECTION-DEBUGGING-BEGIN] + +Kernel Debugging +================ + +Debugging a kernel is a much more difficult process than the debugging +of a program, because there is no support from the operating system. +This is why this process is usually done using two computers, connected +on serial interfaces. + +.. _gdb_intro: + +gdb (Linux) +----------- + +A simpler debug method on Linux, but with many disadvantages, +is local debugging, using `gdb <http://www.gnu.org/software/gdb/>`__, +the uncompressed kernel image (:file:`vmlinux`) and :file:`/proc/kcore` +(the real-time kernel image). This method is usually used to inspect +the kernel and detect certain inconsistencies while it runs. The +method is useful especially if the kernel was compiled using the +:code:`-g` option, which keeps debug information. Some well-known +debug techniques can't be used by this method, such as breakpoints +of data modification. + +.. note:: Because :file:`/proc` is a virtual filesystem, :file:`/proc/kcore` + does not physically exist on the disk. It is generated on-the-fly + by the kernel when a program tries to access :file:`proc/kcore`. + + It is used for debugging purposes. + + From :command:`man proc`, we have: + + :: + + /proc/kcore + This file represents the physical memory of the system and is stored in the ELF core file format. With this pseudo-file, and + an unstripped kernel (/usr/src/linux/vmlinux) binary, GDB can be used to examine the current state of any kernel data struc‐ + tures. + +The uncompressed kernel image offers information about the data structures +and symbols it contains. + +.. code-block:: bash + + student@eg106$ cd ~/src/linux + student@eg106$ file vmlinux + vmlinux: ELF 32-bit LSB executable, Intel 80386, ... + student@eg106$ nm vmlinux | grep sys_call_table + c02e535c R sys_call_table + student@eg106$ cat System.map | grep sys_call_table + c02e535c R sys_call_table + +The :command:`nm` utility is used to show the symbols in an object or +executable file. In our case, :file:`vmlinux` is an ELF file. Alternately, +we can use the file :file:`System.map` to view information about the +symbols in kernel. + +Then we use :command:`gdb` to inspect the symbols using the uncompressed +kernel image. A simple :command:`gdb` session is the following: + +.. code-block:: bash + + student@eg106$ cd ~/src/linux + stduent@eg106$ gdb --quiet vmlinux + Using host libthread_db library "/lib/tls/libthread_db.so.1". + (gdb) x/x 0xc02e535c + 0xc02e535c `<sys_call_table>`: 0xc011bc58 + (gdb) x/16 0xc02e535c + 0xc02e535c `<sys_call_table>`: 0xc011bc58 0xc011482a 0xc01013d3 0xc014363d + 0xc02e536c `<sys_call_table+16>`: 0xc014369f 0xc0142d4e 0xc0142de5 0xc011548b + 0xc02e537c `<sys_call_table+32>`: 0xc0142d7d 0xc01507a1 0xc015042c 0xc0101431 + 0xc02e538c `<sys_call_table+48>`: 0xc014249e 0xc0115c6c 0xc014fee7 0xc0142725 + (gdb) x/x sys_call_table + 0xc011bc58 `<sys_restart_syscall>`: 0xffe000ba + (gdb) x/x &sys_call_table + 0xc02e535c `<sys_call_table>`: 0xc011bc58 + (gdb) x/16 &sys_call_table + 0xc02e535c `<sys_call_table>`: 0xc011bc58 0xc011482a 0xc01013d3 0xc014363d + 0xc02e536c `<sys_call_table+16>`: 0xc014369f 0xc0142d4e 0xc0142de5 0xc011548b + 0xc02e537c `<sys_call_table+32>`: 0xc0142d7d 0xc01507a1 0xc015042c 0xc0101431 + 0xc02e538c `<sys_call_table+48>`: 0xc014249e 0xc0115c6c 0xc014fee7 0xc0142725 + (gdb) x/x sys_fork + 0xc01013d3 `<sys_fork>`: 0x3824548b + (gdb) disass sys_fork + Dump of assembler code for function sys_fork: + 0xc01013d3 `<sys_fork+0>`: mov 0x38(%esp),%edx + 0xc01013d7 `<sys_fork+4>`: mov $0x11,%eax + 0xc01013dc `<sys_fork+9>`: push $0x0 + 0xc01013de `<sys_fork+11>`: push $0x0 + 0xc01013e0 `<sys_fork+13>`: push $0x0 + 0xc01013e2 `<sys_fork+15>`: lea 0x10(%esp),%ecx + 0xc01013e6 `<sys_fork+19>`: call 0xc0111aab `<do_fork>` + 0xc01013eb `<sys_fork+24>`: add $0xc,%esp + 0xc01013ee `<sys_fork+27>`: ret + End of assembler dump. + +It can be noticed that the uncompressed kernel image was used as an argument +for :command:`gdb`. The image can be found in the root of the kernel sources +after compilation. + +A few commands used for debugging using :command:`gdb` are: + +- :command:`x` (examine) - Used to show the contents of the memory area + whose address is specified as an argument to the command (this address + can be the value of a physical address, a symbol or the address of a + symbol). It can take as arguments (preceded by :code:`/`): the format + to display the data in (:code:`x` for hexadecimal, :code:`d` for + decimal, etc.), how many memory units to display and the size of a + memory unit. + +- :command:`disassemble` - Used to disassemble a function. + +- :command:`p` (print) - Used to evaluate and show the value of an + expression. The format to show the data in can be specified as + an argument (:code:`/x` for hexadecimal, :code:`/d` for decimal, etc.). + +The analysis of the kernel image is a method of static analysis. If we +want to perform dynamic analysis (analyzing how the kernel runs, not +only its static image) we can use :file:`/proc/kcore`; this is a dynamic +image (in memory) of the kernel. + +.. code-block:: bash + + student@eg106$ gdb ~/src/linux/vmlinux /proc/kcore + Core was generated by `root=/dev/hda3 ro'. + #0 0x00000000 in ?? () + (gdb) p sys_call_table + $1 = -1072579496 + (gdb) p /x sys_call_table + $2 = 0xc011bc58 + (gdb) p /x &sys_call_table + $3 = 0xc02e535c + (gdb) x/16 &sys_call_table + 0xc02e535c `<sys_call_table>`: 0xc011bc58 0xc011482a 0xc01013d3 0xc014363d + 0xc02e536c `<sys_call_table+16>`: 0xc014369f 0xc0142d4e 0xc0142de5 0xc011548b + 0xc02e537c `<sys_call_table+32>`: 0xc0142d7d 0xc01507a1 0xc015042c 0xc0101431 + 0xc02e538c `<sys_call_table+48>`: 0xc014249e 0xc0115c6c 0xc014fee7 0xc0142725 + +Using the dynamic image of the kernel is useful for detecting `rootkits <http://en.wikipedia.org/wiki/Rootkit>`__. + +- `Linux Device Drivers 3rd Edition - Debuggers and Related Tools <http://linuxdriver.co.il/ldd3/linuxdrive3-CHP-4-SECT-6.html>`__ +- `Detecting Rootkits and Kernel-level Compromises in Linux <http://www.securityfocus.com/infocus/1811>`__ +- `User-Mode Linux <http://user-mode-linux.sf.net/>`__ + +Getting a stack trace +--------------------- + +Sometimes, you will want information about the trace the execution +reaches a certain point. You can determine this information using +:command:`cscope` or LXR, but some function are called from many +execution paths, which makes this method difficult. + +In these situations, it is useful to get a stack trace, which can be +simply done using the function :code:`dump_stack()`. + +.. + _[SECTION-DEBUGGING-END] + +.. + _[SECTION-DOCUMENTATION-BEGIN] + +Documentation +============= + +Kernel development is a difficult process, compared to user space +programming. The API is different and the complexity of the subsystems +in kernel requires additional preparation. The associated documentation +is heterogeneous, sometimes requiring the inspection of multiple sources +to have a more complete understanding of a certain aspect. + +The main advantages of the Linux kernel are the access to sources and +the open development system. Because of this, the Internet offers a +larger number of documentation for the kernel. + +A few links related to the Linux kernel are shown bellow: + +- `KernelNewbies <http://kernelnewbies.org>`__ +- `KernelNewbies - Kernel Hacking <http://kernelnewbies.org/KernelHacking>`__ +- `Kernel Analysis - HOWTO <http://www.tldp.org/HOWTO/KernelAnalysis-HOWTO.html>`__ +- `Linux Kernel Programming <http://web.archive.org/web/20090228191439/http://www.linuxhq.com/lkprogram.html>`__ +- `Linux kernel - Wikibooks <http://en.wikibooks.org/wiki/Linux_kernel>`__ + +The links are not comprehensive. Using `The Internet <http://www.google.com>`__ and +`kernel source code <http://lxr.free-electrons.com/>`__ is essential. + +.. + _[SECTION-DOCUMENTATION-END] + +Exercises +========= + +.. + _[SECTION-EXERCISES-REMARKS-BEGIN] + +Remarks +------- + +.. note:: + + - Usually, the steps used to develop a kernel module are the + following: + + - editing the module source code (on the physical machine); + - module compilation (on the physical machine); + - generation of the minimal image for the virtual machine; + this image contains the kernel, your module, busybox and + eventually test programs; + - starting the virtual machine using QEMU; + - running the tests in the virtual machine. + + - When using cscope, use :file:`~/src/linux`. + If there is no :file:`cscope.out` file, you can generate it using + the command :command:`make ARCH=x86 cscope`. + + - You can find more details about the virtual machine at + :ref:`vm_link`. + +.. important:: + Before solving an exercice, **carefully** read all its bullets. + +.. + _[SECTION-EXERCISES-REMARKS-END] + +.. + _[EXERCISE1-BEGIN] + +Booting the virtual machine +--------------------------- + +A summary of the virtual machine infrastructure: + +- :file:`~/src/linux` - Linux kernel sources, needed to + compile modules. The directory contains the file :file:`cscope.out`, + used for navigation in the source tree. + +- :file:`~/src/linux/tools/labs/qemu`- scripts and auxiliary + files used to generate and run the QEMU VM. + +To start the VM, run :command:`make boot` in the directory :file:`~/src/linux/tools/labs`: + +.. code-block:: shell + + student@eg106:~$ cd ~/src/linux/tools/labs + student@eg106:~/src/linux/tools/labs$ make boot + +By default, you will not get a prompt or any graphical interface, but you can connect to +a console exposed by the virtual machine using :command:`minicom` or :command:`screen`. + +.. code-block:: shell + + student@eg106:~/src/linux/tools/labs$ minicom -D serial.pts + + <press enter> + + qemux86 login: + Poky (Yocto Project Reference Distro) 2.3 qemux86 /dev/hvc0 + +Alternatively, you can start the virtual machine with graphical interface support, using +the :command:`QEMU_DISPLAY=gtk make boot`. + +.. note:: + To access the virtual machine, at the login prompt, enter the + username :code:`root`; there is no need to enter a password. + The virtual machine will start with the permissions of the + root account. + +.. + _[EXERCISE1-END] + +.. + _[EXERCISE2-BEGIN] + +Adding and using a virtual disk +------------------------------- + +.. note:: If you don't have the file :file:`mydisk.img`, you can download + it from the address http://elf.cs.pub.ro/so2/res/laboratoare/mydisk.img. + The file must be placed in :file:`tools/labs`. + +In the :file:`~/src/linux/tools/labs` directory, you have a new virtual +machine disk, in the file :file:`mydisk.img`. We want to add the disk +to the virtual machine and use it within the virtual machine. + +Edit :file:`qemu/Makefile` and add :code:`-drive file=mydisk.img,if=virtio,format=raw` +to the :code:`QEMU_OPTS` variable. + +.. note:: There are already two disks added to qemu (disk1.img and disk2.img). You will need + to add the new one after them. In this case, the new disk can be accessed as + :file:`/dev/vdd` (vda is the root partition, vdb is disk1 and vdc is disk2). + +.. hint:: You do not need to manually create the entry for the new disk in :file:`/dev` + because the virtual machine uses :command:`devtmpfs`. + +Run :code:`make` in :file:`tools/labs` to boot the virtual machine. +Create :file:`/test` directory and try to mount the new disk: + +.. code-block:: bash + + mkdir /test + mount /dev/vdd /test + +The reason why we can not mount the virtual disk is because we do not have support in the +kernel for the filesystem with which the :file:`mydisk.img` is formatted. You will need +to identify the filesystem for :file:`mydisk.img` and compile kernel support for that filesystem. + +Close the virtual machine (close the QEMU window, you do not need to use another command). +Use the :command:`file` command on the physical machine to find out with which filesystem +the :file:`mydisk.img` file is formatted. You will identify the :command:`btrfs` file system. + +You will need to enable :command:`btrfs` support in the kernel and recompile the kernel image. + +.. warning:: If you receive an error while executing the :command:`make menuconfig` + command, you probably do not have the :command:`libncurses5-dev` + package installed. Install it using the command: + + :: + + sudo apt-get install libncurses5-dev + +.. hint:: Enter the :file:`~/src/linux/` subdirectory. Run :command:`make menuconfig` + and go to the *File systems* section. Enable *Btrfs filesystem support*. + You will need to use the builtin option (not the module), i.e. :command:`<*>` must appear + next to the option (**not** :command:`<M>`). + + Save the configuration you have made. Use the default configuration file (:file:`config`). + + In the kernel source subdirectory (:file:`~/src/linux/`) recompile using the command: + + :: + + make + + To wait less, you can use the :command:`-j` option run multiple jobs in parallel. + Generally, it is recommended to use :command:`number of CPUs+1`: + + :: + + make -j5 + +After the kernel recompilation finishes, **restart** the QEMU virtual machine: +that is, launch the :command:`make` command in the subdirectory. You +do not need to copy anything, because the :file:`bzImage` file is a symlink to the kernel +image you just recompiled. + +Inside the QEMU virtual machine, repeat the :command:`mkdir` and :command:`mount` operations. +With support for the :command:`btrfs` filesystem, now :command:`mount` will finish successfully. + +.. note:: When doing your homework, there is no need to recompile the kernel + because you will only use kernel modules. However, it is important + to be familiar with configuring and recompiling a kernel. + + If you still plan to recompile the kernel, make a backup of the bzImage + file (follow the link in ~/src/linux for the full path). This will allow + you to return to the initial setup in order to have an environment + identical to the one used by vmchecker. + +.. + _[EXERCISE2-END] + +.. + _[EXERCISE3-BEGIN] + +GDB and QEMU +------------ + +We can investigate and troubleshoot the QEMU virtual machine in real time. + +.. note:: You can also use the :command:`GDB Dashboard` plugin for a user-friendly interface. + :command:`gdb` must be compiled with Python support. + + In order to install it, you can just run: + :: + + wget -P ~ git.io/.gdbinit + +To do this, we start the QEMU virtual machine first. Then, we can connect +with :command:`gdb` to **a running QEMU virtual machine** using the command + +:: + + make gdb + +We used the QEMU command with the :command:`-s` parameter, which means +listening to port :code:`1234` from :command:`gdb`. We can do debugging +using a **remote target** for :command:`gdb`. The existing :file:`Makefile` +takes care of the details. + +When you attach a debugger to a process, the process is suspended. +You can add breakpoints and inspect the current status of the process. + +Attach to the QEMU virtual machine (using the :command:`make gdb` command) +and place a breakpoint in the :code:`sys_access` function using the +following command in the :command:`gdb` console: + +:: + + break sys_access + +At this time, the virtual machine is suspended. To continue executing it (up to the possible call +of the :code:`sys_access` function), use the command: + +:: + + continue + +in the :command:`gdb` console. + +At this time, the virtual machine is active and has a usable console. +To make a :code:`sys_access` call, issue a :command:`ls` command. +Note that the virtual machine was again suspended by :command:`gdb` +and the corresponding :code:`sys_access` callback message appeared within the :command:`gdb` console. + +Trace code execution using :command:`step` instruction, :command:`continue` or :command:`next` +instruction. You probably do not understand everything that happens, so use commands +such as :command:`list` and :command:`backtrace` to trace the execution. + +.. hint:: At the :command:`gdb` prompt, you can press :command:`Enter` + (without anything else) to rerun the last command. + +.. + _[EXERCISE3-END] + +.. + _[EXERCISE4-BEGIN] + +4. GDB spelunking +----------------- + +Use :command:`gdb` to display the source code of the function that creates kernel threads +(:code:`kernel_thread`). + +.. note:: You can use GDB for static kernel analysis using, in the kernel source directory, + a command such as: + + :: + + gdb vmlinux + + Go over the `gdb (Linux) <#gdb-linux>`__ section of the lab. + +Use :command:`gdb` to find the address of the :code:`jiffies` variable in memory and its contents. +The :code:`jiffies` variable holds the number of ticks (clock beats) since the system started. + +.. hint:: To track the value of the jiffies variable, use dynamic analysis in :command:`gdb` + by running the command: + + :: + + make gdb + + as in the previous exercise. + + Go over the `gdb (Linux) <#gdb-linux>`__ section of the lab. + +.. hint:: The :code:`jiffies` is a 64-bit variable. + You can see that its address is the same as the :code:`jiffies_64` variable. + + To explore the contents of a 64-bit variable, use in the :command:`gdb` console the command: + + :: + + x/gx & jiffies + + If you wanted to display the contents of the 32-bit variable, + you would use in the :command:`gdb` console the command: + + :: + + x/wx & jiffies + +.. + _[EXERCISE4-END] + +.. + _[EXERCISE5-BEGIN] + + +5. Cscope spelunking +-------------------- + +Use LXR or cscope in the :file:`~/src/linux/` directory to discover +the location of certain structures or functions. + +Cscope index files are already generated. Use :command:`vim` and other related commands +to scroll through the source code. For example, use the command: + +:: + + vim + +for opening the :command:`vim` editor. Afterwards, inside the editor, use commands such as: + +:command:`:cs find g task\_struct`. + +Find the file in which the following data types are defined: + +- ``struct task_struct`` + +- ``struct semaphore`` + +- ``struct list_head`` + +- ``spinlock_t`` + +- ``struct file_system_type`` + +.. hint:: For a certain structure, only its name needs to be searched. + + For instance, in the case of :command:`struct task_struct`, + search for the :command:`task_struct` string. + +Usually, you will get more matches. To locate the one you are interested in, do the following: + +#. List all matches by using, in :command:`vim`, :command:`:copen` command. + +#. Look for the right match (where the structure is defined) by looking for an open character + (:command:`{`), a single character on the structure definition line. To search for the open + braid you use in :command:`vim` the construction :command:`/{`. + +#. On the respective line, press :command:`Enter` to get into the source code where the variable + is defined. + +#. Close the secondary window using the command: :command:`:cclose` command. + +Find the file in which the following global kernel variables are declared: + +- ``sys_call_table`` + +- ``file_systems`` + +- ``current`` + +- ``chrdevs`` + +.. hint:: To do this, use a :command:`vim` command with the syntax: + + :command:`:cs f g <symbol>` + + where :command:`<symbol>` is the name of the symbol being searched. + +Find the file in which the following functions are declared: + +- ``copy_from_user`` + +- ``vmalloc`` + +- ``schedule_timeout`` + +- ``add_timer`` + +.. hint:: To do this, use a :command:`vim` command with the syntax: + + :command:`:cs f g <symbol>` + + where :command:`<symbol>` is the name of the symbol being searched. + +Scroll through the following sequence of structures: + +- ``struct task_struct`` + +- ``struct mm_struct`` + +- ``struct vm_area_struct`` + +- ``struct vm_operations_struct`` + +That is, you access a structure and then you find fields with the data type of the +next structure, access the respective fields and so on. +Note in which files these structures are defined; this will be useful to the following labs. + + +.. hint:: In order to search for a symbol in :command:`vim` (with :command:`cscope` support) + when the cursor is placed on it, use the :command:`Ctrl+]` keyboard shortcut. + + To return to the previous match (the one before search/jump), use the + :command:`Ctrl+o` keyboard shortcut. + + To move forward with the search (to return to matches before :command:`Ctrl+o`), + use the :command:`Ctrl+i` keyboard shortcut. + +Following the above instructions, find and go through the function call sequence: + +- ``bio_alloc`` + +- ``bio_alloc_bioset`` + +- ``bvec_alloc`` + +- ``kmem_cache_alloc`` + +- ``slab_alloc`` + +.. note:: Read `cscope <#cscope>`__ or `LXR Cross-Reference <#lxr-cross-reference>`__ sections of the lab. diff --git a/refs/pull/405/merge/_sources/labs/kernel_api.rst.txt b/refs/pull/405/merge/_sources/labs/kernel_api.rst.txt new file mode 100644 index 00000000..f927e5cf --- /dev/null +++ b/refs/pull/405/merge/_sources/labs/kernel_api.rst.txt @@ -0,0 +1,857 @@ +========== +Kernel API +========== + +Lab objectives +============== + + * Familiarize yourself with the basic Linux kernel API + * Description of memory allocation mechanisms + * Description of locking mechanisms + +Overview +======== + +Inside the current lab we present a set of concepts and basic functions required +for starting Linux kernel programming. It is important to note that kernel +programming differs greatly from user space programming. The kernel is a +stand-alone entity that can not use libraries in user-space (not even libc). +As a result, the usual user-space functions (printf, malloc, free, open, read, +write, memcpy, strcpy, etc.) can no longer be used. In conclusion, kernel +programming is based on a totally new and independent API that is unrelated to +the user-space API, whether we refer to POSIX or ANSI C (standard C language +library functions). + +Accessing memory +================ + +An important difference in kernel programming is how to access and allocate +memory. Due to the fact that kernel programming is very close to the physical +machine, there are important rules for memory management. First, it works with +several types of memory: + + * Physical memory + * Virtual memory from the kernel address space + * Virtual memory from a process's address space + * Resident memory - we know for sure that the accessed pages are present in + physical memory + +Virtual memory in a process's address space can not be considered resident due +to the virtual memory mechanisms implemented by the operating system: pages may +be swapped or simply may not be present in physical memory as a result of the +demand paging mechanism. The memory in the kernel address space can be resident +or not. Both the data and code segments of a module and the kernel stack of a +process are resident. Dynamic memory may or may not be resident, depending on +how it is allocated. + +When working with resident memory, things are simple: memory can be accessed at +any time. But if working with non-resident memory, then it can only be accessed +from certain contexts. Non-resident memory can only be accessed from the +process context. Accessing non-resident memory from the context of an +interrupt has unpredictable results and, therefore, when the operating +system detects such access, it will take drastic measures: blocking or +resetting the system to prevent serious corruption. + +The virtual memory of a process can not be accessed directly from the kernel. +In general, it is totally discouraged to access the address space of a process, +but there are situations where a device driver needs to do it. The typical case +is where the device driver needs to access a buffer from the user-space. In +this case, the device driver must use special features and not directly access +the buffer. This is necessary to prevent access to invalid memory areas. + +Another difference from the user-space scheduling, relative to memory, is due to +the stack, a stack whose size is fixed and limited. A stack of 4K is used in +Linux, and a stack of 12K is used in Windows. For this reason, the +allocation of large structures on stack or the use of recursive calls should +be avoided. + +Contexts of execution +===================== + +In relation to kernel execution, we distinguish two contexts: process context +and interrupt context. We are in the process context when we run code as a +result of a system call or when we run in the context of a kernel thread. When +we run in a routine to handle an interrupt or a deferrable action, we run in +an interrupt context. + +Some of the kernel API calls can block the current process. Common examples are +using a semaphore or waiting for a condition. In this case, the process is +put into the ``WAITING`` state and another process is running. An interesting +situation occurs when a function that can lead to the current process to be +suspended, is called from an interrupt context. In this case, there is no +current process, and therefore the results are unpredictable. Whenever the +operating system detects this condition will generate an error condition that +will cause the operating system to shut down. + +Locking +======= + +One of the most important features of kernel programming is parallelism. Linux +supports SMP systems with multiple processors and kernel preemptivity. This +makes kernel programming more difficult because access to global variables must +be synchronized with either spinlock primitives or blocking primitives. Although +it is recommended to use blocking primitives, they can not be used in an +interrupt context, so the only locking solution in the context of an interrupt +is spinlocks. + +Spinlocks are used in order to achieve mutual exclusion. When it can not get +access to the critical region, it does not suspend the current process, but it +uses the busy-waiting mechanism (waiting in a :c:func:`while` loop for the lock +to be released). +The code that runs in the critical region protected by a spinlock is not allowed +to suspend the current process (it must adhere to the execution conditions in +the interrupt context). Moreover, the CPU will not be released except for +the case of an interrupt. Due to the mechanism used, it is important that a +spinlock is being held as little time as possible. + +Preemptivity +============ + +Linux uses preemptive kernels. The notion of preemptive multitasking should not +be confused with the notion of a preemptive kernel. The notion of preemptive +multitasking refers to the fact that the operating system forcefully interrupts +a process running in user space when its quantum (time slice) expires, in order +to run another process. +A kernel is preemptive if a process running in kernel mode (as a result of a +system call) can be interrupted so that another process is being run. + +Because of preemptivity, when we share resources between two portions of code +that can run from different process contexts, we need to protect ourselves with +synchronization primitives, even in the case of a single processor. + +Linux Kernel API +================ + +Convention indicating errors +---------------------------- + +For Linux kernel programming, the convention used for calling functions to +indicate success is the same as in UNIX programming: 0 for success, or a value +other than 0 for failure. +For failures, negative values are returned as shown in the example below: + +.. code-block:: c + + if (alloc_memory() != 0) + return -ENOMEM; + + if (user_parameter_valid() != 0) + return -EINVAL; + +The exhaustive list of errors and a summary explanation can be found in +:file:`include/uapi/asm-generic/errno-base.h` and in +:file:`include/uapi/asm-generic/ernno.h`. + +Strings of characters +--------------------- + +In Linux, the kernel programmer is provided with the usual routine functions: +:c:func:`strcpy`, :c:func:`strncpy`, :c:func:`strlcpy`, :c:func:`strcat`, +:c:func:`strncat`, :c:func:`strlcat`, :c:func:`strcmp`, :c:func:`strncmp`, +:c:func:`strnicmp`, :c:func:`strchr`, :c:func:`strnchr`, :c:func:`strrchr`, +:c:func:`strstr`, :c:func:`strlen`, :c:func:`memset`, :c:func:`memmove`, +:c:func:`memcmp`, etc. These functions are declared in the +:file:`include/linux/string.h` header and are implemented in the kernel in the +:file:`lib/string.c` file. + +printk +------ + +The printf equivalent in the kernel is printk, defined in +:file:`include/linux/printk.h`. The :c:func:`printk` syntax is very similar +to :c:func:`printf`. The first +parameter of :c:func:`printk` decides the log category in which the current log +falls into: + +.. code-block:: c + + #define KERN_EMERG "<0>" /* system is unusable */ + #define KERN_ALERT "<1>" /* action must be taken immediately */ + #define KERN_CRIT "<2>" /* critical conditions */ + #define KERN_ERR "<3>" /* error conditions */ + #define KERN_WARNING "<4>" /* warning conditions */ + #define KERN_NOTICE "<5>" /* normal but significant condition */ + #define KERN_INFO "<6>" /* informational */ + #define KERN_DEBUG "<7>" /* debug-level messages */ + +Thus, a warning message in the kernel would be sent with: + +.. code-block:: c + + printk(KERN_WARNING "my_module input string %s\n", buff); + + +If the logging level is missing from the :c:func:`printk` call, logging is done +with the default level at the time of the call. One thing to keep in mind is +that messages sent with :c:func:`printk` are only visible on the console if and +only if their level exceeds the default level set on the console. + +To reduce the size of lines when using :c:func:`printk`, it is recommended to +use the following help functions instead of directly using the :c:func:`printk` +call: + +.. code-block:: c + + pr_emerg(fmt, ...); /* similar to printk(KERN_EMERG pr_fmt(fmt), ...); */ + pr_alert(fmt, ...); /* similar to printk(KERN_ALERT pr_fmt(fmt), ...); */ + pr_crit(fmt, ...); /* similar to printk(KERN_CRIT pr_fmt(fmt), ...); */ + pr_err(fmt, ...); /* similar to printk(KERN_ERR pr_fmt(fmt), ...); */ + pr_warn(fmt, ...); /* similar to printk(KERN_WARNING pr_fmt(fmt), ...); */ + pr_notice(fmt, ...); /* similar to printk(KERN_NOTICE pr_fmt(fmt), ...); */ + pr_info(fmt, ...); /* similar to printk(KERN_INFO pr_fmt(fmt), ...); */ + pr_debug(fmt, ...); /* similar to printk(KERN_DEBUG pr_fmt(fmt), ...); */ + +A special case is :c:func:`pr_debug` that calls the :c:func:`printk` function +only when the :c:macro:`DEBUG` macro is defined or if dynamic debugging is used. + + +Memory allocation +----------------- + +In Linux only resident memory can be allocated, using :c:func:`kmalloc` call. +A typical :c:func:`kmalloc` call is presented below: + +.. code-block:: c + + #include <linux/slab.h> + + string = kmalloc (string_len + 1, GFP_KERNEL); + if (!string) { + //report error: -ENOMEM; + } + +As you can see, the first parameter indicates the size in bytes of the allocated +area. The function returns a pointer to a memory area that can be directly used +in the kernel, or :c:macro:`NULL` if memory could not be allocated. The second +parameter specifies how allocation should be done and the most commonly used +values for this are: + + * :c:data:`GFP_KERNEL` - using this value may cause the current process to + be suspended. Thus, it can not be used in the interrupt context. + * :c:data:`GFP_ATOMIC` - using this value it ensures that the + :c:func:`kmalloc` function does not suspend the current process. It can be + used anytime. + +The counterpart to the :c:func:`kmalloc` function is :c:func:`kfree`, a function +that receives as argument an area allocated by :c:func:`kmalloc`. This function +does not suspend the current process and can therefore be called from any +context. + +lists +----- + +Because linked lists are often used, the Linux kernel API provides a unified +way of defining and using lists. This involves using a +:c:type:`struct list_head` element in the structure we want to consider as a +list node. The :c:type:`struct list_head` is defined in +:file:`include/linux/list.h` along with all the other functions that manipulate +the lists. The following code shows the definition of +the :c:type:`struct list_head` and the use of an element of this type in another +well-known structure in the Linux kernel: + +.. code-block:: c + + struct list_head { + struct list_head *next, *prev; + }; + + struct task_struct { + ... + struct list_head children; + ... + }; + +The usual routines for working with lists are the following: + + * :c:macro:`LIST_HEAD(name)` is used to declare the sentinel of a list + * :c:func:`INIT_LIST_HEAD(struct list_head *list)` is used to initialize the + sentinel of a list when dynamic allocation is made, by setting the value of + the :c:data:`next` and :c:data:`prev` to list fields. + * :c:func:`list_add(struct list_head *new, struct list_head *head)` adds the + :c:data:`new` element after the :c:data:`head` element. + * :c:func:`list_del(struct list_head *entry)` deletes the item at the + :c:data:`entry` address of the list it belongs to. + * :c:macro:`list_entry(ptr, type, member)` returns the structure with the + type :c:type:`type` that contains the element :c:data:`ptr` from the list, + having the name :c:member:`member` within the structure. + * :c:macro:`list_for_each(pos, head)` iterates over a list using + :c:data:`pos` as a cursor. + * :c:macro:`list_for_each_safe(pos, n, head)` iterates over a list using + :c:data:`pos` as a cursor and :c:data:`n` as a temporary cursor. + This macro is used to delete an item from the list. + +The following code shows how to use these routines: + +.. code-block:: c + + #include <linux/slab.h> + #include <linux/list.h> + + struct pid_list { + pid_t pid; + struct list_head list; + }; + + LIST_HEAD(my_list); + + static int add_pid(pid_t pid) + { + struct pid_list *ple = kmalloc(sizeof *ple, GFP_KERNEL); + + if (!ple) + return -ENOMEM; + + ple->pid = pid; + list_add(&ple->list, &my_list); + + return 0; + } + + static int del_pid(pid_t pid) + { + struct list_head *i, *tmp; + struct pid_list *ple; + + list_for_each_safe(i, tmp, &my_list) { + ple = list_entry(i, struct pid_list, list); + if (ple->pid == pid) { + list_del(i); + kfree(ple); + return 0; + } + } + + return -EINVAL; + } + + static void destroy_list(void) + { + struct list_head *i, *n; + struct pid_list *ple; + + list_for_each_safe(i, n, &my_list) { + ple = list_entry(i, struct pid_list, list); + list_del(i); + kfree(ple); + } + } + +The evolution of the list can be seen in the following figure: + +.. image:: ../res/list_evolution.png + :width: 85% + +You see the stack type behavior introduced by the :c:macro:`list_add` macro, +and the use of a sentinel. + +From the above example, it can be noticed that the way to define and use a list +(double-linked) is generic and, at the same time, it does not introduce an +additional overhead. The :c:type:`struct list_head` is used to maintain the +links between the list elements. It can be noticed that iterating over the list +is also done with this structure, and that retrieving a list element can be done +using :c:macro:`list_entry`. This idea of implementing and using a list is not +new, as it has already been described in The Art of Computer Programming by +Donald Knuth in the 1980s. + +Several kernel list functions and macro definitions are presented and explained +in the :file:`include/linux/list.h` header. + +Spinlock +-------- + +:c:type:`spinlock_t` (defined in :file:`linux/spinlock.h`) is the basic type +that implements the spinlock concept in Linux. It describes a spinlock, and the +operations associated with a spinlock are :c:func:`spin_lock_init`, +:c:func:`spin_lock`, :c:func:`spin_unlock`. An example of use is given below: + +.. code-block:: c + + #include <linux/spinlock.h> + + DEFINE_SPINLOCK(lock1); + spinlock_t lock2; + + spin_lock_init(&lock2); + + spin_lock(&lock1); + /* critical region */ + spin_unlock(&lock1); + + spin_lock(&lock2); + /* critical region */ + spin_unlock(&lock2); + + +In Linux, you can use reader-writer spinlocks, useful for readers-writers +problems. +These types of locks are identified by :c:type:`rwlock_t`, and the functions +that can work on a reader-writer spinlock are +:c:func:`rwlock_init`, +:c:func:`read_lock`, +:c:func:`write_lock`. +An example of use: + + +.. code-block:: c + + #include <linux/spinlock.h> + + DEFINE_RWLOCK(lock); + + struct pid_list { + pid_t pid; + struct list_head list; + }; + + int have_pid(struct list_head *lh, int pid) + { + struct list_head *i; + void *elem; + + read_lock(&lock); + list_for_each(i, lh) { + struct pid_list *pl = list_entry(i, struct pid_list, list); + if (pl->pid == pid) { + read_unlock(&lock); + return 1; + } + } + read_unlock(&lock); + + return 0; + } + + void add_pid(struct list_head *lh, struct pid_list *pl) + { + write_lock(&lock); + list_add(&pl->list, lh); + write_unlock(&lock); + } + +mutex +----- + +A mutex is a variable of the :c:type:`struct mutex` type (defined in +:file:`linux/mutex.h`). +Functions and macros for working with mutexes are listed below: + +.. code-block:: c + + #include <linux/mutex.h> + + /* functions for mutex initialization */ + void mutex_init(struct mutex *mutex); + DEFINE_MUTEX(name); + + /* functions for mutex acquire */ + void mutex_lock(struct mutex *mutex); + + /* functions for mutex release */ + void mutex_unlock(struct mutex *mutex); + +Operations are similar to classic mutex operations in user-space or spinlock +operations: the mutex is acquired before entering the critical region and it is +released after exiting the critical region. Unlike spinlocks, these operations +can only be used in process context. + +.. _atomic-variables: + +Atomic variables +---------------- + +Often, you only need to synchronize access to a simple variable, such as a +counter. For this, an :c:type:`atomic_t` type can be used (defined in +:file:`include/linux/atomic.h`), that holds an integer value. Below are some +operations that can be performed on an :c:type:`atomic_t` variable. + +.. code-block:: c + + #include <asm/atomic.h> + + void atomic_set(atomic_t *v, int i); + int atomic_read(atomic_t *v); + void atomic_add(int i, atomic_t *v); + void atomic_sub(int i, atomic_t *v); + void atomic_inc(atomic_t *v); + void atomic_dec(atomic_t *v); + int atomic_inc_and_test(atomic_t *v); + int atomic_dec_and_test(atomic_t *v); + int atomic_cmpxchg(atomic_t *v, int old, int new); + +Use of atomic variables +*********************** + +A common way of using atomic variables is to store the status of an action +(e.g. a flag). So we can use an atomic variable to mark exclusive actions. For +example, we consider that an atomic variable can have the LOCKED and UNLOCKED +values, and if the respective variable equals LOCKED then a specific function +should return -EBUSY. +Such an usage is shown schematically in the code below: + +.. code-block:: c + + #define LOCKED 0 + #define UNLOCKED 1 + + static atomic_t flag; + + static int my_acquire(void) + { + int initial_flag; + + /* + * Check if flag is UNLOCKED; if so, lock it and do it atomically. + * + * This is the atomic equivalent of + * if (flag == UNLOCKED) + * flag = LOCKED; + * else + * return -EBUSY; + */ + initial_flag = atomic_cmpxchg(&flag, UNLOCKED, LOCKED); + if (initial_flag == LOCKED) { + printk(KERN_ALERT "Already locked.\n"); + return -EBUSY; + } + + /* Do your thing after getting the lock. */ + [...] + } + + static void my_release(void) + { + /* Release flag; mark it as unlocked. */ + atomic_set(&flag, UNLOCKED); + } + + void my_init(void) + { + [...] + /* Atomic variable is initially unlocked. */ + atomic_set(&flag, UNLOCKED); + + [...] + } + + +The above code is the equivalent of using a trylock (such as +:c:func:`pthread_mutex_trylock`). + +We can also use a variable to store the size of a buffer and for atomic +updates of the respective variable. The code below is such an example: + +.. code-block:: c + + static unsigned char buffer[MAX_SIZE]; + static atomic_t size; + + static void add_to_buffer(unsigned char value) + { + buffer[atomic_read(&size)] = value; + atomic_inc(&size); + } + + static unsigned char remove_from_buffer(void) + { + unsigned char value; + + value = buffer[atomic_read(&size)]; + atomic_dec(&size); + + return value + } + + static void reset_buffer(void) + { + atomic_set(&size, 0); + } + + void my_init(void) + { + [...] + /* Initialized buffer and size. */ + atomic_set(&size, 0); + memset(buffer, 0, sizeof(buffer)); + + [...] + } + +Atomic bitwise operations +------------------------- + +The kernel provides a set of functions (in :file:`asm/bitops.h`) that modify or +test bits in an atomic way. + +.. code-block:: c + + #include <asm/bitops.h> + + void set_bit(int nr, void *addr); + void clear_bit(int nr, void *addr); + void change_bit(int nr, void *addr); + int test_and_set_bit(int nr, void *addr); + int test_and_clear_bit(int nr, void *addr); + int test_and_change_bit(int nr, void *addr); + +:c:data:`Addr` represents the address of the memory area whose bits are being +modified or tested and :c:data:`nr` is the bit on which the operation is +performed. + +Exercises +========= + +.. include:: ../labs/exercises-summary.hrst +.. |LAB_NAME| replace:: kernel_api + +0. Intro +-------- + +Using |LXR|_ find the definitions of the following symbols in the Linux kernel: + + * :c:type:`struct list_head` + * :c:func:`INIT_LIST_HEAD` + * :c:func:`list_add` + * :c:macro:`list_for_each` + * :c:macro:`list_entry` + * :c:macro:`container_of` + * :c:macro:`offsetof` + +1. Memory allocation in Linux kernel +------------------------------------ + +Generate the skeleton for the task named **1-mem** and browse the +contents of the :file:`mem.c` file. Observe the use of :c:func:`kmalloc` +call for memory allocation. + + 1. Compile the source code and load the :file:`mem.ko` module using + :command:`insmod`. + 2. View the kernel messages using the :command:`dmesg` command. + 3. Unload the kernel module using the :command:`rmmod mem` command. + +.. note:: Review the `Memory Allocation`_ section in the lab. + +2. Sleeping in atomic context +----------------------------- + +Generate the skeleton for the task named **2-sched-spin** and browse +the contents of the :file:`sched-spin.c` file. + + 1. Compile the source code and load the module, according the above info: + (:command:`make build` and :command:`make copy`) + 2. Notice that it is waiting for 5 seconds until the insertion + order is complete. + 3. Unload the kernel module. + 4. Look for the lines marked with: ``TODO 0`` to create an atomic + section. Re-compile the source code and reload the module into + the kernel. + +You should now get an error. Look at the stack trace. What is the +cause of the error? + +.. hint:: In the error message, follow the line containing the :c:macro:`BUG` + for a description of the error. You are not allowed to sleep in + atomic context. The atomic context is given by a section + between a lock operation and an unlock on a spinlock. + +.. note:: The + :c:func:`schedule_timeout` function, corroborated with the + :c:macro:`set_current_state` macro, forces the current process to wait + for 5 seconds. + +.. note:: Review the `Contexts of execution`_, `Locking`_ and `Spinlock`_ + sections. + +3. Working with kernel memory +----------------------------- + +Generate the skeleton for the task named **3-memory** directory and +browse the contents of the :file:`memory.c` file. Notice the comments +marked with ``TODO``. You must allocate 4 structures of type :c:type:`struct +task_info` and initialize them (in :c:func:`memory_init`), then print and +free them (in :c:func:`memory_exit`). + + 1. (TODO 1) Allocate memory for :c:type:`struct task_info` structure and + initialize its fields: + + * The :c:member:`pid` field to the PID transmitted as a parameter; + * The :c:member:`timestamp` field to the value of the :c:data:`jiffies` + variable, which holds the number of ticks that have occurred since the + system booted. + + 2. (TODO 2) Allocate :c:type:`struct task_info` for the current process, + the parent process, the next process, the next process of the next + process, with the following information: + + * PID of the current process, which can be retrieved from + :c:type:`struct task_struct` structure, returned by :c:macro:`current` + macro. + + .. hint:: + Search for :c:type:`pid` in :c:type:`task_struct`. + + * PID of the parent process of the current process. + + .. hint:: + Search for the relevant field from :c:type:`struct task_struct` + structure. Look after "parent". + + * PID of the next process from the list of processes, relative to the + current process. + + .. hint:: + Use :c:macro:`next_task` macro, which returns a pointer to the next + process (i.e a :c:type:`struct task_struct` structure). + + * PID of the next process of the next process, relative to the current + process. + + .. hint:: + Call the :c:macro:`next_task` macro 2 times. + + 3. (TODO 3) Display the four structures. + + * Use :c:func:`printk` to display their two fields: + :c:member:`pid` and :c:member:`timestamp`. + + 4. (TODO 4) Release the memory occupied by the structures + (use :c:func:`kfree`). + +.. hint:: + * You can access the current process using :c:macro:`current` + macro. + * Look for the relevant fields in the :c:type:`struct task_struct` + structure (:c:member:`pid`, :c:member:`parent`). + * Use the :c:macro:`next_task` macro. The macro returns the pointer to + the next process (ie. a :c:type:`struct task_struct*` structure). + +.. note:: The :c:type:`struct task_struct` structure contains two fields to + designate the parent of a task: + + * :c:member:`real_parent` points to the process that created the + task or to process with pid 1 (init) if the parent + completed its execution. + * :c:member:`parent` indicates to the current task parent (the + process that will be reported if the task completes + execution). + + In general, the values of the two fields are the same, but + there are situations where they differ, for example when + using the :c:func:`ptrace` system call. + +.. hint:: Review the `Memory allocation`_ section in the lab. + + +4. Working with kernel lists +---------------------------- + +Generate the skeleton for the task named **4-list**. Browse the +contents of the :file:`list.c` file and notice the comments marked with +``TODO``. The current process will add the four structures from the +previous exercise into a list. The list will be built in the +:c:func:`task_info_add_for_current` function which is called when module is +loaded. The list will be printed and deleted in the :c:func:`list_exit` +function and the :c:func:`task_info_purge_list` function. + + 1. (TODO 1) Complete the :c:func:`task_info_add_to_list` function to allocate + a :c:type:`struct task_info` structure and add it to the list. + + 2. (TODO 2) Complete the :c:func:`task_info_purge_list` function to delete + all the elements in the list. + + 3. Compile the kernel module. Load and unload the module by + following the messages displayed by the kernel. + +.. hint:: Review the labs `Lists`_ section. When deleting items from + the list, you will need to use either the + :c:macro:`list_for_each_safe` or :c:macro:`list_for_each_entry_safe` + macros. + +5. Working with kernel lists for process handling +------------------------------------------------- + +Generate the skeleton for the task named **5-list-full**. Browse the +contents of the :file:`list-full.c` and notice comments marked with +``TODO``. In addition to the :file:`4-list` functionality we add the +following: + + * A :c:member:`count` field showing how many times a process has been "added" + to the list. + * If a process is "added" several times, no new entry is created in + the list, but: + + * Update the :c:member:`timestamp` field. + * Increment :c:member:`count`. + + * To implement the counter facility, add a :c:func:`task_info_find_pid` + function that searches for a pid in the existing list. + + * If found, return the reference to the :c:type:`task_info` struct. If + not, return :c:macro:`NULL`. + + * An expiration facility. If a process was added more than 3 + seconds ago and if it does not have a :c:member:`count` greater than 5 then + it is considered expired and is removed from the list. + * The expiration facility is already implemented in the + :c:func:`task_info_remove_expired` function. + + 1. (TODO 1) Implement the :c:func:`task_info_find_pid` function. + 2. (TODO 2) Change a field of an item in the list so it does not + expire. It must not satisfy a part of the expiration condition + from :c:func:`task_info_remove_expired`. + + .. hint:: For ``TODO 2``, extract the first element from the list (the one + referred by :c:member:`head.next`) and set the :c:member:`count` + field to a large enough value. Use :c:func:`atomic_set` function. + + 3. Compile, copy, load and unload the kernel module following the displayed + messages. + Kernel module loading will take some time, because :c:func:`sleep` is + being called by :c:func:`schedule_timeout` function. + +6. Synchronizing list work +-------------------------- + +Generate the skeleton for the task named **6-list-sync**. + + 1. Browse the code and look for ``TODO 1`` string. + 2. Use a spinlock or a read-write lock to synchronize access to the + list. + 3. Compile, load and unload the kernel module. + +.. important:: Always lock data, not code! + +.. note:: Read `Spinlock`_ section of the lab. + +7. Test module calling in our list module +----------------------------------------- + +Generate the skeleton for the task named **7-list-test** and browse +the contents of the :file:`list-test.c` file. We'll use it as a test +module. It will call functions exported by the **6-list-sync** +task. The exported functions are the ones marked with **extern** in +:file:`list-test.c` file. + +Uncomment the commented code from :file:`7-list-test.c`. Look for ``TODO 1``. + +To export the above functions from the module located at :file:`6-list-sync/` +directory, the following steps are required: + + 1. Functions must not be static. + 2. Use the :c:macro:`EXPORT_SYMBOL` macro to export the kernel symbols. For + example: :c:macro:`EXPORT_SYMBOL(task_info_remove_expired);`. The + macro must be used for each function after the function is defined. + Browse the code and look for the ``TODO 2`` string in the + :file:`list-sync.c`. + 3. Remove from the module from **6-list-sync** the code that avoids the + expiration of a list item (it is in contradiction to our exercise). + 4. Compile and load the module from :file:`6-list-sync/`. Once loaded, it + exposes exported functions and can be used by the test + module. You can check this by searching for the function names + in :file:`/proc/kallsyms` before and after loading the module. + 5. Compile the test module and then load it. + 6. Use :command:`lsmod` to check that the two modules have been loaded. + What do you notice? + 7. Unload the kernel test module. + +What should be the unload order of the two modules (the module from +**6-list-sync** and the test module)? What happens if you use another order? diff --git a/refs/pull/405/merge/_sources/labs/kernel_modules.rst.txt b/refs/pull/405/merge/_sources/labs/kernel_modules.rst.txt new file mode 100644 index 00000000..6b1ca31f --- /dev/null +++ b/refs/pull/405/merge/_sources/labs/kernel_modules.rst.txt @@ -0,0 +1,1345 @@ +============== +Kernel modules +============== + +Lab objectives +============== + +* creating simple modules +* describing the process of kernel module compilation +* presenting how a module can be used with a kernel +* simple kernel debugging methods + +.. + _[SECTION-OVERVIEW-BEGIN] + +Kernel Modules Overview +======================= + +A monolithic kernel, though faster than a microkernel, has the disadvantage of +lack of modularity and extensibility. On modern monolithic kernels, this has +been solved by using kernel modules. A kernel module (or loadable kernel mode) +is an object file that contains code that can extend the kernel functionality +at runtime (it is loaded as needed); When a kernel module is no longer needed, +it can be unloaded. Most of the device drivers are used in the form of kernel +modules. + +For the development of Linux device drivers, it is recommended to download the +kernel sources, configure and compile them and then install the compiled version +on the test /development tool machine. + +.. + _[SECTION-OVERVIEW-END] + +.. + _[SECTION-MODULE-EXAMPLE-BEGIN] + +An example of a kernel module +============================= + +Below is a very simple example of a kernel module. When loading into the kernel, +it will generate the message :code:`"Hi"`. When unloading the kernel module, the +:code:`"Bye"` message will be generated. + +.. code-block:: c + + #include <linux/kernel.h> + #include <linux/init.h> + #include <linux/module.h> + + MODULE_DESCRIPTION("My kernel module"); + MODULE_AUTHOR("Me"); + MODULE_LICENSE("GPL"); + + static int dummy_init(void) + { + pr_debug("Hi\n"); + return 0; + } + + static void dummy_exit(void) + { + pr_debug("Bye\n"); + } + + module_init(dummy_init); + module_exit(dummy_exit); + + +The generated messages will not be displayed on the console but will be saved +in a specially reserved memory area for this, from where they will be extracted +by the logging daemon (syslog). To display kernel messages, you can use the +:command:`dmesg` command or inspect the logs: + +.. code-block:: bash + + # cat /var/log/syslog | tail -2 + Feb 20 13:57:38 asgard kernel: Hi + Feb 20 13:57:43 asgard kernel: Bye + + # dmesg | tail -2 + Hi + Bye + +.. + _[SECTION-MODULE-EXAMPLE-END] + +.. + _[SECTION-COMPILE-MODULES-BEGIN] + +Compiling kernel modules +======================== + +Compiling a kernel module differs from compiling an user program. First, other +headers should be used. Also, the module should not be linked to libraries. +And, last but not least, the module must be compiled with the same options as +the kernel in which we load the module. For these reasons, there is a standard +compilation method (:code:`kbuild`). This method requires the use of two files: +a :file:`Makefile` and a :file:`Kbuild` file. + +Below is an example of a :file:`Makefile`: + +.. code-block:: bash + + KDIR = /lib/modules/`uname -r`/build + + kbuild: + make -C $(KDIR) M=`pwd` + + clean: + make -C $(KDIR) M=`pwd` clean + +And the example of a :file:`Kbuild` file used to compile a module: + +.. code-block:: bash + + EXTRA_CFLAGS = -Wall -g + + obj-m = modul.o + + +As you can see, calling :command:`make` on the :file:`Makefile` file in the +example shown will result in the :command:`make` invocation in the kernel +source directory (``/lib/modules/`uname -r`/build``) and referring to the +current directory (``M = `pwd```). This process ultimately leads to reading +the :file:`Kbuild` file from the current directory and compiling the module +as instructed in this file. + +.. note:: For labs we will configure different :command:`KDIR`, according to + the virtual machine specifications: + + .. code-block:: bash + + KDIR = /home/student/src/linux + [...] + +A :file:`Kbuild` file contains one or more directives for compiling a kernel +module. The easiest example of such a directive is ``obj-m = +module.o``. Following this directive, a kernel module (:code:`ko` - kernel +object) will be created, starting from the ``module.o`` file. ``module.o`` will +be created starting from ``module.c`` or ``module.S``. All of these files can +be found in the :file:`Kbuild`'s directory. + +An example of a :file:`Kbuild` file that uses several sub-modules is shown +below: + +.. code-block:: bash + + EXTRA_CFLAGS = -Wall -g + + obj-m = supermodule.o + supermodule-y = module-a.o module-b.o + +For the example above, the steps to compile are: + + * compile the :file:`module-a.c` and :file:`module-b.c` sources, + resulting in module-a.o and module-b.o objects + * :file:`module-a.o` and :file:`module-b.o` will then be linked + in :file:`supermodule.o` + * from :file:`supermodule.o` will be created :file:`supermodule.ko` + module + + +The suffix of targets in :file:`Kbuild` determines how they are used, as +follows: + + * M (modules) is a target for loadable kernel modules + + * Y (yes) represents a target for object files to be compiled and then + linked to a module (``$(mode_name)-y``) or within the kernel (``obj-y``) + + * any other target suffix will be ignored by :file:`Kbuild` and will not be + compiled + + +.. note:: These suffixes are used to easily configure the kernel by running the + :command:`make menuconfig` command or directly editing the + :file:`.config` file. This file sets a series of variables that are + used to determine which features are added to the kernel at build + time. For example, when adding BTRFS support with :command:`make + menuconfig`, add the line :code:`CONFIG_BTRFS_FS = y` to the + :file:`.config` file. The BTRFS kbuild contains the line + ``obj-$(CONFIG_BTRFS_FS):= btrfs.o``, which becomes ``obj-y:= + btrfs.o``. This will compile the :file:`btrfs.o` object and will be + linked to the kernel. Before the variable was set, the line became + ``obj:=btrfs.o`` and so it was ignored, and the kernel was build + without BTRFS support. + +For more details, see the :file:`Documentation/kbuild/makefiles.txt` and +:file:`Documentation/kbuild/modules.txt` files within the kernel sources. + +.. + _[SECTION-COMPILE-MODULES-END] + +.. + _[SECTION-LOAD-MODULES-BEGIN] + +Loading/unloading a kernel module +================================= + +To load a kernel module, use the :command:`insmod` utility. This utility +receives as a parameter the path to the :file:`*.ko` file in which the module +was compiled and linked. Unloading the module from the kernel is done using +the :command:`rmmod` command, which receives the module name as a parameter. + +.. code-block:: bash + + $ insmod module.ko + $ rmmod module.ko + +When loading the kernel module, the routine specified as a parameter of the +``module_init`` macro will be executed. Similarly, when the module is unloaded +the routine specified as a parameter of the ``module_exit`` will be executed. + +A complete example of compiling and loading/unloading a kernel module is +presented below: + +.. code-block:: bash + + faust:~/lab-01/modul-lin# ls + Kbuild Makefile modul.c + + faust:~/lab-01/modul-lin# make + make -C /lib/modules/`uname -r`/build M=`pwd` + make[1]: Entering directory `/usr/src/linux-2.6.28.4' + LD /root/lab-01/modul-lin/built-in.o + CC [M] /root/lab-01/modul-lin/modul.o + Building modules, stage 2. + MODPOST 1 modules + CC /root/lab-01/modul-lin/modul.mod.o + LD [M] /root/lab-01/modul-lin/modul.ko + make[1]: Leaving directory `/usr/src/linux-2.6.28.4' + + faust:~/lab-01/modul-lin# ls + built-in.o Kbuild Makefile modul.c Module.markers + modules.order Module.symvers modul.ko modul.mod.c + modul.mod.o modul.o + + faust:~/lab-01/modul-lin# insmod modul.ko + + faust:~/lab-01/modul-lin# dmesg | tail -1 + Hi + + faust:~/lab-01/modul-lin# rmmod modul + + faust:~/lab-01/modul-lin# dmesg | tail -2 + Hi + Bye + +Information about modules loaded into the kernel can be found using the +:command:`lsmod` command or by inspecting the :file:`/proc/modules`, +:file:`/sys/module` directories. + +.. + _[SECTION-LOAD-MODULES-END] + +.. + _[SECTION-DEBUG-MODULES-BEGIN] + +Kernel Module Debugging +======================= + +Troubleshooting a kernel module is much more complicated than debugging a +regular program. First, a mistake in a kernel module can lead to blocking the +entire system. Troubleshooting is therefore much slowed down. To avoid reboot, +it is recommended to use a virtual machine (qemu, virtualbox, vmware). + +When a module containing bugs is inserted into the kernel, it will eventually +generate a `kernel oops <https://en.wikipedia.org/wiki/Linux_kernel_oops>`_. +A kernel oops is an invalid operation detected by the kernel and can only +be generated by the kernel. For a stable kernel version, it almost certainly +means that the module contains a bug. After the oops appears, the kernel will +continue to work. + +Very important to the appearance of a kernel oops is saving the generated +message. As noted above, messages generated by the kernel are saved in logs and +can be displayed with the :command:`dmesg` command. To make sure that no kernel +message is lost, it is recommended to insert/test the kernel directly from the +console, or periodically check the kernel messages. Noteworthy is that an oops +can occur because of a programming error, but also a because of hardware error. + +If a fatal error occurs, after which the system can not return to a stable +state, a `kernel panic <https://en.wikipedia.org/wiki/Linux_kernel_panic>`_ is +generated. + +Look at the kernel module below that contains a bug that generates an oops: + +.. code-block:: c + + /* + * Oops generating kernel module + */ + + #include <linux/kernel.h> + #include <linux/module.h> + #include <linux/init.h> + + MODULE_DESCRIPTION ("Oops"); + MODULE_LICENSE ("GPL"); + MODULE_AUTHOR ("PSO"); + + #define OP_READ 0 + #define OP_WRITE 1 + #define OP_OOPS OP_WRITE + + static int my_oops_init (void) + { + int *a; + + a = (int *) 0x00001234; + #if OP_OOPS == OP_WRITE + *a = 3; + #elif OP_OOPS == OP_READ + printk (KERN_ALERT "value = %d\n", *a); + #else + #error "Unknown op for oops!" + #endif + + return 0; + } + + static void my_oops_exit (void) + { + } + + module_init (my_oops_init); + module_exit (my_oops_exit); + +.. ** + +Inserting this module into the kernel will generate an oops: + +.. code-block:: bash + + faust:~/lab-01/modul-oops# insmod oops.ko + [...] + + faust:~/lab-01/modul-oops# dmesg | tail -32 + BUG: unable to handle kernel paging request at 00001234 + IP: [<c89d4005>] my_oops_init+0x5/0x20 [oops] + *de = 00000000 + Oops: 0002 [#1] PREEMPT DEBUG_PAGEALLOC + last sysfs file: /sys/devices/virtual/net/lo/operstate + Modules linked in: oops(+) netconsole ide_cd_mod pcnet32 crc32 cdrom [last unloaded: modul] + + Pid: 4157, comm: insmod Not tainted (2.6.28.4 #2) VMware Virtual Platform + EIP: 0060:[<c89d4005>] EFLAGS: 00010246 CPU: 0 + EIP is at my_oops_init+0x5/0x20 [oops] + EAX: 00000000 EBX: fffffffc ECX: c89d4300 EDX: 00000001 + ESI: c89d4000 EDI: 00000000 EBP: c5799e24 ESP: c5799e24 + DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068 + Process insmod (pid: 4157, ti=c5799000 task=c665c780 task.ti=c5799000) + Stack: + c5799f8c c010102d c72b51d8 0000000c c5799e58 c01708e4 00000124 00000000 + c89d4300 c5799e58 c724f448 00000001 c89d4300 c5799e60 c0170981 c5799f8c + c014b698 00000000 00000000 c5799f78 c5799f20 00000500 c665cb00 c89d4300 + Call Trace: + [<c010102d>] ? _stext+0x2d/0x170 + [<c01708e4>] ? __vunmap+0xa4/0xf0 + [<c0170981>] ? vfree+0x21/0x30 + [<c014b698>] ? load_module+0x19b8/0x1a40 + [<c035e965>] ? __mutex_unlock_slowpath+0xd5/0x140 + [<c0140da6>] ? trace_hardirqs_on_caller+0x106/0x150 + [<c014b7aa>] ? sys_init_module+0x8a/0x1b0 + [<c0140da6>] ? trace_hardirqs_on_caller+0x106/0x150 + [<c0240a08>] ? trace_hardirqs_on_thunk+0xc/0x10 + [<c0103407>] ? sysenter_do_call+0x12/0x43 + Code: <c7> 05 34 12 00 00 03 00 00 00 5d c3 eb 0d 90 90 90 90 90 90 90 90 + EIP: [<c89d4005>] my_oops_init+0x5/0x20 [oops] SS:ESP 0068:c5799e24 + ---[ end trace 2981ce73ae801363 ]--- + +Although relatively cryptic, the message provided by the kernel to the +appearance of an oops provides valuable information about the error. First line: + +.. code-block:: bash + + BUG: unable to handle kernel paging request at 00001234 + EIP: [<c89d4005>] my_oops_init + 0x5 / 0x20 [oops] + +Tells us the cause and the address of the instruction that generated the error. +In our case this is an invalid access to memory. + +Next line + + ``Oops: 0002 [# 1] PREEMPT DEBUG_PAGEALLOC`` + +Tells us that it's the first oops (#1). This is important in the context that +an oops can lead to other oopses. Usually only the first oops is relevant. +Furthermore, the oops code (``0002``) provides information about the error type +(see :file:`arch/x86/include/asm/trap_pf.h`): + + + * Bit 0 == 0 means no page found, 1 means protection fault + * Bit 1 == 0 means read, 1 means write + * Bit 2 == 0 means kernel, 1 means user mode + +In this case, we have a write access that generated the oops (bit 1 is 1). + +Below is a dump of the registers. It decodes the instruction pointer (``EIP``) +value and notes that the bug appeared in the :code:`my_oops_init` function with +a 5-byte offset (``EIP: [<c89d4005>] my_oops_init+0x5``). The message also +shows the stack content and a backtrace of calls until then. + +If an invalid read call is generated (``#define OP_OOPS OP_READ``), the message +will be the same, but the oops code will differ, which would now be ``0000``: + +.. code-block:: bash + + faust:~/lab-01/modul-oops# dmesg | tail -33 + BUG: unable to handle kernel paging request at 00001234 + IP: [<c89c3016>] my_oops_init+0x6/0x20 [oops] + *de = 00000000 + Oops: 0000 [#1] PREEMPT DEBUG_PAGEALLOC + last sysfs file: /sys/devices/virtual/net/lo/operstate + Modules linked in: oops(+) netconsole pcnet32 crc32 ide_cd_mod cdrom + + Pid: 2754, comm: insmod Not tainted (2.6.28.4 #2) VMware Virtual Platform + EIP: 0060:[<c89c3016>] EFLAGS: 00010292 CPU: 0 + EIP is at my_oops_init+0x6/0x20 [oops] + EAX: 00000000 EBX: fffffffc ECX: c89c3380 EDX: 00000001 + ESI: c89c3010 EDI: 00000000 EBP: c57cbe24 ESP: c57cbe1c + DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068 + Process insmod (pid: 2754, ti=c57cb000 task=c66ec780 task.ti=c57cb000) + Stack: + c57cbe34 00000282 c57cbf8c c010102d c57b9280 0000000c c57cbe58 c01708e4 + 00000124 00000000 c89c3380 c57cbe58 c5db1d38 00000001 c89c3380 c57cbe60 + c0170981 c57cbf8c c014b698 00000000 00000000 c57cbf78 c57cbf20 00000580 + Call Trace: + [<c010102d>] ? _stext+0x2d/0x170 + [<c01708e4>] ? __vunmap+0xa4/0xf0 + [<c0170981>] ? vfree+0x21/0x30 + [<c014b698>] ? load_module+0x19b8/0x1a40 + [<c035d083>] ? printk+0x0/0x1a + [<c035e965>] ? __mutex_unlock_slowpath+0xd5/0x140 + [<c0140da6>] ? trace_hardirqs_on_caller+0x106/0x150 + [<c014b7aa>] ? sys_init_module+0x8a/0x1b0 + [<c0140da6>] ? trace_hardirqs_on_caller+0x106/0x150 + [<c0240a08>] ? trace_hardirqs_on_thunk+0xc/0x10 + [<c0103407>] ? sysenter_do_call+0x12/0x43 + Code: <a1> 34 12 00 00 c7 04 24 54 30 9c c8 89 44 24 04 e8 58 a0 99 f7 31 + EIP: [<c89c3016>] my_oops_init+0x6/0x20 [oops] SS:ESP 0068:c57cbe1c + ---[ end trace 45eeb3d6ea8ff1ed ]--- + +objdump +------- + +Detailed information about the instruction that generated the oops can be found +using the :command:`objdump` utility. Useful options to use are :command:`-d` +to disassemble the code and :command:`-S` for interleaving C code in assembly +language code. For efficient decoding, however, we need the address where the +kernel module was loaded. This can be found in :file:`/proc/modules`. + +Here's an example of using :command:`objdump` on the above module to identify +the instruction that generated the oops: + +.. code-block:: bash + + faust:~/lab-01/modul-oops# cat /proc/modules + oops 1280 1 - Loading 0xc89d4000 + netconsole 8352 0 - Live 0xc89ad000 + pcnet32 33412 0 - Live 0xc895a000 + ide_cd_mod 34952 0 - Live 0xc8903000 + crc32 4224 1 pcnet32, Live 0xc888a000 + cdrom 34848 1 ide_cd_mod, Live 0xc886d000 + + faust:~/lab-01/modul-oops# objdump -dS --adjust-vma=0xc89d4000 oops.ko + + oops.ko: file format elf32-i386 + + + Disassembly of section .text: + + c89d4000 <init_module>: + #define OP_READ 0 + #define OP_WRITE 1 + #define OP_OOPS OP_WRITE + + static int my_oops_init (void) + { + c89d4000: 55 push %ebp + #else + #error "Unknown op for oops!" + #endif + + return 0; + } + c89d4001: 31 c0 xor %eax,%eax + #define OP_READ 0 + #define OP_WRITE 1 + #define OP_OOPS OP_WRITE + + static int my_oops_init (void) + { + c89d4003: 89 e5 mov %esp,%ebp + int *a; + + a = (int *) 0x00001234; + #if OP_OOPS == OP_WRITE + *a = 3; + c89d4005: c7 05 34 12 00 00 03 movl $0x3,0x1234 + c89d400c: 00 00 00 + #else + #error "Unknown op for oops!" + #endif + + return 0; + } + c89d400f: 5d pop %ebp + c89d4010: c3 ret + c89d4011: eb 0d jmp c89c3020 <cleanup_module> + c89d4013: 90 nop + c89d4014: 90 nop + c89d4015: 90 nop + c89d4016: 90 nop + c89d4017: 90 nop + c89d4018: 90 nop + c89d4019: 90 nop + c89d401a: 90 nop + c89d401b: 90 nop + c89d401c: 90 nop + c89d401d: 90 nop + c89d401e: 90 nop + c89d401f: 90 nop + + c89d4020 <cleanup_module>: + + static void my_oops_exit (void) + { + c89d4020: 55 push %ebp + c89d4021: 89 e5 mov %esp,%ebp + } + c89d4023: 5d pop %ebp + c89d4024: c3 ret + c89d4025: 90 nop + c89d4026: 90 nop + c89d4027: 90 nop + +Note that the instruction that generated the oops (``c89d4005`` identified +earlier) is: + + ``C89d4005: c7 05 34 12 00 00 03 movl $ 0x3,0x1234`` + +That is exactly what was expected - storing value 3 at 0x0001234. + +The :file:`/proc/modules` is used to find the address where a kernel module is +loaded. The :command:`--adjust-vma` option allows you to display instructions +relative to ``0xc89d4000``. The :command:`-l` option displays the number of +each line in the source code interleaved with the assembly language code. + +addr2line +--------- + +A more simplistic way to find the code that generated an oops is to use the +:command:`addr2line` utility: + +.. code-block:: bash + + faust:~/lab-01/modul-oops# addr2line -e oops.o 0x5 + /root/lab-01/modul-oops/oops.c:23 + +Where ``0x5`` is the value of the program counter (``EIP = c89d4005``) that +generated the oops, minus the base address of the module (``0xc89d4000``) +according to :file:`/proc/modules` + +minicom +------- + +:command:`Minicom` (or other equivalent utilities, eg :command:`picocom`, +:command:`screen`) is a utility that can be used to connect and interact with a +serial port. The serial port is the basic method for analyzing kernel messages +or interacting with an embedded system in the development phase. There are two +more common ways to connect: + +* a serial port where the device we are going to use is :file:`/dev/ttyS0` + +* a serial USB port (FTDI) in which case the device we are going to use is + :file:`/dev/ttyUSB`. + +For the virtual machine used in the lab, the device that we need to use is +displayed after the virtual machine starts: + +.. code-block:: bash + + char device redirected to /dev/pts/20 (label virtiocon0) + +Minicom use: + +.. code-block:: bash + + #for connecting via COM1 and using a speed of 115,200 characters per second + minicom -b 115200 -D /dev/ttyS0 + + #For USB serial port connection + minicom -D /dev/ttyUSB0 + + #To connect to the serial port of the virtual machine + minicom -D /dev/pts/20 + +netconsole +---------- + +:command:`Netconsole` is a utility that allows logging of kernel debugging +messages over the network. This is useful when the disk logging system does not +work or when serial ports are not available or when the terminal does not +respond to commands. :command:`Netconsole` comes in the form of a kernel +module. + +To work, it needs the following parameters: + + * port, IP address, and the source interface name of the debug station + * port, MAC address, and IP address of the machine to which the debug + messages will be sent + +These parameters can be configured when the module is inserted into the kernel, +or even while the module is inserted if it has been compiled with the +``CONFIG_NETCONSOLE_DYNAMIC`` option. + +An example configuration when inserting :command:`netconsole` kernel module is +as follows: + +.. code-block:: bash + + alice:~# modprobe netconsole netconsole=6666@192.168.191.130/eth0,6000@192.168.191.1/00:50:56:c0:00:08 + +Thus, the debug messages on the station that has the address +``192.168.191.130`` will be sent to the ``eth0`` interface, having source port +``6666``. The messages will be sent to ``192.168.191.1`` with the MAC address +``00:50:56:c0:00:08``, on port ``6000``. + +Messages can be played on the destination station using :command:`netcat`: + +.. code-block:: bash + + bob:~ # nc -l -p 6000 -u + +Alternatively, the destination station can configure :command:`syslogd` to +intercept these messages. More information can be found in +:file:`Documentation/networking/netconsole.txt`. + +Printk debugging +---------------- + +``The two oldest and most useful debugging aids are Your Brain and Printf``. + +For debugging, a primitive way is often used, but it is quite effective: +:code:`printk` debugging. Although a debugger can also be used, it is generally +not very useful: simple bugs (uninitialized variables, memory management +problems, etc.) can be easily localized by control messages and the +kernel-decoded oop message. + +For more complex bugs, even a debugger can not help us too much unless the +operating system structure is very well understood. When debugging a kernel +module, there are a lot of unknowns in the equation: multiple contexts (we have +multiple processes and threads running at a time), interruptions, virtual +memory, etc. + +You can use :code:`printk` to display kernel messages to user space. It is +similar to :code:`printf`'s functionality; the only difference is that the +transmitted message can be prefixed with a string of :code:`"<n>"`, where +:code:`n` indicates the error level (loglevel) and has values between ``0`` and +``7``. Instead of :code:`"<n>"`, the levels can also be coded by symbolic +constants: + +.. code-block:: c + + KERN_EMERG - n = 0 + KERN_ALERT - n = 1 + KERN_CRIT - n = 2 + KERN_ERR - n = 3 + KERN_WARNING - n = 4 + KERN_NOTICE - n = 5 + KERN_INFO - n = 6 + KERN_DEBUG - n = 7 + + +The definitions of all log levels are found in :file:`linux/kern_levels.h`. +Basically, these log levels are used by the system to route messages sent to +various outputs: console, log files in :file:`/var/log` etc. + +.. note:: To display :code:`printk` messages in user space, the :code:`printk` + log level must be of higher priority than `console_loglevel` + variable. The default console log level can be configured from + :file:`/proc/sys/kernel/printk`. + + For instance, the command: + + .. code-block:: bash + + echo 8 > /proc/sys/kernel/printk + + will enable all the kernel log messages to be displayed in the + console. That is, the logging level has to be strictly less than the + :code:`console_loglevel` variable. For example, if the + :code:`console_loglevel` has a value of ``5`` (specific to + :code:`KERN_NOTICE`), only messages with loglevel stricter than ``5`` + (i.e :code:`KERN_EMERG`, :code:`KERN_ALERT`, :code:`KERN_CRIT`, + :code:`KERN_ERR`, :code:`KERN_WARNING`) will be shown. + +Console-redirected messages can be useful for quickly viewing the effect of +executing the kernel code, but they are no longer so useful if the kernel +encounters an irreparable error and the system freezes. In this case, the logs +of the system must be consulted, as they keep the information between system +restarts. These are found in :file:`/var/log` and are text files, populated by +:code:`syslogd` and :code:`klogd` during the kernel run. :code:`syslogd` and +:code:`klogd` take the information from the virtual file system mounted in +:file:`/proc`. In principle, with :code:`syslogd` and :code:`klogd` turned on, +all messages coming from the kernel will go to :file:`/var/log/kern.log`. + +A simpler version for debugging is using the :file:`/var/log/debug` file. It +is populated only with the :code:`printk` messages from the kernel with the +:code:`KERN_DEBUG` log level. + +Given that a production kernel (similar to the one we're probably running with) +contains only release code, our module is among the few that send messages +prefixed with KERN_DEBUG . In this way, we can easily navigate through the +:file:`/var/log/debug` information by finding the messages corresponding to a +debugging session for our module. + +Such an example would be the following: + +.. code-block:: bash + + # Clear the debug file of previous information (or possibly a backup) + $ echo "New debug session" > /var/log/debug + # Run the tests + # If there is no critical error causing a panic kernel, check the output + # if a critical error occurs and the machine only responds to a restart, + restart the system and check /var/log/debug. + +The format of the messages must obviously contain all the information of +interest in order to detect the error, but inserting in the code :code:`printk` +to provide detailed information can be as time-consuming as writing the code to +solve the problem. This is usually a trade-off between the completeness of the +debugging messages displayed using :code:`printk` and the time it takes to +insert these messages into the text. + +A very simple way, less time-consuming for inserting :code:`printk` and +providing the possibility to analyze the flow of instructions for tests is the +use of the predefined constants :code:`__FILE__`, :code:`__LINE__` and +:code:`__func__`: + + * ``__FILE__`` is replaced by the compiler with the name of the source file + it is currently being compiled. + + * ``__LINE__`` is replaced by the compiler with the line number on which the + current instruction is found in the current source file. + + * ``__func__`` /``__FUNCTION__`` is replaced by the compiler with the name + of the function in which the current instruction is found. + +.. note:: + :code:`__FILE__` and :code:`__LINE__` are part of the ANSI C specifications: + :code:`__func__` is part of specification C99; :code:`__FUNCTION__` is a GNU + :code:`C` extension and is not portable; However, since we write code for the + :code:`Linux` kernel, we can use it without any problems. + +The following macro definition can be used in this case: + +.. code-block:: c + + #define PRINT_DEBUG \ + printk (KERN_DEBUG "[% s]: FUNC:% s: LINE:% d \ n", __FILE__, + __FUNCTION__, __LINE__) + +Then, at each point where we want to see if it is "reached" in execution, +insert PRINT_DEBUG; This is a simple and quick way, and can yield by carefully +analyzing the output. + +The :command:`dmesg` command is used to view the messages printed with +:code:`printk` but not appearing on the console. + +To delete all previous messages from a log file, run: + +.. code-block:: bash + + cat /dev/null > /var/log/debug + +To delete messages displayed by the :command:`dmesg` command, run: + +.. code-block:: bash + + dmesg -c + + +Dynamic debugging +----------------- + +Dynamic `dyndbg <https://www.kernel.org/doc/html/v4.15/admin-guide/dynamic-debug-howto.html>`_ +debugging enables dynamic debugging activation/deactivation. +Unlike :code:`printk`, it offers more advanced :code:`printk` options for the +messages we want to display; it is very useful for complex modules or +troubleshooting subsystems. +This significantly reduces the amount of messages displayed, leaving only +those relevant for the debug context. To enable ``dyndbg``, the kernel must be +compiled with the ``CONFIG_DYNAMIC_DEBUG`` option. Once configured, +:code:`pr_debug()`, :code:`dev_dbg()` and :code:`print_hex_dump_debug()`, +:code:`print_hex_dump_bytes()` can be dynamically enabled per call. + +The :file:`/sys/kernel/debug/dynamic_debug/control` file from the debugfs (where +:file:`/sys/kernel/debug` is the path to which debugfs was mounted) is used to +filter messages or to view existing filters. + +.. code-block:: c + + mount -t debugfs none /debug + +`Debugfs <http://opensourceforu.com/2010/10/debugging-linux-kernel-with-debugfs/>`_ +is a simple file system, used as a kernel-space interface and +user-space interface to configure different debug options. Any debug utility +can create and use its own files /folders in debugfs. + +For example, to display existing filters in ``dyndbg``, you will use: + +.. code-block:: bash + + cat /debug/dynamic_debug/control + +And to enable the debug message from line ``1603`` in the :file:`svcsock.c` file: + +.. code-block:: bash + + echo 'file svcsock.c line 1603 +p' > /debug/dynamic_debug/control + +The :file:`/debug/dynamic_debug/control` file is not a regular file. It shows +the ``dyndbg`` settings on the filters. Writing in it with an echo will change +these settings (it will not actually make a write). Be aware that the file +contains settings for ``dyndbg`` debugging messages. Do not log in this file. + +Dyndbg Options +~~~~~~~~~~~~~~ + +* ``func`` - just the debug messages from the functions that have the same + name as the one defined in the filter. + + .. code-block:: bash + + echo 'func svc_tcp_accept +p' > /debug/dynamic_debug/control + +* ``file`` - the name of the file(s) for which we want to display the debug + messages. It can be just the source name, but also the absolute path or + kernel-tree path. + + .. code-block:: bash + + file svcsock.c + file kernel/freezer.c + file /usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c + +* ``module`` - module name. + + .. code-block:: bash + + module sunrpc + +* ``format`` - only messages whose display format contains the specified string. + + .. code-block:: bash + + format "nfsd: SETATTR" + +* ``line`` - the line or lines for which we want to enable debug calls. + + .. code-block:: bash + + # Triggers debug messages between lines 1603 and 1605 in the svcsock.c file + $ echo 'file svcsock.c line 1603-1605 +p' > /sys/kernel/debug/dynamic_debug/control + # Enables debug messages from the beginning of the file to line 1605 + $ echo 'file svcsock.c line -1605 +p' > /sys/kernel/debug/dynamic_debug/control + +In addition to the above options, a series of flags can be added, removed, or set +with operators ``+``, ``-`` or ``=``: + + * ``p`` activates the pr_debug() . + * ``f`` includes the name of the function in the printed message. + * ``l`` includes the line number in the printed message. + * ``m`` includes the module name in the printed message. + * ``t`` includes the thread id if it is not called from interrupt context + * ``_`` no flag is set. + +KDB: Kernel debugger +-------------------- + +The kernel debugger has proven to be very useful to facilitate the development and +debugging process. One of its main advantages is the possibility to perform live debugging. +This allows us to monitor, in real time, the accesses to memory or even modify the memory +while debugging. +The debugger has been integrated in the mainline kernel starting with version 2.6.26-rci. +KDB is not a *source debugger*, but for a complete analysis it can be used in parallel with +gdb and symbol files -- see :ref:`the GDB debugging section <gdb_intro>` + +To use KDB, you have the following options: + + * non-usb keyboard + VGA text console + * serial port console + * USB EHCI debug port + +For the lab, we will use a serial interface connected to the host. +The following command will activate GDB over the serial port: + +.. code-block:: bash + + echo hvc0 > /sys/module/kgdboc/parameters/kgdboc + +KDB is a *stop mode debugger*, which means that, while it is active, all the other processes +are stopped. The kernel can be *forced* to enter KDB during execution using the following +`SysRq <http://en.wikipedia.org/wiki/Magic_SysRq_key>`__ command + +.. code-block:: bash + + echo g > /proc/sysrq-trigger + +or by using the key combination ``Ctrl+O g`` in a terminal connected to the serial port +(for example using :command:`minicom`). + +KDB has various commands to control and define the context of the debugged system: + + * lsmod, ps, kill, dmesg, env, bt (backtrace) + * dump trace logs + * hardware breakpoints + * modifying memory + +For a better description of the available commands you can use the ``help`` command in +the KDB shell. +In the next example, you can notice a simple KDB usage example which sets a hardware +breakpoint to monitor the changes of the ``mVar`` variable. + +.. code-block:: bash + + # trigger KDB + echo g > /proc/sysrq-trigger + # or if we are connected to the serial port issue + Ctrl-O g + # breakpoint on write access to the mVar variable + kdb> bph mVar dataw + # return from KDB + kdb> go + +.. + _[SECTION-DEBUG-MODULES-END] + +Exercises +========= + +.. _exercises_summary: + +.. include:: ../labs/exercises-summary.hrst +.. |LAB_NAME| replace:: kernel_modules + +0. Intro +-------- + +Using :command:`cscope` or |LXR|_ find the definitions of the following symbols +in the Linux kernel source code: + +* :c:func:`module_init` and :c:func:`module_exit` + + - what do the two macros do? What is ``init_module`` and ``cleanup_module``? + +* :c:data:`ignore_loglevel` + + - What is this variable used for? + +.. warning:: + If you have problems using :command:`cscope`, it is possible that the database + is not generated. To generate it, use the following command in the kernel + directory: + + .. code-block:: bash + + make ARCH=x86 cscope + +.. note:: + When searching for a structure using :command:`cscope`, use only the + structure name (without :code:`struct`). So, to search for the + structure :c:type:`struct module`, you will use the command + + .. code-block:: bash + + vim -t module + + or, in :command:`vim`, the command + + .. code-block:: bash + + :cs f g module + +.. note:: + For more info on using :command:`cscope`, read the + :ref:`cscope section <cscope_intro>` in the previous lab. + +.. + _[EXERCISE1-BEGIN] + +1. Kernel module +---------------- + +To work with the kernel modules, we will follow the steps described +:ref:`above <exercises_summary>`. + +Generate the skeleton for the task named **1-2-test-mod** then build the module, + by running the following command in :file:`tools/labs`. + +.. code-block:: bash + + $ LABS=kernel_modules make skels + $ make build + +These command will build all the modules in the current +lab skeleton. + +.. warning:: + Until after solving exercise 3, you will get a compilation error for + ``3-error-mod``. To avoid this issue, remove the directory + :file:`skels/kernel_modules/3-error-mod/` and remove the corresponding + line from ``skels/Kbuild``. + +Start the VM using :command:`make console`, and perform the following tasks: + +* load the kernel module. + +* list the kernel modules and check if current module is present + +* unload the kernel module + +* view the messages displayed at loading/unloading the kernel module using + :command:`dmesg` command + +.. note:: Read `Loading/unloading a kernel module`_ section. When unloading + a kernel module, you can specify only the module name + (without extension). + +.. + _[EXERCISE1-END] + +.. + _[EXERCISE2-BEGIN] + + +2. Printk +--------- + +Watch the virtual machine console. Why were the messages displayed directly +to the virtual machine console? + +Configure the system such that the messages are not displayed directly +on the serial console, and they can only be inspected using ``dmesg``. + +.. hint:: One option is to set the console log level by writting + the desired level to ``/proc/sys/kernel/printk``. + Use a value smaller than the level used for the prints in + the source code of the module. + +Load/unload the module again. +The messages should not be printed to the virtual machine console, +but they should be visible when running ``dmesg``. + +.. + _[EXERCISE2-END] + +.. + _[EXERCISE3-BEGIN] + +3. Error +-------- + +Generate the skeleton for the task named **3-error-mod**. Compile the +sources and get the corresponding kernel module. + +Why have compilation +errors occurred? **Hint:** How does this module differ from the previous module? + +Modify the module to solve the cause of those errors, then compile and test +the module. + +.. + _[EXERCISE3-END] + +.. + _[EXERCISE4-BEGIN] + +4. Sub-modules +-------------- + +Inspect the C source files ``mod1.c`` and ``mod2.c`` in :file:`4-multi-mod/`. +Module 2 contains only the definition of a function used by module 1. + +Change the :file:`Kbuild` file to create the ``multi_mod.ko`` module from the +two C source files. + +.. hint:: Read the `Compiling kernel modules`_ section of the lab. + +Compile, copy, boot the VM, load and unload the kernel module. Make sure messages +are properly displayed on the console. + +.. + _[EXERCISE4-END] + +.. + _[EXERCISE5-BEGIN] + +5. Kernel oops +-------------- + +Enter the directory for the task **5-oops-mod** and inspect the +C source file. Notice where the problem will occur. Add the compilation flag +``-g`` in the Kbuild file. + +.. hint:: Read `Compiling kernel modules`_ section of the lab. + +Compile the corresponding module and load it into the kernel. Identify the memory +address at which the oops appeared. + +.. hint:: Read `Debugging`_ section of the lab. To identify the + address, follow the oops message and extract the value of + the instructions pointer (``EIP``) register. + +Determine which instruction has triggered the oops. + +.. hint:: Use the :file:`proc/modules` information to get the load address of + the kernel module. Use, on the physical machine, objdump + and/or addr2line . Objdump needs debugging support for + compilation! Read the lab's `objdump`_ and `addr2line`_ + sections. + +Try to unload the kernel module. Notice that the operation does not +work because there are references from the kernel module within the +kernel since the oops; Until the release of those references (which is +almost impossible in the case of an oops), the module can not be +unloaded. + +.. + _[EXERCISE5-END] + +.. + _[EXERCISE6-BEGIN] + +6. Module parameters +-------------------- + +Enter the directory for the task **6-cmd-mod** and inspect the C +``cmd_mod.c`` source file. Compile and copy the associated module and +load the kernel module to see the printk message. Then unload the +module from the kernel. + +Without modifying the sources, load the kernel module so that the +message shown is ``Early bird gets tired``. + +.. hint:: The str variable can be changed by passing a parameter to + the module. Find more information `here + <http://tldp.org/LDP/lkmpg/2.6/html/x323.html>`_. + +.. _proc-info: + +.. + _[EXERCISE6-END] + +.. + _[EXERCISE7-BEGIN] + +7. Proc info +------------ + +Check the skeleton for the task named **7-list-proc**. Add code to +display the Process ID (``PID``) and the executable name for the current +process. + +Follow the commands marked with ``TODO``. +The information must be displayed both when loading and unloading the +module. + +.. note:: + * In the Linux kernel, a process is described by the + :c:type:`struct task_struct`. Use |LXR|_ or ``cscope`` to find the + definition of :c:type:`struct task_struct`. + + * To find the structure field that contains the name of the + executable, look for the "executable" comment. + + * The pointer to the structure of the current process + running at a given time in the kernel is given by the + :c:macro:`current` variable (of the type + :c:type:`struct task_struct*`). + +.. hint:: To use :c:macro:`current` you'll need to include the header + in which the :c:type:`struct task_struct` is defined, i.e + ``linux/sched.h``. + +Compile, copy, boot the VM and load the module. Unload the kernel module. + +Repeat the loading/unloading operation. Note that the PIDs of the +displayed processes differ. This is because a process is created +from the executable :file:`/sbin/insmod` when the module is loaded and +when the module is unloaded a process is created from the executable +:file:`/sbin/rmmod`. + +.. + _[EXERCISE7-END] + +.. + _[EXTRA-EXERCISE-BEGIN] + +Extra Exercises +=============== + +1. KDB +------ + +Go to the **8-kdb** directory. Activate KDB over the serial port and enter KDB +mode using :command:`SysRq`. Connect to the pseudo-terminal linked to virtiocon0 +using :command:`minicom`, configure KDB to use the hvc0 serial port: + +.. code-block:: bash + + echo hvc0 > /sys/module/kgdboc/parameters/kgdboc + +and enable it using SysRq (:command:`Ctrl + O g`). +Review the current system status (:command:`help` to see the available KDB +commands). Continue the kernel execution using the :command:`go` command. + +Load the :file:`hello_kdb` module. +The module will simulate a bug when writing to the :file:`/proc/hello_kdb_bug` +file. To simulate a bug, use the below command: + +.. code-block:: bash + + echo 1 > /proc/hello_kdb_bug + +After running the above command, at every oops/panic the kernel stops the +execution and enters debug mode. + +Analyze the stacktrace and determine the code that generated the bug. +How can we find out from KDB the address where the module was loaded? + +In parallel, use GDB in a new window to view the code based on KDB information. + +.. hint:: + Load the symbol file. Use :command:`info line`. + +When writing to :file:`/proc/hello_kdb_break`, the module will increment the +:c:data:`kdb_write_address` variable. Enter KDB and set a breakpoint for each +write access of the :c:data:`kdb_write_address` variable. +Return to kernel to trigger a write using: + +.. code-block:: bash + + echo 1 > /proc/hello_kdb_break + +2. PS Module +------------ + +Update the created kernel module at :ref:`proc-info` in order to display +information about all the processes in the system, when inserting the kernel +module, not just about the current process. Afterwards, compare the obtained +result with the output of the :command:`ps` command. + +.. hint:: + * Processes in the system are structured in a circular list. + + * :c:macro:`for_each _...` macros (such as :c:macro:`for_each_process`) are + useful when you want to navigate the items in a list. + + * To understand how to use a feature or a macro, use |LXR|_ or Vim and + :command:`cscope` and search for usage scenarios. + +3. Memory Info +-------------- + +Create a kernel module that displays the virtual memory areas of the current +process; for each memory area it will display the start address and the end +address. + +.. hint:: + * Start from an existing kernel module. + + * Investigate the structures :c:type:`struct task_struct`, + :c:type:`struct mm_struct` and :c:type:`struct vm_area_struct`. A + memory area is indicated by a structure of type :c:type:`struct + vm_area_struct`. + + * Don't forget to include the headers where the necessary structures are + defined. + +4. Dynamic Debugging +-------------------- + +Go to the **9-dyndbg** directory and compile the :code:`dyndbg.ko` module. + +Familiarize yourself with the :code:`debugfs` file system mounted in +:file:`/debug` and analyze the contents of the file +:file:`/debug/dynamic_debug/control`. Insert the :code:`dyndbg.ko` module and +notice the new content of the :file:`dynamic_debug/control` file. + +What appears extra in the respective file? Run the following command: + +.. code-block:: bash + + grep dyndbg /debug/dynamic_debug/control + +Configure :command:`dyndbg` so that only messages marked as "Important" in +:c:func:`my_debug_func` function are displayed when the module is unloaded. +The exercise will only filter out the :c:func:`pr_debug` calls; :c:func:`printk` +calls being always displayed. + +Specify two ways to filter. + +.. hint:: + Read the `Dynamic debugging`_ section and look at the :command:`dyndbg` + options (for example, :command:`line`, :command:`format`). + +Perform the filtering and revise the :file:`dynamic_debug/control` file. What +has changed? How do you know which calls are activated? + +.. hint:: + Check the :command:`dyndbg` flags. Unload the kernel module and observe the + log messages. + +5. Dynamic Debugging During Initialization +------------------------------------------ + +As you have noticed, :c:func:`pr_debug` calls can only be activated /filtered +after module insertion. In some situations, it might be helpful to view the +messages from the initialization of the module. This can be done by using a +default (fake) parameter called :command:`dyndbg` that can be passed as an +argument to initialize the module. With this parameter you can add /delete +:command:`dyndbg` flags. + +.. hint:: + Read the last part of the `Dynamic debugging`_ section and see the available + flags (e.g.: :command:`+/- p`). + +Read the `Debug Messages section at Module Initialization Time +<https://01.org/linuxgraphics/gfx-docs/drm/admin-guide/dynamic-debug-howto.html#debug-messages-at-module-initialization-time>`_ +and insert the module so that the messages in :c:func:`my_debug_func` (called +:c:func:`dyndbg_init`) are also displayed during initialization. + +.. warning:: + In the VM from the lab, you will need to use :command:`insmod` instead of + :command:`modprobe`. + +Without unloading the module, deactivate :c:func:`pr_debug` calls. + +.. hint:: + You can delete the set flags. Unload the kernel module. + +.. + _[EXTRA-EXERCISE-END] diff --git a/refs/pull/405/merge/_sources/labs/kernel_profiling.rst.txt b/refs/pull/405/merge/_sources/labs/kernel_profiling.rst.txt new file mode 100644 index 00000000..34c3810e --- /dev/null +++ b/refs/pull/405/merge/_sources/labs/kernel_profiling.rst.txt @@ -0,0 +1,474 @@ +================ +Kernel Profiling +================ + +Lab Objectives +============== + + * Familiarize yourself with the basics of Linux kernel profiling + * Understanding basic profiling tools + * Learning profiling methodologies and good practices + +Overview +======== + +Up until now we have studied how the different components of the Linux kernel +work, and how to write drivers that interface with them in order to provide +support for devices or protocols. This has helped us understand how the Linux +kernel works, but most people will not get to write kernel drivers. + +Nonetheless, the skills learned will help us to write applications that better +integrate with the whole operating system. In order to do this, one has to have +a good view of both the user space and the kernel space. + +This session aims to merge the work we have done up until now in the kernel +space with real world use cases where we do not write kernel space code, but we +look through the kernel using profiling tools, in order to debug issues that +we're having when writing regular, low-level, applications. + +Another focus of this session will be learning a general methodology for +debugging software issues, and we will approach some tools that give us insight +from the kernel on the way our application runs. + +Profiling Tools +=============== + +The main tool that we will focus our attention on is ``perf``, which offers +support for tracing applications, and also inspecting general aspects of the +system. We will also be using debugging tools that most people have used in +their day to day life, such as ``htop``, ``ps``, ``lsof`` and others. + +perf +---- + +``perf`` is a tool that instruments the CPU using +tracepoints, kprobes and uprobes. This tool allows us to take a look at what +functions are being called at a given point. This allows us to take a peak at +where the kernel is pending the most time, print out call stacks of functions, +and in general log what the CPU is running. + +``perf`` integrates modules such as: +* static tracing +* dynamic tracing +* resource monitoring + +The tracing interface that is offered by perf can be used by itself, using the +``perf`` command together with its subcommands. + + +.. code-block:: bash + + root@qemux86:~# ./skels/kernel_profiling/perf + + usage: perf [--version] [--help] [OPTIONS] COMMAND [ARGS] + + The most commonly used perf commands are: + annotate Read perf.data (created by perf record) and display annotated code + archive Create archive with object files with build-ids found in perf.data file + bench General framework for benchmark suites + buildid-cache Manage build-id cache. + buildid-list List the buildids in a perf.data file + c2c Shared Data C2C/HITM Analyzer. + config Get and set variables in a configuration file. + data Data file related processing + diff Read perf.data files and display the differential profile + evlist List the event names in a perf.data file + ftrace simple wrapper for kernel's ftrace functionality + inject Filter to augment the events stream with additional information + kallsyms Searches running kernel for symbols + kmem Tool to trace/measure kernel memory properties + kvm Tool to trace/measure kvm guest os + list List all symbolic event types + lock Analyze lock events + mem Profile memory accesses + record Run a command and record its profile into perf.data + report Read perf.data (created by perf record) and display the profile + sched Tool to trace/measure scheduler properties (latencies) + script Read perf.data (created by perf record) and display trace output + stat Run a command and gather performance counter statistics + test Runs sanity tests. + timechart Tool to visualize total system behavior during a workload + top System profiling tool. + version display the version of perf binary + probe Define new dynamic tracepoints + + See 'perf help COMMAND' for more information on a specific command. + +In the output above we can see all of perf's subcommands together with a +description of their functionality, the most significant of which are: + +* ``stat`` - displays statistics such as the number of context switches and page + faults; +* ``top`` - an interactive interface where we can inspect the most frequent + function calls and their caller. This interface allows us direct feedback + while profiling; +* ``list`` - lists the static trace point that we can instrument inside the + kernel. These are useful when trying to get an insight from inside the kernel; +* ``probe`` - add a dynamic trace point that instruments a function call in + order to be recorded by perf; +* ``record`` - records function calls and stack traces based on tracing points + defined by the user; It can also record specific function calls and their + stack traces. The record is saved in a file, named ``perf.data`` by default; +* ``report`` - displays the information saved in a perf recording. + +Another way to use perf's interface is through scripts that wrap over perf that +offer a higher level way of looking at events or data, without needing to know +the intricacies of the command. An example of this is the ``iosnoop.sh`` script, +which displays what I/O transfers are taking place. + +ps +-- + +``ps`` is the Linux tool that allows us to monitor the processes that are +running at a given time on the machine, including the kernel threads. This is a +simple and easy to use way of checking at a glance what processes are running on +the CPU, and what is their CPU and memory usage. + +In order to list all the processes running, we use to ``ps aux`` command in the +following way: + +.. code-block:: c + + TODO + root@qemux86:~/skels/kernel_profiling/0-demo# cd + root@qemux86:~# ps aux + USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND + root 1 0.0 0.5 2004 1256 ? Ss 12:06 0:12 init [5] + root 2 0.0 0.0 0 0 ? S 12:06 0:00 [kthreadd] + [...] + root 350 4.5 4.4 11132 10688 hvc0 T 12:07 17:21 ./io-app + root 1358 0.0 0.0 0 0 ? I 14:30 0:00 [kworker/u2:1-e + root 2293 0.1 1.5 5516 3704 ? Ss 18:18 0:00 sshd: root@pts/ + root 2295 0.0 1.3 3968 3232 pts/0 Ss+ 18:19 0:00 -sh + root 2307 0.0 0.0 0 0 ? I 18:19 0:00 [kworker/u2:2-e + root 2350 0.0 0.7 3032 1792 hvc0 R+ 18:26 0:00 ps aux + root 2392 2.6 0.0 0 0 ? D 18:31 0:00 test-script + +One information of note is that the 7th column represents the that of the +process, ``S`` meaning suspended, ``D`` suspended due to I/O, and ``R`` meaning +running. + +time +---- + +The ``time`` command allows us to inspect the amount of time spent by a +process in I/O, running the application code, or running code in kernel space. +This can be useful in order to find out whether an application's issue comes +from running too much in kernel space, so it has some overhead when it does +system calls, or the issue is in the user code. + +.. code-block:: c + + root@qemux86:~# time dd if=/dev/urandom of=./test-file bs=1K count=10 + 10+0 records in + 10+0 records out + 10240 bytes (10 kB, 10 KiB) copied, 0.00299749 s, 3.4 MB/s + + real 0m0.020s + user 0m0.001s + sys 0m0.015s + +In the output above we timed the generation of a file using ``dd``. The result +of the timing is displayed at the bottom of output. The values outputted by the +tool are the following: + +* ``real`` - the amount of time has passed from the start of the application to + its finishing; +* ``user`` - time spent running the ``dd`` code; +* ``sys`` - time spent running kernel code on behalf of the process. + +We see that the sum of the ``user`` and ``sys`` values doesn't add up to the +``real`` value. This happens either when the application runs on multiple cores, +in which case the sum might be higher, or the application sleeps, in which case +the sum is lower. + +top +--- + +``top`` is an application that is found on most systems which lists in real time +the applications that are running on the system. ``top`` runs interactively, and +it auto-refreshes its output, as opposed to ``ps``. We use this tool when we +want a high level of continuous monitoring. + +Profiling Methodology +===================== + +When doing profiling, our goal is to identify the cause of a problem. Usually +this problem is observed by someone when their application doesn't work as +expected. When we say that an application did not work as expected, this can +mean different things for different people. For example, one person might +complain that the application has a slowdown, while another might say that the +application runs on the CPU, but it doesn't output anything. + +The first step in any problem solving context is to understand the default +behaviour of the application we're trying to debug, and to make sure that it is +now not running in the expected parameters. + +Exercises +========= + +.. include:: ../labs/exercises-summary.hrst +.. |LAB_NAME| replace:: kernel_profiling + +.. note:: + + This session will require us to use the ``perf`` tracing tool. When running + natively on our systems, we have to install the + ``linux-tools-<version>-generic`` package using a package manager in order + to run it. Because in our visual machine we don't have access to a package + manager, we will be downloading the ``perf`` binary from `this + <http://swarm.cs.pub.ro/~sweisz/perf>`_ link. Download the application in + the ``skels/kernel_profiling`` directory, and grant in execution + permissions. + +.. warning:: + + When running ``perf``, make sure that you're running the downloaded version, + not the version in the ``PATH`` variable. + +.. note:: + + When going through this session's exercises, we will have to run command in + parallel. In order to do this, we will have to connect to the virtual machine + using SSH. We recommend using the ``core-image-sato-sdk-qemu`` image, since it + has the tools that we need. To run the virtual machine using the + ``core-image-sato-sdk-qemu`` file system, uncomment line 16 in the + ``qemu/Makefile`` file. + +.. note:: + + If you wish to run the ``perf-tools`` based scripts that we have included in + the repository, such as ``iosnoop.sh``, you will have to grant it execution + privilleges, in order to be copied to the virtual machine file system. + +.. note:: + + In order to improve the course of SO2, its components and the way it is + conducted, your opinions are very useful to us. Please fill the feedback form + on `curs.upb.ro platform <https://curs.upb.ro/2022/mod/feedbackadm/view.php?id=15292>`_. + + The form is anonymous and is active between May 22 and June 2, 2023. The + results will be visible to the SO2 team after all the grades have been + marked. + + We invite you to evaluate the activity of the SO2 team and specify its + strengths and weaknesses and your suggestions for improving the subject. + Your feedback is very important to us to increase the quality of the subject + in the coming years. + + We are particularly interested in: + + * What did you not like and what do you think did not go well? + * Why didn't you like it and why do you think it didn't go well? + * What should we do to make things better? + +0. Demo: Profiling I/O Problems +=============================== + +When working with I/O, we have to keep in mind that it is one of the slowest +systems in the operating system, compared to memory, which is an order of +magnitude faster, and scheduling, which deals with what is currently running on +the CPU. + +Because of this, I/O operations have do be thought out, because you might starve +you application by saturating the system with requests. Another issue that you +might face is that the I/O's slow speed might affect your application's +responsiveness, if it waits for the I/O operations to finish. + +Let's take a look at an application and debug its issues. + +We are going to run the ``io-app`` application, from the ``0-demo`` directory. + +In order to inspect what is running on the CPU, and look at the stack of the +process, we can use the ``perf record`` subcommand in the following way: + +.. code-block:: bash + + root@qemux86:~# ./perf record -a -g + Couldn't synthesize bpf events. + ^C[ perf record: Woken up 7 times to write data ] + [ perf record: Captured and wrote 1.724 MB perf.data (8376 samples) ] + + +perf will record values indefinitely, but we can close it using the ``Ctrl+c`` +hotkey. We used the ``-a`` option in order to probe all CPUs, and ``-g`` option, +which record the whole call stack. + +To visualize the recorded information, we will use the ``perf report`` command, +which will bring up a pager which will display the most frequent function calls +that were found on the CPU, and their call stack. + +.. code-block:: bash + + root@qemux86:~# ./perf report --header -F overhead,comm,parent + # Total Lost Samples: 0 + # + # Samples: 8K of event 'cpu-clock:pppH' + # Event count (approx.): 2094000000 + # + # Overhead Command Parent symbol + # ........ ............... ............. + # + 58.63% io-app [other] + | + --58.62%--__libc_start_main + main + __kernel_vsyscall + | + --58.61%--__irqentry_text_end + do_SYSENTER_32 + do_fast_syscall_32 + __noinstr_text_start + __ia32_sys_write + ksys_write + vfs_write + | + --58.60%--ext4_file_write_iter + ext4_buffered_write_iter + [...] + +We have used the ``--header`` in order to print the table header, and ``-F +overhead,comm,parent``, in order to print the percentage of time where the call +stack, the command and the caller. + +We can see that the ``io-app`` command is doing some writes in the file system, +and this contributes to much of the load on the system. + +Armed with this information, we know that there are many I/O calls being done by +the application. In order to look at the size of these requests, we can use the +``iosnoop.sh`` script in order to see how big these requests are. + +.. code-block:: bash + + root@qemux86:~/skels/kernel_profiling# ./iosnoop.sh 1 + Tracing block I/O. Ctrl-C to end. + COMM PID TYPE DEV BLOCK BYTES LATms + io-app 889 WS 254,0 4800512 1310720 2.10 + io-app 889 WS 254,0 4803072 1310720 2.04 + io-app 889 WS 254,0 4805632 1310720 2.03 + io-app 889 WS 254,0 4808192 1310720 2.43 + io-app 889 WS 254,0 4810752 1310720 3.48 + io-app 889 WS 254,0 4813312 1310720 3.46 + io-app 889 WS 254,0 4815872 524288 1.03 + io-app 889 WS 254,0 5029888 1310720 5.82 + io-app 889 WS 254,0 5032448 786432 5.80 + jbd2/vda-43 43 WS 254,0 2702392 8192 0.22 + kworker/0:1H 34 WS 254,0 2702408 4096 0.40 + io-app 889 WS 254,0 4800512 1310720 2.60 + io-app 889 WS 254,0 4803072 1310720 2.58 + [...] + +From this output we see that the ``io-app`` is reading in a loop from the fact +that the first block ``4800512`` is repeating, and that it is doing big reads, +since it is reading one megabyte fer request. This constant looping adds the +load to the system that we're experiencing. + +1. Investigating Reduced Responsiveness +--------------------------------------- + +The ``io.ko`` module, located in the ``kernel_profiling/1-io`` directory, +decreases the system's responsiveness when inserted. We see that the command +line stutters when typing commands, but when running top, we see that the +system's load is not high, and there aren't any processes that are hogging +resources. + +Find out what the ``io.ko`` module is doing and why is it leading to the +stuttering effect that we experience. + +.. hint:: + + Trace all the functions being called and check where the CPU is + spending most of its time. In order to do this, you can run either ``perf + record`` and ``perf report`` to view the output, or ``perf top``. + +2. Launching New Threads +------------------------ + +We want to run the same function in a loop 100 times in parallel. We have +implemented two solutions inside the ``scheduling`` binary file, located in the +``kernel_profiling/2-scheduling`` directory. + +When executing the ``scheduling`` binary, it prints a message in parallel from +100 running instances. We can tune this execution by running the application +either with the first parameter ``0`` or ``1``. + +Find out which solution is better, and why. + +3. Tuning ``cp`` +---------------- + +Our goal is to write a copy of the ``cp`` tool integrated in Linux, which has +been implemented by the ``memory`` binary, in the ``kernel_profiling/3-memory`` +directory. It implements two approaches that we can take for the copy operation: + +* reading the contents of the source file in a buffer in memory using the + ``read()`` system call, and writing that buffer to the destination file using + the ``write()`` system call; +* mapping the source and destination files to memory using the ``mmap`` system + call, and copying the contents of the source file to the destination in + memory. + +Another tunable parameter that we're going to use is the block size of to copies +that we're going to make, either through reads/writes or in memory. + +1) Investigate which of the two copying mechanisms is faster. For this step, you +will use the 1024 block size. + +2) Once you have found which copying mechanism is faster, change the block size +parameter and see which value gives you the best copies. Why? + +4. I/O Latency +-------------- + +We have written a module that reads the content of a disk. Insert the ``bio.ko`` +module, located in the ``4-bio`` module, we see a large spike in the system's +load, as can be seen in the ``top`` command, but we see that the system is still +responsive. + +Investigate what is causing the increased load to the system. Is it an I/O issue, +or is it a scheduling issue? + +.. hint:: + + Try to trace the I/O operations using ``perf``, or use the + ``iosnoop.sh`` script in order to inspect what I/O is happening at a + certain point. + +5. Bad ELF +---------- + +.. note:: + + This is a bonus exercise that has been tested on a native Linux system. + It may run under the QEMU virtual machine, but the behavior was weird in our testing. + We recommend you used a native (or VirtualBox or VMware) Linux system. + +We managed to build (as part of a `Unikraft <https://github.com/unikraft/unikraft>`__ build) an ELF file that is valid when doing static analysis, but that can't be executed. +The file is ``bad_elf``, located in the ``5-bad-elf/`` folder. + +Running it triggers a *segmentation fault* message. +Running it using ``strace`` show an error with ``execve()``. + +.. code:: + + ... skels/kernel_profiling/5-bad-elf$ ./bad_elf + Segmentation fault + + ... skels/kernel_profiling/5-bad-elf$ strace ./bad_elf + execve("./bad_elf", ["./bad_elf"], 0x7ffc3349ba50 /* 70 vars \*/) = -1 EINVAL (Invalid argument) + --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=NULL} --- + +++ killed by SIGSEGV +++ + Segmentation fault (core dumped) + +The ELF file itself is valid: + +.. code:: + + ... skels/kernel_profiling/5-bad-elf$ readelf -a bad_elf + +The issue is to be detected in the kernel. + +Use either ``perf``, or, better yet `ftrace <https://jvns.ca/blog/2017/03/19/getting-started-with-ftrace/>`__ to inspect the kernel function calls done by the program. +Identify the function call that sends out the ``SIGSEGV`` signal. +Identify the cause of the issue. +Find that cause in the `manual page elf(5) <https://linux.die.net/man/5/elf>`__. diff --git a/refs/pull/405/merge/_sources/labs/memory_mapping.rst.txt b/refs/pull/405/merge/_sources/labs/memory_mapping.rst.txt new file mode 100644 index 00000000..e9d15e15 --- /dev/null +++ b/refs/pull/405/merge/_sources/labs/memory_mapping.rst.txt @@ -0,0 +1,499 @@ +============== +Memory mapping +============== + +Lab objectives +============== + +* Understand address space mapping mechanisms +* Learn about the most important structures related to memory management + +Keywords: + +* address space +* :c:func:`mmap` +* :c:type:`struct page` +* :c:type:`struct vm_area_struct` +* :c:type:`struct vm_struct` +* :c:type:`remap_pfn_range` +* :c:func:`SetPageReserved` +* :c:func:`ClearPageReserved` + + +Overview +======== + +In the Linux kernel it is possible to map a kernel address space to a +user address space. This eliminates the overhead of copying user space +information into the kernel space and vice versa. This can be done +through a device driver and the user space device interface +(:file:`/dev`). + +This feature can be used by implementing the :c:func:`mmap` operation +in the device driver's :c:type:`struct file_operations` and using the +:c:func:`mmap` system call in user space. + +The basic unit for virtual memory management is a page, which size is +usually 4K, but it can be up to 64K on some platforms. Whenever we +work with virtual memory we work with two types of addresses: virtual +address and physical address. All CPU access (including from kernel +space) uses virtual addresses that are translated by the MMU into +physical addresses with the help of page tables. + +A physical page of memory is identified by the Page Frame Number +(PFN). The PFN can be easily computed from the physical address by +dividing it with the size of the page (or by shifting the physical +address with PAGE_SHIFT bits to the right). + +.. image:: ../res/paging.png + :width: 49 % + +For efficiency reasons, the virtual address space is divided into +user space and kernel space. For the same reason, the kernel space +contains a memory mapped zone, called **lowmem**, which is contiguously +mapped in physical memory, starting from the lowest possible physical +address (usually 0). The virtual address where lowmem is mapped is +defined by :c:macro:`PAGE_OFFSET`. + +On a 32bit system, not all available memory can be mapped in lowmem and +because of that there is a separate zone in kernel space called +**highmem** which can be used to arbitrarily map physical memory. + +Memory allocated by :c:func:`kmalloc` resides in lowmem and it is +physically contiguous. Memory allocated by :c:func:`vmalloc` is not +contiguous and does not reside in lowmem (it has a dedicated zone in +highmem). + +.. image:: ../res/kernel-virtmem-map.png + :width: 49 % + +Structures used for memory mapping +================================== + +Before discussing about the memory mapping mechanism over a device, +we will present some of the basic structures used by the Linux memory +management subsystem. +Some of the basic structures are: :c:type:`struct page`, +:c:type:`struct vm_area_struct`, :c:type:`struct mm_struct`. + +:c:type:`struct page` +--------------------- + +:c:type:`struct page` is used to embed information about all physical +pages in the system. The kernel has a :c:type:`struct page` structure +for all pages in the system. + +There are many functions that interact with this structure: + +* :c:func:`virt_to_page` returns the page associated with a virtual + address +* :c:func:`pfn_to_page` returns the page associated with a page frame + number +* :c:func:`page_to_pfn` return the page frame number associated with a + :c:type:`struct page` +* :c:func:`page_address` returns the virtual address of a + :c:type:`struct page`; this functions can be called only for pages from + lowmem +* :c:func:`kmap` creates a mapping in kernel for an arbitrary physical + page (can be from highmem) and returns a virtual address that can be + used to directly reference the page + +:c:type:`struct vm_area_struct` +------------------------------- + +:c:type:`struct vm_area_struct` holds information about a contiguous +virtual memory area. The memory areas of a process can be viewed by +inspecting the *maps* attribute of the process via procfs: + +.. code-block:: shell + + root@qemux86:~# cat /proc/1/maps + #address perms offset device inode pathname + 08048000-08050000 r-xp 00000000 fe:00 761 /sbin/init.sysvinit + 08050000-08051000 r--p 00007000 fe:00 761 /sbin/init.sysvinit + 08051000-08052000 rw-p 00008000 fe:00 761 /sbin/init.sysvinit + 092e1000-09302000 rw-p 00000000 00:00 0 [heap] + 4480c000-4482e000 r-xp 00000000 fe:00 576 /lib/ld-2.25.so + 4482e000-4482f000 r--p 00021000 fe:00 576 /lib/ld-2.25.so + 4482f000-44830000 rw-p 00022000 fe:00 576 /lib/ld-2.25.so + 44832000-449a9000 r-xp 00000000 fe:00 581 /lib/libc-2.25.so + 449a9000-449ab000 r--p 00176000 fe:00 581 /lib/libc-2.25.so + 449ab000-449ac000 rw-p 00178000 fe:00 581 /lib/libc-2.25.so + 449ac000-449af000 rw-p 00000000 00:00 0 + b7761000-b7763000 rw-p 00000000 00:00 0 + b7763000-b7766000 r--p 00000000 00:00 0 [vvar] + b7766000-b7767000 r-xp 00000000 00:00 0 [vdso] + bfa15000-bfa36000 rw-p 00000000 00:00 0 [stack] + +A memory area is characterized by a start address, a stop address, +length, permissions. + +A :c:type:`struct vm_area_struct` is created at each :c:func:`mmap` +call issued from user space. A driver that supports the :c:func:`mmap` +operation must complete and initialize the associated +:c:type:`struct vm_area_struct`. The most important fields of this +structure are: + +* :c:member:`vm_start`, :c:member:`vm_end` - the beginning and the end of + the memory area, respectively (these fields also appear in + :file:`/proc/<pid>/maps`); +* :c:member:`vm_file` - the pointer to the associated file structure (if any); +* :c:member:`vm_pgoff` - the offset of the area within the file; +* :c:member:`vm_flags` - a set of flags; +* :c:member:`vm_ops` - a set of working functions for this area +* :c:member:`vm_next`, :c:member:`vm_prev` - the areas of the same process + are chained by a list structure + +:c:type:`struct mm_struct` +-------------------------- + +:c:type:`struct mm_struct` encompasses all memory areas associated +with a process. The :c:member:`mm` field of :c:type:`struct task_struct` +is a pointer to the :c:type:`struct mm_struct` of the current process. + + +Device driver memory mapping +============================ + +Memory mapping is one of the most interesting features of a Unix +system. From a driver's point of view, the memory-mapping facility +allows direct memory access to a user space device. + +To assign a :c:func:`mmap` operation to a driver, the :c:member:`mmap` +field of the device driver's :c:type:`struct file_operations` must be +implemented. If that is the case, the user space process can then use +the :c:func:`mmap` system call on a file descriptor associated with +the device. + +The mmap system call takes the following parameters: + +.. code-block:: c + + void *mmap(caddr_t addr, size_t len, int prot, + int flags, int fd, off_t offset); + +To map memory between a device and user space, the user process must +open the device and issue the :c:func:`mmap` system call with the resulting +file descriptor. + +The device driver :c:func:`mmap` operation has the following signature: + +.. code-block:: c + + int (*mmap)(struct file *filp, struct vm_area_struct *vma); + +The *filp* field is a pointer to a :c:type:`struct file` created when +the device is opened from user space. The *vma* field is used to +indicate the virtual address space where the memory should be mapped +by the device. A driver should allocate memory (using +:c:func:`kmalloc`, :c:func:`vmalloc`, :c:func:`alloc_pages`) and then +map it to the user address space as indicated by the *vma* parameter +using helper functions such as :c:func:`remap_pfn_range`. + +:c:func:`remap_pfn_range` will map a contiguous physical address space +into the virtual space represented by :c:type:`vm_area_struct`: + +.. code-block:: c + + int remap_pfn_range (structure vm_area_struct *vma, unsigned long addr, + unsigned long pfn, unsigned long size, pgprot_t prot); + +:c:func:`remap_pfn_range` expects the following parameters: + +* *vma* - the virtual memory space in which mapping is made; +* *addr* - the virtual address space from where remapping begins; page + tables for the virtual address space between addr and addr + size + will be formed as needed +* *pfn* - the page frame number to which the virtual address should be + mapped +* *size* - the size (in bytes) of the memory to be mapped +* *prot* - protection flags for this mapping + +Here is an example of using this function that contiguously maps the +physical memory starting at page frame number *pfn* (memory that was +previously allocated) to the *vma->vm_start* virtual address: + +.. code-block:: c + + struct vm_area_struct *vma; + unsigned long len = vma->vm_end - vma->vm_start; + int ret ; + + ret = remap_pfn_range(vma, vma->vm_start, pfn, len, vma->vm_page_prot); + if (ret < 0) { + pr_err("could not map the address area\n"); + return -EIO; + } + +To obtain the page frame number of the physical memory we must +consider how the memory allocation was performed. For each +:c:func:`kmalloc`, :c:func:`vmalloc`, :c:func:`alloc_pages`, we must +used a different approach. For :c:func:`kmalloc` we can use something +like: + +.. code-block:: c + + static char *kmalloc_area; + + unsigned long pfn = virt_to_phys((void *)kmalloc_area)>>PAGE_SHIFT; + +while for :c:func:`vmalloc`: + +.. code-block:: c + + static char *vmalloc_area; + + unsigned long pfn = vmalloc_to_pfn(vmalloc_area); + +and finally for :c:func:`alloc_pages`: + +.. code-block:: c + + struct page *page; + + unsigned long pfn = page_to_pfn(page); + +.. attention:: Note that memory allocated with :c:func:`vmalloc` is not + physically contiguous so if we want to map a range allocated + with :c:func:`vmalloc`, we have to map each page individually + and compute the physical address for each page. + +Since the pages are mapped to user space, they might be swapped +out. To avoid this we must set the PG_reserved bit on the page. +Enabling is done using :c:func:`SetPageReserved` while reseting it +(which must be done before freeing the memory) is done with +:c:func:`ClearPageReserved`: + +.. code-block:: c + + void alloc_mmap_pages(int npages) + { + int i; + char *mem = kmalloc(PAGE_SIZE * npages); + + if (!mem) + return mem; + + for(i = 0; i < npages * PAGE_SIZE; i += PAGE_SIZE) + SetPageReserved(virt_to_page(((unsigned long)mem) + i)); + + return mem; + } + + void free_mmap_pages(void *mem, int npages) + { + int i; + + for(i = 0; i < npages * PAGE_SIZE; i += PAGE_SIZE) + ClearPageReserved(virt_to_page(((unsigned long)mem) + i)); + + kfree(mem); + } + + +Further reading +=============== + +* `Linux Device Drivers 3rd Edition - Chapter 15. Memory Mapping and DMA <http://lwn.net/images/pdf/LDD3/ch15.pdf>`_ +* `Linux Device Driver mmap Skeleton <http://www.xml.com/ldd/chapter/book/ch13.html>`_ +* `Driver porting: supporting mmap () <http://lwn.net/Articles/28746/>`_ +* `Device Drivers Concluded <http://www.linuxjournal.com/article/1287>`_ +* `mmap <http://en.wikipedia.org/wiki/Mmap>`_ + +Exercises +========= + +.. include:: ../labs/exercises-summary.hrst +.. |LAB_NAME| replace:: memory_mapping + +1. Mapping contiguous physical memory to userspace +-------------------------------------------------- + +Implement a device driver that maps contiguous physical memory +(e.g. obtained via :c:func:`kmalloc`) to userspace. + +Review the `Device driver memory mapping`_ section, generate the +skeleton for the task named **kmmap** and fill in the areas marked +with **TODO 1**. + +Start with allocating a NPAGES+2 memory area page using :c:func:`kmalloc` +in the module init function and find the first address in the area that is +aligned to a page boundary. + +.. hint:: The size of a page is *PAGE_SIZE*. + + Store the allocated area in *kmalloc_ptr* and the page + aligned address in *kmalloc_area*: + + Use :c:func:`PAGE_ALIGN` to determine *kmalloc_area*. + +Enable the PG_reserved bit of each page with +:c:func:`SetPageReserved`. Clear the bit with +:c:func:`ClearPageReserved` before freeing the memory. + +.. hint:: Use :c:func:`virt_to_page` to translate virtual pages into + physical pages, as required by :c:func:`SetPageReserved` + and :c:func:`ClearPageReserved`. + +For verification purpose (using the test below), fill in the first 4 +bytes of each page with the following values: 0xaa, 0xbb, 0xcc, 0xdd. + +Implement the :c:func:`mmap` driver function. + +.. hint:: For mapping, use :c:func:`remap_pfn_range`. The third + argument for :c:func:`remap_pfn_range` is a page frame number (PFN). + + To convert from virtual kernel address to physical address, + use :c:func:`virt_to_phys`. + + To convert a physical address to its PFN, shift the address + with PAGE_SHIFT bits to the right. + +For testing, load the kernel module and run: + +.. code-block:: shell + + root@qemux86:~# skels/memory_mapping/test/mmap-test 1 + +If everything goes well, the test will show "matched" messages. + +2. Mapping non-contiguous physical memory to userspace +------------------------------------------------------ + +Implement a device driver that maps non-contiguous physical memory +(e.g. obtained via :c:func:`vmalloc`) to userspace. + +Review the `Device driver memory mapping`_ section, generate the +skeleton for the task named **vmmap** and fill in the areas marked +with **TODO 1**. + +Allocate a memory area of NPAGES with :c:func:`vmalloc`. + +.. hint:: The size of a page is *PAGE_SIZE*. + Store the allocated area in *vmalloc_area*. + Memory allocated by :c:func:`vmalloc` is paged aligned. + +Enable the PG_reserved bit of each page with +:c:func:`SetPageReserved`. Clear the bit with +:c:func:`ClearPageReserved` before freeing the memory. + +.. hint:: Use :c:func:`vmalloc_to_page` to translate virtual pages + into physical pages used by the functions + :c:func:`SetPageReserved` and :c:func:`ClearPageReserved`. + +For verification purpose (using the test below), fill in the first 4 +bytes of each page with the following values: 0xaa, 0xbb, 0xcc, 0xdd. + +Implement the mmap driver function. + +.. hint:: To convert from virtual vmalloc address to physical address, + use :c:func:`vmalloc_to_pfn` which returns a PFN directly. + +.. attention:: vmalloc pages are not physically contiguous so it is + needed to use :c:func:`remap_pfn_range` for each page. + + Loop through all virtual pages and for each: + * determine the physical address + * map it with :c:func:`remap_pfn_range` + + Make sure that you determine the physical address + each time and that you use a range of one page for mapping. + +For testing, load the kernel module and run: + +.. code-block:: shell + + root@qemux86:~# skels/memory_mapping/test/mmap-test 1 + +If everything goes well, the test will show "matched" messages. + +3. Read / write operations in mapped memory +------------------------------------------- + +Modify one of the previous modules to allow read / write operations on +your device. This is a didactic exercise to see that the same space +can also be used with the :c:func:`mmap` call and with :c:func:`read` +and :c:func:`write` calls. + +Fill in areas marked with **TODO 2**. + +.. note:: The offset parameter sent to the read / write operation can + be ignored as all reads / writes from the test program will + be done with 0 offsets. + +For testing, load the kernel module and run: + +.. code-block:: shell + + root@qemux86:~# skels/memory_mapping/test/mmap-test 2 + + +4. Display memory mapped in procfs +---------------------------------- + +Using one of the previous modules, create a procfs file in which you +display the total memory mapped by the calling process. + +Fill in the areas marked with **TODO 3**. + +Create a new entry in procfs (:c:macro:`PROC_ENTRY_NAME`, defined in +:file:`mmap-test.h`) that will show the total memory mapped by the process +that called the :c:func:`read` on that file. + +.. hint:: Use :c:func:`proc_create`. For the mode parameter, use 0, + and for the parent parameter use NULL. Use + :c:func:`my_proc_file_ops` for operations. + +In the module exit function, delete the :c:macro:`PROC_ENTRY_NAME` entry +using :c:func:`remove_proc_entry`. + +.. note:: A (complex) use and description of the :c:type:`struct + seq_file` interface can be found here in this `example + <http://tldp.org/LDP/lkmpg/2.6/html/x861.html>`_ . + + For this exercise, just a simple use of the interface + described `here <http://lwn.net/Articles/22355/>`_ is + sufficient. Check the "extra-simple" API described there. + +In the :c:func:`my_seq_show` function you will need to: + +* Obtain the :c:type:`struct mm_struct` structure of the current process + using the :c:func:`get_task_mm` function. + + .. hint:: The current process is available via the *current* variable + of type :c:type:`struct task_struct*`. + +* Iterate through the entire :c:type:`struct vm_area_struct` list + associated with the process. + + .. hint:: Use the variable :c:data:`vma_iterator` and start from + :c:data:`mm->mmap`. Use the :c:member:`vm_next` field of + the :c:type:`struct vm_area_struct` to navigate through + the list of memory areas. Stop when you reach :c:macro:`NULL`. + +* Use *vm_start* and *vm_end* for each area to compute the total size. + +* Use :c:func:`pr_info("%lx %lx\n, ...)` to print *vm_start* and *vm_end* for + each area. + +* To release :c:type:`struct mm_struct`, decrement the reference + counter of the structure using :c:func:`mmput`. + +* Use :c:func:`seq_printf` to write to the file. Show only the total count, + no other messages. Do not even show newline (\n). + +In :c:func:`my_seq_open` register the display function +(:c:func:`my_seq_show`) using :c:func:`single_open`. + +.. note:: :c:func:`single_open` can use :c:macro:`NULL` as its third argument. + +For testing, load the kernel module and run: + +.. code-block:: shell + + root@qemux86:~# skels/memory_mapping/test/mmap-test 3 + +.. note:: The test waits for a while (it has an internal sleep + instruction). As long as the test waits, use the + :command:`pmap` command in another console to see the + mappings of the test and compare those to the test results. diff --git a/refs/pull/405/merge/_sources/labs/networking.rst.txt b/refs/pull/405/merge/_sources/labs/networking.rst.txt new file mode 100644 index 00000000..3eab836d --- /dev/null +++ b/refs/pull/405/merge/_sources/labs/networking.rst.txt @@ -0,0 +1,1262 @@ +============================ +Networking +============================ + +Lab objectives +============== + + * Understanding the Linux kernel networking architecture + * Acquiring practical IP packet management skills using a packet filter or + firewall + * Familiarize yourself with how to use sockets at the Linux kernel level + +Overview +======== + +The development of the Internet has led to an exponential increase in network +applications and, as a consequence, to increasing the speed and productivity +requirements of an operating system's networking subsystem. The networking +subsystem is not an essential component of an operating system kernel (the Linux +kernel can be compiled without networking support). It is, however, quite +unlikely for a computing system (or even an embedded device) to have a +non-networked operating system due to the need for connectivity. Modern operating +systems use the `TCP/IP stack +<https://en.wikipedia.org/wiki/Internet_protocol_suite>`_. Their kernel +implements protocols up to the transport layer, while application layer protocols +are typically implemented in user space (HTTP, FTP, SSH, etc.). + +Networking in user space +------------------------ + +In user space the abstraction of network communication is the socket. The +socket abstracts a communication channel and is the kernel-based TCP/IP stack +interaction interface. An IP socket is associated with an IP address, the +transport layer protocol used (TCP, UDP etc) and a port. Common function calls +that use sockets are: creation (``socket``), initialization +(``bind``), connecting (``connect``), waiting for a connection +(``listen``, ``accept``), closing a socket (``close``). + +Network communication is accomplished via ``read``/``write`` or ``recv``/``send`` calls +for TCP sockets and ``recvfrom``/``sendto`` for UDP sockets. Transmission and +reception operations are transparent to the application, leaving encapsulation +and transmission over network at the kernel's discretion. However, it is +possible to implement the TCP/IP stack in user space using raw sockets (the +``PF_PACKET`` option when creating a socket), or implementing an application +layer protocol in kernel (`TUX web server +<http://en.wikipedia.org/wiki/TUX_web_server>`_). + +For more details about user space programming using sockets, see `Beej's Guide to +Network Programming Using Internet +Sockets <https://www.beej.us/guide/bgnet/>`_. + +Linux networking +================ + +The Linux kernel provides three basic structures for working with network +packets: :c:type:`struct socket`, :c:type:`struct sock` and :c:type:`struct +sk_buff`. + +The first two are abstractions of a socket: + + * :c:type:`struct socket` is an abstraction very close to user space, ie `BSD + sockets <http://en.wikipedia.org/wiki/Berkeley_sockets>`_ used to program + network applications; + * :c:type:`struct sock` or *INET socket* in Linux terminology is the network + representation of a socket. + +The two structures are related: the :c:type:`struct socket` contains an INET +socket field, and the :c:type:`struct sock` has a BSD socket that holds it. + +The :c:type:`struct sk_buff` structure is the representation of a network packet +and its status. The structure is created when a kernel packet is received, +either from the user space or from the network interface. + +The :c:type:`struct socket` structure +------------------------------------- + +The :c:type:`struct socket` structure is the kernel representation of a BSD +socket, the operations that can be executed on it are similar to those offered +by the kernel (through system calls). Common operations with sockets +(creation, initialization/bind, closing, etc.) result in specific system +calls; they work with the :c:type:`struct socket` structure. + +The :c:type:`struct socket` operations are described in :file:`net/socket.c` and +are independent of the protocol type. The :c:type:`struct socket` structure is thus +a generic interface over particular network operations implementations. +Typically, the names of these operations begin with the ``sock_`` prefix. + +.. _SocketStructOps: + +Operations on the socket structure +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Socket operations are: + +Creation +"""""""" + +Creation is similar to calling the :c:func:`socket` function in user space, but the +:c:type:`struct socket` created will be stored in the ``res`` parameter: + + * ``int sock_create(int family, int type, int protocol, struct socket **res)`` + creates a socket after the :c:func:`socket` system call; + * ``int sock_create_kern(struct net *net, int family, int type, int protocol, + struct socket **res)`` creates a kernel socket; + * ``int sock_create_lite(int family, int type, int protocol, struct socket **res)`` + creates a kernel socket without parameter sanity checks. + +The parameters of these calls are as follows: + + * ``net``, where it is present, used as reference to the network namespace used; + we will usually initialize it with ``init_net``; + * ``family`` represents the family of protocols used in the transfer of + information; they usually begin with the ``PF_`` (Protocol Family) string; + the constants representing the family of protocols used are found in + :file:`linux/socket.h`, of which the most commonly used is ``PF_INET``, for + TCP/IP protocols; + * ``type`` is the type of socket; the constants used for this parameter are + found in :file:`linux/net.h`, of which the most used are ``SOCK_STREAM`` for + a connection based source-to-destination communication and ``SOCK_DGRAM`` + for connectionless communication; + * ``protocol`` represents the protocol used and is closely related to the + ``type`` parameter; the constants used for this parameter are found in + :file:`linux/in.h`, of which the most used are ``IPPROTO_TCP`` for TCP and + ``IPPROTO_UDP`` for UDP. + +To create a TCP socket in kernel space, you must call: + +.. code-block:: c + + struct socket *sock; + int err; + + err = sock_create_kern(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); + if (err < 0) { + /* handle error */ + } + +and for creating UDP sockets: + +.. code-block:: c + + struct socket *sock; + int err; + + err = sock_create_kern(&init_net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); + if (err < 0) { + /* handle error */ + } + +A usage sample is part of the :c:func:`sys_socket` system call handler: + +.. code-block:: c + + SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) + { + int retval; + struct socket *sock; + int flags; + + /* Check the SOCK_* constants for consistency. */ + BUILD_BUG_ON(SOCK_CLOEXEC != O_CLOEXEC); + BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) != SOCK_TYPE_MASK); + BUILD_BUG_ON(SOCK_CLOEXEC & SOCK_TYPE_MASK); + BUILD_BUG_ON(SOCK_NONBLOCK & SOCK_TYPE_MASK); + + flags = type & ~SOCK_TYPE_MASK; + if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) + return -EINVAL; + type &= SOCK_TYPE_MASK; + + if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) + flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; + + retval = sock_create(family, type, protocol, &sock); + if (retval < 0) + goto out; + + return sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK)); + } + +Closing +""""""" + +Close connection (for sockets using connection) and release associated +resources: + + * ``void sock_release(struct socket *sock)`` calls the ``release`` function in + the ``ops`` field of the socket structure: + +.. code-block:: c + + void sock_release(struct socket *sock) + { + if (sock->ops) { + struct module *owner = sock->ops->owner; + + sock->ops->release(sock); + sock->ops = NULL; + module_put(owner); + } + //... + } + +Sending/receiving messages +"""""""""""""""""""""""""" + +The messages are sent/received using the following functions: + + * ``int sock_recvmsg(struct socket *sock, struct msghdr *msg, int flags);`` + * ``int kernel_recvmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t num, size_t size, int flags);`` + * ``int sock_sendmsg(struct socket *sock, struct msghdr *msg);`` + * ``int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t num, size_t size);`` + +The message sending/receiving functions will then call the ``sendmsg``/ +``recvmsg`` function in the ``ops`` field of the socket. Functions +containing ``kernel_`` as a prefix are used when the socket is used in the +kernel. + +The parameters are: + + * ``msg``, a :c:type:`struct msghdr` structure, containing the message to be + sent/received. Among the important components of this structure are ``msg_name`` + and ``msg_namelen``, which, for UDP sockets, must be filled in with the address + to which the message is sent (:c:type:`struct sockaddr_in`); + * ``vec``, a :c:type:`struct kvec` structure, containing a pointer to the buffer + containing its data and size; as can be seen, it has a similar structure to the + :c:type:`struct iovec` structure (the :c:type:`struct iovec` structure + corresponds to the user space data, and the :c:type:`struct kvec` structure + corresponds to kernel space data). + +A usage example can be seen in the :c:func:`sys_sendto` system call handler: + +.. code-block:: c + + SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, + unsigned int, flags, struct sockaddr __user *, addr, + int, addr_len) + { + struct socket *sock; + struct sockaddr_storage address; + int err; + struct msghdr msg; + struct iovec iov; + int fput_needed; + + err = import_single_range(WRITE, buff, len, &iov, &msg.msg_iter); + if (unlikely(err)) + return err; + sock = sockfd_lookup_light(fd, &err, &fput_needed); + if (!sock) + goto out; + + msg.msg_name = NULL; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_namelen = 0; + if (addr) { + err = move_addr_to_kernel(addr, addr_len, &address); + if (err < 0) + goto out_put; + msg.msg_name = (struct sockaddr *)&address; + msg.msg_namelen = addr_len; + } + if (sock->file->f_flags & O_NONBLOCK) + flags |= MSG_DONTWAIT; + msg.msg_flags = flags; + err = sock_sendmsg(sock, &msg); + + out_put: + fput_light(sock->file, fput_needed); + out: + return err; + } + +The :c:type:`struct socket` fields +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + /** + * struct socket - general BSD socket + * @state: socket state (%SS_CONNECTED, etc) + * @type: socket type (%SOCK_STREAM, etc) + * @flags: socket flags (%SOCK_NOSPACE, etc) + * @ops: protocol specific socket operations + * @file: File back pointer for gc + * @sk: internal networking protocol agnostic socket representation + * @wq: wait queue for several uses + */ + struct socket { + socket_state state; + + short type; + + unsigned long flags; + + struct socket_wq __rcu *wq; + + struct file *file; + struct sock *sk; + const struct proto_ops *ops; + }; + +The noteworthy fields are: + + * ``ops`` - the structure that stores pointers to protocol-specific functions; + * ``sk`` - The ``INET socket`` associated with it. + +The :c:type:`struct proto_ops` structure +"""""""""""""""""""""""""""""""""""""""" + +The :c:type:`struct proto_ops` structure contains the implementations of the specific +operations implemented (TCP, UDP, etc.); these functions will be called from +generic functions through :c:type:`struct socket` (:c:func:`sock_release`, +:c:func:`sock_sendmsg`, etc.) + +The :c:type:`struct proto_ops` structure therefore contains a number of function +pointers for specific protocol implementations: + +.. code-block:: c + + struct proto_ops { + int family; + struct module *owner; + int (*release) (struct socket *sock); + int (*bind) (struct socket *sock, + struct sockaddr *myaddr, + int sockaddr_len); + int (*connect) (struct socket *sock, + struct sockaddr *vaddr, + int sockaddr_len, int flags); + int (*socketpair)(struct socket *sock1, + struct socket *sock2); + int (*accept) (struct socket *sock, + struct socket *newsock, int flags, bool kern); + int (*getname) (struct socket *sock, + struct sockaddr *addr, + int peer); + //... + } + +The initialization of the ``ops`` field from :c:type:`struct socket` is done in +the :c:func:`__sock_create` function, by calling the :c:func:`create` function, +specific to each protocol; an equivalent call is the implementation of the +:c:func:`__sock_create` function: + +.. code-block:: c + + //... + err = pf->create(net, sock, protocol, kern); + if (err < 0) + goto out_module_put; + //... + +This will instantiate the function pointers with calls specific to the protocol +type associated with the socket. The :c:func:`sock_register` and +:c:func:`sock_unregister` calls are used to fill the ``net_families`` vector. + +For the rest of the socket operations (other than creating, closing, and +sending/receiving a message as described above in the `Operations on the socket +structure`_ section), the functions sent via pointers in this structure will be +called. For example, for ``bind``, which associates a socket with a socket on +the local machine, we will have the following code sequence: + +.. code-block:: c + + #define MY_PORT 60000 + + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = htons (MY_PORT), + .sin_addr = { htonl (INADDR_LOOPBACK) } + }; + + //... + err = sock->ops->bind (sock, (struct sockaddr *) &addr, sizeof(addr)); + if (err < 0) { + /* handle error */ + } + //... + +As you can see, for transmitting the address and port information that +will be associated with the socket, a :c:type:`struct sockaddr_in` is filled. + +The :c:type:`struct sock` structure +----------------------------------- + +The :c:type:`struct sock` describes an ``INET`` socket. Such a structure is +associated with a user space socket and implicitly with a :c:type:`struct +socket` structure. The structure is used to store information about the status +of a connection. The structure's fields and associated operations usually begin +with the ``sk_`` string. Some fields are listed below: + +.. code-block:: c + + struct sock { + //... + unsigned int sk_padding : 1, + sk_no_check_tx : 1, + sk_no_check_rx : 1, + sk_userlocks : 4, + sk_protocol : 8, + sk_type : 16; + //... + struct socket *sk_socket; + //... + struct sk_buff *sk_send_head; + //... + void (*sk_state_change)(struct sock *sk); + void (*sk_data_ready)(struct sock *sk); + void (*sk_write_space)(struct sock *sk); + void (*sk_error_report)(struct sock *sk); + int (*sk_backlog_rcv)(struct sock *sk, + struct sk_buff *skb); + void (*sk_destruct)(struct sock *sk); + }; + +\ + + * ``sk_protocol`` is the type of protocol used by the socket; + * ``sk_type`` is the socket type (``SOCK_STREAM``, ``SOCK_DGRAM``, etc.); + * ``sk_socket`` is the BSD socket that holds it; + * ``sk_send_head`` is the list of :c:type:`struct sk_buff` structures for + transmission; + * the function pointers at the end are callbacks for different situations. + +Initializing the :c:type:`struct sock` and attaching it to a BSD socket is done +using the callback created from ``net_families`` (called +:c:func:`__sock_create`). Here's how to initialize the :c:type:`struct sock` +structure for the IP protocol, in the :c:func:`inet_create` function: + +.. code-block:: c + + /* + * Create an inet socket. + */ + + static int inet_create(struct net *net, struct socket *sock, int protocol, + int kern) + { + + struct sock *sk; + + //... + err = -ENOBUFS; + sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot, kern); + if (!sk) + goto out; + + err = 0; + if (INET_PROTOSW_REUSE & answer_flags) + sk->sk_reuse = SK_CAN_REUSE; + + + //... + sock_init_data(sock, sk); + + sk->sk_destruct = inet_sock_destruct; + sk->sk_protocol = protocol; + sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv; + //... + } + +.. _StructSKBuff: + +The :c:type:`struct sk_buff` structure +-------------------------------------- + +The :c:type:`struct sk_buff` (socket buffer) describes a network packet. The +structure fields contain information about both the header and packet contents, +the protocols used, the network device used, and pointers to the other +:c:type:`struct sk_buff`. A summary description of the content of the structure +is presented below: + +.. code-block:: c + + struct sk_buff { + union { + struct { + /* These two members must be first. */ + struct sk_buff *next; + struct sk_buff *prev; + + union { + struct net_device *dev; + /* Some protocols might use this space to store information, + * while device pointer would be NULL. + * UDP receive path is one user. + */ + unsigned long dev_scratch; + }; + }; + + struct rb_node rbnode; /* used in netem & tcp stack */ + }; + struct sock *sk; + + union { + ktime_t tstamp; + u64 skb_mstamp; + }; + + /* + * This is the control buffer. It is free to use for every + * layer. Please put your private variables there. If you + * want to keep them across layers you have to do a skb_clone() + * first. This is owned by whoever has the skb queued ATM. + */ + char cb[48] __aligned(8); + + unsigned long _skb_refdst; + void (*destructor)(struct sk_buff *skb); + union { + struct { + unsigned long _skb_refdst; + void (*destructor)(struct sk_buff *skb); + }; + struct list_head tcp_tsorted_anchor; + }; + /* ... */ + + unsigned int len, + data_len; + __u16 mac_len, + hdr_len; + + /* ... */ + + __be16 protocol; + __u16 transport_header; + __u16 network_header; + __u16 mac_header; + + /* private: */ + __u32 headers_end[0]; + /* public: */ + + /* These elements must be at the end, see alloc_skb() for details. */ + sk_buff_data_t tail; + sk_buff_data_t end; + unsigned char *head, + *data; + unsigned int truesize; + refcount_t users; + }; + +where: + + * ``next`` and ``prev`` are pointers to the next, and previous element in the + buffer list; + * ``dev`` is the device which sends or receives the buffer; + * ``sk`` is the socket associated with the buffer; + * ``destructor`` is the callback that deallocates the buffer; + * ``transport_header``, ``network_header``, and ``mac_header`` are offsets + between the beginning of the packet and the beginning of the various headers + in the packets. They are internally maintained by the various processing + layers through which the packet passes. To get pointers to the headers, use + one of the following functions: :c:func:`tcp_hdr`, :c:func:`udp_hdr`, + :c:func:`ip_hdr`, etc. In principle, each protocol provides a function to + get a reference to the header of that protocol within a received packet. + Keep in mind that the ``network_header`` field is not set until the packet + reaches the network layer and the ``transport_header`` field is not set + until the packet reaches the transport layer. + +The structure of an `IP header <https://en.wikipedia.org/wiki/IPv4#Header>`_ +(:c:type:`struct iphdr`) has the following fields: + +.. code-block:: c + + struct iphdr { + #if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 ihl:4, + version:4; + #elif defined (__BIG_ENDIAN_BITFIELD) + __u8 version:4, + ihl:4; + #else + #error "Please fix <asm/byteorder.h>" + #endif + __u8 tos; + __be16 tot_len; + __be16 id; + __be16 frag_off; + __u8 ttl; + __u8 protocol; + __sum16 check; + __be32 saddr; + __be32 daddr; + /*The options start here. */ + }; + +where: + + * ``protocol`` is the transport layer protocol used; + * ``saddr`` is the source IP address; + * ``daddr`` is the destination IP address. + +The structure of a `TCP header +<https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_segment_structure>`_ +(:c:type:`struct tcphdr`) has the following fields: + +.. code-block:: c + + struct tcphdr { + __be16 source; + __be16 dest; + __be32 seq; + __be32 ack_seq; + #if defined(__LITTLE_ENDIAN_BITFIELD) + __u16 res1:4, + doff:4, + fin:1, + syn:1, + rst:1, + psh:1, + ack:1, + urg:1, + ece:1, + cwr:1; + #elif defined(__BIG_ENDIAN_BITFIELD) + __u16 doff:4, + res1:4, + cwr:1, + ece:1, + urg:1, + ack:1, + psh:1, + rst:1, + syn:1, + fin:1; + #else + #error "Adjust your <asm/byteorder.h> defines" + #endif + __be16 window; + __sum16 check; + __be16 urg_ptr; + }; + +where: + + * ``source`` is the source port; + * ``dest`` is the destination port; + * ``syn``, ``ack``, ``fin`` are the TCP flags used; for a more detailed view, + see this `diagram + <http://www.eventhelix.com/Realtimemantra/Networking/Tcp.pdf>`_. + +The structure of a `UDP header +<https://en.wikipedia.org/wiki/User_Datagram_Protocol#Packet_structure>`_ +(:c:type:`struct udphdr`) has the following fields: + +.. code-block:: c + + struct udphdr { + __be16 source; + __be16 dest; + __be16 len; + __sum16 check; + }; + +where: + + * ``source`` is the source port; + * ``dest`` is the destination port. + +An example of accessing the information present in the headers of a network +packet is as follows: + +.. code-block:: c + + struct sk_buff *skb; + + struct iphdr *iph = ip_hdr(skb); /* IP header */ + /* iph->saddr - source IP address */ + /* iph->daddr - destination IP address */ + if (iph->protocol == IPPROTO_TCP) { /* TCP protocol */ + struct tcphdr *tcph = tcp_hdr(skb); /* TCP header */ + /* tcph->source - source TCP port */ + /* tcph->dest - destination TCP port */ + } else if (iph->protocol == IPPROTO_UDP) { /* UDP protocol */ + struct udphdr *udph = udp_hdr(skb); /* UDP header */ + /* udph->source - source UDP port */ + /* udph->dest - destination UDP port */ + } + +.. _Conversions: + +Conversions +=========== + +In different systems, there are several ways of ordering bytes in a word +(`Endianness <http://en.wikipedia.org/wiki/Endianness>`_), including: `Big +Endian <http://en.wikipedia.org/wiki/Endianness#Big-endian>`_ (the most +significant byte first) and `Little +Endian <http://en.wikipedia.org/wiki/Endianness#Little-endian>`_ (the least +significant byte first). Since a network interconnects systems with different +platforms, the Internet has imposed a standard sequence for the storage of +numerical data, called `network byte-order +<http://en.wikipedia.org/wiki/Endianness#Endianness_in_networking>`_. In +contrast, the byte sequence for the representation of numerical data on the host +computer is called host byte-order. Data received/sent from/to the network is in +the network byte-order format and should be converted between this format and +the host byte-order. + +For converting we use the following macros: + + * ``u16 htons(u16 x)`` converts a 16 bit integer from host byte-order to + network byte-order (host to network short); + * ``u32 htonl(u32 x)`` converts a 32 bit integer from host byte-order to + network byte-order (host to network long); + * ``u16 ntohs(u16 x)`` converts a 16 bit integer from network byte-order to + host byte-order (network to host short); + * ``u32 ntohl(u32 x)`` converts a 32 bit integer from network byte-order to + host byte-order (network to host long). + +.. _netfilter: + +netfilter +========= + +Netfilter is the name of the kernel interface for capturing network packets for +modifying/analyzing them (for filtering, NAT, etc.). `The netfilter +<http://www.netfilter.org/>`_ interface is used in user space by `iptables +<http://www.frozentux.net/documents/iptables-tutorial/>`_. + +In the Linux kernel, packet capture using netfilter is done by attaching hooks. +Hooks can be specified in different locations in the path followed by a kernel +network packet, as needed. An organization chart with the route followed by a +package and the possible areas for a hook can be found `here +<http://linux-ip.net/nf/nfk-traversal.png>`_. + +The header included when using netfilter is :file:`linux/netfilter.h`. + +A hook is defined through the :c:type:`struct nf_hook_ops` structure: + +.. code-block:: c + + struct nf_hook_ops { + /* User fills in from here down. */ + nf_hookfn *hook; + struct net_device *dev; + void *priv; + u_int8_t pf; + unsigned int hooknum; + /* Hooks are ordered in ascending priority. */ + int priority; + }; + +where: + + * ``pf`` is the package type (``PF_INET``, etc.); + * ``priority`` is the priority; priorities are defined in + :file:`uapi/linux/netfilter_ipv4.h` as follows: + +.. code-block:: c + + enum nf_ip_hook_priorities { + NF_IP_PRI_FIRST = INT_MIN, + NF_IP_PRI_CONNTRACK_DEFRAG = -400, + NF_IP_PRI_RAW = -300, + NF_IP_PRI_SELINUX_FIRST = -225, + NF_IP_PRI_CONNTRACK = -200, + NF_IP_PRI_MANGLE = -150, + NF_IP_PRI_NAT_DST = -100, + NF_IP_PRI_FILTER = 0, + NF_IP_PRI_SECURITY = 50, + NF_IP_PRI_NAT_SRC = 100, + NF_IP_PRI_SELINUX_LAST = 225, + NF_IP_PRI_CONNTRACK_HELPER = 300, + NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX, + NF_IP_PRI_LAST = INT_MAX, + }; + +\ + + + * ``dev`` is the device (network interface) on which the capture is + intended; + + + * ``hooknum`` is the type of hook used. When a packet is captured, the + processing mode is defined by the ``hooknum`` and ``hook`` fields. For IP, + hook types are defined in :file:`linux/netfilter.h`: + +.. code-block:: c + + enum nf_inet_hooks { + NF_INET_PRE_ROUTING, + NF_INET_LOCAL_IN, + NF_INET_FORWARD, + NF_INET_LOCAL_OUT, + NF_INET_POST_ROUTING, + NF_INET_NUMHOOKS + }; + +\ + + * ``hook`` is the handler called when capturing a network packet (packet sent + as a :c:type:`struct sk_buff` structure). The ``private`` field is private information + handed to the handler. The capture handler prototype is defined by the + :c:type:`nf_hookfn` type: + +.. code-block:: c + + struct nf_hook_state { + unsigned int hook; + u_int8_t pf; + struct net_device *in; + struct net_device *out; + struct sock *sk; + struct net *net; + int (*okfn)(struct net *, struct sock *, struct sk_buff *); + }; + + typedef unsigned int nf_hookfn(void *priv, + struct sk_buff *skb, + const struct nf_hook_state *state); + +For the :c:func:`nf_hookfn` capture function, the ``priv`` parameter is the +private information with which the :c:type:`struct nf_hook_ops` was +initialized. ``skb`` is the pointer to the captured network packet. Based on +``skb`` information, packet filtering decisions are made. The function's +``state`` parameter is the status information related to the packet capture, +including the input interface, the output interface, the priority, the hook +number. Priority and hook number are useful for allowing the same function to +be called by several hooks. + +A capture handler can return one of the constants ``NF_*``: + +.. code-block:: c + + /* Responses from hook functions. */ + #define NF_DROP 0 + #define NF_ACCEPT 1 + #define NF_STOLEN 2 + #define NF_QUEUE 3 + #define NF_REPEAT 4 + #define NF_STOP 5 + #define NF_MAX_VERDICT NF_STOP + +``NF_DROP`` is used to filter (ignore) a packet, and ``NF_ACCEPT`` is used to +accept a packet and forward it. + +Registering/unregistering a hook is done using the functions defined in +:file:`linux/netfilter.h`: + +.. code-block:: c + + /* Function to register/unregister hook points. */ + int nf_register_net_hook(struct net *net, const struct nf_hook_ops *ops); + void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *ops); + int nf_register_net_hooks(struct net *net, const struct nf_hook_ops *reg, + unsigned int n); + void nf_unregister_net_hooks(struct net *net, const struct nf_hook_ops *reg, + unsigned int n); + + +.. attention:: + + Prior to version 3.11-rc2 of the Linux kernel, + there are some restrictions related to the use of header extraction functions + from a :c:type:`struct sk_buff` structure set as a parameter in a netfilter + hook. While the IP header can be obtained each time using :c:func:`ip_hdr`, + the TCP and UDP headers can be obtained with :c:func:`tcp_hdr` and + :c:func:`udp_hdr` only for packages that come from inside the system rather + than the ones that are received from outside the system. In the latter case, + you must manually calculate the header offset in the package: + + .. code-block:: c + + // For TCP packets (iph->protocol == IPPROTO_TCP) + tcph = (struct tcphdr*)((__u32*)iph + iph->ihl); + // For UDP packets (iph->protocol == IPPROTO_UDP) + udph = (struct udphdr*)((__u32*)iph + iph->ihl); + + This code works in all filtering situations, so it's recommended to use it + instead of header access functions. + +A usage example for a netfilter hook is shown below: + +.. code-block:: c + + #include <linux/netfilter.h> + #include <linux/netfilter_ipv4.h> + #include <linux/net.h> + #include <linux/in.h> + #include <linux/skbuff.h> + #include <linux/ip.h> + #include <linux/tcp.h> + + static unsigned int my_nf_hookfn(void *priv, + struct sk_buff *skb, + const struct nf_hook_state *state) + { + /* process packet */ + //... + + return NF_ACCEPT; + } + + static struct nf_hook_ops my_nfho = { + .hook = my_nf_hookfn, + .hooknum = NF_INET_LOCAL_OUT, + .pf = PF_INET, + .priority = NF_IP_PRI_FIRST + }; + + int __init my_hook_init(void) + { + return nf_register_net_hook(&init_net, &my_nfho); + } + + void __exit my_hook_exit(void) + { + nf_unregister_net_hook(&init_net, &my_nfho); + } + + module_init(my_hook_init); + module_exit(my_hook_exit); + +netcat +====== + +When developing applications that include networking code, one of the most +used tools is netcat. Also nicknamed "Swiss-army knife for TCP / IP". It allows: + + * Initiating TCP connections; + * Waiting for a TCP connection; + * Sending and receiving UDP packets; + * Displaying traffic in hexdump format; + * Run a program after establishing a connection (eg, a shell); + * Set special options in sent packages. + +Initiating TCP connections: + +.. code-block:: console + + nc hostname port + +Listening to a TCP port: + +.. code-block:: console + + nc -l -p port + +Sending and receiving UDP packets is done adding the ``-u`` command line option. + +.. note:: + + The command is :command:`nc`; often :command:`netcat` is an alias for this + command. There are other implementations of the netcat command, some of which + have slightly different parameters than the classic implementation. Run + :command:`man nc` or :command:`nc -h` to check how to use it. + +For more information on netcat, check the following `tutorial +<https://www.win.tue.nl/~aeb/linux/hh/netcat_tutorial.pdf>`_. + +Further reading +=============== + +#. Understanding Linux Network Internals +#. `Linux IP networking`_ +#. `The TUX Web Server`_ +#. `Beej's Guide to Network Programming Using Internet Sockets`_ +#. `Kernel Korner - Network Programming in the Kernel`_ +#. `Hacking the Linux Kernel Network Stack`_ +#. `The netfilter.org project`_ +#. `A Deep Dive Into Iptables and Netfilter Architecture`_ +#. `Linux Foundation Networking Page`_ + +.. _Linux IP networking: http://www.cs.unh.edu/cnrg/gherrin/ +.. _The TUX Web Server: http://www.stllinux.org/meeting_notes/2001/0719/myTUX/ +.. _Beej's Guide to Network Programming Using Internet Sockets: https://www.beej.us/guide/bgnet/ +.. _Kernel Korner - Network Programming in the Kernel: http://www.linuxjournal.com/article/7660 +.. _Hacking the Linux Kernel Network Stack: http://phrack.org/issues/61/13.html +.. _The netfilter.org project: http://www.netfilter.org/ +.. _A Deep Dive Into Iptables and Netfilter Architecture: https://www.digitalocean.com/community/tutorials/a-deep-dive-into-iptables-and-netfilter-architecture +.. _Linux Foundation Networking Page: http://www.linuxfoundation.org/en/Net:Main_Page + +Exercises +========= + +.. include:: ../labs/exercises-summary.hrst +.. |LAB_NAME| replace:: networking + +.. important:: + + You need to make sure that the ``netfilter`` support is active in kernel. It + is enabled via ``CONFIG_NETFILTER``. To activate it, run :command:`make menuconfig` in + the :file:`linux` directory and check the ``Network packet filtering framework + (Netfilter)`` option in ``Networking support -> Networking options``. If it + was not enabled, enable it (as builtin, not external module - it must be + marked with ``*``). + + +1. Displaying packets in kernel space +------------------------------------- + +Write a kernel module that displays the source address and port for TCP packets +that initiate an outbound connection. Start from the code in +:file:`1-2-netfilter` and fill in the areas marked with ``TODO 1``, taking into +account the comments below. + +You will need to register a netfilter hook of type ``NF_INET_LOCAL_OUT`` as explained +in the `netfilter`_ section. + +`The struct sk_buff structure`_ lets you access the packet headers using +specific functions. The :c:func:`ip_hdr` function returns the IP header as a +pointer to a :c:type:`struct iphdr` structure. The :c:func:`tcp_hdr` function +returns the TCP header as a pointer to a :c:type:`struct tcphdr` structure. + +The `diagram`_ explains how to make a TCP connection. The connection initiation +packet has the ``SYN`` flag set in the TCP header and the ``ACK`` flag cleared. + +.. note:: + + To display the source IP address, use the ``%pI4`` format of the printk + function. Details can be found in the `kernel documentation + <https://www.kernel.org/doc/Documentation/printk-formats.txt>`_ (``IPv4 + addresses`` section). The following is an example code snippet that uses + ``%pI4``: + + .. code-block:: c + + printk("IP address is %pI4\n", &iph->saddr); + + When using the ``%pI4`` format, the argument to printk is a pointer. Hence the + construction ``&iph->saddr`` (with operator & - ampersand) instead of + ``iph->saddr``. + +The source TCP port is, in the TCP header, in the `network byte-order`_ format. +Read through the :ref:`Conversions` section. Use :c:func:`ntohs` to convert. + +For testing, use the :file:`1-2-netfilter/user/test-1.sh` file. The test creates +a connection to the localhost, a connection that will be intercepted and +displayed by the kernel module. The script is copied on the virtual machine by +the :command:`make copy` command only if it is marked as executable. The script +uses the statically compiled :command:`netcat` tool stored in +:file:`skels/networking/netcat`; this program must have execution +permissions. + +After running the checker the output should be similar to the one bellow: + +.. code-block:: c + + # ./test-1.sh + [ 229.783512] TCP connection initiated from 127.0.0.1:44716 + Should show up in filter. + Check dmesg output. + +2. Filtering by destination address +----------------------------------- + +Extend the module from exercise 1 so that you can specify a destination address +by means of a ``MY_IOCTL_FILTER_ADDRESS`` ioctl call. You'll only show packages +containing the specified destination address. To solve this task, fill in the +areas marked with ``TODO 2`` and follow the specifications below. + +To implement the ioctl routine, you must fill out the ``my_ioctl`` function. +Review the section in :ref:`ioctl`. The address sent from user space is in +`network byte-order`_, so there will be **NO need** for conversion. + +.. note:: + + The IP address sent via ``ioctl`` is sent by address, not by value. The + address must be stored in the ``ioctl_set_addr`` variable. For copying use + :c:func:`copy_from_user`. + +To compare the addresses, fill out the ``test_daddr`` function. Addresses in +network byte-order will be used without having to convert addresses (if they +are equal from left to right they will be equal if reversed too). + +The ``test_daddr`` function must be called from the netfilter hook to display +the connection initialization packets for which the destination address is the +one sent through the ioctl routine. The connection initiation packet has the +``SYN`` flag set in the TCP header and the ``ACK`` flag cleared. You have to +check two things: + + * the TCP flags; + * the destination address of the packet (using ``test_addr``). + +For testing, use the :file:`1-2-netfilter/user/test-2.sh` script. This script +needs to compile the :file:`1-2-netfilter/user/test.c` file in the test +executable. Compilation is done automatically on the physical system when +running the :command:`make build` command. The test script is copied to the +virtual machine only if it is marked as executable. The script uses the +statically compiled :command:`netcat` tool in :file:`skels/networking/netcat`; +this executable must have execution permissions. + +After running the checker the output should be similar to the one bellow: + +.. code-block:: console + + # ./test-2.sh + [ 797.673535] TCP connection initiated from 127.0.0.1:44721 + Should show up in filter. + Should NOT show up in filter. + Check dmesg output. + +The test ask for packet filtering first for the ``127.0.0.1`` IP address and +then for the ``127.0.0.2`` IP address. The first connection initiation packet +(to ``127.0.0.1``) is intercepted and displayed by the filter, while the second +(to ``127.0.0.2``) is not intercepted. + +3. Listening on a TCP socket +---------------------------- + +Write a kernel module that creates a TCP socket that listens to connections on +port ``60000`` on the loopback interface (in ``init_module``). Start from the +code in :file:`3-4-tcp-sock` fill in the areas marked with ``TODO 1`` taking +into account the observations below. + +Read the `Operations on the socket structure`_ and `The struct proto_ops +structure`_ sections. + +The ``sock`` socket is a ``server socket`` and must be put in the listening +state. That is, the ``bind`` and ``listen`` operations must be applied to the +socket. For the ``bind`` and ``listen`` equivalent, in kernel space you will +need to call ``sock->ops->...;`` examples of such functions you can call are +``sock->ops->bind``, ``sock->ops->listen`` etc. + +.. note:: + + For example, call ``sock->ops->bind``, or ``sock->ops->listen`` functions, see + how they are called in the :c:func:`sys_bind` and :c:func:`sys_listen` system + call handlers. + + Look for the system call handlers in the ``net/socket.c`` file in the Linux + kernel source code tree. + +.. note:: + + For the second argument of the ``listen`` (backlog) call, use the + ``LISTEN_BACKLOG``. + +Remember to release the socket in the module's exit function and in the area +marked with error labels; use :c:func:`sock_release`. + +For testing, run the :command:`3-4-tcp_sock/test-3.sh` script. The script is +copied on the virtual machine by :command:`make copy` only if it is marked as +executable. + +After running the test, a TCP socket will be displayed by listening to +connections on port ``60000``. + +4. Accepting connections in kernel space +---------------------------------------- + +Expand the module from the previous exercise to allow an external connection (no +need to send any message, only accept new connections). Fill in the areas marked +with ``TODO 2``. + +Read the `Operations on the socket structure`_ and `The struct proto_ops +structure`_ sections. + +For the kernel space ``accept`` equivalent, see the system call handler for +:c:func:`sys_accept4`. Follow the `lnet_sock_accept +<https://elixir.bootlin.com/linux/v4.17/source/drivers/staging/lustre/lnet/lnet/lib-socket.c#L511>`_ +implementation, and how the ``sock->ops->accept`` call is used. Use ``0`` as +the value for the second to last argument (``flags``), and ``true`` for the +last argument (``kern``). + +.. note:: + + Look for the system call handlers in the ``net/socket.c`` file in the Linux + kernel source code tree. + +.. note:: + + The new socket (``new_sock``) must be created with the + :c:func:`sock_create_lite` function and then its operations must be configured + using + + .. code-block:: console + + newsock->ops = sock->ops; + +Print the address and port of the destination socket. To find the peer name of a +socket (its address), refer to the :c:func:`sys_getpeername` system call handler. + +.. note:: + + The first argument for the ``sock->ops->getname`` function will be the + connection socket, ie ``new_sock``, the one initialized with by the ``accept`` + call. + + The last argument of the ``sock->ops->getname`` function will be ``1``, + meaning that we want to know about the endpoint or the peer (*remote end* or + *peer*). + + Display the peer address (indicated by the ``raddr`` variable) using the + ``print_sock_address`` macro defined in the file. + +Release the newly created socket (after accepting the connection) in the module +exit function and after the error label. After adding the ``accept`` code to the +module initialization function, the :command:`insmod` operation will lock until +a connection is established. You can unlock using :command:`netcat` on that +port. Consequently, the test script from the previous exercise will not work. + +For testing, run the :file:`3-4-tcp_sock/test-4.sh` script. The script is copied on +the virtual machine by :command:`make copy` only if it is marked as executable. + +Nothing special will be displayed (in the kernel buffer). The success of the +test will be defined by the connection establishment. Then use ``Ctrl+c`` to +stop the test script, and then you can remove the kernel module. + +5. UDP socket sender +-------------------- + +Write a kernel module that creates a UDP socket and sends the message from the +``MY_TEST_MESSAGE`` macro on the socket to the loopback address on port +``60001``. + +Start from the code in :file:`5-udp-sock`. + +Read the `Operations on the socket structure`_ and `The struct proto_ops +structure`_ sections. + +To see how to send messages in the kernel space, see the :c:func:`sys_send` +system call handler or `Sending/receiving messages`_. + +.. hint:: + + The ``msg_name`` field of the :c:type:`struct msghdr` structure must be + initialized to the destination address (pointer to :c:type:`struct sockaddr`) + and the ``msg_namelen`` field to the address size. + + Initialize the ``msg_flags`` field of the :c:type:`struct msghdr` structure + to ``0``. + + Initialize the ``msg_control`` and ``msg_controllen`` fields of the + :c:type:`struct msghdr` structure to ``NULL`` and ``0`` respectively. + +For sending the message use :c:func:`kernel_sendmsg`. + +The message transmission parameters are retrieved from the kernel space. Cast +the :c:type:`struct iovec` structure pointer to a :c:type:`struct kvec` pointer +in the :c:func:`kernel_sendmsg` call. + +.. hint:: + + The last two parameters of :c:func:`kernel_sendmsg` are ``1`` (number of I/O + vectors) and ``len`` (message size). + +For testing, use the :file:`test-5.sh` file. The script is copied on the virtual +machine by the :command:`make copy` command only if it is marked as executable. +The script uses the statically compiled ``netcat`` tool stored in +:file:`skels/networking/netcat`; this executable must have execution +permissions. + +For a correct implementation, running the :file:`test-5.sh` script will cause +the ``kernelsocket`` message to be displayed like in the output below: + +.. code-block:: console + + /root # ./test-5.sh + + pid=1059 + + sleep 1 + + nc -l -u -p 60001 + + insmod udp_sock.ko + kernelsocket + + rmmod udp_sock + + kill 1059 diff --git a/refs/pull/405/merge/_sources/lectures/address-space.rst.txt b/refs/pull/405/merge/_sources/lectures/address-space.rst.txt new file mode 100644 index 00000000..2150cbe9 --- /dev/null +++ b/refs/pull/405/merge/_sources/lectures/address-space.rst.txt @@ -0,0 +1,1080 @@ +============= +Address Space +============= + +`View slides <address-space-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +Lecture objectives: +=================== + +.. slide:: Address Space + :inline-contents: True + :level: 2 + + * x86 MMU + + * Segmentation + + * Paging + + * TLB + + * Linux Address Space + + * User + + * Kernel + + * High memory + + +x86 MMU +======= + +The x86 MMU has a segmentation and a pagination unit. The segmentation +unit can be used to define logical memory segments defined by a +logical (virtual) start address, a base linear (mapped) address and a +size. A segment can also restrict access based on the access type +(read, execute, write) or the privilege level (we can define some +segments to be accessible only by kernel for example). + +When the CPU makes a memory access, it will use the segmentation unit +to translate the logical address to a linear address, based on the +information in the segment descriptor. + +If pagination is enabled the linear address will be further +transformed into a physical address, using the information from the +page tables. + +Note that the segmentation unit can not be disabled, so if the MMU has +been enabled, segmentation will always be used. + +.. slide:: x86 MMU + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + +--------------+ +------------+ + logical | | linear | | physical + ---------> | Segmentation | --------> | Paging | ----------> + address | Unit | address | Unit | address + | | | | + +--------------+ +------------+ + +Selectors +--------- + +A program can use multiple segments and in order to determine which +segment to use, special registers (named selectors) are used. The +basic selectors that are typically used are CS - "Code Selector", DS - +"Data Selector" and SS - "Stack Selector". + +Instruction fetches will by default use CS, while data access will by +default use DS unless the stack is used (e.g. data access through the +pop and push instructions) in which case SS will be used by default. + +Selectors have three main fields: the index, the table index and the +running privilege level: + + +.. slide:: Selectors + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + 15 3 2 1 0 + +------------+----+-----+ + | | | | + Segment selectors | index | TI | RPL | + (CS, DS, SS, ES, FS, GS) | | | | + +------------+----+-----+ + + .. ifslides:: + + * Selectors: CS, DS, SS, ES, FS, GS + + * Index: indexes the segment descriptor table + + * TI: selects either the GDT or LDT + + * RPL: for CS only indicates the running (current) priviledge level + + * GDTR and LDTR registers points to the base of GDP and LDT + + +The index will be used to determine which entry of the descriptor +table should be used. `TI` is used to select either the Global +Descriptor Table (GDT) or the Local Descriptor Table (LDT). The tables +are effectively arrays that start at the location specified in the +special registers `GDTR` (for GDT) and `LDTR` (for LDT). + +.. note:: LDT was designed so that applications can define their own + particular segments. Although not many applications use this + feature, Linux (and Windows) provide system calls that + allows an application to create their own segments. + +`RPL` is only used for CS and it represents the current privilege +level. There are 4 privilege levels, the highest level being 0 (and +typically used by the kernel) and the lowest is 3 (and typically used +by user applications). + + +Segment descriptor +------------------ + +The CPU will use the `index` field of the selector to access an 8 byte +descriptor: + +.. slide:: Segment descriptor + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + 63 56 44 40 32 + +-------------------------------+---+---+---+---+---------------+---+---+---+---+---------------+-------------------------------+ + | | | D | | A | Segment | | D | | | | + | Base Address 31:24 | G | / | L | V | Limit | P | P | S | Type | Base Address 23:16 | + | | | B | | L | 19:16 | | L | | | | + +-------------------------------+---+---+---+---+---------------+---+---+---+---+---------------+-------------------------------+ + | | | + | Base address 15:0 | Segment Limit 15:0 | + | | | + +---------------------------------------------------------------+---------------------------------------------------------------+ + 31 15 0 + + + * Base: linear address for the start of the segment + + * Limit: size of the segment + + * G: granularity bit: if set the size is in bytes otherwise in 4K pages + + * B/D: data/code + + * Type: code segment, data/stack, TSS, LDT, GDT + + * Protection: the minimum priviledge level required to access the + segment (RPL is checked against DPL) + + +Some of the descriptor fields should be familiar. And that is because +there is some resemblance with Interrupt Descriptors we looked at +previously. + + +Segmentation in Linux +--------------------- + +In Linux, segments are not used to define the stack, code or +data. These will be setup using the paging unit as it allows better +granularity and more importantly it allows Linux to use a generic +approach that works on other architectures (that don't have +segmentation support). + +However, because the segmentation unit can not be disabled Linux must +create 4 generic 0 - 4GB segments for: kernel code, kernel data, user +code and user data. + +Besides these, Linux uses segments for implementing Thread Local +Storage (TLS) together with the `set_thread_area` system call. + +It also uses the TSS segment in order to define the kernel stack to +use when a change of privilege (e.g. system call, interrupt while +running in user-space) occurs. + +.. slide:: Segmentation in Linux + :inline-contents: True + :level: 2 + + .. code-block:: c + + /* + * The layout of the per-CPU GDT under Linux: + * + * 0 - null <=== cacheline #1 + * 1 - reserved + * 2 - reserved + * 3 - reserved + * + * 4 - unused <=== cacheline #2 + * 5 - unused + * + * ------- start of TLS (Thread-Local Storage) segments: + * + * 6 - TLS segment #1 [ glibc's TLS segment ] + * 7 - TLS segment #2 [ Wine's %fs Win32 segment ] + * 8 - TLS segment #3 <=== cacheline #3 + * 9 - reserved + * 10 - reserved + * 11 - reserved + * + * ------- start of kernel segments: + * + * 12 - kernel code segment <=== cacheline #4 + * 13 - kernel data segment + * 14 - default user CS + * 15 - default user DS + * 16 - TSS <=== cacheline #5 + * 17 - LDT + * 18 - PNPBIOS support (16->32 gate) + * 19 - PNPBIOS support + * 20 - PNPBIOS support <=== cacheline #6 + * 21 - PNPBIOS support + * 22 - PNPBIOS support + * 23 - APM BIOS support + * 24 - APM BIOS support <=== cacheline #7 + * 25 - APM BIOS support + * + * 26 - ESPFIX small SS + * 27 - per-cpu [ offset to per-cpu data area ] + * 28 - stack_canary-20 [ for stack protector ] <=== cacheline #8 + * 29 - unused + * 30 - unused + * 31 - TSS for double fault handler + */ + + DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = { + #ifdef CONFIG_X86_64 + /* + * We need valid kernel segments for data and code in long mode too + * IRET will check the segment types kkeil 2000/10/28 + * Also sysret mandates a special GDT layout + * + * TLS descriptors are currently at a different place compared to i386. + * Hopefully nobody expects them at a fixed place (Wine?) + */ + [GDT_ENTRY_KERNEL32_CS] = GDT_ENTRY_INIT(0xc09b, 0, 0xfffff), + [GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(0xa09b, 0, 0xfffff), + [GDT_ENTRY_KERNEL_DS] = GDT_ENTRY_INIT(0xc093, 0, 0xfffff), + [GDT_ENTRY_DEFAULT_USER32_CS] = GDT_ENTRY_INIT(0xc0fb, 0, 0xfffff), + [GDT_ENTRY_DEFAULT_USER_DS] = GDT_ENTRY_INIT(0xc0f3, 0, 0xfffff), + [GDT_ENTRY_DEFAULT_USER_CS] = GDT_ENTRY_INIT(0xa0fb, 0, 0xfffff), + #else + [GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(0xc09a, 0, 0xfffff), + [GDT_ENTRY_KERNEL_DS] = GDT_ENTRY_INIT(0xc092, 0, 0xfffff), + [GDT_ENTRY_DEFAULT_USER_CS] = GDT_ENTRY_INIT(0xc0fa, 0, 0xfffff), + [GDT_ENTRY_DEFAULT_USER_DS] = GDT_ENTRY_INIT(0xc0f2, 0, 0xfffff), + /* + * Segments used for calling PnP BIOS have byte granularity. + * They code segments and data segments have fixed 64k limits, + * the transfer segment sizes are set at run time. + */ + /* 32-bit code */ + [GDT_ENTRY_PNPBIOS_CS32] = GDT_ENTRY_INIT(0x409a, 0, 0xffff), + /* 16-bit code */ + [GDT_ENTRY_PNPBIOS_CS16] = GDT_ENTRY_INIT(0x009a, 0, 0xffff), + /* 16-bit data */ + [GDT_ENTRY_PNPBIOS_DS] = GDT_ENTRY_INIT(0x0092, 0, 0xffff), + /* 16-bit data */ + [GDT_ENTRY_PNPBIOS_TS1] = GDT_ENTRY_INIT(0x0092, 0, 0), + /* 16-bit data */ + [GDT_ENTRY_PNPBIOS_TS2] = GDT_ENTRY_INIT(0x0092, 0, 0), + /* + * The APM segments have byte granularity and their bases + * are set at run time. All have 64k limits. + */ + /* 32-bit code */ + [GDT_ENTRY_APMBIOS_BASE] = GDT_ENTRY_INIT(0x409a, 0, 0xffff), + /* 16-bit code */ + [GDT_ENTRY_APMBIOS_BASE+1] = GDT_ENTRY_INIT(0x009a, 0, 0xffff), + /* data */ + [GDT_ENTRY_APMBIOS_BASE+2] = GDT_ENTRY_INIT(0x4092, 0, 0xffff), + + [GDT_ENTRY_ESPFIX_SS] = GDT_ENTRY_INIT(0xc092, 0, 0xfffff), + [GDT_ENTRY_PERCPU] = GDT_ENTRY_INIT(0xc092, 0, 0xfffff), + GDT_STACK_CANARY_INIT + #endif + } }; + EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); + + +Inspecting selectors and segments +--------------------------------- + +.. slide:: Inspecting selectors and segments + :inline-contents: True + :level: 2 + + |_| + + .. asciicast:: ../res/selectors-and-segments.cast + + +x86 Paging +---------- + +The x86 paging unit support two types of paging: regular and extended paging. + +Regular paging has 2 levels and a fixed page size of 4KB. The linear +address is split in three fields: + +* Directory (the 10 most significant bits) + +* Table (the next 10 most bits) + +* Offset (the least significant 12 bits) + + +.. slide:: Regular paging + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + :--no-separation: + + Virtual Address + +------------+ +------------------+----------------+---------------+ + | CR3 | | DIRECTORY cEEE| TABLE cDDD | OFFSET cCCC| + +------------+ +------------------+----------------+---------------+ + | | | | + | | | | PAGE + | | | | /-----------------------\ + | | | | | | + | | | | | | + | | +-----------+ | +-----------------------+ + | | | +--->| Physical Address cCCC| + | | | +-----------------------+ + | +-----------------+ | | | + | | | PAGE | | + | | | TABLE | | + | | PAGE | /------------\ | | + | | DIRECTORY | | | | | + | | /------------\ | | | | | + | | | | | +------------+ +----> \-----------------------/ + | | | | +---->| cDDD |---+ + | | | | +------------+ + | | | | | | + | | | | | | + | | +------------+ | | + | +----->|cEEE |---+ | | + | +------------+ | | | + | | | +---->\------------/ + | | | + +--------->\------------/ + + +When extended paging is enabled, a single level is used and pages are +4MB. The linear address is split in two fields: + +* Directory (10 most significant bits) + +* Offset (least significant 22 bits) + +.. slide:: Extended paging + :inline-contents: True + :level: 2 + + .. ditaa:: + :--no-separation: + + Virtual Address + +------------+ +-------------------+-----------------------------+ + | CR3 | | DIRECTORY cEEE | OFFSET cDDD | + +------------+ +-------------------+-----------------------------+ + | | | + | | | PAGE + | | | /----------------------\ + | | | | | + | | | | | + | | | +----------------------+ + | | +--->| Physical Address cDDD| + | | +----------------------+ + | +-----------------+ | | + | | | | + | | | | + | | PAGE | | + | | DIRECTORY | | + | | /------------\ | | + | | | | +------------------>\----------------------/ + | | | | | + | | | | | + | | | | | + | | | | | + | | +------------+ | + | +----->| cEEE |-------------+ + | +------------+ + | | | + | | | + +---------->\------------/ + + +Page tables +------------ + +We can mix regular and extended paging, the directory page has a bit +that specifies if extended or regular paging should be used. The +special CR3 register points to the base of the page directory and page +directory entries point to the base of the page table. + +Both page directory and page table have 1024 entries and each entry +has 4 bytes. + +All tables are stored in memory and the page table addresses are +physical addresses. + + +.. slide:: Page tables + :inline-contents: False + :level: 2 + + * Both page directory and page table have 1024 entries + + * Each entry has 4 bytes + + * The special CR3 register point to the base of the page directory + + * Page directory entries points to the base of the page table + + * All tables are stored in memory + + * All table addresses are physical addresses + + +Page table entry fields: + +.. slide:: Page table entry fields + :inline-contents: True + :level: 2 + + * Present/Absent + + * PFN (Page Frame Number): the most 20 significant bits of the physical address + + * Accessed - not updated by hardware (can be used by OS for housekeeping) + + * Dirty - not updated by hardware (can be used by OS for housekeeping) + + * Access rights: Read/Write + + * Privilege: User/Supervisor + + * Page size - only for page directory; if set extended paging is used + + * PCD (page cache disable), PWT (page write through) + + +Linux paging +------------ + +Linux paging uses 4 levels in order to support 64bit +architectures. The diagram below shows how the various virtual address +chunks are used to index the page tables and compute the physical +address. + + +.. slide:: Linux paging + :inline-contents: True + :level: 2 + + .. ditaa:: + :--no-separation: + + Virtual Address + +------------+ +------------------+-----------------+------------------+-------------------+---------------+ + | CR3 | | GLOBAL DIR cEEE| UPPER DIR cDDD| MIDDLE DIR cCCC| TABLE cBBB| OFFSET cAAA | + +------------+ +------------------+-----------------+------------------+-------------------+---------------+ + | | | | | | + | | | | | | PAGE + | | | | | | /----------------------\ + | | | | | | | | + | | | | | | | | + | | +-----------+ | | PAGE GLOBAL | +----------------------+ + | | | | | DIRECTORY +-------->| Physical Address cAAA| + | | | | PAGE MIDDLE | /------------\ +----------------------+ + | +-----------------+ | | DIRECTORY | | | | | + | | | PAGE UPPER | /------------\ | | | | | + | | | DIRECTORY | | | | | | | | + | | PAGE GLOBAL | /------------\ | | | | | | | | + | | DIRECTORY | | | | +------------+ | | | | | + | | /------------\ | | | +--->| cCCC |---+ | +------------+ | | + | | | | | | | +------------+ | +--->| cBBB |---------->\----------------------/ + | | | | | | | | | | +------------+ + | | | | | +------------+ +----->\------------/ | | | + | | | | +---->| cDDD |---+ | | | + | | | | +------------+ +----->\------------/ + | | +------------+ | | + | +----->| cEEE |--+ | | + | +------------+ | | | + | | | +----->\------------/ + | | | + +--------->\------------/ + + +Linux has a common API for creating and walking page tables. Creating +and modifying address spaces for kernel and processes is done using +the same generic code which relies on macros and functions to +translate these generic operations in code that runs on different +architectures. + +Here is an example of how we can translate a virtual address to a +physical address, using the Linux page table APIs: + +.. slide:: Linux APIs for page table handling + :inline-contents: True + :level: 2 + + .. code-block:: c + + struct * page; + pgd_t pgd; + pmd_t pmd; + pud_t pud; + pte_t pte; + void *laddr, *paddr; + + pgd = pgd_offset(mm, vaddr); + pud = pud_offet(pgd, vaddr); + pmd = pmd_offset(pud, vaddr); + pte = pte_offset(pmd, vaddr); + page = pte_page(pte); + laddr = page_address(page); + paddr = virt_to_phys(laddr); + + +In order to support architectures with less than 4 levels of +pagination (such as for x86 32bits) some macros and / or functions are +0 / empty: + +.. slide:: What about platforms with less then 4 levels of pagination? + :inline-contents: True + :level: 2 + + .. code-block:: c + + static inline pud_t * pud_offset(pgd_t * pgd,unsigned long address) + { + return (pud_t *)pgd; + } + + static inline pmd_t * pmd_offset(pud_t * pud,unsigned long address) + { + return (pmd_t *)pud; + } + + +Translation Look-aside Buffer +----------------------------- + +When using virtual memory, due to the table page organization, we may +need an extra 1 (x86 extended paging), 2 (x86 regular paging) or 3 +(x86 64bit) memory access(es). + +A special cache, called Translation Look-aside Buffer (TLB) is used to +speed up translations from virtual address to physical addresses. + +The TLB has the following properties: + +.. slide:: Translation Look-aside Buffer + :inline-contents: True + :level: 2 + + * Caches paging information (PFN, rights, privilege) + + * Content Addressable Memory / Associative Memory + + * Very small (64-128) + + * Very fast (single cycle due to parallel search implementation) + + * CPUs usually have two TLBs: i-TLB (code) and d-TLB (data) + + * TLB miss penalty: up hundreds of cycles + + +As with other caches, we must be careful to not create consistency +issues. + +For example, when changing the mapping of one page to point to a +different physical memory location in the page tables, we must +invalidate the associated TLB entry. Otherwise, the MMU will do the +translation to the old physical address instead of the new physical +address. + +The x86 platform supports TLB invalidation through two types of +operations. + +.. slide:: TLB invalidation + :inline-contents: True + :level: 2 + + Single address invalidation: + + .. code-block:: asm + + mov $addr, %eax + invlpg %(eax) + + Full invalidation: + + .. code-block:: asm + + mov %cr3, %eax + mov %eax, %cr3 + + +Linux address space +=================== + +Address space options for 32bit systems +--------------------------------------- + +There are two main options for implementing kernel and user space: +either dedicated address spaces for each, or split a shared address +space. + +.. slide:: Address space options for 32bit systems + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + +-------------------+ +-------------------+ 0xFFFFFFFF +-------------------+ ^ + | | | | | | | + | | | | | | | Kernel space + | | | | | | | + | User | | Kernel | 0xC0000000 +-------------------+ v + | space | | space | | | ^ + | | | | | | | User space + | | | | | | | + | | | | | | | + | | | | | | | + | | | | | | | + | | | | | | | + | | | | | | | + | | | | | | | + +-------------------+ +-------------------+ 0x00000000 +-------------------+ v + + + (a) 4/4 split (b) 1/3 or2/2 split + + +Each has advantages and disadvantages: + +.. slide:: Advantages and disadvantages + :inline-contents: True + :level: 2 + + * Disadvantages for dedicated kernel space: + + * Fully invalidating the TLB for every system call + + * Disadvantages for shared address space + + * Less address space for both kernel and user processes + + +Linux is using a split address space for 32 bit systems, although in +the past there were options for supporting 4/4s split or dedicated +kernel address space (on those architecture that supports it, +e.g. x86). Linux always uses split address space for 64 bit systems. + +On overview of the Linux address space is presented below: + +.. slide:: Linux address space for 32bit systems + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + :--no-separation: + + : : : : + | User space | Lowmem | Highmem | + | arbitrary mapping | linear mapping | arbitrary mapping | + | | | | + +----+----+--------------------+----+------+----+----+---------------+----+----+-----+----+----+ Virtual + |cEEE|cGRE|cEEE |cRED|cEEE |cAAA|cGRE| cAAA |cEEE|cGRE|cEEE |cRED|cEEE| memory + | | | | | | | | | | | | | | + +----+----+--------------------+----+------+----+----+---------------+----+----+-----+----+----+ + | | 3G | 3.896G | | 4G + | +-------+ | | | + | | | | | + |<----------------------------------+------+<-------------------------+ | + | | | + | |<-------------------------------------------+ + | | + v V + +----+----+---------------+--------------+----+------------------------------------------------+ Physical + |cAAA|cGRE| cAAA | cEEE |cRED| cEEE | memory + | | | | | | | + +----+----+---------------+--------------+----+------------------------------------------------+ + 896MB + + +Linear mappings +--------------- + +Linear mappings refer to particular way of mapping virtual pages to +physical pages, where virtual page V, V + 1, ... V + n is mapped to +physical pages P, P + 1, ..., P + n. + +To understand the necessity of linear mappings, we should look at +common kernel operations that involves using both the virtual and +physical address of a page such as an I/O transfer: + +.. slide:: Virtual to physical address translations for I/O transfers + :inline-contents: True + :level: 2 + + * Use the virtual address of a kernel buffer in order to copy to + data from from user space + + * Walk the page tables to transform the kernel buffer virtual + address to a physical address + + * Use the physical address of the kernel buffer to start a DMA + transfer + + +However, if we use linear mappings and the kernel buffers are in the +linear mapping area, then: + +.. slide:: Linear mappings + :inline-contents: True + :level: 2 + + * Virtual to physical address space translation is reduced to one + operation (instead of walking the page tables) + + * Less memory is used to create the page tables + + * Less TLB entries are used for the kernel memory + + +Highmem +------- + +The "highmem" part of the virtual address space is used to create +arbitrary mappings (as opposed to linear mappings in lowmem). On 32bit +systems the highmem area is absolutely required in order to access +physical memory outside of lowmem. However, highmem is also used on +64bit systems but the use-case there is mainly to allow arbitrary +mappings in kernel space. + + +.. slide:: Highmem + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + +--------+ 8MB +-----------+ 4KB +-----------+ +-----------+ 4KB +------------+-----------+------------+ + | | | | | | | | | Persistent | Temporary | Fix-mapped | + | Lowmem | <-----> | VMAP area | <-----> | VMAP area | ... | VMAP area | <-----> | Kernel | Kernel | linear | + | | | | | | | | | Mappings | Mappings | addresses | + +--------+ +-----------+ +-----------+ +-----------+ +------------+-----------+------------+ + : : + | 128MB | + |<------------------------------------------------------------------------------------------------------------->| + | | + | | + VMALLOC_START 4GB + (896MB) + + +There are multiple types of mappings in the highmem area: + +* Multi-page permanent mappings (vmalloc, ioremap) + +* Temporary 1 page mappings (atomic_kmap) + +* Permanent 1 page mappings (kmap, fix-mapped linear addresses) + + +Multiple page mappings allows mapping of ranges of physical memory +into the highmem area. Each such mapping is guarded by a +non-accessible page to catch buffer overflow and underflow errors. + + +The APIs that maps multiple pages into highmem are: + +.. slide:: Multi-page permanent mappings + :inline-contents: True + :level: 2 + + .. code-block:: c + + void* vmalloc(unsigned long size); + void vfree(void * addr); + + void *ioremap(unsigned long offset, unsigned size); + void iounmap(void * addr); + +:c:func:`vmalloc` is used to allocate non-contiguous system memory +pages as a contiguous segment in the kernel virtual address space. It +is usefully when allocating large buffers because due to fragmentation +it is unlikely to find free large chunks of physical contiguous memory. + +:c:func:`ioremap` is used to map device memory or device registers +into the kernel address space. It maps a contiguous physical memory +range into highmem with page caching disabled. + +Fixed-mapped linear addresses +----------------------------- + +Fixed-mapped linear addresses are a special class of singular page +mappings that are used for accessing registers of commonly used +peripherals such as the APIC or IO APIC. + +Typical I/O access for peripherals is to use a base (the kernel +virtual address space where the peripheral registers are mapped) + +offsets for various registers. + +In order to optimize access, the base is reserved at compile time +(e.g. 0xFFFFF000). Since the base is constant, the various register +accesses of the form `base + register offset` will also be constant +and thus the compiler will avoid generating an extra instruction. + +In summary, fixed-mapped linear addresses are: + +.. slide:: Fixed-mapped linear addresses + :inline-contents: True + :level: 2 + + * Reserved virtual addresses (constants) + + * Mapped to physical addresses during boot + + .. code-block:: c + + set_fixmap(idx, phys_addr) + set_fixmap_nocache(idx, phys_addr) + + +These addresses are architecture defined and, as an example, this is +the map for x86: + +.. slide:: Fixed-mapped linear addresses + :inline-contents: True + :level: 2 + + .. code-block:: c + + /* + * Here we define all the compile-time 'special' virtual + * addresses. The point is to have a constant address at + * compile time, but to set the physical address only + * in the boot process. + * for x86_32: We allocate these special addresses + * from the end of virtual memory (0xfffff000) backwards. + * Also this lets us do fail-safe vmalloc(), we + * can guarantee that these special addresses and + * vmalloc()-ed addresses never overlap. + * + * These 'compile-time allocated' memory buffers are + * fixed-size 4k pages (or larger if used with an increment + * higher than 1). Use set_fixmap(idx,phys) to associate + * physical memory with fixmap indices. + * + * TLB entries of such buffers will not be flushed across + * task switches. + */ + + enum fixed_addresses { + #ifdef CONFIG_X86_32 + FIX_HOLE, + #else + #ifdef CONFIG_X86_VSYSCALL_EMULATION + VSYSCALL_PAGE = (FIXADDR_TOP - VSYSCALL_ADDR) >> PAGE_SHIFT, + #endif + #endif + FIX_DBGP_BASE, + FIX_EARLYCON_MEM_BASE, + #ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT + FIX_OHCI1394_BASE, + #endif + #ifdef CONFIG_X86_LOCAL_APIC + FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */ + #endif + #ifdef CONFIG_X86_IO_APIC + FIX_IO_APIC_BASE_0, + FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS - 1, + #endif + #ifdef CONFIG_X86_32 + FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ + FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, + #ifdef CONFIG_PCI_MMCONFIG + FIX_PCIE_MCFG, + #endif + + +Notice how easy is to do the conversion between the virtual address +and the fixed address indexes: + +.. slide:: Conversion between virtual address fixed address indexes + :inline-contents: True + :level: 2 + + + .. code-block:: c + + #define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) + #define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT) + + #ifndef __ASSEMBLY__ + /* + * 'index to address' translation. If anyone tries to use the idx + * directly without translation, we catch the bug with a NULL-deference + * kernel oops. Illegal ranges of incoming indices are caught too. + */ + static __always_inline unsigned long fix_to_virt(const unsigned int idx) + { + BUILD_BUG_ON(idx >= __end_of_fixed_addresses); + return __fix_to_virt(idx); + } + + static inline unsigned long virt_to_fix(const unsigned long vaddr) + { + BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START); + return __virt_to_fix(vaddr); + } + + + inline long fix_to_virt(const unsigned int idx) + { + if (idx >= __end_of_fixed_addresses) + __this_fixmap_does_not_exist(); + return (0xffffe000UL - (idx << PAGE_SHIFT)); + } + + +Temporary mappings +------------------ + +Temporary mappings can be used to map a single physical page, very +fast, in kernel space. It can be used in interrupt context but the +atomic kmap section, defined in between the :c:func:`kmap_atomic` and +:c:func:`kunmap_atomic` can not be preempted. That is why these are +called temporary mappings, as they can only be used momentarily. + + +.. slide:: Temporary mappings + :inline-contents: false + :level: 2 + + * :c:func:`kmap_atomic`, :c:func:`kunmap_atomic` + + * No context switch is permitted in atomic kmap section + + * Can be used in interrupt context + + * No locking required + + * Only invalidates on TLB entry + + +Temporary mappings are very fast because there is no locking or +searching required and also there is no full TLB invalidation, just +the particular virtual page will be TLB invalidated. + +Here are some code snippets that show that temporary mappings are +implemented: + +.. slide:: Temporary mappings implementation + :inline-contents: True + :level: 2 + + + .. code-block:: c + + #define kmap_atomic(page) kmap_atomic_prot(page, kmap_prot) + + void *kmap_atomic_high_prot(struct page *page, pgprot_t prot) + { + unsigned long vaddr; + int idx, type; + + type = kmap_atomic_idx_push(); + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); + BUG_ON(!pte_none(*(kmap_pte-idx))); + set_pte(kmap_pte-idx, mk_pte(page, prot)); + arch_flush_lazy_mmu_mode(); + + return (void *)vaddr; + } + EXPORT_SYMBOL(kmap_atomic_high_prot); + + static inline int kmap_atomic_idx_push(void) + { + int idx = __this_cpu_inc_return(__kmap_atomic_idx) - 1; + + #ifdef CONFIG_DEBUG_HIGHMEM + WARN_ON_ONCE(in_irq() && !irqs_disabled()); + BUG_ON(idx >= KM_TYPE_NR); + #endif + return idx; + } + + +Notice that fix-mapped linear addresses and a stack like approach is +used: each CPU has KM_TYPE_NR reserved entries which are used in a +first code first serve option. This allows using multiple temporary +mappings at once, for example one in process context, one in an +interrupt handler, and a few more in tasklets or softirqs. + +.. slide:: Implementation of temporary mappings + :inline-contents: false + :level: 2 + + * Use the fixed-mapped linear addresses + + * Every CPU has KM_TYPE_NR reserved entries to be used for + temporary mappings + + * Stack like selection: every user picks the current entry and + increments the "stack" counter + +Permanent mappings +------------------ + +Permanent mappings allows users to hold on to a mapping for long +(undefined) periods of time which means that context switch are +allowed after a mapping and before releasing it. + +This flexibility comes with a price though. A search operation is +performed to find a free entry and they can not be used in interrupt +context - the operation that tries to find a free virtual address page +may block. There is a limited number of permanent mappings available +(topically one page is reserved for permanent mappings) + +.. slide:: Permanent mappings + :inline-contents: false + :level: 2 + + * :c:func:`kmap`, :c:func:`kunmap` + + * Context switches are allowed + + * Only available in process context + + * One page table is reserved for permanent mappings + + * Page counter + + * 0 - page is not mapped, free and ready to use + + * 1 - page is not mapped, may be present in TLB needs flushing before using + + * N - page is mapped N-1 times + + diff --git a/refs/pull/405/merge/_sources/lectures/arch.rst.txt b/refs/pull/405/merge/_sources/lectures/arch.rst.txt new file mode 100644 index 00000000..ef97e871 --- /dev/null +++ b/refs/pull/405/merge/_sources/lectures/arch.rst.txt @@ -0,0 +1,217 @@ +================== +Architecture Layer +================== + +`View slides <arch-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +Lecture objectives: +=================== + +.. slide:: Introduction + :inline-contents: True + :level: 2 + + * Overview of the arch layer + + * Overview of the boot process + + +Overview of the arch layer +========================== + +.. slide:: Overview of the arch layer + :level: 2 + :inline-contents: True + + .. ditaa:: + :height: 100% + + +---------------+ +--------------+ +---------------+ + | Application 1 | | Application2 | ... | Application n | + +---------------+ +--------------+ +---------------+ + | | | + v v v + +--------------------------------+------------------------+ + | Kernel core & subsystems | Generic Drivers | + +--------------------------------+------------------------+ + | Generic Architecture Code | + +---------------------------------------------------------+ + | Architecture Specific Code | + | | + | +-----------+ +--------+ +---------+ +--------+ | + | | Bootstrap | | Memory | | Threads | | Timers | | + | +-----------+ +--------+ +---------+ +--------+ | + | +------+ +----------+ +------------------+ | + | | IRQs | | Syscalls | | Platform Drivers | | + | +------+ +----------+ +------------------+ | + | +------------------+ +---------+ +---------+ | + | | Platform Drivers | | machine | ... | machine | | + | +------------------+ +---------+ +---------+ | + +---------------------------------------------------------+ + | | | + v v v + +--------------------------------------------------------+ + | Hardware | + +--------------------------------------------------------+ + + +Boot strap +---------- + +.. slide:: Bootstrap + :level: 2 + :inline-contents: True + + * The first kernel code that runs + + * Typically runs with the MMU disabled + + * Move / Relocate kernel code + + +Boot strap +---------- + +.. slide:: Bootstrap + :level: 2 + :inline-contents: True + + * The first kernel code that runs + + * Typically runs with the MMU disabled + + * Copy bootloader arguments and determine kernel run location + + * Move / relocate kernel code to final location + + * Initial MMU setup - map the kernel + + + +Memory setup +------------ + +.. slide:: Memory Setup + :level: 2 + :inline-contents: True + + * Determine available memory and setup the boot memory allocator + + * Manages memory regions before the page allocator is setup + + * Bootmem - used a bitmap to track free blocks + + * Memblock - deprecates bootmem and adds support for memory ranges + + * Supports both physical and virtual addresses + + * support NUMA architectures + + +MMU management +-------------- + +.. slide:: MMU management + :level: 2 + :inline-contents: True + + * Implements the generic page table manipulation APIs: types, + accessors, flags + + * Implement TLB management APIs: flush, invalidate + + +Thread Management +----------------- + +.. slide:: Thread Management + :level: 2 + :inline-contents: True + + * Defines the thread type (struct thread_info) and implements + functions for allocating threads (if needed) + + * Implement :c:func:`copy_thread` and :c:func:`switch_context` + + +Time Management +---------------- + +.. slide:: Timer Management + :level: 2 + :inline-contents: True + + * Setup the timer tick and provide a time source + + * Mostly transitioned to platform drivers + + * clock_event_device - for scheduling timers + + * clocksource - for reading the time + + +IRQs and exception management +----------------------------- + +.. slide:: IRQs and exception management + :level: 2 + :inline-contents: True + + * Define interrupt and exception handlers / entry points + + * Setup priorities + + * Platform drivers for interrupt controllers + + +System calls +------------ + +.. slide:: System calls + :level: 2 + :inline-contents: True + + * Define system call entry point(s) + + * Implement user-space access primitives (e.g. copy_to_user) + + +Platform Drivers +---------------- + +.. slide:: Platform Drivers + :level: 2 + :inline-contents: True + + * Platform and architecture specific drivers + + * Bindings to platform device enumeration methods (e.g. device tree + or ACPI) + +Machine specific code +--------------------- + +.. slide:: Machine specific code + :level: 2 + :inline-contents: True + + * Some architectures use a "machine" / "platform" abstraction + + * Typical for architecture used in embedded systems with a lot of + variety (e.g. ARM, powerPC) + + +Overview of the boot process +============================ + + +.. slide:: Boot flow inspection + :level: 2 + :inline-contents: True + + + .. asciicast:: ../res/boot.cast diff --git a/refs/pull/405/merge/_sources/lectures/debugging.rst.txt b/refs/pull/405/merge/_sources/lectures/debugging.rst.txt new file mode 100644 index 00000000..dc384855 --- /dev/null +++ b/refs/pull/405/merge/_sources/lectures/debugging.rst.txt @@ -0,0 +1,942 @@ +========= +Debugging +========= + +`View slides <debugging-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +Lecture objectives: +=================== + +One essential part of Linux kernel development is debugging. In user space we had +the support of the kernel so we could easily stop processes and use gdb to inspect +their behavior. In the kernel, in order to use gdb we need to use hypervisor like +QEMU or JTAG based hardware interfaces which are not always available. The Linux +kernel provides a set of tools and debug options useful for investigating abnormal +behavior. + +In this lecture we will learn about: + +.. slide:: Debugging + :inline-contents: True + :level: 2 + + * decoding an oops/panic + * list debugging + * memory debugging + * locking debugging + * profiling + +Decoding an oops/panic +====================== + +An oops is an inconsistent state that the kernel detects inside itself. +Upon detecting an oops the Linux kernel kills the offending process, +prints information that can help debug the problem and continues execution +but with limited reliability. + +Lets consider the following Linux kernel module: + +.. slide:: Oops module + :inline-contents: True + :level: 2 + + .. code-block:: c + + static noinline void do_oops(void) + { + *(int*)0x42 = 'a'; + } + + static int so2_oops_init(void) + { + pr_info("oops_init\n"); + do_oops(); + + return 0; + } + + static void so2_oops_exit(void) + { + pr_info("oops exit\n"); + } + + module_init(so2_oops_init); + module_exit(so2_oops_exit); + +Notice that ''do_oops'' function tries to write at an invalid memory address. Because the kernel +cannot find a suitable physical page were to write, it kills the insmod task in the context of +which ''do_oops'' runs. Then it prints the following oops message: + + .. code-block:: bash + + root@qemux86:~/skels/debugging/oops# insmod oops.ko + BUG: unable to handle kernel NULL pointer dereference at 00000042 + IP: do_oops+0x8/0x10 [oops] + *pde = 00000000 + Oops: 0002 [#1] SMP + Modules linked in: oops(O+) + CPU: 0 PID: 234 Comm: insmod Tainted: G O 4.15.0+ #3 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014 + EIP: do_oops+0x8/0x10 [oops] + EFLAGS: 00000292 CPU: 0 + EAX: 00000061 EBX: 00000000 ECX: c7ed3584 EDX: c7ece8dc + ESI: c716c908 EDI: c8816010 EBP: c7257df0 ESP: c7257df0 + DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 + CR0: 80050033 CR2: 00000042 CR3: 0785f000 CR4: 00000690 + Call Trace: + so2_oops_init+0x17/0x20 [oops] + do_one_initcall+0x37/0x170 + ? cache_alloc_debugcheck_after.isra.19+0x15f/0x2f0 + ? __might_sleep+0x32/0x90 + ? trace_hardirqs_on_caller+0x11c/0x1a0 + ? do_init_module+0x17/0x1c2 + ? kmem_cache_alloc+0xa4/0x1e0 + ? do_init_module+0x17/0x1c2 + do_init_module+0x46/0x1c2 + load_module+0x1f45/0x2380 + SyS_init_module+0xe5/0x100 + do_int80_syscall_32+0x61/0x190 + entry_INT80_32+0x2f/0x2f + EIP: 0x44902cc2 + EFLAGS: 00000206 CPU: 0 + EAX: ffffffda EBX: 08afb050 ECX: 0000eef4 EDX: 08afb008 + ESI: 00000000 EDI: bf914dbc EBP: 00000000 ESP: bf914c1c + DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 007b + Code: <a3> 42 00 00 00 5d c3 90 55 89 e5 83 ec 04 c7 04 24 24 70 81 c8 e8 + EIP: do_oops+0x8/0x10 [oops] SS:ESP: 0068:c7257df0 + CR2: 0000000000000042 + ---[ end trace 011848be72f8bb42 ]--- + Killed + +An oops contains information about the IP which caused the fault, register status, process, +CPU on which the fault happend like below: + +.. slide:: Oops information + :inline-contents: True + :level: 2 + + .. code-block:: bash + + root@qemux86:~/skels/debugging/oops# insmod oops.ko + BUG: unable to handle kernel NULL pointer dereference at 00000042 + IP: do_oops+0x8/0x10 [oops] + *pde = 00000000 + Oops: 0002 [#1] SMP + Modules linked in: oops(O+) + CPU: 0 PID: 234 Comm: insmod Tainted: G O 4.15.0+ #3 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014 + EIP: do_oops+0x8/0x10 [oops] + CR0: 80050033 CR2: 00000042 CR3: 0785f000 CR4: 00000690 + EIP: 0x44902cc2 + EFLAGS: 00000206 CPU: 0 + EAX: ffffffda EBX: 08afb050 ECX: 0000eef4 EDX: 08afb008 + ESI: 00000000 EDI: bf914dbc EBP: 00000000 ESP: bf914c1c + DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 007b + Code: <a3> 42 00 00 00 5d c3 90 55 89 e5 83 ec 04 c7 04 24 24 70 81 c8 e8 + Killed + +Another important thing that an oops can provide is the stack trace of functions called before +the fault happend: + +.. slide:: Oops stacktrace + :inline-contents: True + :level: 2 + + + .. code-block:: bash + + root@qemux86:~/skels/debugging/oops# insmod oops.ko + BUG: unable to handle kernel NULL pointer dereference at 00000042 + Call Trace: + so2_oops_init+0x17/0x20 [oops] + do_one_initcall+0x37/0x170 + ? cache_alloc_debugcheck_after.isra.19+0x15f/0x2f0 + ? __might_sleep+0x32/0x90 + ? trace_hardirqs_on_caller+0x11c/0x1a0 + ? do_init_module+0x17/0x1c2 + ? kmem_cache_alloc+0xa4/0x1e0 + ? do_init_module+0x17/0x1c2 + do_init_module+0x46/0x1c2 + load_module+0x1f45/0x2380 + SyS_init_module+0xe5/0x100 + do_int80_syscall_32+0x61/0x190 + entry_INT80_32+0x2f/0x2f + Killed + +Decoding an oops +---------------- + +.. slide:: Debugging + :inline-contents: True + :level: 2 + + * CONFIG_DEBUG_INFO + * addr2line + * gdb + * objdump -dSr + +addr2line +--------- + +*addr2line* translates addresses into file names and line numbers. Given +an address in an executable it uses the debugging information to figure out +which file name and line number are associated with it. + +Modules are loaded at dynamic addresses but are compiled starting with 0 as +a base address. So, in order to find the line number for a given dynamic address +we need to know module's load address. + +.. slide:: addr2line + :inline-contents: True + :level: 2 + + .. code-block:: bash + + $ addr2line -e oops.o 0x08 + $ skels/debugging/oops/oops.c:5 + $ # 0x08 is the offset of the offending instruction inside the oops.ko module + +objdump +------- + +Similar we can determine the offending line using objdump: + +.. slide:: objdump + :inline-contents: True + :level: 2 + + .. code-block:: bash + + $ cat /proc/modules + oops 20480 1 - Loading 0xc8816000 (O+) + + $ objdump -dS --adjust-vma=0xc8816000 oops.ko + c8816000: b8 61 00 00 00 mov $0x61,%eax + + static noinline void do_oops(void) + { + c8816005: 55 push %ebp + c8816006: 89 e5 mov %esp,%ebp + *(int*)0x42 = 'a'; + c8816008: a3 42 00 00 00 mov %eax,0x42 + +gdb +--- + +.. slide:: gdb + :inline-contents: True + :level: 2 + + .. code-block:: bash + + $ gdb ./vmlinux + + (gdb) list *(do_panic+0x8) + 0xc1244138 is in do_panic (lib/test_panic.c:8). + 3 + 4 static struct timer_list panic_timer; + 5 + 6 static void do_panic(struct timer_list *unused) + 7 { + 8 *(int*)0x42 = 'a'; + 9 } + 10 + 11 static int so2_panic_init(void) + +Kernel panic +------------ + +A kernel panic is a special type of oops where the kernel cannot continue execution. For example +if the function do_oops from above was called in the interrupt context, the kernel wouldn't know how to kill +and it will decide that it is better to crash the kernel and stop execution. + +Here is a sample code that will generate a kernel panic: + +.. slide:: Kernel panic + :inline-contents: True + :level: 2 + + .. code-block:: c + + static struct timer_list panic_timer; + + static void do_panic(struct timer_list *unused) + { + *(int*)0x42 = 'a'; + } + + static int so2_panic_init(void) + { + pr_info("panic_init\n"); + + timer_setup(&panic_timer, do_panic, 0); + mod_timer(&panic_timer, jiffies + 2 * HZ); + + return 0; + } + +Loading the module will generate the following kernel panic message: + +.. code-block:: bash + + root@qemux86:~/skels/debugging/panic# insmod panic.ko + panic: loading out-of-tree module taints kernel. + panic_init + root@qemux86:~/skels/debugging/panic# BUG: unable to handle kernel NULL pointer dereference at 00000042 + IP: do_panic+0x8/0x10 [panic] + *pde = 00000000 + Oops: 0002 [#1] SMP + Modules linked in: panic(O) + CPU: 0 PID: 0 Comm: swapper/0 Tainted: G O 4.15.0+ #19 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014 + EIP: do_panic+0x8/0x10 [panic] + EFLAGS: 00010246 CPU: 0 + EAX: 00000061 EBX: 00000101 ECX: 000002d8 EDX: 00000000 + ESI: c8817000 EDI: c8819200 EBP: c780ff34 ESP: c780ff34 + DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 + CR0: 80050033 CR2: 00000042 CR3: 0716b000 CR4: 00000690 + Call Trace: + <SOFTIRQ> + call_timer_fn+0x63/0xf0 + ? process_timeout+0x10/0x10 + run_timer_softirq+0x14f/0x170 + ? 0xc8817000 + ? trace_hardirqs_on_caller+0x9b/0x1a0 + __do_softirq+0xde/0x1f2 + ? __irqentry_text_end+0x6/0x6 + do_softirq_own_stack+0x57/0x70 + </SOFTIRQ> + irq_exit+0x7d/0x90 + smp_apic_timer_interrupt+0x4f/0x90 + ? trace_hardirqs_off_thunk+0xc/0x1d + apic_timer_interrupt+0x3a/0x40 + EIP: default_idle+0xa/0x10 + EFLAGS: 00000246 CPU: 0 + EAX: c15c97c0 EBX: 00000000 ECX: 00000000 EDX: 00000001 + ESI: 00000000 EDI: 00000000 EBP: c15c3f48 ESP: c15c3f48 + DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 + arch_cpu_idle+0x9/0x10 + default_idle_call+0x19/0x30 + do_idle+0x105/0x180 + cpu_startup_entry+0x25/0x30 + rest_init+0x1e3/0x1f0 + start_kernel+0x305/0x30a + i386_start_kernel+0x95/0x99 + startup_32_smp+0x15f/0x164 + Code: <a3> 42 00 00 00 5d c3 90 55 89 e5 83 ec 08 c7 04 24 24 80 81 c8 e8 + EIP: do_panic+0x8/0x10 [panic] SS:ESP: 0068:c780ff34 + CR2: 0000000000000042 + ---[ end trace 77f49f83f2e42f91 ]--- + Kernel panic - not syncing: Fatal exception in interrupt + Kernel Offset: disabled + ---[ end Kernel panic - not syncing: Fatal exception in interrupt + + +List debugging +============== + +In order to catch access to uninitialized elements the kernel uses poison +magic values. + +.. slide:: List debugging + :inline-contents: True + :level: 2 + + .. code-block:: bash + + static inline void list_del(struct list_head *entry) + { + __list_del(entry->prev, entry->next); + entry->next = (struct list_head*)LIST_POISON1; + entry->prev = (struct list_head*)LIST_POISON2; + } + + BUG: unable to handle kernel NULL pointer dereference at 00000100 + IP: crush+0x80/0xb0 [list] + +Memory debugging +================ + +There are several tools for memory debugging: + +.. slide:: Memory debugging + :inline-contents: True + :level: 2 + + * SLAB/SLUB debugging + * KASAN + * kmemcheck + * DEBUG_PAGEALLOC + +Slab debugging +--------------- + +Slab debugging uses a memory poison technique to detect several types of memory +bugs in the SLAB/SUB allocators. + +The allocated buffers are guarded with memory that has been filled in with +special markers. Any adjacent writes to the buffer will be detected at a later +time when other memory management operations on that buffer are performed +(e.g. when the buffer is freed). + +Upon allocation of the buffer, the buffer it is also filled in with a special +value to potentially detect buffer access before initialization (e.g. if the +buffer holds pointers). The value is selected in such a way that it is unlikely +to be a valid address and as such to trigger kernel bugs at the access time. + +A similar technique is used when freeing the buffer: the buffer is filled with +another special value that will cause kernel bugs if pointers are accessed after +the memory is freed. In this case, the allocator also checks the next time the +buffer is allocated that the buffer was not modified. + +The diagram bellow shows a summary of the way SLAB/SLUB poisoning works: + + +.. slide:: Slab debugging + :inline-contents: True + :level: 2 + + * CONFIG_DEBUG_SLAB + * poisoned based memory debuggers + + .. ditaa:: + +--------------+-----------------------+--------------+ + | cF88 | c8F8 | cF88 | + | Buffer | Allocated buffer | Buffer | + | Underflow | 0x5a5a5a5a | Overflow | + | Poison | 0x5a5a5a5a | Poison | + | | 0x5a5a5a5a | | + +--------------+-----------------------+--------------+ + + +--------------+-----------------------+--------------+ + | cF88 | c888 | cF88 | + | Buffer | Freed buffer | Buffer | + | Underflow | 0x6b6b6b6b | Overflow | + | Poison | 0x6b6b6b6b | Poison | + | | 0x6b6b6b6b | | + +--------------+-----------------------+--------------+ + + +Example of an use before initialize bug: + +.. slide:: Use before initialize bugs + :inline-contents: True + :level: 2 + + :: + + BUG: unable to handle kernel paging request at 5a5a5a5a + IP: [<c1225063>] __list_del_entry+0x37/0x71 + … + Call Trace: + [<c12250a8>] list_del+0xb/0x1b + [<f1de81a2>] use_before_init+0x31/0x38 [crusher] + [<f1de8265>] crush_it+0x38/0xa9 [crusher] + [<f1de82de>] init_module+0x8/0xa [crusher] + [<c1001072>] do_one_initcall+0x72/0x119 + [<f1de82d6>] ? crush_it+0xa9/0xa9 [crusher] + [<c106b8ae>] sys_init_module+0xc8d/0xe77 + [<c14d7d18>] syscall_call+0x7/0xb + + .. code-block:: c + + noinline void use_before_init(void) + { + struct list_m *m = kmalloc(sizeof(*m), GFP_KERNEL); + + printk("%s\n", __func__); + list_del(&m->lh); + } + +Example of an use after free bug: + +.. slide:: Use after free bug + :inline-contents: True + :level: 2 + + :: + + BUG: unable to handle kernel paging request at 6b6b6b6b + IP: [<c1225063>] __list_del_entry+0x37/0x71 + … + Call Trace: + [<c12250a8>] list_del+0xb/0x1b + [<f4c6816a>] use_after_free+0x38/0x3f [crusher] + [<f4c6827f>] crush_it+0x52/0xa9 [crusher] + [<f4c682de>] init_module+0x8/0xa [crusher] + [<c1001072>] do_one_initcall+0x72/0x119 + [<f4c682d6>] ? crush_it+0xa9/0xa9 [crusher] + [<c106b8ae>] sys_init_module+0xc8d/0xe77 + [<c14d7d18>] syscall_call+0x7/0xb + + .. code-block:: c + + noinline void use_after_free(void) + { + struct list_m *m = kmalloc(sizeof(*m), GFP_KERNEL); + + printk("%s\n", __func__); + kfree(m); + list_del(&m->lh); + } + +Another example of an use after free bug is shown below. Note that this time the +bug is detected at the next allocation. + +.. slide:: Use after free bug + :inline-contents: True + :level: 2 + + :: + + # insmod /system/lib/modules/crusher.ko test=use_before_init + Slab corruption: size-4096 start=ed612000, len=4096 + 000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6b 6b + + .. code-block:: c + + noinline void use_after_free2(void) + { + char *b = kmalloc(3000, GFP_KERNEL); + kfree(b); + memset(b, 0, 30); + b = kmalloc(3000, GFP_KERNEL); + kfree(b); + } + +Finally this is an example of a buffer overflow bug: + +.. slide:: Buffer overflow bugs + :inline-contents: True + :level: 2 + + :: + + slab error in verify_redzone_free(): cache `dummy': memory outside object was overwritten + Pid: 1282, comm: insmod Not tainted 3.0.16-mid10-00007-ga4a6b62-dirty #70 + Call Trace: + [<c10cc1de>] __slab_error+0x17/0x1c + [<c10cc7ca>] __cache_free+0x12c/0x317 + [<c10ccaba>] kmem_cache_free+0x2b/0xaf + [<f27f1138>] buffer_overflow+0x4c/0x57 [crusher] + [<f27f12aa>] crush_it+0x6c/0xa9 [crusher] + [<f27f12ef>] init_module+0x8/0xd [crusher] + [<c1001072>] do_one_initcall+0x72/0x119 + [<c106b8ae>] sys_init_module+0xc8d/0xe77 + [<c14d7d18>] syscall_call+0x7/0xb + eb002bf8: redzone 1:0xd84156c5635688c0, redzone 2:0x0 + + .. code-block:: c + + noinline void buffer_overflow(void) + { + struct kmem_cache *km = kmem_cache_create("dummy", 3000, 0, 0, NULL); + char *b = kmem_cache_alloc(km, GFP_KERNEL); + + printk("%s\n", __func__); + memset(b, 0, 3016); + kmem_cache_free(km, b); + } + + +DEBUG_PAGEALLOC +--------------- + +.. slide:: DEBUG_PAGEALLOC + :inline-contents: True + :level: 2 + + * Memory debugger that works at a page level + * Detects invalid accesses either by: + + * Filling pages with poison byte patterns and checking the pattern at + reallocation + * Unmapping the dellocated pages from kernel space (just a few + architectures) + + +KASan +----- + +KASan is a dynamic memory error detector designed to find use-after-free +and out-of-bounds bugs. + +The main idea of KASAN is to use shadow memory to record whether each byte +of memory is safe to access or not, and use compiler's instrumentation to +check the shadow memory on each memory access. + +Address sanitizer uses 1 byte of shadow memory to track 8 bytes of kernel +address space. It uses 0-7 to encode the number of consecutive bytes at +the beginning of the eigh-byte region that are valid. + +See `The Kernel Address Sanitizer (KASAN)` for more information and have a look +at lib/test_kasan.c for an example of problems that KASan can detect. + +.. slide:: KASan + :inline-contents: True + :level: 2 + + * dynamic memory error detector + * finds user-after-free or out-of-bound bugs + * uses shadow memory to track memory operations + * lib/test_kasan.c + + +KASan vs DEBUG_PAGEALLOC +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. slide:: KASan vs DEBUG_PAGEALLOC + :inline-contents: True + :level: 2 + + KASan is slower than DEBUG_PAGEALLOC, but KASan works on sub-page granularity + level, so it able to find more bugs. + + +KASan vs SLUB_DEBUG +~~~~~~~~~~~~~~~~~~~ + +.. slide:: KASan vs SLUB_DEBUG + :inline-contents: True + :level: 2 + + * SLUB_DEBUG has lower overhead than KASan. + * SLUB_DEBUG in most cases are not able to detect bad reads, KASan able to + detect both reads and writes. + * In some cases (e.g. redzone overwritten) SLUB_DEBUG detect bugs only on + allocation/freeing of object. KASan catch bugs right before it will happen, + so we always know exact place of first bad read/write. + + +Kmemleak +-------- + +Kmemleak provides a way of detecting kernel memory leaks in a way similar to a +tracing garbage collector. Since tracing pointers is not possible in C, kmemleak +scans the kernel stacks as well as dynamically and statically kernel memory for +pointers to allocated buffers. A buffer for which there is no pointer is +considered as leaked. The basic steps to use kmemleak are presented bellow, for +more information see `Kernel Memory Leak Detector` + + +.. slide:: Kmemleak + :inline-contents: True + :level: 2 + + * enable kernel config: `CONFIG_DEBUG_KMEMLEAK` + * setup: `mount -t debugfs nodev /sys/kernel/debug` + * trigger a memory scan: `echo scan > /sys/kernel/debug/kmemleak` + * show memory leaks: `cat /sys/kernel/debug/kmemleak` + * clear all possible leaks: `echo clear > /sys/kernel/debug/kmemleak` + +As an example, lets look at the following simple module: + +.. slide:: Kmemleak example + :inline-contents: True + :level: 2 + + .. code-block:: c + + static int leak_init(void) + { + pr_info("%s\n", __func__); + + (void)kmalloc(16, GFP_KERNEL); + + return 0; + } + + MODULE_LICENSE("GPL v2"); + module_init(leak_init); + +Loading the module and triggering a kmemleak scan will issue the +following report: + +.. slide:: Kmemleak report + :inline-contents: True + :level: 2 + + :: + + root@qemux86:~# insmod skels/debugging/leak/leak.ko + leak: loading out-of-tree module taints kernel. + leak_init + root@qemux86:~# echo scan > /sys/kernel/debug/kmemleak + root@qemux86:~# echo scan > /sys/kernel/debug/kmemleak + kmemleak: 1 new suspected memory leaks (see /sys/kernel/debug/kmemleak) + root@qemux86:~# cat /sys/kernel/debug/kmemleak + unreferenced object 0xd7871500 (size 32): + comm "insmod", pid 237, jiffies 4294902108 (age 24.628s) + hex dump (first 32 bytes): + 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ + 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a a5 ZZZZZZZZZZZZZZZ. + backtrace: + [<(ptrval)>] kmem_cache_alloc_trace+0x163/0x310 + [<(ptrval)>] leak_init+0x2f/0x1000 [leak] + [<(ptrval)>] do_one_initcall+0x57/0x2e0 + [<(ptrval)>] do_init_module+0x4b/0x1be + [<(ptrval)>] load_module+0x201a/0x2590 + [<(ptrval)>] sys_init_module+0xfd/0x120 + [<(ptrval)>] do_int80_syscall_32+0x6a/0x1a0 + + +.. note:: Notice that we did not had to unload the module to detect the memory + leak since kmemleak detects that the allocated buffer is not + reachable anymore. + + +Lockdep checker +=============== + +.. slide:: Lockdep checker + :inline-contents: True + :level: 2 + + * CONFIG_DEBUG_LOCKDEP + * Detects lock inversio, circular dependencies, incorrect usage of locks + (including interrupt context) + * Maintains dependency between classes of locks not individual locks + * Each scenario is only checked once and hashed + + +Lets take for example the following kernel module that runs two kernel threads: + +.. slide:: AB BA Deadlock Example + :inline-contents: True + :level: 2 + + .. code-block:: c + + static noinline int thread_a(void *unused) + { + mutex_lock(&a); pr_info("%s acquired A\n", __func__); + mutex_lock(&b); pr_info("%s acquired B\n", __func__); + + mutex_unlock(&b); + mutex_unlock(&a); + + return 0; + } + + .. code-block:: c + + static noinline int thread_b(void *unused) + { + mutex_lock(&b); pr_info("%s acquired B\n", __func__); + mutex_lock(&a); pr_info("%s acquired A\n", __func__); + + mutex_unlock(&a); + mutex_unlock(&b); + + return 0; + } + + +Loading this module with lockdep checker active will produce the following +kernel log: + +.. slide:: AB BA Deadlock Report + :inline-contents: True + :level: 2 + + :: + + thread_a acquired A + thread_a acquired B + thread_b acquired B + + ====================================================== + WARNING: possible circular locking dependency detected + 4.19.0+ #4 Tainted: G O + ------------------------------------------------------ + thread_b/238 is trying to acquire lock: + (ptrval) (a){+.+.}, at: thread_b+0x48/0x90 [locking] + + but task is already holding lock: + (ptrval) (b){+.+.}, at: thread_b+0x27/0x90 [locking] + + which lock already depends on the new lock. + + +As you can see, although the deadlock condition did not trigger (because thread +A did not complete execution before thread B started execution) the lockdep +checker identified a potential deadlock scenario. + +Lockdep checker will provide even more information to help determine what caused +the deadlock, like the dependency chain: + +.. slide:: AB BA Deadlock Report (dependency chain) + :inline-contents: True + :level: 2 + + :: + + the existing dependency chain (in reverse order) is: + + -> #1 (b){+.+.}: + __mutex_lock+0x60/0x830 + mutex_lock_nested+0x20/0x30 + thread_a+0x48/0x90 [locking] + kthread+0xeb/0x100 + ret_from_fork+0x2e/0x38 + + -> #0 (a){+.+.}: + lock_acquire+0x93/0x190 + __mutex_lock+0x60/0x830 + mutex_lock_nested+0x20/0x30 + thread_b+0x48/0x90 [locking] + kthread+0xeb/0x100 + ret_from_fork+0x2e/0x38 + +and even an unsafe locking scenario: + +.. slide:: AB BA Deadlock Report (unsafe locking scenario) + :inline-contents: True + :level: 2 + + :: + + other info that might help us debug this: + + Possible unsafe locking scenario: + + CPU0 CPU1 + ---- ---- + lock(b); + lock(a); + lock(b); + lock(a); + + *** DEADLOCK *** + + +Another example of unsafe locking issues that lockdep checker detects +is unsafe locking from interrupt context. Lets consider the following +kernel module: + +.. slide:: IRQ Deadlock Example + :inline-contents: True + :level: 2 + + .. code-block:: c + + static DEFINE_SPINLOCK(lock); + + static void timerfn(struct timer_list *unused) + { + pr_info("%s acquiring lock\n", __func__); + spin_lock(&lock); pr_info("%s acquired lock\n", __func__); + spin_unlock(&lock); pr_info("%s released lock\n", __func__); + } + + static DEFINE_TIMER(timer, timerfn); + + int init_module(void) + { + mod_timer(&timer, jiffies); + + pr_info("%s acquiring lock\n", __func__); + spin_lock(&lock); pr_info("%s acquired lock\n", __func__); + spin_unlock(&lock); pr_info("%s released lock\n", __func__); + return 0; + } + + +As in the previous case, loading the module will trigger a lockdep +warning: + +.. slide:: IRQ Deadlock Report + :inline-contents: True + :level: 2 + + :: + + init_module acquiring lock + init_module acquired lock + init_module released lock + timerfn acquiring lock + + ================================ + WARNING: inconsistent lock state + 4.19.0+ #4 Tainted: G O + -------------------------------- + inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage. + ksoftirqd/0/9 [HC0[0]:SC1[1]:HE1:SE0] takes: + (ptrval) (lock#4){+.?.}, at: timerfn+0x25/0x60 [locking2] + {SOFTIRQ-ON-W} state was registered at: + lock_acquire+0x93/0x190 + _raw_spin_lock+0x39/0x50 + init_module+0x35/0x70 [locking2] + do_one_initcall+0x57/0x2e0 + do_init_module+0x4b/0x1be + load_module+0x201a/0x2590 + sys_init_module+0xfd/0x120 + do_int80_syscall_32+0x6a/0x1a0 + restore_all+0x0/0x8d + + +The warning will also provide additional information and a potential unsafe +locking scenario: + +.. slide:: IRQ Deadlock Report + :inline-contents: True + :level: 2 + + :: + + Possible unsafe locking scenario: + + CPU0 + ---- + lock(lock#4); + <Interrupt> + lock(lock#4); + + *** DEADLOCK *** + + 1 lock held by ksoftirqd/0/9: + #0: (ptrval) (/home/tavi/src/linux/tools/labs/skels/./debugging/locking2/locking2.c:13){+.-.}, at: call_timer_f0 + stack backtrace: + CPU: 0 PID: 9 Comm: ksoftirqd/0 Tainted: G O 4.19.0+ #4 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014 + Call Trace: + dump_stack+0x66/0x96 + print_usage_bug.part.26+0x1ee/0x200 + mark_lock+0x5ea/0x640 + __lock_acquire+0x4b4/0x17a0 + lock_acquire+0x93/0x190 + _raw_spin_lock+0x39/0x50 + timerfn+0x25/0x60 [locking2] + + +perf +==== + +.. slide:: perf + :inline-contents: True + :level: 2 + + * performance counters, tracepoints, kprobes, uprobes + * hardware events: CPU cycles, TLB misses, cache misses + * software events: page faults , context switches + * collects backtraces (user + kernel) + +Other tools +=========== + +.. slide:: Other tools + :inline-contents: True + :level: 2 + + * ftrace + * kprobes + * sparse + * coccinelle + * checkpatch.pl + * printk + * dump_stack() diff --git a/refs/pull/405/merge/_sources/lectures/fs.rst.txt b/refs/pull/405/merge/_sources/lectures/fs.rst.txt new file mode 100644 index 00000000..20b4e6d6 --- /dev/null +++ b/refs/pull/405/merge/_sources/lectures/fs.rst.txt @@ -0,0 +1,775 @@ +===================== +Filesystem Management +===================== + +`View slides <fs-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +Lecture objectives: +=================== + +.. slide:: Filesystem Management + :inline-contents: True + :level: 2 + + * Filesystem abstractions + + * Filesystem operations + + * Linux VFS + + * Overview of Linux I/O Management + + +Filesystem Abstractions +======================= + +A fileystem is a way to organize files and directories on storage +devices such as hard disks, SSDs or flash memory. There are many types +of filesystems (e.g. FAT, ext4, btrfs, ntfs) and on one running system +we can have multiple instances of the same filesystem type in use. + +While filesystems use different data structures to organizing the +files, directories, user data and meta (internal) data on storage +devices there are a few common abstractions that are used in almost +all filesystems: + +.. slide:: Filesystem Abstractions + :inline-contents: True + :level: 2 + + * superblock + + * file + + * inode + + * dentry + + +Some of these abstractions are present both on disk and in memory +while some are only present in memory. + +The *superblock* abstraction contains information about the filesystem +instance such as the block size, the root inode, filesystem size. It +is present both on storage and in memory (for caching purposes). + +The *file* abstraction contains information about an opened file such +as the current file pointer. It only exists in memory. + +The *inode* is identifying a file on disk. It exists both on storage +and in memory (for caching purposes). An inode identifies a file in a +unique way and has various properties such as the file size, access +rights, file type, etc. + +.. note:: The file name is not a property of the file. + +The *dentry* associates a name with an inode. It exists both on +storage and in memory (for caching purposes). + +The following diagram shows the relationship between the various filesystem +abstractions as they used in memory: + +.. slide:: Filesystem Abstractions - in memory + :inline-contents: True + :level: 2 + + .. ditaa:: + :--no-separation: + + file + descriptor + table + +------------+ +--------+ +--------+ +---------+ + | |------+--->| FILE |------->| dentry |------->| inode | + +------------+ | +--------+ +--------+ ^ +---------+ + +-> | |------+ dup | | type | + | +------------+ hard link | | perm | + | | ... | | | .... | + | +------------+ +--------+ +--------+ | +---------+ + | | |---------->| FILE |------->| dentry |---+ | + | +------------+ +--------+ +--------+ | + fd | + | + +------+ <-------------------+ + | data | + +------+ + +------+ +------+ + | data | | data | + +------+ +------+ + +------+ + | data | + +------+ + +Note that not all of the one to many relationships between the various +abstractions are depicted. + +Multiple file descriptors can point to the same *file* because we can +use the :c:func:`dup` system call to duplicate a file descriptor. + +Multiple *file* abstractions can point to the same *dentry* if we open +the same path multiple times. + +Multiple *dentries* can point to the same *inode* when hard links are +used. + +The following diagram shows the relationship of the filesystem +abstraction on storage: + +.. slide:: Filesystem Abstractions - on storage + :inline-contents: True + :level: 2 + + .. ditaa:: + :--no-separation: + + + +--------+ +-------+ data +--------+ + | dentry |-------------->| inode |--------+ | dentry | + +--------+ +-------+ | +--------+ + | ...... | | ..... | | | ...... | + +--------+ +-------+ dir | +--------+ + | dentry | | inode |--------|--+ | dentry | + +--------+ +-------+ | | +--------+ + ^ | | ^ + | | | | + | | | +--------+ + | V v | + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + blocks | | | | | | | | | | | | | | | | | | + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | | + | +------------+ | ++++++++++++ + +--->| superblock | +--->|||||||||||| block management + +------------+ ++++++++++++ + + +The diagram shows that the *superblock* is typically stored at the +beginning of the fileystem and that various blocks are used with +different purposes: some to store dentries, some to store inodes and +some to store user data blocks. There are also blocks used to manage +the available free blocks (e.g. bitmaps for the simple filesystems). + +The next diagram show a very simple filesystem where blocks are +grouped together by function: + +* the superblock contains information about the block size as well as + the IMAP, DMAP, IZONE and DZONE areas. + +* the IMAP area is comprised of multiple blocks which contains a + bitmap for inode allocation; it maintains the allocated/free state + for all inodes in the IZONE area + +* the DMAP area is comprised of multiple blocks which contains a + bitmap for data blocks; it maintains the allocated/free state for + all blocks the DZONE area + + +.. slide:: Simple filesystem example + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + :--no-separation: + + +--------------+--------+--------+---------+---------+ + | | | | | | + | Superblock | IMAP | DMAP | IZONE | DZONE | + | | | | | | + +--------------+--------+--------+---------+---------+ + + +Filesystem Operations +===================== + +The following diagram shows a high level overview of how the file +system drivers interact with the rest of the file system "stack". In +order to support multiple filesystem types and instances Linux +implements a large and complex subsystem that deals with filesystem +management. This is called Virtual File System (or sometimes Virtual +File Switch) and it is abbreviated with VFS. + + +.. slide:: Overview + :inline-contents: True + :level: 2 + + .. ditaa:: + + ^ ^ ^ + | stat | open | read + v v v + +------------------------------------------------------------+ + | | + | Virtual Filesystem Switch | + | | + +------------------------------------------------------------+ + ^ ^ + | | + v v + +-------------+ +-------------+ + | Filesystem | | Filesystem | + | driver | | driver | + +-------------+ +-------------+ + ^ ^ + | | + v v + +------------------------------------------------------------+ + | | + | Block I/O layer | + | | + +------------------------------------------------------------+ + +VFS translates the complex file management related system calls to +simpler operations that are implemented by the device drivers. These +are some of the operations that a file system must implement: + +.. slide:: Filesystem Operations + :inline-contents: True + :level: 2 + + * Mount + + * Open a file + + * Querying file attributes + + * Reading data from a file + + * Writing file to a file + + * Creating a file + + * Deleting a file + + +The next sections will look in-depth at some of these operations. + +Mounting a filesystem +--------------------- + +A summary of a typical implementation is presented below: + +.. slide:: Mounting a filesystem + :inline-contents: True + :level: 2 + + * Input: a storage device (partition) + + * Output: dentry pointing to the root directory + + * Steps: check device, determine filesystem parameters, locate the root inode + + * Example: check magic, determine block size, read the root inode and create dentry + + +Opening a file +-------------- + +A summary of a typical implementation is presented below: + +.. slide:: Opening a file + :inline-contents: True + :level: 2 + + * Input: path + + * Output: file descriptor + + * Steps: + + * Determine the filesystem type + + * For each name in the path: lookup parent dentry, load inode, + load data, find dentry + + * Create a new *file* that points to the last *dentry* + + * Find a free entry in the file descriptor table and set it to *file* + + +Querying file attributes +------------------------ + +A summary of a typical implementation is presented below: + +.. slide:: Querying file attributes + :inline-contents: True + :level: 2 + + * Input: path + + * Output: file attributes + + * Steps: + + * Access `file->dentry->inode` + + * Read file attributes from the *inode* + +Reading data from a file +------------------------ + +A summary of a typical implementation is presented below: + +.. slide:: Reading data from a file + :inline-contents: True + :level: 2 + + * Input: file descriptor, offset, length + + * Output: data + + * Steps: + + * Access `file->dentry->inode` + + * Determine data blocks + + * Copy data blocks to memory + + +Writing data to a file +---------------------- + +A summary of a typical implementation is presented below: + +.. slide:: Writing data to a file + :inline-contents: True + :level: 2 + + * Input: file descriptor, offset, length, data + + * Output: + + * Steps: + + * Allocate one or more data blocks + + * Add the allocated blocks to the inode and update file size + + * Copy data from userspace to internal buffers and write them to + storage + + +Closing a file +-------------- + +A summary of a typical implementation is presented below: + +.. slide:: Closing a file + :inline-contents: True + :level: 2 + + * Input: file descriptor + + * Output: + + * Steps: + + * set the file descriptor entry to NULL + + * Decrement file reference counter + + * When the counter reaches 0 free *file* + + +Directories +----------- + +.. slide:: Directories + :inline-contents: True + :level: 2 + + Directories are special files which contain one or more dentries. + +Creating a file +--------------- + +A summary of a typical implementation is presented below: + +.. slide:: Creating a file + :inline-contents: True + :level: 2 + + * Input: path + + * Output: + + * Steps: + + * Determine the inode directory + + * Read data blocks and find space for a new dentry + + * Write back the modified inode directory data blocks + + +Deleting a file +--------------- + +A summary of a typical implementation is presented below: + + +.. slide:: Deleting a file + :inline-contents: True + :level: 2 + + * Input: path + + * Output: + + * Steps: + + * determine the parent inode + + * read parent inode data blocks + + * find and erase the dentry (check for links) + + * when last file is closed: deallocate data and inode blocks + + +Linux Virtual File System +========================= + +Although the main purpose for the original introduction of VFS in UNIX +kernels was to support multiple filesystem types and instances, a side +effect was that it simplified fileystem device driver development +since command parts are now implement in the VFS. Almost all of the +caching and buffer management is dealt with VFS, leaving just +efficient data storage management to the filesystem device driver. + +In order to deal with multiple filesystem types, VFS introduced the +common filesystem abstractions previously presented. Note that the +filesystem driver can also use its own particular fileystem +abstractions in memory (e.g. ext4 inode or dentry) and that there +might be a different abstraction on storage as well. Thus we may end +up with three slightly different filesystem abstractions: one for +VFS - always in memory, and two for a particular filesystem - one in +memory used by the filesystem driver, and one on storage. + +.. slide:: Virtual File System + :level: 2 + :inline-contents: True + + .. ditaa:: + :height: 100% + + + ^ ^ ^ + | stat | open | read + v v v + +------------------------------------------------------------+ + | Virtual File System | + | | + | | + | /-------\ /--------\ /--------\ | + | | inode |<----------+ dentry |<----------+ FILE | | + | \---+---/ \----+---/ \---+----/ | + | | | | | + | | | | | + | v v v | + | +-------+ +--------+ +-------+ | + | | inode | | dentry | | page | | + | | cache | | cache | | cache | | + | +-------+ +--------+ +-------+ | + | | + +------------------------------------------------------------+ + ^ ^ + | | + v v + +-------------+ +-------------+ + | Filesystem | | Filesystem | + | driver | | driver | + +-------------+ +-------------+ + + +Superblock Operations +--------------------- + +VFS requires that all filesystem implement a set of "superblock +operations". + +They deal with initializing, updating and freeing the VFS superblock: + + * :c:func:`fill_super` - reads the filesystem statistics (e.g. total + number of inode, free number of inodes, total number of blocks, free + number of blocks) + + * :c:func:`write_super` - updates the superblock information on storage + (e.g. updating the number of free inode or data blocks) + + * :c:func:`put_super` - free any data associated with the filsystem + instance, called when unmounting a filesystem + +The next class of operations are dealing with manipulating fileystem +inodes. These operations will receive VFS inodes as parameters but the +filesystem driver may use its own inode structures internally and, if +so, they will convert in between them as necessary. + +A summary of the superblock operations are presented below: + +.. slide:: Superblock Operations + :level: 2 + :inline-contents: True + + .. hlist:: + :columns: 2 + + * fill_super + * put_super + * write_super + * read_inode + * write_inode + * evict_inode + * statfs + * remount_fs + + +Inode Operations +---------------- + +The next set of operations that VFS calls when interacting with +filesystem device drivers are the "inode operations". Non-intuitively +these mostly deal with manipulating dentries - looking up a file name, +creating, linking and removing files, dealing with symbolic links, +creating and removing directories. + +This is the list of the most important inode operations: + +.. slide:: Inode Operations + :level: 2 + :inline-contents: True + + .. hlist:: + :columns: 2 + + * create + * lookup + * link + * unlink + * symlink + * mkdir + * rmdir + * rename + * readlink + * follow_link + * put_link + * ... + + +The Inode Cache +--------------- + +The inode cache is used to avoid reading and writing inodes to and +from storage every time we need to read or update them. The cache uses +a hash table and inodes are indexed with a hash function which takes +as parameters the superblock (of a particular filesystem instance) and +the inode number associated with an inode. + +inodes are cached until either the filesystem is unmounted, the inode +deleted or the system enters a memory pressure state. When this +happens the Linux memory management system will (among other things) +free inodes from the inode cache based on how often they were +accessed. + +.. slide:: The Inode Cache + :level: 2 + :inline-contents: True + + * Caches inodes into memory to avoid costly storage operations + + * An inode is cached until low memory conditions are triggered + + * inodes are indexed with a hash table + + * The inode hash function takes the superblock and inode number as + inputs + + +The Dentry Cache +---------------- + +.. slide:: The Dentry Cache + :level: 2 + :inline-contents: True + + * State: + + * Used – *d_inode* is valid and the *dentry* object is in use + + * Unused – *d_inode* is valid but the dentry object is not in use + + * Negative – *d_inode* is not valid; the inode was not yet loaded + or the file was erased + + * Dentry cache + + * List of used dentries (dentry->d_state == used) + + * List of the most recent used dentries (sorted by access time) + + * Hash table to avoid searching the tree + +The Page Cache +-------------- + +.. slide:: The Page Cache + :level: 2 + :inline-contents: True + + * Caches file data and not block device data + + * Uses the :c:type:`struct address_space` to translate file offsets + to block offsets + + * Used for both `read` / `write` and `mmap` + + * Uses a radix tree + + + +.. slide:: struct address_space + :level: 2 + :inline-contents: True + + .. code-block:: c + + /** + * struct address_space - Contents of a cacheable, mappable object. + * @host: Owner, either the inode or the block_device. + * @i_pages: Cached pages. + * @gfp_mask: Memory allocation flags to use for allocating pages. + * @i_mmap_writable: Number of VM_SHARED mappings. + * @nr_thps: Number of THPs in the pagecache (non-shmem only). + * @i_mmap: Tree of private and shared mappings. + * @i_mmap_rwsem: Protects @i_mmap and @i_mmap_writable. + * @nrpages: Number of page entries, protected by the i_pages lock. + * @nrexceptional: Shadow or DAX entries, protected by the i_pages lock. + * @writeback_index: Writeback starts here. + * @a_ops: Methods. + * @flags: Error bits and flags (AS_*). + * @wb_err: The most recent error which has occurred. + * @private_lock: For use by the owner of the address_space. + * @private_list: For use by the owner of the address_space. + * @private_data: For use by the owner of the address_space. + */ + struct address_space { + struct inode *host; + struct xarray i_pages; + gfp_t gfp_mask; + atomic_t i_mmap_writable; + #ifdef CONFIG_READ_ONLY_THP_FOR_FS + /* number of thp, only for non-shmem files */ + atomic_t nr_thps; + #endif + struct rb_root_cached i_mmap; + struct rw_semaphore i_mmap_rwsem; + unsigned long nrpages; + unsigned long nrexceptional; + pgoff_t writeback_index; + const struct address_space_operations *a_ops; + unsigned long flags; + errseq_t wb_err; + spinlock_t private_lock; + struct list_head private_list; + void *private_data; + } __attribute__((aligned(sizeof(long)))) __randomize_layout; + + struct address_space_operations { + int (*writepage)(struct page *page, struct writeback_control *wbc); + int (*readpage)(struct file *, struct page *); + + /* Write back some dirty pages from this mapping. */ + int (*writepages)(struct address_space *, struct writeback_control *); + + /* Set a page dirty. Return true if this dirtied it */ + int (*set_page_dirty)(struct page *page); + + /* + * Reads in the requested pages. Unlike ->readpage(), this is + * PURELY used for read-ahead!. + */ + int (*readpages)(struct file *filp, struct address_space *mapping, + struct list_head *pages, unsigned nr_pages); + void (*readahead)(struct readahead_control *); + + int (*write_begin)(struct file *, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata); + int (*write_end)(struct file *, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata); + + /* Unfortunately this kludge is needed for FIBMAP. Don't use it */ + sector_t (*bmap)(struct address_space *, sector_t); + void (*invalidatepage) (struct page *, unsigned int, unsigned int); + int (*releasepage) (struct page *, gfp_t); + void (*freepage)(struct page *); + ssize_t (*direct_IO)(struct kiocb *, struct iov_iter *iter); + /* + * migrate the contents of a page to the specified target. If + * migrate_mode is MIGRATE_ASYNC, it must not block. + */ + int (*migratepage) (struct address_space *, + struct page *, struct page *, enum migrate_mode); + bool (*isolate_page)(struct page *, isolate_mode_t); + void (*putback_page)(struct page *); + int (*launder_page) (struct page *); + int (*is_partially_uptodate) (struct page *, unsigned long, + unsigned long); + void (*is_dirty_writeback) (struct page *, bool *, bool *); + int (*error_remove_page)(struct address_space *, struct page *); + + /* swapfile support */ + int (*swap_activate)(struct swap_info_struct *sis, struct file *file, + sector_t *span); + void (*swap_deactivate)(struct file *file); + }; + + +.. slide:: Reading data + :level: 2 + :inline-contents: True + + .. code-block:: c + + /** + * generic_file_read_iter - generic filesystem read routine + * @iocb: kernel I/O control block + * @iter: destination for the data read + * + * This is the "read_iter()" routine for all filesystems + * that can use the page cache directly. + * + * The IOCB_NOWAIT flag in iocb->ki_flags indicates that -EAGAIN shall + * be returned when no data can be read without waiting for I/O requests + * to complete; it doesn't prevent readahead. + * + * The IOCB_NOIO flag in iocb->ki_flags indicates that no new I/O + * requests shall be made for the read or for readahead. When no data + * can be read, -EAGAIN shall be returned. When readahead would be + * triggered, a partial, possibly empty read shall be returned. + * + * Return: + * * number of bytes copied, even for partial reads + * * negative error code (or 0 if IOCB_NOIO) if nothing was read + */ + ssize_t + generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) + + /* + * Generic "read page" function for block devices that have the normal + * get_block functionality. This is most of the block device filesystems. + * Reads the page asynchronously --- the unlock_buffer() and + * set/clear_buffer_uptodate() functions propagate buffer state into the + * page struct once IO has completed. + */ + int block_read_full_page(struct page *page, get_block_t *get_block) + diff --git a/refs/pull/405/merge/_sources/lectures/interrupts.rst.txt b/refs/pull/405/merge/_sources/lectures/interrupts.rst.txt new file mode 100644 index 00000000..ecb43bbd --- /dev/null +++ b/refs/pull/405/merge/_sources/lectures/interrupts.rst.txt @@ -0,0 +1,976 @@ +========== +Interrupts +========== + +`View slides <interrupts-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +Lecture objectives +================== + +.. slide:: Interrupts + :inline-contents: True + :level: 2 + + * Interrupts and exceptions (x86) + + * Interrupts and exceptions (Linux) + + * Deferrable work + + * Timers + +What is an interrupt? +===================== + +An interrupt is an event that alters the normal execution flow of a +program and can be generated by hardware devices or even by the CPU +itself. When an interrupt occurs the current flow of execution is +suspended and interrupt handler runs. After the interrupt handler runs +the previous execution flow is resumed. + +Interrupts can be grouped into two categories based on the source of +the interrupt. They can also be grouped into two other categories based +on the ability to postpone or temporarily disable the interrupt: + +.. slide:: Interrupts + :inline-contents: True + :level: 2 + + * **synchronous**, generated by executing an instruction + + * **asynchronous**, generated by an external event + + * **maskable** + + * can be ignored + + * signaled via INT pin + + * **non-maskable** + + * cannot be ignored + + * signaled via NMI pin + +Synchronous interrupts, usually named exceptions, handle conditions detected by the +processor itself in the course of executing an instruction. Divide by zero or +a system call are examples of exceptions. + +Asynchronous interrupts, usually named interrupts, are external events generated +by I/O devices. For example a network card generates an interrupts to signal +that a packet has arrived. + +Most interrupts are maskable, which means we can temporarily postpone +running the interrupt handler when we disable the interrupt until the +time the interrupt is re-enabled. However, there are a few critical +interrupts that can not be disabled/postponed. + +Exceptions +---------- + +There are two sources for exceptions: + +.. slide:: Exceptions + :inline-contents: True + :level: 2 + + * processor detected + + - **faults** + + - **traps** + + - **aborts** + + * programmed + + - **int n** + +Processor detected exceptions are raised when an abnormal condition is +detected while executing an instruction. + +A fault is a type of exception that is reported before the execution of the +instruction and can be usually corrected. The saved EIP is the address of +the instruction that caused the fault, so after the fault is corrected +the program can re-execute the faulty instruction. (e.g page fault). + +A trap is a type of exception that is reported after the execution of the +instruction in which the exception was detected. The saved EIP is the address +of the instruction after the instruction that caused the trap. (e.g debug trap). + +Quiz: interrupt terminology +--------------------------- + +.. slide:: Quiz: interrupt terminology + :inline-contents: True + :level: 2 + + For each of the following terms on the left select all the terms + from right that best describe them. + + .. hlist:: + :columns: 2 + + * Watchdog + * Demand paging + * Division by zero + * Timer + * System call + * Breakpoint + + * Exception + * Interrupt + * Maskable + * Nonmaskable + * Trap + * Fault + + + +Hardware Concepts +================= + +Programmable Interrupt Controller +--------------------------------- + +.. slide:: Programmable Interrupt Controller + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + +-----------+ NMI + | | + | |<----------+ + | | + | | +------------+ + | | | | IRQ0 + | | | |<------------+ device0 + | CPU | | | IRQ1 + | | INTR | PIC |<------------+ device1 + | |<----------+ | IRQN + | | | |<------------+ deviceN + | | | | + +-----------+ +------------+ + +A device supporting interrupts has an output pin used for signaling an Interrupt ReQuest. IRQ +pins are connected to a device named Programmable Interrupt Controller (PIC) which is connected +to CPU's INTR pin. + +A PIC usually has a set of ports used to exchange information with the CPU. When a device +connected to one of the PIC's IRQ lines needs CPU attention the following flow happens: + + * device raises an interrupt on the corresponding IRQn pin + * PIC converts the IRQ into a vector number and writes it to a port for CPU to read + * PIC raises an interrupt on CPU INTR pin + * PIC waits for CPU to acknowledge an interrupt before raising another interrupt + * CPU acknowledges the interrupt then it starts handling the interrupt + +Will see later how the CPU handles the interrupt. Notice that by +design PIC won't raise another interrupt until the CPU acknowledged +the current interrupt. + +.. note:: + + Once the interrupt is acknowledged by the CPU the interrupt + controller can request another interrupt, regardless if the CPU + finished handled the previous interrupt or not. Thus, depending on + how the OS controls the CPU it is possible to have nested + interrupts. + +The interrupt controller allows each IRQ line to be individually +disabled. This allows simplifying design by making sure that interrupt +handlers are always executed serially. + +Interrupt controllers in SMP systems +------------------------------------ + +In SMP systems we may have multiple interrupt controllers in the +systems. + +For example, on the x86 architecture each core has a local APIC used +to process interrupts from locally connected devices like timers or +thermals sensors. Then there is an I/O APIC is used to distribute IRQ +from external devices to CPU cores. + +.. slide:: Interrupt controllers in SMP systems + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + + CPU0 CPU1 + +-------------+ +-------------+ + | | | | + | |local IRQs | |local IRQs + | +---------- | +---------- + | | | | + | local APIC | | local APIC | + | | LINT0, LINT1 | | LINT0, LINT1 + | +------------- | +------------- + | | | | + +-------+-----+ +------+------+ + | | + | | + | | + +-------+--------------------------------+------+ + | | + | Interrupt Controller Communication BUS | + +----------------------+------------------------+ + | + | + +--------+--------+ + | | + | I/O APIC | + | | + +--------+--------+ + | + | + | + External interrupts + + + +Interrupt Control +----------------- + +In order to synchronize access to shared data between the interrupt handler +and other potential concurrent activities such as driver initialization or +driver data processing, it is often required to enable and disable interrupts in +a controlled fashion. + +This can be accomplished at several levels: + +.. slide:: Enabling/disabling the interrupts + :inline-contents: True + :level: 2 + + * at the device level + + * by programming the device control registers + + * at the PIC level + + * PIC can be programmed to disable a given IRQ line + + * at the CPU level; for example, on x86 one can use the following + instructions: + + * cli (CLear Interrupt flag) + * sti (SeT Interrupt flag) + + +Interrupt priorities +--------------------- + +Most architectures also support interrupt priorities. When this is +enabled, it permits interrupt nesting only for those interrupts that +have a higher priority than the current priority level. + +.. slide:: Interrupt priorities + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + Process + context + | + v + IRQ10 | irq10 handler + -----------------------------> +-------------+ + | + IRQ20 (lower priority) | + -----------------------------> pending v + | + IRQ5 (higher priority) | irq5 handler + -----------------------------> +-------->---------+ + | + v + | + +--------<---------+ + | + v + | + -------<-------+ + irq20 handler + Pending IRQ20 ------->-------+ + | + v + | + +--------------+ + | + v + + +.. note:: + + Not all architectures support interrupt priorities. It is also + difficult to support defining a generic scheme for interrupt + priorities for general use OSes and some kernels (Linux included) + do not use interrupt priorities. On the other hand most RTOS use + interrupt priorities since they are typically used in more + constraint use-cases where it is easier to define interrupt + priorities. + + +Quiz: hardware concepts +----------------------- + +.. slide:: Quiz: hardware concepts + :inline-contents: True + :level: 2 + + Which of the following statements are true? + + * The CPU can start processing a new interrupt before the current + one is finished + + * Interrupts can be disabled at the device level + + * Lower priority interrupts can not preempt handlers for higher + priority interrupts + + * Interrupts can be disabled at the interrupt controller level + + * On SMP systems the same interrupt can be routed to different CPUs + + * Interrupts can be disabled at the CPU level + + +Interrupt handling on the x86 architecture +========================================== + +This section will examine how interrupts are handled by the CPU on the +x86 architecture. + +Interrupt Descriptor Table +-------------------------- + +The interrupt descriptor table (IDT) associates each interrupt or exception +identifier with a descriptor for the instructions that service the associated +event. We will name the identifier as vector number and the associated +instructions as interrupt/exception handler. + +An IDT has the following characteristics: + +.. slide:: Interrupt Descriptor Table + :inline-contents: True + :level: 2 + + * it is used as a jump table by the CPU when a given vector is triggered + * it is an array of 256 x 8 bytes entries + * may reside anywhere in physical memory + * processor locates IDT by the means of IDTR + +Below we can find Linux IRQ vector layout. The first 32 entries are reserved +for exceptions, vector 128 is used for syscall interface and the rest are +used mostly for hardware interrupts handlers. + +.. slide:: Linux IRQ vector layout + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + arch/x86/include/asm/irq_vectors.h + +------+ + | 0 | 0..31, system traps and exceptions + +------+ + | 1 | + +------+ + | | + +------+ + | | + | | + | | + +------+ + | 32 | 32..127, device interrupts + +------+ + | | + | | + | | + +------+ + | 128 | int80 syscall interface + +------+ + | 129 | 129..255, other interrupts + +------+ + | | + | | + | | + +------+ + | 255 | + +------+ + +On x86 an IDT entry has 8 bytes and it is named gate. There can be 3 types of gates: + + * interrupt gate, holds the address of an interrupt or exception handler. + Jumping to the handler disables maskable interrupts (IF flag is cleared). + * trap gates, similar to an interrupt gate but it does not disable maskable + interrupts while jumping to interrupt/exception handler. + * task gates (not used in Linux) + +Let's have a look at several fields of an IDT entry: + + * segment selector, index into GDT/LDT to find the start of the code segment where + the interrupt handlers reside + * offset, offset inside the code segment + * T, represents the type of gate + * DPL, minimum privilege required for using the segments content. + +.. slide:: Interrupt descriptor table entry (gate) + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + 63 47 42 32 + +------------------------------+---+---+----+---+---------------+ + | | | D | | | | + | offset (16..31 | P | P | | T | | + | | | L | | | | + +------------------------------+---+---+----+---+---------------+ + | | | + | segment selector | offset (0..15) | + | | | + +------------------------------+--------------------------------+ + 31 15 0 + + +Interrupt handler address +------------------------- + +In order to find the interrupt handler address we first need to find the start +address of the code segment where interrupt handler resides. For this we +use the segment selector to index into GDT/LDT where we can find the corresponding +segment descriptor. This will provide the start address kept in the 'base' field. +Using base address and the offset we can now go to the start of the interrupt handler. + + +.. slide:: Interrupt handler address + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + + Interrupt Descriptor + +----------------------------------------------+ + | | + | +------------------+ +--------+ +------+ | + | | segment selector | | offset| | PL | | + | +----+-------------+ +---+----+ +------+ | + | | | | + +----------------------------------------------+ + | | + | | + +-------------+ +----------------------------> +---------------+ + | ^ | ISR address | + | Segment Descriptor | +---------------+ + | +----------------------------------------------+ | + | | | | + +---->| +------------------+ +--------+ +------+ | | + | | base | | limit | | PL | | | + | +---------+--------+ +--------+ +------+ | | + | | | | + +----------------------------------------------+ | + | | + +--------------------------------------------+ + + +Stack of interrupt handler +-------------------------- + +Similar to control transfer to a normal function, a control transfer +to an interrupt or exception handler uses the stack to store the +information needed for returning to the interrupted code. + +As can be seen in the figure below, an interrupt pushes the EFLAGS register +before saving the address of the interrupted instruction. Certain types +of exceptions also cause an error code to be pushed on the stack to help +debug the exception. + + +.. slide:: Interrupt handler stack + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + + w/o privilege transition w/ privilege transition + + + +---------------------+ +---------------------+ + | | | | | + | | | OLD SS:ESP | OLD SS | NEW SS:ESP from TSS + | +---------------------+ +---------------------+ + | | | | | + | | OLD EFLAGS | | OLD ESP | + | +---------------------+ +---------------------+ + | | | | | + | | OLD CS | | OLD EFLAGS | + | +---------------------+ +---------------------+ + | | | | | + | | OLD EIP | | OLD CS | + | +---------------------+ +---------------------+ + | | | | | + | | (error code) | NEW SS:ESP | OLD EIP | + | +---------------------+ +---------------------+ + | | | | | + | | | | (error code) | NEW SS:ESP + | | | +---------------------+ + | | | | | + | | | | | + | | | | | + | | | | | + | | | | | + | | | | | + | | | | | + v +---------------------+ +---------------------+ + + +Handling an interrupt request +----------------------------- + +After an interrupt request has been generated the processor runs a sequence of +events that eventually end up with running the kernel interrupt handler: + + +.. slide:: Handling an interrupt request + :inline-contents: True + :level: 2 + + + * CPU checks the current privilege level + * if need to change privilege level + + * change stack with the one associated with new privilege + * save old stack information on the new stack + + * save EFLAGS, CS, EIP on stack + * save error code on stack in case of an abort + * execute the kernel interrupt handler + +Returning from an interrupt handler +----------------------------------- + +Most architectures offer special instructions to clean up the stack and resume +the execution after the interrupt handler has been executed. On x86 IRET is used +to return from an interrupt handler. IRET is similar to RET except that IRET +increments ESP by extra four bytes (because of the flags on stack) and moves the +saved flags into EFLAGS register. + +To resume the execution after an interrupt the following sequence is used (x86): + +.. slide:: Returning from an interrupt + :inline-contents: True + :level: 2 + + * pop the error code (in case of an abort) + * call IRET + + * pops values from the stack and restore the following register: CS, EIP, EFLAGS + * if privilege level changed returns to the old stack and old privilege level + +Inspecting the x86 interrupt handling +------------------------------------- + +.. slide:: Inspecting the x86 interrupt handling + :inline-contents: True + :level: 2 + + |_| + + .. asciicast:: ../res/intr_x86.cast + + +Quiz: x86 interrupt handling +---------------------------- + +.. slide:: Quiz: x86 interrupt handling + :inline-contents: True + :level: 2 + + The following gdb commands are used to determine the handler for + the int80 based system call exception. Select and arrange the + commands or output of the commands in the correct order. + + .. code-block:: gdb + + (void *) 0xc15de780 <entry_SYSENTER_32> + + set $idtr_addr=($idtr_entry>>48<<16)|($idtr_entry&0xffff) + + print (void*)$idtr_addr + + set $idtr = 0xff800000 + + (void *) 0xc15de874 <entry_INT80_32> + + set $idtr = 0xff801000 + + set $idtr_entry = *(uint64_t*)($idtr + 8 * 128) + + monitor info registers + +Interrupt handling in Linux +=========================== + +In Linux the interrupt handling is done in three phases: critical, immediate and +deferred. + +In the first phase the kernel will run the generic interrupt handler that +determines the interrupt number, the interrupt handler for this particular +interrupt and the interrupt controller. At this point any timing critical +actions will also be performed (e.g. acknowledge the interrupt at the interrupt +controller level). Local processor interrupts are disabled for the duration of +this phase and continue to be disabled in the next phase. + +In the second phase, all of the device driver's handlers associated with this +interrupt will be executed. At the end of this phase, the interrupt controller's +"end of interrupt" method is called to allow the interrupt controller to +reassert this interrupt. The local processor interrupts are enabled at this +point. + +.. note:: + + It is possible that one interrupt is associated with multiple + devices and in this case it is said that the interrupt is + shared. Usually, when using shared interrupts it is the + responsibility of the device driver to determine if the interrupt + is target to its device or not. + +Finally, in the last phase of interrupt handling interrupt context deferrable +actions will be run. These are also sometimes known as "bottom half" of the +interrupt (the upper half being the part of the interrupt handling that runs +with interrupts disabled). At this point, interrupts are enabled on the local +processor. + +.. slide:: Interrupt handling in Linux + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + + phase 1 + +----------------+ + | critical | phase 2 + +----------------+ +-----------------+ + | | | immediate | phase 3 + | - IRQ disabled | +-----------------+ +----------------+ + | - ACK IRQ +-----+ | | | deferred | + | | +---> - IRQ disabled | +----------------+ + +----------------+ | - device handler| | | + | - EOI IRQ +-----+ | - IRQ enabled | + +-----------------+ +----> - execute later| + | | + +----------------+ + + +Nested interrupts and exceptions +-------------------------------- + +Linux used to support nested interrupts but this was removed some time +ago in order to avoid increasingly complex solutions to stack +overflows issues - allow just one level of nesting, allow multiple +levels of nesting up to a certain kernel stack depth, etc. + +However, it is still possible to have nesting between exceptions and +interrupts but the rules are fairly restrictive: + +.. slide:: IRQ and exception nesting in Linux + :inline-contents: True + :level: 2 + + * an exception (e.g. page fault, system call) can not preempt an interrupt; + if that occurs it is considered a bug + + * an interrupt can preempt an exception + + * an interrupt can not preempt another interrupt (it used to be possible) + + +The diagram below shows the possible nesting scenarios: + +.. slide:: Interrupt/Exception nesting + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + + ^ + ^ + | | | | + | Syscall | IRQi| | + User Mode | Exception (e.g. page fault) | | | + | | | | + +------------------------------------+-----+-----------------+ + | iret| | iret^ IRQj| iret| + | | | | | | + Kernel Mode v-------+ ^-------+ ^------+ v-----+ v-----+ + | | | | + IRQi| iret| IRQj| iret| + v------+ v------+ + +Interrupt context +----------------- + +While an interrupt is handled (from the time the CPU jumps to the interrupt +handler until the interrupt handler returns - e.g. IRET is issued) it is said +that code runs in "interrupt context". + +Code that runs in interrupt context has the following properties: + +.. slide:: Interrupt context + :inline-contents: True + :level: 2 + + * it runs as a result of an IRQ (not of an exception) + * there is no well defined process context associated + * not allowed to trigger a context switch (no sleep, schedule, or user memory access) + +Deferrable actions +------------------ + +Deferrable actions are used to run callback functions at a later time. If +deferrable actions scheduled from an interrupt handler, the associated callback +function will run after the interrupt handler has completed. + +There are two large categories of deferrable actions: those that run in +interrupt context and those that run in process context. + +The purpose of interrupt context deferrable actions is to avoid doing too much +work in the interrupt handler function. Running for too long with interrupts +disabled can have undesired effects such as increased latency or poor system +performance due to missing other interrupts (e.g. dropping network packets +because the CPU did not react in time to dequeue packets from the network +interface and the network card buffer is full). + +Deferrable actions have APIs to: **initialize** an instance, **activate** or +**schedule** the action and **mask/disable** and **unmask/enable** the execution +of the callback function. The latter is used for synchronization purposes between +the callback function and other contexts. + +Typically the device driver will initialize the deferrable action +structure during the device instance initialization and will activate +/ schedule the deferrable action from the interrupt handler. + +.. slide:: Deferrable actions + :inline-contents: False + :level: 2 + + + * Schedule callback functions to run at a later time + + * Interrupt context deferrable actions + + * Process context deferrable actions + + * APIs for initialization, scheduling, and masking + +Soft IRQs +--------- + +Soft IRQs is the term used for the low-level mechanism that implements deferring +work from interrupt handlers but that still runs in interrupt context. + +.. slide:: Soft IRQs + :inline-contents: True + :level: 2 + + Soft IRQ APIs: + + * initialize: :c:func:`open_softirq` + * activation: :c:func:`raise_softirq` + * masking: :c:func:`local_bh_disable`, :c:func:`local_bh_enable` + + Once activated, the callback function :c:func:`do_softirq` runs either: + + * after an interrupt handler or + * from the ksoftirqd kernel thread + + +Since softirqs can reschedule themselves or other interrupts can occur that +reschedules them, they can potentially lead to (temporary) process starvation if +checks are not put into place. Currently, the Linux kernel does not allow +running soft irqs for more than :c:macro:`MAX_SOFTIRQ_TIME` or rescheduling for +more than :c:macro:`MAX_SOFTIRQ_RESTART` consecutive times. + +Once these limits are reached a special kernel thread, **ksoftirqd** is woken up +and all of the rest of pending soft irqs will be run from the context of this +kernel thread. + +.. slide:: ksoftirqd + :inline-contents: False + :level: 2 + + * minimum priority kernel thread + * runs softirqs after certain limits are reached + * tries to achieve good latency and avoid process starvation + +Soft irqs usage is restricted, they are use by a handful of subsystems that have +low latency requirements and high frequency: + +.. slide:: Types of soft IRQs + :inline-contents: True + :level: 2 + + .. code-block:: c + + /* PLEASE, avoid to allocate new softirqs, if you need not _really_ high + frequency threaded job scheduling. For almost all the purposes + tasklets are more than enough. F.e. all serial device BHs et + al. should be converted to tasklets, not to softirqs. + */ + + enum + { + HI_SOFTIRQ=0, + TIMER_SOFTIRQ, + NET_TX_SOFTIRQ, + NET_RX_SOFTIRQ, + BLOCK_SOFTIRQ, + IRQ_POLL_SOFTIRQ, + TASKLET_SOFTIRQ, + SCHED_SOFTIRQ, + HRTIMER_SOFTIRQ, + RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */ + + NR_SOFTIRQS + }; + + +Packet flood example +--------------------- + +The following screencast will look at what happens when we flood the +system with a large number of packets. Since at least a part of the +packet processing is happening in softirq we should expect the CPU to +spend most of the time running softirqs but the majority of that +should be in the context of the `ksoftirqd` thread. + +.. slide:: Packet flood example + :inline-contents: True + :level: 2 + + |_| + + .. asciicast:: ../res/ksoftirqd-packet-flood.cast + + +Tasklets +-------- + +.. slide:: Tasklets + :inline-contents: True + :level: 2 + + Tasklets are a dynamic type (not limited to a fixed number) of + deferred work running in interrupt context. + + Tasklets API: + + * initialization: :c:func:`tasklet_init` + * activation: :c:func:`tasklet_schedule` + * masking: :c:func:`tasklet_disable`, :c:func:`tasklet_enable` + + Tasklets are implemented on top of two dedicated softirqs: + :c:macro:`TASKLET_SOFITIRQ` and :c:macro:`HI_SOFTIRQ` + + Tasklets are also serialized, i.e. the same tasklet can only execute on one processor. + + +Workqueues +---------- + + .. slide:: Workqueues + :inline-contents: True + :level: 2 + + Workqueues are a type of deferred work that runs in process context. + + They are implemented on top of kernel threads. + + Workqueues API: + + * init: :c:macro:`INIT_WORK` + * activation: :c:func:`schedule_work` + +Timers +------ + +.. slide:: Timers + :inline-contents: True + :level: 2 + + Timers are implemented on top of the :c:macro:`TIMER_SOFTIRQ` + + Timer API: + + * initialization: :c:func:`setup_timer` + * activation: :c:func:`mod_timer` + +Deferrable actions summary +-------------------------- + +Here is a cheat sheet which summarizes Linux deferrable actions: + + +.. slide:: Deferrable actions summary + :inline-contents: True + :level: 2 + + * softIRQ + + * runs in interrupt context + * statically allocated + * same handler may run in parallel on multiple cores + + * tasklet + + * runs in interrupt context + * can be dynamically allocated + * same handler runs are serialized + + * workqueues + + * run in process context + +Quiz: Linux interrupt handling +------------------------------ + +.. slide:: Quiz: Linux interrupt handling + :inline-contents: True + :level: 2 + + Which of the following phases of interrupt handling runs with + interrupts disabled at the CPU level? + + * Critical + + * Immediate + + * Deferred diff --git a/refs/pull/405/merge/_sources/lectures/intro.rst.txt b/refs/pull/405/merge/_sources/lectures/intro.rst.txt new file mode 100644 index 00000000..7d336d39 --- /dev/null +++ b/refs/pull/405/merge/_sources/lectures/intro.rst.txt @@ -0,0 +1,1166 @@ +============ +Introduction +============ + +`View slides <intro-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +Lecture objectives: +=================== + +.. slide:: Introduction + :inline-contents: True + :level: 2 + + * Basic operating systems terms and concepts + + * Overview of the Linux kernel + + +Basic operating systems terms and concepts +========================================== + +User vs Kernel +-------------- + +.. slide:: User vs Kernel + :level: 2 + + * Execution modes + + * Kernel mode + + * User mode + + * Memory protection + + * Kernel-space + + * User-space + + +Kernel and user are two terms that are often used in operating +systems. Their definition is pretty straight forward: The kernel is +the part of the operating system that runs with higher privileges +while user (space) usually means by applications running with low +privileges. + +However these terms are heavily overloaded and might have very +specific meanings in some contexts. + +User mode and kernel mode are terms that may refer specifically to the +processor execution mode. Code that runs in kernel mode can fully +[#hypervisor]_ control the CPU while code that runs in user mode has +certain limitations. For example, local CPU interrupts can only be +disabled or enable while running in kernel mode. If such an operation +is attempted while running in user mode an exception will be generated +and the kernel will take over to handle it. + +.. [#hypervisor] some processors may have even higher privileges than + kernel mode, e.g. a hypervisor mode, that is only + accessible to code running in a hypervisor (virtual + machine monitor) + +User space and kernel space may refer specifically to memory +protection or to virtual address spaces associated with either the +kernel or user applications. + +Grossly simplifying, the kernel space is the memory area that is +reserved to the kernel while user space is the memory area reserved to +a particular user process. The kernel space is accessed protected so +that user applications can not access it directly, while user space +can be directly accessed from code running in kernel mode. + + +Typical operating system architecture +------------------------------------- + +In the typical operating system architecture (see the figure below) +the operating system kernel is responsible for access and sharing the +hardware in a secure and fair manner with multiple applications. + +.. slide:: Typical operating system architecture + :level: 2 + :inline-contents: True + + .. ditaa:: + + +---------------+ +--------------+ +---------------+ -\ + | Application 1 | | Application2 | ... | Application n | | + +---------------+ +--------------+ +---------------+ |> User space + | | | | + v v v -/ + +--------------------------------------------------------+ -\ + | System Call Interface | | + +--------------------------------------------------------+ | + | | | | + v v v |> Kernel space + +--------------------------------------------------------+ | + | Kernel | | + +--------------------------------------------------------+ | + | Device drivers | | + +--------------------------------------------------------+ -/ + | | | -\ + v v v |> Hardware + -/ + + + +The kernel offers a set of APIs that applications issue which are +generally referred to as "System Calls". These APIs are different from +regular library APIs because they are the boundary at which the +execution mode switch from user mode to kernel mode. + +In order to provide application compatibility, system calls are rarely +changed. Linux particularly enforces this (as opposed to in kernel +APIs that can change as needed). + +The kernel code itself can be logically separated in core kernel +code and device drivers code. Device drivers code is responsible of +accessing particular devices while the core kernel code is +generic. The core kernel can be further divided into multiple logical +subsystems (e.g. file access, networking, process management, etc.) + + +Monolithic kernel +----------------- + +A monolithic kernel is one where there is no access protection between +the various kernel subsystems and where public functions can be +directly called between various subsystems. + + +.. slide:: Monolithic kernel + :level: 2 + :inline-contents: True + + .. ditaa:: + + +-----+ +-----+ +-----+ + | App | | App | | App | + +-----+ +-----+ +-----+ + | | | User + =--|-------=--------|--------=-------|-------------------=- + | | | Kernel + v v v + +--------------------------------------------------------+ + | System Call Interface | + +--------------------------------------------------------+ + | | + v v + +-----+ +-----+ + | |<---------------------------->| | Kernel + | |<---+ +------->| | functions + +--+--+ | | +-----+ + | | | ^ + | | +-----+ | | + |+------+---->| |<---+ | + || | +-----+ | + || | | + vv | v + +--++-+ | +-----+ + | | +------------------------>| | Device + | |<---------------------------->| | Drivers + +--+--+ +--+--+ + | | + v v + +--------------------------------------------------------+ + | Hardware | + +--------------------------------------------------------+ + + +However, most monolithic kernels do enforce a logical separation +between subsystems especially between the core kernel and device +drivers with relatively strict APIs (but not necessarily fixed in +stone) that must be used to access services offered by one subsystem +or device drivers. This, of course, depends on the particular kernel +implementation and the kernel's architecture. + + +Micro kernel +------------ + +A micro-kernel is one where large parts of the kernel are protected +from each-other, usually running as services in user space. Because +significant parts of the kernel are now running in user mode, the +remaining code that runs in kernel mode is significantly smaller, hence +micro-kernel term. + +.. slide:: Micro-kernel + :level: 2 + :inline-contents: True + + .. ditaa:: + + +-----+ +--------+ +---------+ +---------+ + | App | | File | | Network | | Display |<--+ + | | | Server | | Server | | Server |-+ | + +-----+ +--------+ +---------+ +---------+ | | + | ^ | | User + -|-|----------------------------------------=-|-|-------=- + | | | | Kernel + | | | | + | | | | + | | | | + | | Reply +----------------------------+ | | + | +--------| |----+ | + +--------->| Micro kernel |------+ + Request | (IPC, Memory, Scheduler) | + | | + +----------------------------+ + | + v + +--------------------------------------------------------+ + | Hardware | + +--------------------------------------------------------+ + + +In a micro-kernel architecture the kernel contains just enough code +that allows for message passing between different running +processes. Practically that means implement the scheduler and an IPC +mechanism in the kernel, as well as basic memory management to setup +the protection between applications and services. + +One of the advantages of this architecture is that the services are +isolated and hence bugs in one service won't impact other services. + +As such, if a service crashes we can just restart it without affecting +the whole system. However, in practice this is difficult to achieve +since restarting a service may affect all applications that depend on +that service (e.g. if the file server crashes all applications with +opened file descriptors would encounter errors when accessing them). + +This architecture imposes a modular approach to the kernel and offers +memory protection between services but at a cost of performance. What +is a simple function call between two services on monolithic kernels +now requires going through IPC and scheduling which will incur a +performance penalty [#minix-vs-linux]_. + +.. [#minix-vs-linux] https://lwn.net/Articles/220255/ + + +Micro-kernels vs monolithic kernels +----------------------------------- + +Advocates of micro-kernels often suggest that micro-kernel are +superior because of the modular design a micro-kernel +enforces. However, monolithic kernels can also be modular and there +are several approaches that modern monolithic kernels use toward this +goal: + +.. slide:: Monolithic kernels *can* be modular + :level: 2 + :inline-contents: True + + * Components can enabled or disabled at compile time + + * Support of loadable kernel modules (at runtime) + + * Organize the kernel in logical, independent subsystems + + * Strict interfaces but with low performance overhead: macros, + inline functions, function pointers + + +There is a class of operating systems that (used to) claim to be +hybrid kernels, in between monolithic and micro-kernels (e.g. Windows, +Mac OS X). However, since all of the typical monolithic services run +in kernel-mode in these operating systems, there is little merit to +qualify them other then monolithic kernels. + +.. slide:: "Hybrid" kernels + :level: 2 + :inline-contents: True + + Many operating systems and kernel experts have dismissed the label + as meaningless, and just marketing. Linus Torvalds said of this + issue: + + "As to the whole 'hybrid kernel' thing - it's just marketing. It's + 'oh, those microkernels had good PR, how can we try to get good PR + for our working kernel? Oh, I know, let's use a cool name and try + to imply that it has all the PR advantages that that other system + has'." + + +Address space +------------- + +.. slide:: Address space + :level: 2 + + * Physical address space + + * RAM and peripheral memory + + * Virtual address space + + * How the CPU sees the memory (when in protected / paging mode) + + * Process address space + + * Kernel address space + + +The address space term is an overload term that can have different +meanings in different contexts. + +The physical address space refers to the way the RAM and device +memories are visible on the memory bus. For example, on 32bit Intel +architecture, it is common to have the RAM mapped into the lower +physical address space while the graphics card memory is mapped high +in the physical address space. + +The virtual address space (or sometimes just address space) refers to +the way the CPU sees the memory when the virtual memory module is +activated (sometime called protected mode or paging enabled). The +kernel is responsible of setting up a mapping that creates a virtual +address space in which areas of this space are mapped to certain +physical memory areas. + +Related to the virtual address space there are two other terms that +are often used: process (address) space and kernel (address) space. + +The process space is (part of) the virtual address space associated +with a process. It is the "memory view" of processes. It is a +continuous area that starts at zero. Where the process's address space +ends depends on the implementation and architecture. + +The kernel space is the "memory view" of the code that runs in kernel +mode. + + +User and kernel sharing the virtual address space +------------------------------------------------- + +A typical implementation for user and kernel spaces is one where the +virtual address space is shared between user processes and the kernel. + +In this case kernel space is located at the top of the address space, +while user space at the bottom. In order to prevent the user processes +from accessing kernel space, the kernel creates mappings that prevent +access to the kernel space from user mode. + +.. slide:: User and kernel sharing the virtual address space + :level: 2 + :inline-contents: True + + .. ditaa:: + + +-------------------+ ^ + 0xFFFFFFFF | | | + | | | Kernel space + | | | + +-------------------+ v + 0xC0000000 | | ^ + | | | User space + | | | + | | | + | | | + | | | + | | | + | | | + | | | + 0x00000000 +-------------------+ v + + 32bit Virtual Address Space + +Execution contexts +------------------ + +.. slide:: Execution contexts + :level: 2 + + * Process context + + * Code that runs in user mode, part of a process + + * Code that runs in kernel mode, as a result of a system call + issued by a process + + * Interrupt context + + * Code that runs as a result of an interrupt + + * Always runs in kernel mode + + +One of the most important jobs of the kernel is to service interrupts +and to service them efficiently. This is so important that a special +execution context is associated with it. + +The kernel executes in interrupt context when it runs as a result of +an interrupt. This includes the interrupt handler, but it is not +limited to it, there are other special (software) constructs that run +in interrupt mode. + +Code running in interrupt context always runs in kernel mode and there +are certain limitations that the kernel programmer has to be aware of +(e.g. not calling blocking functions or accessing user space). + +Opposed to interrupt context there is process context. Code that runs +in process context can do so in user mode (executing application code) +or in kernel mode (executing a system call). + + +Multi-tasking +------------- + +.. slide:: Multi-tasking + :level: 2 + + * An OS that supports the "simultaneous" execution of multiple processes + + * Implemented by fast switching between running processes to allow + the user to interact with each program + + * Implementation: + + * Cooperative + + * Preemptive + +Multitasking is the ability of the operating system to +"simultaneously" execute multiple programs. It does so by quickly +switching between running processes. + +Cooperative multitasking requires the programs to cooperate to achieve +multitasking. A program will run and relinquish CPU control back +to the OS, which will then schedule another program. + +With preemptive multitasking the kernel will enforce strict limits for +each process, so that all processes have a fair chance of +running. Each process is allowed to run a time slice (e.g. 100ms) +after which, if it is still running, it is forcefully preempted and +another task is scheduled. + +Preemptive kernel +----------------- + +.. slide:: Preemptive kernel + :level: 2 + :inline-contents: True + + Preemptive multitasking and preemptive kernels are different terms. + + A kernel is preemptive if a process can be preempted while running + in kernel mode. + + However, note that non-preemptive kernels may support preemptive + multitasking. + + +Pageable kernel memory +---------------------- + +.. slide:: Pageable kernel memory + :level: 2 + :inline-contents: True + + A kernel supports pageable kernel memory if parts of kernel memory + (code, data, stack or dynamically allocated memory) can be swapped + to disk. + +Kernel stack +------------ + +.. slide:: Kernel stack + :level: 2 + :inline-contents: True + + Each process has a kernel stack that is used to maintain the + function call chain and local variables state while it is executing + in kernel mode, as a result of a system call. + + The kernel stack is small (4KB - 12 KB) so the kernel developer has + to avoid allocating large structures on stack or recursive calls + that are not properly bounded. + +Portability +----------- + +In order to increase portability across various architectures and +hardware configurations, modern kernels are organized as follows at the +top level: + +.. slide:: Portability + :level: 2 + :inline-contents: True + + * Architecture and machine specific code (C & ASM) + + * Independent architecture code (C): + + * kernel core (further split in multiple subsystems) + + * device drivers + +This makes it easier to reuse code as much as possible between +different architectures and machine configurations. + + +Asymmetric MultiProcessing (ASMP) +--------------------------------- + +Asymmetric MultiProcessing (ASMP) is a way of supporting multiple +processors (cores) by a kernel, where a processor is dedicated to the +kernel and all other processors run user space programs. + +The disadvantage of this approach is that the kernel throughput +(e.g. system calls, interrupt handling, etc.) does not scale with the +number of processors and hence typical processes frequently use system +calls. The scalability of the approach is limited to very specific +systems (e.g. scientific applications). + + +.. slide:: Asymmetric MultiProcessing (ASMP) + :level: 2 + :inline-contents: True + + .. ditaa:: + + +-----------+ + | | + +------------------>| Memory |<-----------------+ + | | | | + | +-----------+ | + | ^ | + | | | + v v v + +--------------+ +---------------+ +---------------+ + | | | | | | + | Processor A | | Processor B | | Processor C | + | | | | | | + | | | +-----------+ | | +-----------+ | + | | | | Process 1 | | | | Process 1 | | + | | | +-----------+ | | +-----------+ | + | | | | | | + | +----------+ | | +-----------+ | | +-----------+ | + | | kernel | | | | Process 2 | | | | Process 2 | | + | +----------+ | | +-----------+ | | +-----------+ | + | | | | | | + | | | +-----------+ | | +-----------+ | + | | | | Process 3 | | | | Process 3 | | + | | | +-----------+ | | +-----------+ | + +--------------+ +---------------+ +---------------+ + + +Symmetric MultiProcessing (SMP) +------------------------------- + +As opposed to ASMP, in SMP mode the kernel can run on any of the +existing processors, just as user processes. This approach is more +difficult to implement, because it creates race conditions in the +kernel if two processes run kernel functions that access the same +memory locations. + +In order to support SMP the kernel must implement synchronization +primitives (e.g. spin locks) to guarantee that only one processor is +executing a critical section. + +.. slide:: Symmetric MultiProcessing (SMP) + :level: 2 + :inline-contents: True + + .. ditaa:: + + +-----------+ + | | + +------------------->| Memory |<------------------+ + | | | | + | +-----------+ | + | ^ | + | | | + v v v + +---------------+ +---------------+ +---------------+ + | | | | | | + | Processor A | | Processor B | | Processor C | + | | | | | | + | +-----------+ | | +-----------+ | | +-----------+ | + | | Process 1 | | | | Process 1 | | | | Process 1 | | + | +-----------+ | | +-----------+ | | +-----------+ | + | | | | | | + | +-----------+ | | +-----------+ | | +-----------+ | + | | Process 2 | | | | Process 2 | | | | Process 2 | | + | +-----------+ | | +-----------+ | | +-----------+ | + | | | | | | + | +-----------+ | | +-----------+ | | +-----------+ | + | | kernel | | | | kernel | | | | kernel | | + | +-----------+ | | +-----------+ | | +-----------+ | + +---------------+ +---------------+ +---------------+ + + +CPU Scalability +--------------- + +CPU scalability refers to how well the performance scales with +the number of cores. There are a few things that the kernel developer +should keep in mind with regard to CPU scalability: + +.. slide:: CPU Scalability + :level: 2 + :inline-contents: True + + * Use lock free algorithms when possible + + * Use fine grained locking for high contention areas + + * Pay attention to algorithm complexity + + +Overview of the Linux kernel +============================ + + +Linux development model +----------------------- + +.. slide:: Linux development model + :level: 2 + + * Open source, GPLv2 License + + * Contributors: companies, academia and independent developers + + * Development cycle: 3 – 4 months which consists of a 1 - 2 week + merge window followed by bug fixing + + * Features are only allowed in the merge window + + * After the merge window a release candidate is done on a weekly + basis (rc1, rc2, etc.) + +The Linux kernel is one the largest open source projects in the world +with thousands of developers contributing code and millions of lines of +code changed for each release. + +It is distributed under the GPLv2 license, which simply put, +requires that any modification of the kernel done on software that is +shipped to customer should be made available to them (the customers), +although in practice most companies make the source code publicly +available. + +There are many companies (often competing) that contribute code to the +Linux kernel as well as people from academia and independent +developers. + +The current development model is based on doing releases at fixed +intervals of time (usually 3 - 4 months). New features are merged into +the kernel during a one or two week merge window. After the merge +window, a release candidate is done on a weekly basis (rc1, rc2, etc.) + + +Maintainer hierarchy +-------------------- + +In order to scale the development process, Linux uses a hierarchical +maintainership model: + +.. slide:: Maintainer hierarchy + :level: 2 + :inline-contents: True + + * Linus Torvalds is the maintainer of the Linux kernel and merges pull + requests from subsystem maintainers + + * Each subsystem has one or more maintainers that accept patches or + pull requests from developers or device driver maintainers + + * Each maintainer has its own git tree, e.g.: + + * Linux Torvalds: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git + + * David Miller (networking): git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git/ + + * Each subsystem may maintain a -next tree where developers can submit + patches for the next merge window + +Since the merge window is only a maximum of two weeks, most of the +maintainers have a -next tree where they accept new features from +developers or maintainers downstream while even when the merge window +is closed. + +Note that bug fixes are accepted even outside merge window in the +maintainer's tree from where they are periodically pulled by the +upstream maintainer regularly, for every release candidate. + + + +Linux source code layout +------------------------- + +.. slide:: Linux source code layout + :level: 2 + :inline-contents: True + + .. ditaa:: + + +-------+ + | linux | + +-+-----+ + | + +------+--------+---------+---------+--------------+--------------+ + | | | | | | | + | v v v v v v + | +------+ +-------+ +-------+ +--------+ +---------------+ +---------+ + | | arch | | block | | certs | | crypto | | Documentation | | drivers | + | +------+ +-------+ +-------+ +--------+ +---------------+ +---------+ + | + +-------+----------+--------+---------+--------+--------+---------+ + | | | | | | | | + | v v v v v v v + | +----------+ +----+ +---------+ +------+ +-----+ +--------+ +-----+ + | | firmware | | fs | | include | | init | | ipc | | kernel | | lib | + | +----------+ +----+ +---------+ +------+ +-----+ +--------+ +-----+ + | + +-----+------+---------+------------+------------+------------+ + | | | | | | | + | v v v v v v + | +----+ +-----+ +---------+ +---------+ +----------+ +-------+ + | | mm | | net | | samples | | scripts | | security | | sound | + | +----+ +-----+ +---------+ +---------+ +----------+ +-------+ + | + +------+--------+--------+ + | | | + v v v + +-------+ +-----+ +------+ + | tools | | usr | | virt | + +-------+ +-----+ +------+ + + +These are the top level of the Linux source code folders: + +* arch - contains architecture specific code; each architecture is + implemented in a specific sub-folder (e.g. arm, arm64, x86) + +* block - contains the block subsystem code that deals with reading + and writing data from block devices: creating block I/O requests, + scheduling them (there are several I/O schedulers available), + merging requests, and passing them down through the I/O stack to the + block device drivers + +* certs - implements support for signature checking using certificates + +* crypto - software implementation of various cryptography algorithms + as well as a framework that allows offloading such algorithms in + hardware + +* Documentation - documentation for various subsystems, Linux kernel + command line options, description for sysfs files and format, device + tree bindings (supported device tree nodes and format) + +* drivers - driver for various devices as well as the Linux driver + model implementation (an abstraction that describes drivers, devices + buses and the way they are connected) + +* firmware - binary or hex firmware files that are used by various + device drivers + +* fs - home of the Virtual Filesystem Switch (generic filesystem code) + and of various filesystem drivers + +* include - header files + +* init - the generic (as opposed to architecture specific) + initialization code that runs during boot + +* ipc - implementation for various Inter Process Communication system + calls such as message queue, semaphores, shared memory + +* kernel - process management code (including support for kernel + thread, workqueues), scheduler, tracing, time management, generic + irq code, locking + +* lib - various generic functions such as sorting, checksums, + compression and decompression, bitmap manipulation, etc. + +* mm - memory management code, for both physical and virtual memory, + including the page, SL*B and CMA allocators, swapping, virtual memory + mapping, process address space manipulation, etc. + +* net - implementation for various network stacks including IPv4 and + IPv6; BSD socket implementation, routing, filtering, packet + scheduling, bridging, etc. + +* samples - various driver samples + +* scripts - parts the build system, scripts used for building modules, + kconfig the Linux kernel configurator, as well as various other + scripts (e.g. checkpatch.pl that checks if a patch is conform with + the Linux kernel coding style) + +* security - home of the Linux Security Module framework that allows + extending the default (Unix) security model as well as + implementation for multiple such extensions such as SELinux, smack, + apparmor, tomoyo, etc. + +* sound - home of ALSA (Advanced Linux Sound System) as well as the + old Linux sound framework (OSS) + +* tools - various user space tools for testing or interacting with + Linux kernel subsystems + +* usr - support for embedding an initrd file in the kernel image + +* virt - home of the KVM (Kernel Virtual Machine) hypervisor + + +Linux kernel architecture +------------------------- + +.. slide:: Linux kernel architecture + :level: 2 + :inline-contents: True + + .. ditaa:: + :height: 100% + + +---------------+ +--------------+ +---------------+ + | Application 1 | | Application2 | ... | Application n | + +---------------+ +--------------+ +---------------+ + | | | + v v v + +--------------------------------------------------------+ + | Kernel | + | | + | +----------------------+ +-------------------+ | + | | Process Management | | Memory Management | | + | +----------------------+ +-------------------+ | + | | + | +------------+ +------------+ +------------+ | + | | Block I/O | | VFS | | Networking | | + | +------------+ +------------+ +------------+ | + | | + | +------------+ +------------+ +------------+ | + | | IPC | | Security | | Crypto | | + | +------------+ +------------+ +------------+ | + | | + | +------------+ +------------+ +------------+ | + | | DRM | | ALSA | | USB | | + | +------------+ +------------+ +------------+ | + | ... | + +--------------------------------------+-----------------+ + | Device drivers | arch | + | | | + | +----+ +-----+ +--------+ +----+ | +----------+ | + | |char| |block| |ethernet| |wifi| | | machine 1| | + | +----+ +-----+ +--------+ +----+ | +----------+ | + | +----------+ +-----+ +----+ +---+ | +----------+ | + | |filesystem| |input| |iio | |usb| | | machine 2| | + | +----------+ +-----+ +----+ +---+ | +----------+ | + | +-----------+ +----------+ +---+ | | + | |framebuffer| | platform | |drm| | ... | + | +-----------+ +----------+ +---+ | | + +-------------------------+----+-------+-----------------+ + | | | + v v v + + +--------------------------------------------------------+ + | Hardware | + +--------------------------------------------------------+ + + +arch +.... + +.. slide:: arch + :level: 2 + :inline-contents: True + + * Architecture specific code + + * May be further sub-divided in machine specific code + + * Interfacing with the boot loader and architecture specific + initialization + + * Access to various hardware bits that are architecture or machine + specific such as interrupt controller, SMP controllers, BUS + controllers, exceptions and interrupt setup, virtual memory handling + + * Architecture optimized functions (e.g. memcpy, string operations, + etc.) + +This part of the Linux kernel contains architecture specific code and +may be further sub-divided in machine specific code for certain +architectures (e.g. arm). + +"Linux was first developed for 32-bit x86-based PCs (386 or +higher). These days it also runs on (at least) the Compaq Alpha AXP, +Sun SPARC and UltraSPARC, Motorola 68000, PowerPC, PowerPC64, ARM, +Hitachi SuperH, IBM S/390, MIPS, HP PA-RISC, Intel IA-64, DEC VAX, AMD +x86-64 and CRIS architectures.” + +It implements access to various hardware bits that are architecture or +machine specific such as interrupt controller, SMP controllers, BUS +controllers, exceptions and interrupt setup, virtual memory handling. + +It also implements architecture optimized functions (e.g. memcpy, +string operations, etc.) + + +Device drivers +.............. + +.. slide:: Device drivers + :level: 2 + + * Unified device model + + * Each subsystem has its own specific driver interfaces + + * Many device driver types (TTY, serial, SCSI, fileystem, ethernet, + USB, framebuffer, input, sound, etc.) + +The Linux kernel uses a unified device model whose purpose is to +maintain internal data structures that reflect the state and structure +of the system. Such information includes what devices are present, +what is their status, what bus they are attached to, to what driver +they are attached, etc. This information is essential for implementing +system wide power management, as well as device discovery and dynamic +device removal. + +Each subsystem has its own specific driver interface that is tailored +to the devices it represents in order to make it easier to write +correct drivers and to reduce code duplication. + +Linux supports one of the most diverse set of device drivers type, +some examples are: TTY, serial, SCSI, fileystem, ethernet, USB, +framebuffer, input, sound, etc. + + +Process management +.................. + +.. slide:: Process management + :level: 2 + + * Unix basic process management and POSIX threads support + + * Processes and threads are abstracted as tasks + + * Operating system level virtualization + + * Namespaces + + * Control groups + +Linux implements the standard Unix process management APIs such as +fork(), exec(), wait(), as well as standard POSIX threads. + +However, Linux processes and threads are implemented particularly +different than other kernels. There are no internal structures +implementing processes or threads, instead there is a :c:type:`struct +task_struct` that describe an abstract scheduling unit called task. + +A task has pointers to resources, such as address space, file +descriptors, IPC ids, etc. The resource pointers for tasks that are +part of the same process point to the same resources, while resources +of tasks of different processes will point to different resources. + +This peculiarity, together with the `clone()` and `unshare()` system +call allows for implementing new features such as namespaces. + +Namespaces are used together with control groups (cgroup) to implement +operating system virtualization in Linux. + +cgroup is a mechanism to organize processes hierarchically and +distribute system resources along the hierarchy in a controlled and +configurable manner. + + +Memory management +................. + +Linux memory management is a complex subsystem that deals with: + +.. slide:: Memory management + :level: 2 + :inline-contents: True + + * Management of the physical memory: allocating and freeing memory + + * Management of the virtual memory: paging, swapping, demand + paging, copy on write + + * User services: user address space management (e.g. mmap(), brk(), + shared memory) + + * Kernel services: SL*B allocators, vmalloc + + + +Block I/O management +.................... + +The Linux Block I/O subsystem deals with reading and writing data from +or to block devices: creating block I/O requests, transforming block I/O +requests (e.g. for software RAID or LVM), merging and sorting the +requests and scheduling them via various I/O schedulers to the block +device drivers. + +.. slide:: Block I/O management + :level: 2 + :inline-contents: True + + .. ditaa:: + :height: 100% + + +---------------------------------+ + | Virtual Filesystem Switch | + +---------------------------------+ + ^ + | + v + +---------------------------------+ + | Device Mapper | + +---------------------------------+ + ^ + | + v + +---------------------------------+ + | Generic Block Layer | + +---------------------------------+ + ^ + | + v + +--------------------------------+ + | I/O scheduler | + +--------------------------------+ + ^ ^ + | | + v v + +--------------+ +--------------+ + | Block device | | Block device | + | driver | | driver | + +--------------+ +--------------+ + + +Virtual Filesystem Switch +......................... + +The Linux Virtual Filesystem Switch implements common / generic +filesystem code to reduce duplication in filesystem drivers. It +introduces certain filesystem abstractions such as: + +* inode - describes the file on disk (attributes, location of data + blocks on disk) + +* dentry - links an inode to a name + +* file - describes the properties of an opened file (e.g. file + pointer) + +* superblock - describes the properties of a formatted filesystem + (e.g. number of blocks, block size, location of root directory on + disk, encryption, etc.) + +.. slide:: Virtual Filesystem Switch + :level: 2 + :inline-contents: True + + .. ditaa:: + :height: 100% + + + ^ ^ ^ + | stat | open | read + v v v + +------------------------------------------------------------+ + | Virtual Filesystem Switch | + | | + | | + | /-------\ /--------\ /--------\ | + | | inode |<----------+ dentry |<----------+ FILE | | + | \---+---/ \----+---/ \---+----/ | + | | | | | + | | | | | + | v v v | + | +-------+ +--------+ +-------+ | + | | inode | | dentry | | page | | + | | cache | | cache | | cache | | + | +-------+ +--------+ +-------+ | + | | + +------------------------------------------------------------+ + ^ ^ + | | + v v + +-------------+ +-------------+ + | Filesystem | | Filesystem | + | driver | | driver | + +-------------+ +-------------+ + + +The Linux VFS also implements a complex caching mechanism which +includes the following: + +* the inode cache - caches the file attributes and internal file + metadata + +* the dentry cache - caches the directory hierarchy of a filesystem + +* the page cache - caches file data blocks in memory + + + +Networking stack +................ + +.. slide:: Networking stack + :level: 2 + :inline-contents: True + + .. ditaa:: + :height: 100% + + +---------------------------+ + | Berkeley Socket Interface | + +---------------------------+ + + +---------------------------+ + | Transport layer | + +-------------+-------------+ + | TCP | UDP | + +-------------+-------------+ + + +---------------------------+ + | Network layer | + +-----+---------+-----------+ + | IP | Routing | NetFilter | + +-----+---------+-----------+ + + +---------------------------+ + | Data link layer | + +-------+-------+-----------+ + | ETH | ARP | BRIDGING | + +-------+-------+-----------+ + + +---------------------------+ + | Queuing discipline | + +---------------------------+ + + +---------------------------+ + | Network device drivers | + +---------------------------+ + +Linux Security Modules +...................... + +.. slide:: Linux Security Modules + :level: 2 + :inline-contents: True + + * Hooks to extend the default Linux security model + + * Used by several Linux security extensions: + + * Security Enhancened Linux + + * AppArmor + + * Tomoyo + + * Smack diff --git a/refs/pull/405/merge/_sources/lectures/memory-management.rst.txt b/refs/pull/405/merge/_sources/lectures/memory-management.rst.txt new file mode 100644 index 00000000..b6401eec --- /dev/null +++ b/refs/pull/405/merge/_sources/lectures/memory-management.rst.txt @@ -0,0 +1,484 @@ +================= +Memory Management +================= + +`View slides <memory-management-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +Lecture objectives: +=================== + +.. slide:: Memory Management + :inline-contents: True + :level: 2 + + * Physical Memory Management + + * Page allocations + + * Small allocations + + * Virtual Memory Management + + * Page Fault Handling Overview + + +Physical Memory Management +========================== + +.. slide:: Physical Memory Management + :inline-contents: True + :level: 2 + + * Algorithms and data structure that keep track of physical memory + pages + + * Independent of virtual memory management + + * Both virtual and physical memory management is required for complete + memory management + + * Physical pages are being tracked using a special data structure: + :c:type:`struct page` + + * All physical pages have an entry reserved in the :c:data:`mem_map` + vector + + * The physical page status may include: a counter for how many + times is a page used, position in swap or file, buffers for this + page, position int the page cache, etc. + +Memory zones +------------ + +.. slide:: Memory zones + :inline-contents: True + :level: 2 + + * DMA zone + + * DMA32 zone + + * Normal zone (LowMem) + + * HighMem Zone + + * Movable Zone + + +Non-Uniform Memory Access +------------------------- + +.. slide:: Non-Uniform Memory Access + :inline-contents: True + :level: 2 + + * Physical memory is split in between multiple nodes, one for each CPU + + * There is single physical address space accessible from every node + + * Access to the local memory is faster + + * Each node maintains is own memory zones (.e. DMA, NORMAL, HIGHMEM, etc.) + + +Page allocation +--------------- + +.. slide:: Page allocation + :inline-contents: True + :level: 2 + + + .. code-block:: c + + /* Allocates 2^order contiguous pages and returns a pointer to the + * descriptor for the first page + */ + struct page *alloc_pages(gfp_mask, order); + + /* allocates a single page */ + struct page *alloc_page(gfp_mask); + + + /* helper functions that return the kernel virtual address */ + void *__get_free_pages(gfp_mask, order); + void *__get_free_page(gfp_mask); + void *__get_zero_page(gfp_mask); + void *__get_dma_pages(gfp_mask, order); + + +.. slide:: Why only allocate pages in chunks of power of 2? + :inline-contents: True + :level: 2 + + * Typical memory allocation algorithms have linear complexity + + * Why not use paging? + + * Sometime we do need contiguous memory allocations (for DMA) + + * Allocation would require page table changes and TLB flushes + + * Not able to use extended pages + + * Some architecture directly (in hardware) linearly maps a part + of the address space (e.g. MIPS) + + +.. slide:: The buddy algorithm + :inline-contents: True + :level: 2 + + * Free blocks are distributed in multiple lists + + * Each list contains blocks of the same size + + * The block size is a power of two + + +.. slide:: Allocating a block of size N + :inline-contents: True + :level: 2 + + * If there is a free block in the N-size list, pick the first + + * If not, look for a free block in the 2N-size list + + * Split the 2N-size block in two N-size blocks and add them to the + N-size list + + * Now that we have the N-size list populated, pick the first free + block from that list + + +.. slide:: Freeing a block of size N + :inline-contents: True + :level: 2 + + * If the "buddy" is free coalesce into a 2N-size block + + * Try until no more free buddy block is found and place the + resulting block in the respective list + + +.. slide:: The Linux implementation + :inline-contents: True + :level: 2 + + * 11 lists for blocks of 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, + 1024 pages + + * Each memory zone has its own buddy allocator + + * Each zone has a vector of descriptors for free blocks, one entry + for each size + + * The descriptor contains the number of free blocks and the head of + the list + + * Blocks are linked in the list using the `lru` field of + :c:type:`struct page` + + * Free pages have the PG_buddy flag set + + * The page descriptor keeps a copy of the block size in the private + field to easily check if the "buddy" is free + + +Small allocations +----------------- + +.. slide:: Small allocations + :inline-contents: True + :level: 2 + + * Buddy is used to allocate pages + + * Many of the kernel subsystems need to allocate buffers smaller + than a page + + * Typical solution: variable size buffer allocation + + * Leads to external fragmentation + + * Alternative solution: fixed size buffer allocation + + * Leads to internal fragmentation + + * Compromise: fixed size block allocation with multiple sizes, geometrically distributed + + * e.g.: 32, 64, ..., 131056 + + +.. slide:: The SLAB allocator + :inline-contents: True + :level: 2 + + * Buffers = objects + + * Uses buddy to allocate a pool of pages for object allocations + + * Each object (optionally) has a constructor and destructor + + * Deallocated objects are cached - avoids subsequent calls for + constructors and buddy allocation / deallocation + +.. slide:: Why SLAB? + :inline-contents: True + :level: 2 + + * The kernel will typically allocate and deallocate multiple types + the same data structures over time (e.g. :c:type:`struct + task_struct`) effectively using fixed size allocations. Using the + SLAB reduces the frequency of the more heavy + allocation/deallocation operations. + + * For variable size buffers (which occurs less frequently) a + geometric distribution of caches with fixed-size can be used + + * Reduces the memory allocation foot-print since we are searching a + much smaller memory area, compared to buddy which can span over a + larger area + + * Employs cache optimization techniques (slab coloring) + + +.. slide:: Slab architecture + :inline-contents: True + :level: 2 + + .. image:: ../res/slab-overview.png + + +.. slide:: Cache descriptors + :inline-contents: True + :level: 2 + + * A name to identify the cache for stats + + * object constructor and destructor functions + + * size of the objects + + * Flags + + * Size of the slab in power of 2 pages + + * GFP masks + + * One or mores slabs, grouped by state: full, partially full, empty + +.. slide:: SLAB descriptors + :inline-contents: True + :level: 2 + + * Number of objects + + * Memory region where the objects are stored + + * Pointer to the first free object + + * Descriptor are stored either in + + * the SLAB itself (if the object size is lower the 512 or if + internal fragmentation leaves enough space for the SLAB + descriptor) + + * in generic caches internally used by the SLAB allocator + + +.. slide:: Slab detailed architecture + :inline-contents: True + :level: 2 + + .. image:: ../res/slab-detailed-arch.png + + +.. slide:: Generic vs specific caches + :inline-contents: True + :level: 2 + + * Generic caches are used internally by the slab allocator + + * allocating memory for cache and slab descriptors + + * They are also used to implement :c:func:`kmalloc` by implementing + 20 caches with object sizes geometrically distributed between + 32bytes and 4MB + + * Specific cache are created on demand by kernel subsystems + + +.. slide:: Object descriptors + :inline-contents: True + :level: 2 + + .. image:: ../res/slab-object-descriptors.png + +.. slide:: Object descriptors + :inline-contents: True + :level: 2 + + * Only used for free objects + + * An integer that points to the next free object + + * The last free object uses a terminator value + + * Internal descriptors - stored in the slab + + * External descriptors - stored in generic caches + + +.. slide:: SLAB coloring + :inline-contents: True + :level: 2 + + .. image:: ../res/slab-coloring.png + + +Virtual memory management +========================= + +.. slide:: Virtual memory management + :inline-contents: True + :level: 2 + + * Used in both kernel and user space + + * Using virtual memory requires: + + * reserving (allocating) a segment in the *virtual* address space + (be it kernel or user) + + * allocating one or more physical pages for the buffer + + * allocating one or more physical pages for page tables and + internal structures + + * mapping the virtual memory segment to the physical allocated + pages + +.. slide:: Address space descriptors + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + :--no-separation: + + +------------------+ +------------+ + | Address space | | |-------------->+------------+ + | descriptor | +------------+ | | + +------------------+ | | Page +------------+ + | +------------+ tables | | + +------------------+--------------+ | ... | +------------+ + | | +------------+ | ... | + v v | |-------+ +------------+ + +------------+ +------------+ +------------+ | | | + | Area | | Area | | +------------+ + | descriptor | | descriptor | | + +------------+ +------------+ | + | | + +-------------+------------------+ +------>+------------+ + | | | | + v v +------------+ + +------------+ +------------+ | | + | Area | | Area | +------------+ + | descriptor | | descriptor | | ... | + +------------+ +------------+ +------------+ + | | | + +-----------+-----------+ +------------+ + | | + v v + +------------+ +------------+ + | Area | | Area | + | descriptor | | descriptor | + +------------+ +------------+ + + +.. slide:: Address space descriptors + :inline-contents: True + :level: 2 + + * Page table is used either by: + + * The CPU's MMU + + * The kernel to handle TLB exception (some RISC processors) + + * The address space descriptor is used by the kernel to maintain + high level information such as file and file offset (for mmap + with files), read-only segment, copy-on-write segment, etc. + + +.. slide:: Allocating virtual memory + :inline-contents: True + :level: 2 + + * Search a free area in the address space descriptor + + * Allocate memory for a new area descriptor + + * Insert the new area descriptor in the address space descriptor + + * Allocate physical memory for one or more page tables + + * Setup the page tables for the newly allocated area in the virtual + address space + + * Allocating (on demand) physical pages and map them in the virtual + address space by updating the page tables + + +.. slide:: Freeing virtual memory + :inline-contents: True + :level: 2 + + * Removing the area descriptor + + * Freeing the area descriptor memory + + * Updating the page tables to remove the area from the virtual + address space + + * Flushing the TLB for the freed virtual memory area + + * Freeing physical memory of the page tables associated with the + freed area + + * Freeing physical memory of the freed virtual memory area + + +.. slide:: Linux virtual memory management + :inline-contents: True + :level: 2 + + * Kernel + + * vmalloc + + * area descriptor: :c:type:`struct vm_struct` + + * address space descriptor: simple linked list of :c:type:`struct vm_struct` + + * Userspace + + * area descriptor: :c:type:`struct vm_area_struct` + + * address space descriptor: :c:type:`struct mm_struct`, red-black tree + + +Fault page handling +=================== + +.. slide:: Linux virtual memory management + :inline-contents: True + :level: 2 + + .. image:: ../res/page-fault-handling.png diff --git a/refs/pull/405/merge/_sources/lectures/networking.rst.txt b/refs/pull/405/merge/_sources/lectures/networking.rst.txt new file mode 100644 index 00000000..8813d0ca --- /dev/null +++ b/refs/pull/405/merge/_sources/lectures/networking.rst.txt @@ -0,0 +1,594 @@ +================== +Network Management +================== + +`View slides <networking-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +Lecture objectives: +=================== + +.. slide:: Network Management + :inline-contents: True + :level: 2 + + * Socket implementation + + * Routing implementation + + * Network Device Interface + + * Hardware and Software Acceleration Techniques + + +Network Management Overview +=========================== + +.. slide:: Network Management Overview + :inline-contents: True + :level: 2 + + .. ditaa:: + :height: 100% + + +---------------------------+ + | Berkeley Socket Interface | + +---------------------------+ + + +---------------------------+ + | Transport layer | + +-------------+-------------+ + | TCP | UDP | + +-------------+-------------+ + + +---------------------------+ + | Network layer | + +-----+---------+-----------+ + | IP | Routing | NetFilter | + +-----+---------+-----------+ + + +---------------------------+ + | Data link layer | + +-------+-------+-----------+ + | ETH | ARP | BRIDGING | + +-------+-------+-----------+ + + +---------------------------+ + | Queuing discipline | + +---------------------------+ + + +---------------------------+ + | Network device drivers | + +---------------------------+ + + +Sockets Implementation Overview +=============================== + +.. slide:: Sockets Implementation Overview + :inline-contents: True + :level: 2 + + .. ditaa:: + :height: 100% + + Socket + File + +------+ Operations + | FILE | ----------------------> +-----------+ + +------+ | read | + | | struct socket_alloc +-----------+ + | | +---------------+ | write | + | +------->| struct socket | +-----------+ + | f_private| +-----------+ | | select | + | | | ... | | +-----------+ + | | +-----------+ | | ... | + | +---------------+ +-----------+ + +--------->| struct inode | + f_inode | +-----------+ | + | | ... | | + | +-----------+ | + +---------------+ + + +Sockets Families and Protocols +=============================== + +.. slide:: Sockets Families and Protocols + :inline-contents: True + :level: 2 + + .. ditaa:: + :height: 100% + + + + struct socket +---------> struct proto_ops + +--------------------+ | +-----------------+ + | struct socket | | | release | + | | | +-----------------+ + +--------------------+ | | bind | + | struct proto_ops * |--------+ +-----------------+ + +--------------------+ | connect | + | ... | +-----------------+ + +---------------+ | accept | + +---------| struct sock * |-------+ +-----------------+ + | +---------------+ | | sendmsg | + | | +-----------------+ + | | | recvmsg | + | | +-----------------+ + | | | poll | + | | +-----------------+ + | | | ... | + | | +-----------------+ + | | + v v +--> struct sk_prot + struct tcp_sock struct tcp_sock | +--------------------+ + +-------------------+ +-------------------+ | | inet_dgram_connect | + | struct inet_sock | | struct inet_sock | | +--------------------+ + | +---------------+ | | +---------------+ | | | inet_sendmsg | + | | struct sock | | | | struct sock | | | +--------------------+ + | | +-----------+ | | | | +-----------+ | | | | udp_poll | + | | | ... | | | | | | ... | | | | +--------------------+ + | | +-----------+ | | | | +-----------+ | | | | inet_release | + | +---------------+ | | +---------------+ | | +--------------------+ + | | sk_prot * | | | | sk_prot * | |--+ | inet_bind | + | +---------------+ | | +---------------+ | +--------------------+ + +-------------------+ +-------------------+ | ... | + | ... | | ... | +--------------------+ + +-------------------+ +-------------------+ + + +Example: UDP send +----------------- + +.. slide:: Example: UDP send + :inline-contents: True + :level: 2 + + + .. code-block:: c + + char c; + struct sockaddr_in addr; + int s; + + s = socket(AF_INET, SOCK_DGRAM, 0); + connect(s, (struct sockaddr*)&addr, sizeof(addr)); + write(s, &c, 1); + close(s); + + +.. slide:: Example: UDP send + :inline-contents: True + :level: 2 + + .. ditaa:: + + -:------------------------------------------------------------------------------------ + + VFS layer sys_write → vfs_write → do_sync_write → filp->f_op->aio_write + + -:------------------------------------------------------------------------------------ + + Generic socket layer sock_aio_write → sock->ops->sendmsg + + -:------------------------------------------------------------------------------------ + + IP socket layer sk->sk_prot->sendmsg + + -:------------------------------------------------------------------------------------ + + UDP socket layer ip_append_data udp_flush_pending_frames + | | + -:------------------------------+------------------------------+----------------------- + V V + IP socket layer skb = sock_alloc_send_skb(); ip_local_out + skb_queue_tail(sk, skb) + + -:------------------------------------------------------------------------------------ + + routing + + +Network processing phases +========================= + +.. slide:: Network processing phases + :inline-contents: True + :level: 2 + + * Interrupt handler - device driver fetches data from the RX ring, + creates a network packet and queues it to the network stack for + processing + + * NET_SOFTIRQ - packet goes through the stack layer and it is + processed: decapsulate Ethernet frame, check IP packet and route + it, if local packet decapsulate protocol packet (e.g. TCP) and + queues it to a socket + + * Process context - application fetches data from the socket queue + or pushes data to the socket queue + + +Packet Routing +============== + +.. slide:: Packet Routing + :inline-contents: True + :level: 2 + + .. ditaa:: + + +----------------------+ +----------------------+ + | Application | | Application | + +----------------------+ +----------------------+ + | ^ | ^ + | send() | recv() | send() | recv() + V | V | + +----------------------+ +----------------------+ + | Socket | | Socket | + +----------------------+ +----------------------+ + | ^ | ^ + | | | | + v | v | + +---------------------------------------------------------+ + | Transport layer | + +---------------------------------------------------------+ + | ^ | ^ + | | | | + v | v | + +---------------------------------------------------------+ + | Network layer | + +---------------------------------------------------------+ + | ^ + | | + v | + /---------------------------------------------------------\ + | Routing | ----> Drop packet + \---------------------------------------------------------/ + ^ | ^ | + | RX | TX | RX | TX + | v | v + +-----------------------+ +-----------------------+ + | Network Device Driver | | Network Device Driver | + +-----------------------+ +-----------------------+ + + +Routing Table(s) +---------------- + +.. slide:: Routing Table + :inline-contents: True + :level: 2 + + + .. code-block:: shell + + tavi@desktop-tavi:~/src/linux$ ip route list table main + default via 172.30.240.1 dev eth0 + 172.30.240.0/20 dev eth0 proto kernel scope link src 172.30.249.241 + + tavi@desktop-tavi:~/src/linux$ ip route list table local + broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1 + local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1 + local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1 + broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1 + broadcast 172.30.240.0 dev eth0 proto kernel scope link src 172.30.249.241 + local 172.30.249.241 dev eth0 proto kernel scope host src 172.30.249.241 + broadcast 172.30.255.255 dev eth0 proto kernel scope link src 172.30.249.241 + + tavi@desktop-tavi:~/src/linux$ ip rule list + 0: from all lookup local + 32766: from all lookup main + 32767: from all lookup default + + +Routing Policy Database +----------------------- + +.. slide:: Routing Policy Database + :inline-contents: True + :level: 2 + + * "Regular" routing only uses the destination address + + * To increase flexibility a "Routing Policy Database" is used that + allows different routing based on other fields such as the source + address, protocol type, transport ports, etc. + + * This is encoded as a list of rules that are evaluated based on + their priority (priority 0 is the highest) + + * Each rule has a selector (how to match the packet) and an + action (what action to take if the packet matches) + + * Selectors: source address, destination address, type of service (TOS), + input interface, output interface, etc. + + * Action: lookup / unicast - use given routing table, blackhole - + drop packet, unreachable - send ICMP unreachable message and drop + packet, etc. + + + +Routing table processing +------------------------ + +.. slide:: Routing table processing + :inline-contents: True + :level: 2 + + * Special table for local addreses -> route packets to sockets + based on family, type, ports + + * Check every routing entry for starting with the most specific + routes (e.g. 192.168.0.0/24 is checked before 192.168.0.0/16) + + * A route matches if the packet destination addreess logical ORed + with the subnet mask equals the subnet address + + * Once a route matches the following information is retrieved: + interface, link layer next-hop address, network next host address + + +Forwarding Information Database +------------------------------- + +.. slide:: Forward Information Database (removed in 3.6) + :inline-contents: True + :level: 2 + + |_| + + .. image:: ../res/fidb-overview.png + + +.. slide:: Forward Information Database (removed in 3.6) + :inline-contents: True + :level: 2 + + .. image:: ../res/fidb-details.png + +.. slide:: Routing Cache (removed in 3.6) + :inline-contents: True + :level: 2 + + |_| + + .. image:: ../res/routing-cache.png + +.. slide:: FIB TRIE + :inline-contents: True + :level: 2 + + |_| + + .. image:: ../res/fib-trie.png + +.. slide:: Compressed Trie + :inline-contents: True + :level: 2 + + |_| + + .. image:: ../res/fib-trie-compressed.png + + +Netfilter +========= + +.. slide:: Netfilter + :inline-contents: True + :level: 2 + + + * Framework that implements packet filtering and NAT + + * It uses hooks inserted in key places in the packet flow: + + * NF_IP_PRE_ROUTING + + * NF_IP_LOCAL_IN + + * NF_IP_FORWARD + + * NF_IP_LOCAL_OUT + + * NF_IP_POST_ROUTING + + * NF_IP_NUMHOOKS + + + +Network packets / skbs (struct sk_buff) +======================================= + +.. slide:: Network packets (skbs) + :inline-contents: True + :level: 2 + + .. image:: ../res/skb.png + + +.. slide:: struct sk_buff + :inline-contents: True + :level: 2 + + .. code-block:: c + + struct sk_buff { + struct sk_buff *next; + struct sk_buff *prev; + + struct sock *sk; + ktime_t tstamp; + struct net_device *dev; + char cb[48]; + + unsigned int len, + data_len; + __u16 mac_len, + hdr_len; + + void (*destructor)(struct sk_buff *skb); + + sk_buff_data_t transport_header; + sk_buff_data_t network_header; + sk_buff_data_t mac_header; + sk_buff_data_t tail; + sk_buff_data_t end; + + unsigned char *head, + *data; + unsigned int truesize; + atomic_t users; + + +.. slide:: skb APIs + :inline-contents: True + :level: 2 + + .. code-block:: c + + /* reserve head room */ + void skb_reserve(struct sk_buff *skb, int len); + + /* add data to the end */ + unsigned char *skb_put(struct sk_buff *skb, unsigned int len); + + /* add data to the top */ + unsigned char *skb_push(struct sk_buff *skb, unsigned int len); + + /* discard data at the top */ + unsigned char *skb_pull(struct sk_buff *skb, unsigned int len); + + /* discard data at the end */ + unsigned char *skb_trim(struct sk_buff *skb, unsigned int len); + + unsigned char *skb_transport_header(const struct sk_buff *skb); + + void skb_reset_transport_header(struct sk_buff *skb); + + void skb_set_transport_header(struct sk_buff *skb, const int offset); + + unsigned char *skb_network_header(const struct sk_buff *skb); + + void skb_reset_network_header(struct sk_buff *skb); + + void skb_set_network_header(struct sk_buff *skb, const int offset); + + unsigned char *skb_mac_header(const struct sk_buff *skb); + + int skb_mac_header_was_set(const struct sk_buff *skb); + + void skb_reset_mac_header(struct sk_buff *skb); + + void skb_set_mac_header(struct sk_buff *skb, const int offset); + + +.. slide:: skb data management + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + :height: 50% + + Head + ^ +---------------+ + skb_push | | | | skb_reserve + +---------------+ v + | Data | | skb_pull + ^ | | v + skb_trim | | Tail | + +---------------+ + | | | skb_put + +---------------+ v + End + + +Network Device +============== + +.. slide:: Network Device Interface + :inline-contents: True + :level: 2 + + .. image:: ../res/net-dev-hw.png + + +.. slide:: Advanced features + :inline-contents: True + :level: 2 + + * Scatter-Gather + + * Checksum offloading: Ethernet, IP, UDP, TCP + + * Adaptive interrupt handling (coalescence, adaptive) + + + +Hardware and Software Acceleration Techniques +============================================= + +.. slide:: TCP offload + :inline-contents: True + :level: 2 + + * Full offload - Implement TCP/IP stack in hardware + + * Issues: + + * Scaling number of connections + + * Security + + * Conformance + +.. slide:: Performance observation + :inline-contents: True + :level: 2 + + * Performance is proportional with the number of packets to be + processed + + * Example: if an end-point can process 60K pps + + * 1538 MSS -> 738Mbps + * 2038 MSS -> 978Mbps + * 9038 MSS -> 4.3Gbps + * 20738 MSS -> 9.9Gbps + +.. slide:: Stateless offload + :inline-contents: True + :level: 2 + + * The networking stack processes large packets + + * TX path: the hardware splits large packets in smaller packets + (TCP Segmentation Offload) + + * RX path: the hardware aggregates small packets into larger + packets (Large Receive Offload - LRO) + + +.. slide:: TCP Segmentation Offload + :inline-contents: True + :level: 2 + + .. image:: ../res/tso.png + +.. slide:: Large Receive Offload + :inline-contents: True + :level: 2 + + .. image:: ../res/lro.png + + + diff --git a/refs/pull/405/merge/_sources/lectures/processes.rst.txt b/refs/pull/405/merge/_sources/lectures/processes.rst.txt new file mode 100644 index 00000000..95c8e2f7 --- /dev/null +++ b/refs/pull/405/merge/_sources/lectures/processes.rst.txt @@ -0,0 +1,1312 @@ +========= +Processes +========= + +`View slides <processes-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +Lecture objectives +================== + +.. slide:: Processes and threads + :inline-contents: True + :level: 2 + + * Process and threads + + * Context switching + + * Blocking and waking up + + * Process context + + + +Processes and threads +===================== + +A process is an operating system abstraction that groups together +multiple resources: + +.. slide:: What is a process? + :inline-contents: True + :level: 2 + + .. hlist:: + :columns: 2 + + * An address space + * One or more threads + * Opened files + * Sockets + * Semaphores + * Shared memory regions + * Timers + * Signal handlers + * Many other resources and status information + + All this information is grouped in the Process Control Group + (PCB). In Linux this is :c:type:`struct task_struct`. + + +Overview of process resources +----------------------------- + +A summary of the resources a process has can be obtain from the +`/proc/<pid>` directory, where `<pid>` is the process id for the +process we want to look at. + +.. slide:: Overview of process resources + :inline-contents: True + :level: 2 + + .. fixme: ditta does not work well with text containing ':' or '-' characters + .. code-block:: none + + +-------------------------------------------------------------------+ + | dr-x------ 2 tavi tavi 0 2021 03 14 12:34 . | + | dr-xr-xr-x 6 tavi tavi 0 2021 03 14 12:34 .. | + | lrwx------ 1 tavi tavi 64 2021 03 14 12:34 0 -> /dev/pts/4 | + +--->| lrwx------ 1 tavi tavi 64 2021 03 14 12:34 1 -> /dev/pts/4 | + | | lrwx------ 1 tavi tavi 64 2021 03 14 12:34 2 -> /dev/pts/4 | + | | lr-x------ 1 tavi tavi 64 2021 03 14 12:34 3 -> /proc/18312/fd | + | +-------------------------------------------------------------------+ + | +----------------------------------------------------------------+ + | | 08048000-0804c000 r-xp 00000000 08:02 16875609 /bin/cat | + $ ls -1 /proc/self/ | 0804c000-0804d000 rw-p 00003000 08:02 16875609 /bin/cat | + cmdline | | 0804d000-0806e000 rw-p 0804d000 00:00 0 [heap] | + cwd | | ... | + environ | +----------->| b7f46000-b7f49000 rw-p b7f46000 00:00 0 | + exe | | | b7f59000-b7f5b000 rw-p b7f59000 00:00 0 | + fd --------+ | | b7f5b000-b7f77000 r-xp 00000000 08:02 11601524 /lib/ld-2.7.so | + fdinfo | | b7f77000-b7f79000 rw-p 0001b000 08:02 11601524 /lib/ld-2.7.so | + maps -----------+ | bfa05000-bfa1a000 rw-p bffeb000 00:00 0 [stack] | + mem | ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso] | + root +----------------------------------------------------------------+ + stat +----------------------------+ + statm | Name: cat | + status ------+ | State: R (running) | + task | | Tgid: 18205 | + wchan +------>| Pid: 18205 | + | PPid: 18133 | + | Uid: 1000 1000 1000 1000 | + | Gid: 1000 1000 1000 1000 | + +----------------------------+ + + +:c:type:`struct task_struct` +---------------------------- + +Lets take a close look at :c:type:`struct task_struct`. For that we +could just look at the source code, but here we will use a tool called +`pahole` (part of the dwarves install package) in order to get +some insights about this structure: + + +.. slide:: struct task_struct + :inline-contents: True + :level: 2 + + .. code-block:: c + + $ pahole -C task_struct vmlinux + + struct task_struct { + struct thread_info thread_info; /* 0 8 */ + volatile long int state; /* 8 4 */ + void * stack; /* 12 4 */ + + ... + + /* --- cacheline 45 boundary (2880 bytes) --- */ + struct thread_struct thread __attribute__((__aligned__(64))); /* 2880 4288 */ + + /* size: 7168, cachelines: 112, members: 155 */ + /* sum members: 7148, holes: 2, sum holes: 12 */ + /* sum bitfield members: 7 bits, bit holes: 2, sum bit holes: 57 bits */ + /* paddings: 1, sum paddings: 2 */ + /* forced alignments: 6, forced holes: 2, sum forced holes: 12 */ + } __attribute__((__aligned__(64))); + + +As you can see it is a pretty large data structure: almost 8KB in size +and 155 fields. + + +Inspecting task_struct +---------------------- + +The following screencast is going to demonstrate how we can inspect +the process control block (:c:type:`struct task_struct`) by connecting +the debugger to the running virtual machine. We are going to use a +helper gdb command `lx-ps` to list the processes and the address of +the task_struct for each process. + +.. slide:: Inspecting task_struct + :inline-contents: True + :level: 2 + + |_| + + .. asciicast:: ../res/inspect_task_struct.cast + + +Quiz: Inspect a task to determine opened files +---------------------------------------------- + +.. slide:: Quiz: Inspect opened files + :inline-contents: True + :level: 2 + + Use the debugger to inspect the process named syslogd. + + * What command should we use to list the opened file descriptors? + + * How many file descriptors are opened? + + * What command should we use the determine the file name for opened file descriptor 3? + + * What is the filename for file descriptor 3? + + +Threads +------- + +A thread is the basic unit that the kernel process scheduler uses to +allow applications to run the CPU. A thread has the following +characteristics: + +.. slide:: Threads + :inline-contents: True + :level: 2 + + * Each thread has its own stack and together with the register + values it determines the thread execution state + + * A thread runs in the context of a process and all threads in the + same process share the resources + + * The kernel schedules threads not processes and user-level threads + (e.g. fibers, coroutines, etc.) are not visible at the kernel level + + +The typical thread implementation is one where the threads is +implemented as a separate data structure which is then linked to the +process data structure. For example, the Windows kernel uses such an +implementation: + + +.. slide:: Classic implementation (Windows) + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + EPROCESS + +------------------+ + +->| KPROCESS | + | +------------------+ + | | Process ID (PID) | + | +------------------+ + | | ... | + | +------------------+ + | | Thread list |--------------+------------------------------------+ + | +------------------+ | | + | | Opened files | ETHREAD V ETHREAD V + | | +--------------+ | + | | | FILE | | + | | +--------------+ | + | | | ... | | + | | +--------------+ | + | +------------------+ +-----------------------+ +-----------------------+ + | | Address Space | | KTHREAD | | KTHREAD | + | + +--------------+ | +-----------------------+ +-----------------------+ + | | | ... | | | Thread ID (TID) | | Thread ID (TID) | + | | +--------------+ | +-----------------------+ +-----------------------+ + | +------------------+ | Thread Start Address | | Thread Start Address | + | +-----------------------+ +-----------------------+ + | | ... | ... | ... | + | +-----------------------+ +-----------------------+ + | | Process | | Process | + | +-----------------------+ +-----------------------+ + | | | + +---------------------------------------+------------------------------------+ + + +Linux uses a different implementation for threads. The basic unit is +called a task (hence the :c:type:`struct task_struct`) and it is used +for both threads and processes. Instead of embedding resources in the +task structure it has pointers to these resources. + +Thus, if two threads are the same process will point to the same +resource structure instance. If two threads are in different processes +they will point to different resource structure instances. + + +.. slide:: Linux implementation + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + Opened files + task_struct +-------------------+ task_struct + +-----------------------+ | FILE | +-----------------------+ + | Thread Group ID (PID) | +--->+-------------------+<---+ | Thread Group ID (PID) | + +-----------------------+ | | .... | | +-----------------------+ + | Thread ID (TID) | | +-------------------+ | | Thread ID (TID) | + +-----------------------+ | | +-----------------------+ + | ... | | | | ... | + +-----------------------+ | | +-----------------------+ + | Opened files |--+ +--| Opened files | + +-----------------------+ Address Space +-----------------------+ + | Address Space |---+ +-------------------+ +---| Address Space | + +-----------------------+ | | | | +-----------------------+ + | ... | +-->| .... |<--+ | ... | + +-----------------------+ | | +-----------------------+ + +-------------------+ + + +The clone system call +--------------------- + +In Linux a new thread or process is create with the :c:func:`clone` +system call. Both the :c:func:`fork` system call and the +:c:func:`pthread_create` function uses the :c:func:`clone` +implementation. + +It allows the caller to decide what resources should be shared with +the parent and which should be copied or isolated: + +.. slide:: The clone system call + :inline-contents: True + :level: 2 + + * CLONE_FILES - shares the file descriptor table with the parent + + * CLONE_VM - shares the address space with the parent + + * CLONE_FS - shares the filesystem information (root directory, + current directory) with the parent + + * CLONE_NEWNS - does not share the mount namespace with the parent + + * CLONE_NEWIPC - does not share the IPC namespace (System V IPC + objects, POSIX message queues) with the parent + + * CLONE_NEWNET - does not share the networking namespaces (network + interfaces, routing table) with the parent + + +For example, if `CLONE_FILES | CLONE_VM | CLONE_FS` is used by the +caller then effectively a new thread is created. If these flags are +not used then a new process is created. + +Namespaces and "containers" +--------------------------- + +"Containers" are a form of lightweight virtual machines that share the +same kernel instance, as opposed to normal virtualization where a +hypervisor runs multiple VMs, each with its one kernel +instance. + +Examples of container technologies are LXC - that allows running +lightweight "VM" and docker - a specialized container for running a +single application. + +Containers are built on top of a few kernel features, one of which is +namespaces. They allow isolation of different resources that would +otherwise be globally visible. For example, without containers, all +processes would be visible in /proc. With containers, processes in one +container will not be visible (in /proc or be killable) to other +containers. + +To achieve this partitioning, the :c:type:`struct nsproxy` structure +is used to group types of resources that we want to partition. It +currently supports IPC, networking, cgroup, mount, networking, PID, +time namespaces. For example, instead of having a global list for +networking interfaces, the list is part of a :c:type:`struct net`. The +system initializes with a default namespace (:c:data:`init_net`) and by +default all processes will share this namespace. When a new namespace +is created a new net namespace is created and then new processes can +point to that new namespace instead of the default one. + + +.. slide:: Namespaces and "containers" + :inline-contents: False + :level: 2 + + * Containers = a form of lightweight virtual machines + + * Container based technologies: LXC, docker + + * Containers are built of top of kernel namespaces + + * Kernel namespaces allows isolation of otherwise globally visible + resources + + * :c:type:`struct nsproxy` has multiple namespaces each of which + can be selectively shared between groups of processes + + * At boot initial namespaces are created (e.g. :c:data:`init_net`) + that are by default shared between new processes (e.g. list of + available network interfaces) + + * New namespace can be created a runtime and new processes can + point to these new namespaces + + +Accessing the current process +----------------------------- + +.. slide:: Accessing the current process + :inline-contents: True + :level: 2 + + Accessing the current process is a frequent operation: + + * opening a file needs access to :c:type:`struct task_struct`'s + file field + + * mapping a new file needs access to :c:type:`struct task_struct`'s + mm field + + * Over 90% of the system calls needs to access the current process + structure so it needs to be fast + + * The :c:macro:`current` macro is available to access to current + process's :c:type:`struct task_struct` + +In order to support fast access in multi processor configurations a +per CPU variable is used to store and retrieve the pointer to the +current :c:type:`struct task_struct`: + +.. slide:: Accessing the current process on x86 + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + CPU0 + +------------+ task_struct + | ... | +--------> +-----------------------+ + +------------- | | Thread Group ID (PID) | + +--| FS | | +-----------------------+ + | +------------- | | Thread ID (TID) | + | | ... | | +-----------------------+ + | +------------+ | | ... | + | | +-----------------------+ + | Per CPU variables | | Opened files | + +->+-----------------------+ | +-----------------------+ + | ... | | | Address Space | + +-----------------------+ | +-----------------------+ + | current_task |------+ | ... | + +-----------------------+ +-----------------------+ + | ... | + +-----------------------+ + + +Previously the following sequence was used as the implementation for +the :c:macro:`current` macro: + +.. slide:: Previous implementation for current (x86) + :inline-contents: True + :level: 2 + + .. code-block:: c + + /* how to get the current stack pointer from C */ + register unsigned long current_stack_pointer asm("esp") __attribute_used__; + + /* how to get the thread information struct from C */ + static inline struct thread_info *current_thread_info(void) + { + return (struct thread_info *)(current_stack_pointer & ~(THREAD_SIZE – 1)); + } + + #define current current_thread_info()->task + + +Quiz: previous implementation for current (x86) +----------------------------------------------- + +.. slide:: Quiz: previous implementation for current (x86) + :inline-contents: True + :level: 2 + + What is the size of :c:type:`struct thread_info`? + + Which of the following are potential valid sizes for + :c:type:`struct thread_info`: 4095, 4096, 4097? + + + +Context switching +================= + +The following diagram shows an overview of the Linux kernel context +switch process: + +.. slide:: Overview the context switching processes + :inline-contents: True + :level: 2 + + .. ditaa:: + + Userspace Kernel Kernel Userspace + T0 T0 T1 T1 + + | + | syscall +-------------------+ + V --------->| Save user regs on | +-----------------+ + interrupt | the kernel stack | | Save user regs | + +-------------------+ | on kernel stack | + | +-----------------+ + |schedule() | + | |schedule() + V | + +-----------------+ V + | context_switch |------+ +-----------------+ + +-----------------+ | | context_switch | + +-----> +-----------------+ + | + V + +-------------------+ + | Pop user regs | + | from kernel stack | + +-------------------+ + | + | exit syscall + +--------------------> | + | + V + + +Note that before a context switch can occur we must do a kernel +transition, either with a system call or with an interrupt. At that +point the user space registers are saved on the kernel stack. At some +point the :c:func:`schedule` function will be called which can decide +that a context switch must occur from T0 to T1 (e.g. because the +current thread is blocking waiting for an I/O operation to complete or +because it's allocated time slice has expired). + +At that point :c:func:`context_switch` will perform architecture +specific operations and will switch the address space if needed: + + +.. slide:: context_switch + :inline-contents: True + :level: 2 + + .. code-block:: c + + static __always_inline struct rq * + context_switch(struct rq *rq, struct task_struct *prev, + struct task_struct *next, struct rq_flags *rf) + { + prepare_task_switch(rq, prev, next); + + /* + * For paravirt, this is coupled with an exit in switch_to to + * combine the page table reload and the switch backend into + * one hypercall. + */ + arch_start_context_switch(prev); + + /* + * kernel -> kernel lazy + transfer active + * user -> kernel lazy + mmgrab() active + * + * kernel -> user switch + mmdrop() active + * user -> user switch + */ + if (!next->mm) { // to kernel + enter_lazy_tlb(prev->active_mm, next); + + next->active_mm = prev->active_mm; + if (prev->mm) // from user + mmgrab(prev->active_mm); + else + prev->active_mm = NULL; + } else { // to user + membarrier_switch_mm(rq, prev->active_mm, next->mm); + /* + * sys_membarrier() requires an smp_mb() between setting + * rq->curr / membarrier_switch_mm() and returning to userspace. + * + * The below provides this either through switch_mm(), or in + * case 'prev->active_mm == next->mm' through + * finish_task_switch()'s mmdrop(). + */ + switch_mm_irqs_off(prev->active_mm, next->mm, next); + + if (!prev->mm) { // from kernel + /* will mmdrop() in finish_task_switch(). */ + rq->prev_mm = prev->active_mm; + prev->active_mm = NULL; + } + } + + rq->clock_update_flags &= ~(RQCF_ACT_SKIP|RQCF_REQ_SKIP); + + prepare_lock_switch(rq, next, rf); + + /* Here we just switch the register state and the stack. */ + switch_to(prev, next, prev); + barrier(); + + return finish_task_switch(prev); + } + + +Then it will call the architecture specific :c:macro:`switch_to` +implementation to switch the registers state and kernel stack. Note +that registers are saved on stack and that the stack pointer is saved +in the task structure: + +.. slide:: switch_to + :inline-contents: True + :level: 2 + + .. code-block:: c + :emphasize-lines: 28-30,56 + + #define switch_to(prev, next, last) \ + do { \ + ((last) = __switch_to_asm((prev), (next))); \ + } while (0) + + + /* + * %eax: prev task + * %edx: next task + */ + .pushsection .text, "ax" + SYM_CODE_START(__switch_to_asm) + /* + * Save callee-saved registers + * This must match the order in struct inactive_task_frame + */ + pushl %ebp + pushl %ebx + pushl %edi + pushl %esi + /* + * Flags are saved to prevent AC leakage. This could go + * away if objtool would have 32bit support to verify + * the STAC/CLAC correctness. + */ + pushfl + + /* switch stack */ + movl %esp, TASK_threadsp(%eax) + movl TASK_threadsp(%edx), %esp + + #ifdef CONFIG_STACKPROTECTOR + movl TASK_stack_canary(%edx), %ebx + movl %ebx, PER_CPU_VAR(stack_canary)+stack_canary_offset + #endif + + #ifdef CONFIG_RETPOLINE + /* + * When switching from a shallower to a deeper call stack + * the RSB may either underflow or use entries populated + * with userspace addresses. On CPUs where those concerns + * exist, overwrite the RSB with entries which capture + * speculative execution to prevent attack. + */ + FILL_RETURN_BUFFER %ebx, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW + #endif + + /* Restore flags or the incoming task to restore AC state. */ + popfl + /* restore callee-saved registers */ + popl %esi + popl %edi + popl %ebx + popl %ebp + + jmp __switch_to + SYM_CODE_END(__switch_to_asm) + .popsection + + +You can notice that the instruction pointer is not explicitly +saved. It is not needed because: + + * a task will always resume in this function + + * the :c:func:`schedule` (:c:func:`context_switch` is always + inlined) caller's return address is saved on the kernel stack + + * a jmp is used to execute :c:func:`__switch_to` which is a function + and when it returns it will pop the original (next task) return + address from the stack + + +The following screencast uses the debugger to setup a breaking in +__switch_to_asm and examine the stack during the context switch: + +.. slide:: Inspecting task_struct + :inline-contents: True + :level: 2 + + |_| + + .. asciicast:: ../res/context_switch.cast + + +Quiz: context switch +-------------------- + +.. slide:: Quiz: context switch + :inline-contents: True + :level: 2 + + We are executing a context switch. Select all of the statements that are true. + + * the ESP register is saved in the task structure + + * the EIP register is saved in the task structure + + * general registers are saved in the task structure + + * the ESP register is saved on the stack + + * the EIP register is saved on the stack + + * general registers are saved on the stack + + +Blocking and waking up tasks +============================ + +Task states +----------- + +The following diagram shows to the task (threads) states and the +possible transitions between them: + +.. slide:: Task states + :inline-contents: True + :level: 2 + + .. ditaa:: + + preemption + +------------------------------+ + | | + V | + +------------+ +--------------+ +-------------+ + clone() | | schedule() | | exit() | | + -----------> | TASK_READY |-------------->| TASK_RUNNING |---------------->| TASK_DEAD | + | | | |--------+ | TASK_ZOMBIE | + +------------+ +--------------+ | | | + ^ | +-------------+ + | | + | | + | | + | signal +----------------------+ | + +-----------| | | + | | | wait_event() | + | wake_up() | TASK_INTERRUPTIBLE |<--------------+ + +-----------| | | + | | | | + | +----------------------+ | + | | + | | + | +----------------------+ | + | | | wait_event() | + | wake_up() | TASK_UNINTERRUPTIBLE |<--------------+ + +-----------| | + +----------------------+ + + +Blocking the current thread +--------------------------- + +Blocking the current thread is an important operation we need to +perform to implement efficient task scheduling - we want to run other +threads while I/O operations complete. + +In order to accomplish this the following operations take place: + +.. slide:: Blocking the current thread + :inline-contents: True + :level: 2 + + * Set the current thread state to TASK_UINTERRUPTIBLE or + TASK_INTERRUPTIBLE + + * Add the task to a waiting queue + + * Call the scheduler which will pick up a new task from the READY + queue + + * Do the context switch to the new task + +Below are some snippets for the :c:macro:`wait_event` +implementation. Note that the waiting queue is a list with some extra +information like a pointer to the task struct. + +Also note that a lot of effort is put into making sure no deadlock can +occur between :c:macro:`wait_event` and :c:macro:`wake_up`: the task +is added to the list before checking :c:data:`condition`, signals are +checked before calling :c:func:`schedule`. + +.. slide:: wait_event + :inline-contents: True + :level: 2 + + .. code-block:: c + + /** + * wait_event - sleep until a condition gets true + * @wq_head: the waitqueue to wait on + * @condition: a C expression for the event to wait for + * + * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the + * @condition evaluates to true. The @condition is checked each time + * the waitqueue @wq_head is woken up. + * + * wake_up() has to be called after changing any variable that could + * change the result of the wait condition. + */ + #define wait_event(wq_head, condition) \ + do { \ + might_sleep(); \ + if (condition) \ + break; \ + __wait_event(wq_head, condition); \ + } while (0) + + #define __wait_event(wq_head, condition) \ + (void)___wait_event(wq_head, condition, TASK_UNINTERRUPTIBLE, 0, 0, \ + schedule()) + + /* + * The below macro ___wait_event() has an explicit shadow of the __ret + * variable when used from the wait_event_*() macros. + * + * This is so that both can use the ___wait_cond_timeout() construct + * to wrap the condition. + * + * The type inconsistency of the wait_event_*() __ret variable is also + * on purpose; we use long where we can return timeout values and int + * otherwise. + */ + #define ___wait_event(wq_head, condition, state, exclusive, ret, cmd) \ + ({ \ + __label__ __out; \ + struct wait_queue_entry __wq_entry; \ + long __ret = ret; /* explicit shadow */ \ + \ + init_wait_entry(&__wq_entry, exclusive ? WQ_FLAG_EXCLUSIVE : 0); \ + for (;;) { \ + long __int = prepare_to_wait_event(&wq_head, &__wq_entry, state);\ + \ + if (condition) \ + break; \ + \ + if (___wait_is_interruptible(state) && __int) { \ + __ret = __int; \ + goto __out; \ + } \ + \ + cmd; \ + } \ + finish_wait(&wq_head, &__wq_entry); \ + __out: __ret; \ + }) + + void init_wait_entry(struct wait_queue_entry *wq_entry, int flags) + { + wq_entry->flags = flags; + wq_entry->private = current; + wq_entry->func = autoremove_wake_function; + INIT_LIST_HEAD(&wq_entry->entry); + } + + long prepare_to_wait_event(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry, int state) + { + unsigned long flags; + long ret = 0; + + spin_lock_irqsave(&wq_head->lock, flags); + if (signal_pending_state(state, current)) { + /* + * Exclusive waiter must not fail if it was selected by wakeup, + * it should "consume" the condition we were waiting for. + * + * The caller will recheck the condition and return success if + * we were already woken up, we can not miss the event because + * wakeup locks/unlocks the same wq_head->lock. + * + * But we need to ensure that set-condition + wakeup after that + * can't see us, it should wake up another exclusive waiter if + * we fail. + */ + list_del_init(&wq_entry->entry); + ret = -ERESTARTSYS; + } else { + if (list_empty(&wq_entry->entry)) { + if (wq_entry->flags & WQ_FLAG_EXCLUSIVE) + __add_wait_queue_entry_tail(wq_head, wq_entry); + else + __add_wait_queue(wq_head, wq_entry); + } + set_current_state(state); + } + spin_unlock_irqrestore(&wq_head->lock, flags); + + return ret; + } + + static inline void __add_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry) + { + list_add(&wq_entry->entry, &wq_head->head); + } + + static inline void __add_wait_queue_entry_tail(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry) + { + list_add_tail(&wq_entry->entry, &wq_head->head); + } + + /** + * finish_wait - clean up after waiting in a queue + * @wq_head: waitqueue waited on + * @wq_entry: wait descriptor + * + * Sets current thread back to running state and removes + * the wait descriptor from the given waitqueue if still + * queued. + */ + void finish_wait(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry) + { + unsigned long flags; + + __set_current_state(TASK_RUNNING); + /* + * We can check for list emptiness outside the lock + * IFF: + * - we use the "careful" check that verifies both + * the next and prev pointers, so that there cannot + * be any half-pending updates in progress on other + * CPU's that we haven't seen yet (and that might + * still change the stack area. + * and + * - all other users take the lock (ie we can only + * have _one_ other CPU that looks at or modifies + * the list). + */ + if (!list_empty_careful(&wq_entry->entry)) { + spin_lock_irqsave(&wq_head->lock, flags); + list_del_init(&wq_entry->entry); + spin_unlock_irqrestore(&wq_head->lock, flags); + } + } + + + +Waking up a task +---------------- + +We can wake-up tasks by using the :c:macro:`wake_up` primitive. The +following high level operations are performed to wake up a task: + +.. slide:: Waking up a task + :inline-contents: True + :level: 2 + + * Select a task from the waiting queue + + * Set the task state to TASK_READY + + * Insert the task into the scheduler's READY queue + + * On SMP system this is a complex operation: each processor has its + own queue, queues need to be balanced, CPUs needs to be signaled + + +.. slide:: wake_up + :inline-contents: True + :level: 2 + + .. code-block:: c + + #define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL) + + /** + * __wake_up - wake up threads blocked on a waitqueue. + * @wq_head: the waitqueue + * @mode: which threads + * @nr_exclusive: how many wake-one or wake-many threads to wake up + * @key: is directly passed to the wakeup function + * + * If this function wakes up a task, it executes a full memory barrier before + * accessing the task state. + */ + void __wake_up(struct wait_queue_head *wq_head, unsigned int mode, + int nr_exclusive, void *key) + { + __wake_up_common_lock(wq_head, mode, nr_exclusive, 0, key); + } + + static void __wake_up_common_lock(struct wait_queue_head *wq_head, unsigned int mode, + int nr_exclusive, int wake_flags, void *key) + { + unsigned long flags; + wait_queue_entry_t bookmark; + + bookmark.flags = 0; + bookmark.private = NULL; + bookmark.func = NULL; + INIT_LIST_HEAD(&bookmark.entry); + + do { + spin_lock_irqsave(&wq_head->lock, flags); + nr_exclusive = __wake_up_common(wq_head, mode, nr_exclusive, + wake_flags, key, &bookmark); + spin_unlock_irqrestore(&wq_head->lock, flags); + } while (bookmark.flags & WQ_FLAG_BOOKMARK); + } + + /* + * The core wakeup function. Non-exclusive wakeups (nr_exclusive == 0) just + * wake everything up. If it's an exclusive wakeup (nr_exclusive == small +ve + * number) then we wake all the non-exclusive tasks and one exclusive task. + * + * There are circumstances in which we can try to wake a task which has already + * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns + * zero in this (rare) case, and we handle it by continuing to scan the queue. + */ + static int __wake_up_common(struct wait_queue_head *wq_head, unsigned int mode, + int nr_exclusive, int wake_flags, void *key, + wait_queue_entry_t *bookmark) + { + wait_queue_entry_t *curr, *next; + int cnt = 0; + + lockdep_assert_held(&wq_head->lock); + + if (bookmark && (bookmark->flags & WQ_FLAG_BOOKMARK)) { + curr = list_next_entry(bookmark, entry); + + list_del(&bookmark->entry); + bookmark->flags = 0; + } else + curr = list_first_entry(&wq_head->head, wait_queue_entry_t, entry); + + if (&curr->entry == &wq_head->head) + return nr_exclusive; + + list_for_each_entry_safe_from(curr, next, &wq_head->head, entry) { + unsigned flags = curr->flags; + int ret; + + if (flags & WQ_FLAG_BOOKMARK) + continue; + + ret = curr->func(curr, mode, wake_flags, key); + if (ret < 0) + break; + if (ret && (flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive) + break; + + if (bookmark && (++cnt > WAITQUEUE_WALK_BREAK_CNT) && + (&next->entry != &wq_head->head)) { + bookmark->flags = WQ_FLAG_BOOKMARK; + list_add_tail(&bookmark->entry, &next->entry); + break; + } + } + + return nr_exclusive; + } + + int autoremove_wake_function(struct wait_queue_entry *wq_entry, unsigned mode, int sync, void *key) + { + int ret = default_wake_function(wq_entry, mode, sync, key); + + if (ret) + list_del_init_careful(&wq_entry->entry); + + return ret; + } + + int default_wake_function(wait_queue_entry_t *curr, unsigned mode, int wake_flags, + void *key) + { + WARN_ON_ONCE(IS_ENABLED(CONFIG_SCHED_DEBUG) && wake_flags & ~WF_SYNC); + return try_to_wake_up(curr->private, mode, wake_flags); + } + + /** + * try_to_wake_up - wake up a thread + * @p: the thread to be awakened + * @state: the mask of task states that can be woken + * @wake_flags: wake modifier flags (WF_*) + * + * Conceptually does: + * + * If (@state & @p->state) @p->state = TASK_RUNNING. + * + * If the task was not queued/runnable, also place it back on a runqueue. + * + * This function is atomic against schedule() which would dequeue the task. + * + * It issues a full memory barrier before accessing @p->state, see the comment + * with set_current_state(). + * + * Uses p->pi_lock to serialize against concurrent wake-ups. + * + * Relies on p->pi_lock stabilizing: + * - p->sched_class + * - p->cpus_ptr + * - p->sched_task_group + * in order to do migration, see its use of select_task_rq()/set_task_cpu(). + * + * Tries really hard to only take one task_rq(p)->lock for performance. + * Takes rq->lock in: + * - ttwu_runnable() -- old rq, unavoidable, see comment there; + * - ttwu_queue() -- new rq, for enqueue of the task; + * - psi_ttwu_dequeue() -- much sadness :-( accounting will kill us. + * + * As a consequence we race really badly with just about everything. See the + * many memory barriers and their comments for details. + * + * Return: %true if @p->state changes (an actual wakeup was done), + * %false otherwise. + */ + static int + try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) + { + ... + + +Preempting tasks +================ + +Up until this point we look at how context switches occurs voluntary +between threads. Next we will look at how preemption is handled. We +will start wight the simpler case where the kernel is configured as +non preemptive and then we will move to the preemptive kernel case. + +Non preemptive kernel +--------------------- + +.. slide:: Non preemptive kernel + :inline-contents: True + :level: 2 + + * At every tick the kernel checks to see if the current process has + its time slice consumed + + * If that happens a flag is set in interrupt context + + * Before returning to userspace the kernel checks this flag and + calls :c:func:`schedule` if needed + + * In this case tasks are not preempted while running in kernel mode + (e.g. system call) so there are no synchronization issues + + +Preemptive kernel +----------------- + +In this case the current task can be preempted even if we are running +in kernel mode and executing a system call. This requires using a +special synchronization primitives: :c:macro:`preempt_disable` and +:c:macro:`preempt_enable`. + +In order to simplify handling for preemptive kernels and since +synchronization primitives are needed for the SMP case anyway, +preemption is disabled automatically when a spinlock is used. + +As before, if we run into a condition that requires the preemption of +the current task (its time slices has expired) a flag is set. This +flag is checked whenever the preemption is reactivated, e.g. when +exiting a critical section through a :c:func:`spin_unlock` and if +needed the scheduler is called to select a new task. + + +.. slide:: Preemptive kernel + :inline-contents: False + :level: 2 + + * Tasks can be preempted even when running in kernel mode + + * It requires new synchronization primitives to be used in critical + sections: :c:macro:`preempt_disable` and + :c:macro:`preempt_enable` + + * Spinlocks also disable preemption + + * When a thread needs to be preempted a flag is set and action is + taken (e.g. scheduler is called) when preemption is reactivated + + +Process context +=============== + +Now that we have examined the implementation of processes and threads +(tasks), how context switching occurs, how we can block, wake-up and +preempt tasks, we can finally define what the process context is what +are its properties: + +.. slide:: Process context + :inline-contents: True + :level: 2 + + The kernel is executing in process context when it is running a + system call. + + In process context there is a well defined context and we can + access the current process data with :c:macro:`current` + + In process context we can sleep (wait on a condition). + + In process context we can access the user-space (unless we are + running in a kernel thread context). + + +Kernel threads +-------------- + +.. slide:: Kernel threads + :inline-contents: True + :level: 2 + + Sometimes the kernel core or device drivers need to perform blocking + operations and thus they need to run in process context. + + Kernel threads are used exactly for this and are a special class of + tasks that don't "userspace" resources (e.g. no address space or + opened files). + + +The following screencast takes a closer look at kernel threads: + +.. slide:: Inspecting kernel threads + :inline-contents: True + :level: 2 + + |_| + + .. asciicast:: ../res/kernel_threads.cast + + +Using gdb scripts for kernel inspection +======================================= + +The Linux kernel comes with a predefined set of gdb extra commands we +can use to inspect the kernel during debugging. They will +automatically be loaded as long gdbinit is properly setup + +.. code-block:: sh + + ubuntu@so2:/linux/tools/labs$ cat ~/.gdbinit + add-auto-load-safe-path /linux/scripts/gdb/vmlinux-gdb.py + +All of the kernel specific commands are prefixed with lx-. You can use +TAB in gdb to list all of them: + +.. code-block:: sh + + (gdb) lx- + lx-clk-summary lx-dmesg lx-mounts + lx-cmdline lx-fdtdump lx-ps + lx-configdump lx-genpd-summary lx-symbols + lx-cpus lx-iomem lx-timerlist + lx-device-list-bus lx-ioports lx-version + lx-device-list-class lx-list-check + lx-device-list-tree lx-lsmod + +The implementation of the commands can be found at +`script/gdb/linux`. Lets take a closer look at the lx-ps +implementation: + + +.. code-block:: python + + task_type = utils.CachedType("struct task_struct") + + + def task_lists(): + task_ptr_type = task_type.get_type().pointer() + init_task = gdb.parse_and_eval("init_task").address + t = g = init_task + + while True: + while True: + yield t + + t = utils.container_of(t['thread_group']['next'], + task_ptr_type, "thread_group") + if t == g: + break + + t = g = utils.container_of(g['tasks']['next'], + task_ptr_type, "tasks") + if t == init_task: + return + + + class LxPs(gdb.Command): + """Dump Linux tasks.""" + + def __init__(self): + super(LxPs, self).__init__("lx-ps", gdb.COMMAND_DATA) + + def invoke(self, arg, from_tty): + gdb.write("{:>10} {:>12} {:>7}\n".format("TASK", "PID", "COMM")) + for task in task_lists(): + gdb.write("{} {:^5} {}\n".format( + task.format_string().split()[0], + task["pid"].format_string(), + task["comm"].string())) + + + +Quiz: Kernel gdb scripts +------------------------ + +.. slide:: Quiz: Kernel gdb scripts + :inline-contents: True + :level: 2 + + What is the following change of the lx-ps script trying to + accomplish? + + .. code-block:: diff + + diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py + index 17ec19e9b5bf..7e43c163832f 100644 + --- a/scripts/gdb/linux/tasks.py + +++ b/scripts/gdb/linux/tasks.py + @@ -75,10 +75,13 @@ class LxPs(gdb.Command): + def invoke(self, arg, from_tty): + gdb.write("{:>10} {:>12} {:>7}\n".format("TASK", "PID", "COMM")) + for task in task_lists(): + - gdb.write("{} {:^5} {}\n".format( + + check = task["mm"].format_string() == "0x0" + + gdb.write("{} {:^5} {}{}{}\n".format( + task.format_string().split()[0], + task["pid"].format_string(), + - task["comm"].string())) + + "[" if check else "", + + task["comm"].string(), + + "]" if check else "")) + + + LxPs() + diff --git a/refs/pull/405/merge/_sources/lectures/smp.rst.txt b/refs/pull/405/merge/_sources/lectures/smp.rst.txt new file mode 100644 index 00000000..29706286 --- /dev/null +++ b/refs/pull/405/merge/_sources/lectures/smp.rst.txt @@ -0,0 +1,1184 @@ +========================== +Symmetric Multi-Processing +========================== + +`View slides <smp-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +Lecture objectives: +=================== + +.. slide:: Symmetric Multi-Processing + :inline-contents: True + :level: 2 + + * Kernel Concurrency + + * Atomic operations + + * Spin locks + + * Cache thrashing + + * Optimized spin locks + + * Process and Interrupt Context Synchronization + + * Mutexes + + * Per CPU data + + * Memory Ordering and Barriers + + * Read-Copy Update + + +Synchronization basics +====================== + +Because the Linux kernel supports symmetric multi-processing (SMP) it +must use a set of synchronization mechanisms to achieve predictable +results, free of race conditions. + +.. note:: We will use the terms core, CPU and processor as + interchangeable for the purpose of this lecture. + +Race conditions can occur when the following two conditions happen +simultaneously: + +.. slide:: Race conditions + :inline-contents: True + :level: 2 + + * there are at least two execution contexts that run in "parallel": + + * truly run in parallel (e.g. two system calls running on + different processors) + + * one of the contexts can arbitrary preempt the other (e.g. an + interrupt preempts a system call) + + * the execution contexts perform read-write accesses to shared + memory + + +Race conditions can lead to erroneous results that are hard to debug, +because they manifest only when the execution contexts are scheduled +on the CPU cores in a very specific order. + +A classical race condition example is an incorrect implementation for +a release operation of a resource counter: + +.. slide:: Race condition: resource counter release + :inline-contents: True + :level: 2 + + .. code-block:: c + + void release_resource() + { + counter--; + + if (!counter) + free_resource(); + } + + +A resource counter is used to keep a shared resource available until +the last user releases it but the above implementation has a race +condition that can cause freeing the resource twice: + + +.. slide:: Race condition scenario + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + counter is 2 + + Thread A Thread B + + * + | + | + +---------------------+ + | dec counter | counter is 1 + | cEEE | + +---------------------+ + | + | B preempts A + +-----------------------------------------------+ + | + v + +----------------------+ + counter is 0 | dec counter | + | if (!counter) | + resource is freed | free_resource(); | + | cEEE | + +----------------------+ + B finishes, A continues | + +-----------------------------------------------+ + | + v + +----------------------+ + | if (!counter) | + | free_resource(); | resource is freed + | cEEE | + +----------------------+ + +In most cases the `release_resource()` function will only free the +resource once. However, in the scenario above, if thread A is +preempted right after decrementing `counter` and thread B calls +`release_resource()` it will cause the resource to be freed. When +resumed, thread A will also free the resource since the counter value +is 0. + +To avoid race conditions the programmer must first identify the +critical section that can generate a race condition. The critical +section is the part of the code that reads and writes shared memory +from multiple parallel contexts. + +In the example above, the minimal critical section is starting with +the counter decrement and ending with checking the counter's value. + +Once the critical section has been identified race conditions can be +avoided by using one of the following approaches: + +.. slide:: Avoiding race conditions + :inline-contents: True + :level: 2 + + * make the critical section **atomic** (e.g. use atomic + instructions) + + * **disable preemption** during the critical section (e.g. disable + interrupts, bottom-half handlers, or thread preemption) + + * **serialize the access** to the critical section (e.g. use spin + locks or mutexes to allow only one context or thread in the + critical section) + + + +Linux kernel concurrency sources +================================ + +There are multiple source of concurrency in the Linux kernel that +depend on the kernel configuration as well as the type of system it +runs on: + + +.. slide:: Linux kernel concurrency sources + :inline-contents: True + :level: 2 + + * **single core systems**, **non-preemptive kernel**: the current + process can be preempted by interrupts + + * **single core systems**, **preemptive kernel**: above + the + current process can be preempted by other processes + + * **multi-core systems**: above + the current process can run + in parallel with another process or with an interrupt running on + another processor + +.. note:: We only discuss kernel concurrency and that is why a + non-preemptive kernel running on an single core system + has interrupts as the only source of concurrency. + + +Atomic operations +================= + +In certain circumstances we can avoid race conditions by using atomic +operations that are provided by hardware. Linux provides a unified API +to access atomic operations: + +.. slide:: Atomic operations + :inline-contents: True + :level: 2 + + * integer based: + + * simple: :c:func:`atomic_inc`, :c:func:`atomic_dec`, + :c:func:`atomic_add`, :c:func:`atomic_sub` + + * conditional: :c:func:`atomic_dec_and_test`, :c:func:`atomic_sub_and_test` + + * bit based: + + * simple: :c:func:`test_bit`, :c:func:`set_bit`, + :c:func:`change_bit` + + * conditional: :c:func:`test_and_set_bit`, :c:func:`test_and_clear_bit`, + :c:func:`test_and_change_bit` + +For example, we could use :c:func:`atomic_dec_and_test` to implement +the resource counter decrement and value checking atomic: + +.. slide:: Using :c:func:`atomic_dec_and_test` to implement resource counter release + :inline-contents: True + :level: 2 + + .. code-block:: c + + void release_resource() + { + if (atomic_dec_and_test(&counter)) + free_resource(); + } + + +One complication with atomic operations is encountered in +multi-core systems, where an atomic operation is not longer +atomic at the system level (but still atomic at the core level). + +To understand why, we need to decompose the atomic operation in memory +loads and stores. Then we can construct race condition scenarios where +the load and store operations are interleaved across CPUs, like in the +example below where incrementing a value from two processors will +produce an unexpected result: + +.. slide:: Atomic operations may not be atomic on SMP systems + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + + +------------+ + | Memory | + +-------------+ LOAD (0) | | +-------------+ + | CPU 0 |<--------------| v <- 0 | LOAD (0) | CPU 1 | + | | STORE (1) | |-------------->| | + | inc v |-------------->| v <- 1 | STORE (1) | inc v | + | cEEE | | v <- 1 |<--------------| cEEE | + +-------------+ | cEEE | +-------------+ + +------------+ + + +In order to provide atomic operations on SMP systems different +architectures use different techniques. For example, on x86 a LOCK +prefix is used to lock the system bus while executing the prefixed +operation: + +.. slide:: Fixing atomic operations for SMP systems (x86) + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + +------------+ + +-------------+ BUS LOCK | Memory | + | CPU 1 |<------------->| | + | | LOAD (0) | | + | inc v |<--------------| v <- 0 | + | | STORE (1) | | + | |-------------->| v <- 1 | + | | BUS UNLOCK | | + | cEEE |<------------->| | BUS LOCK +-------------+ + +-------------+ | |<------------->| CPU 1 | + | | LOAD (1) | | + | |<--------------| inc v | + | v <- 2 | STORE (2) | | + | |-------------->| | + | | BUS UNLOCK | | + | cEEE |<------------->| cEEE | + +------------+ +-------------+ + + +On ARM the LDREX and STREX instructions are used together to guarantee +atomic access: LDREX loads a value and signals the exclusive monitor +that an atomic operation is in progress. The STREX attempts to store a +new value but only succeeds if the exclusive monitor has not detected +other exclusive operations. So, to implement atomic operations the +programmer must retry the operation (both LDREX and STREX) until the +exclusive monitor signals a success. + +Although they are often interpreted as "light" or "efficient" +synchronization mechanisms (because they "don't require spinning or +context switches", or because they "are implemented in hardware so +they must be more efficient", or because they "are just instructions +so they must have similar efficiency as other instructions"), as seen +from the implementation details, atomic operations are actually +expensive. + + +Disabling preemption (interrupts) +================================= + +On single core systems and non preemptive kernels the only source of +concurrency is the preemption of the current thread by an +interrupt. To prevent concurrency is thus sufficient to disable +interrupts. + +This is done with architecture specific instructions, but Linux offers +architecture independent APIs to disable and enable interrupts: + +.. slide:: Synchronization with interrupts (x86) + :inline-contents: True + :level: 2 + + .. code-block:: c + + #define local_irq_disable() \ + asm volatile („cli” : : : „memory”) + + #define local_irq_enable() \ + asm volatile („sti” : : : „memory”) + + #define local_irq_save(flags) \ + asm volatile ("pushf ; pop %0" :"=g" (flags) + : /* no input */: "memory") \ + asm volatile("cli": : :"memory") + + #define local_irq_restore(flags) \ + asm volatile ("push %0 ; popf" + : /* no output */ + : "g" (flags) :"memory", "cc"); + + +Although the interrupts can be explicitly disabled and enable with +:c:func:`local_irq_disable` and :c:func:`local_irq_enable` these APIs +should only be used when the current state and interrupts is +known. They are usually used in core kernel code (like interrupt +handling). + +For typical cases where we want to avoid interrupts due to concurrency +issues it is recommended to use the :c:func:`local_irq_save` and +:c:func:`local_irq_restore` variants. They take care of saving and +restoring the interrupts states so they can be freely called from +overlapping critical sections without the risk of accidentally +enabling interrupts while still in a critical section, as long as the +calls are balanced. + +Spin Locks +========== + +Spin locks are used to serialize access to a critical section. They +are necessary on multi-core systems where we can have true execution +parallelism. This is a typical spin lock implementation: + + +.. slide:: Spin Lock Implementation Example (x86) + :inline-contents: True + :level: 2 + + .. code-block:: asm + + spin_lock: + lock bts [my_lock], 0 + jc spin_lock + + /* critical section */ + + spin_unlock: + mov [my_lock], 0 + + **bts dts, src** - bit test and set; it copies the src bit from the dts + memory address to the carry flag and then sets it: + + .. code-block:: c + + CF <- dts[src] + dts[src] <- 1 + + +As it can be seen, the spin lock uses an atomic instruction to make +sure that only one core can enter the critical section. If there are +multiple cores trying to enter they will continuously "spin" until the +lock is released. + +While the spin lock avoids race conditions, it can have a significant +impact on the system's performance due to "lock contention": + + +.. slide:: Lock Contention + :inline-contents: True + :level: 2 + + * There is lock contention when at least one core spins trying to + enter the critical section lock + + * Lock contention grows with the critical section size, time spent + in the critical section and the number of cores in the system + + +Another negative side effect of spin locks is cache thrashing. + +.. slide:: Cache Thrashing + :inline-contents: True + :level: 2 + + Cache thrashing occurs when multiple cores are trying to read and + write to the same memory resulting in excessive cache misses. + + Since spin locks continuously access memory during lock contention, + cache thrashing is a common occurrence due to the way cache + coherency is implemented. + + +Cache coherency in multi-processor systems +========================================== + +The memory hierarchy in multi-processor systems is composed of local +CPU caches (L1 caches), shared CPU caches (L2 caches) and the main +memory. To explain cache coherency we will ignore the L2 cache and +only consider the L1 caches and main memory. + +In the figure below we present a view of the memory hierarchy with two +variables A and B that fall into different cache lines and where +caches and the main memory are synchronized: + +.. slide:: Synchronized caches and memory + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + +-------+ +-------+ + | CPU 0 | | CPU 1 | + +-------+ +-------+ + cache cache + +-------+ +-------+ + A | 1 | | 1 | A + +-------+ +-------+ + B | 2 | | 2 | B + +-------+ +-------+ + memory + +-----------------------------+ + A | 1 | + +-----------------------------+ + B | 2 | + +-----------------------------+ + + +In the absence of a synchronization mechanism between the caches and +main memory, when CPU 0 executes `A = A + B` and CPU 1 executes `B = +A + B` we will have the following memory view: + +.. slide:: Unsynchronized caches and memory + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + +-------+ +-------+ + | CPU 0 | | CPU 1 | + +-------+ +-------+ + A <- A + B B <- A + B + + +-------+ +-------+ + A | 3 | | 1 | A + +-------+ +-------+ + B | 2 | | 3 | B + +-------+ +-------+ + write back caches + +-----------------------------+ + A | 1 | + +-----------------------------+ + B | 2 | + +-----------------------------+ + + +In order to avoid the situation above multi-processor systems use +cache coherency protocols. There are two main types of cache coherency +protocols: + +.. slide:: Cache Coherency Protocols + :inline-contents: True + :level: 2 + + * Bus snooping (sniffing) based: memory bus transactions are + monitored by caches and they take actions to preserve + coherency + + * Directory based: there is a separate entity (directory) that + maintains the state of caches; caches interact with directory + to preserve coherency + + Bus snooping is simpler but it performs poorly when the number of + cores goes beyond 32-64. + + Directory based cache coherence protocols scale much better (up + to thousands of cores) and are usually used in NUMA systems. + + +A simple cache coherency protocol that is commonly used in practice is +MESI (named after the acronym of the cache line states names: +**Modified**, **Exclusive**, **Shared** and **Invalid**). It's main +characteristics are: + +.. slide:: MESI Cache Coherence Protocol + :inline-contents: True + :level: 2 + + * Caching policy: write back + + * Cache line states + + * Modified: owned by a single core and dirty + + * Exclusive: owned by a single core and clean + + * Shared: shared between multiple cores and clean + + * Invalid : the line is not cached + +Issuing read or write requests from CPU cores will trigger state +transitions, as exemplified below: + +.. slide:: MESI State Transitions + :inline-contents: True + :level: 2 + + * Invalid -> Exclusive: read request, all other cores have the line + in Invalid; line loaded from memory + + * Invalid -> Shared: read request, at least one core has the line + in Shared or Exclusive; line loaded from sibling cache + + * Invalid/Shared/Exclusive -> Modified: write request; **all + other** cores **invalidate** the line + + * Modified -> Invalid: write request from other core; line is + flushed to memory + + +.. note:: The most important characteristic of the MESI protocol is + that it is a write-invalidate cache protocol. When writing to a + shared location all other caches are invalidated. + +This has important performance impact in certain access patterns, and +one such pattern is contention for a simple spin lock implementation +like we discussed above. + +To exemplify this issue lets consider a system with three CPU cores, +where the first has acquired the spin lock and it is running the +critical section while the other two are spinning waiting to enter the +critical section: + +.. slide:: Cache thrashing due to spin lock contention + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + +-------+ +-------+ +-------+ + | CPU 0 |<---------------+ | CPU 1 | Invalidate | CPU 0 | + | cache |<-------------+ | | cache |<---+ +---------->| cache | + +-------+ Invalidate | | +-------+ | | +-------+ + | | | | + | | +----------------------------+ + spin_lock(&lock); | | | | + | | READ lock | | + | +---- WRITE lock ---+ | + | | + | READ lock | + +-------------------------------- WRITE lock ----+ + + ... ... ... + READ data READ lock READ lock + | | | + | | | + | | | + +------------------------------+-------------------------+ + | + v + + cache miss + +As it can be seen from the figure above due to the writes issued by +the cores spinning on the lock we see frequent cache line invalidate +operations which means that basically the two waiting cores will flush +and load the cache line while waiting for the lock, creating +unnecessary traffic on the memory bus and slowing down memory accesses +for the first core. + +Another issue is that most likely data accessed by the first CPU +during the critical section is stored in the same cache line with the +lock (common optimization to have the data ready in the cache after +the lock is acquired). Which means that the cache invalidation +triggered by the two other spinning cores will slow down the execution +of the critical section which in turn triggers more cache invalidate +actions. + +Optimized spin locks +==================== + +As we have seen simple spin lock implementations can have poor +performance issues due to cache thrashing, especially as the number of +cores increase. To avoid this issue there are two possible strategies: + +* reduce the number of writes and thus reduce the number of cache + invalidate operations + +* avoid the other processors spinning on the same cache line, and thus + avoid the cache invalidate operations + + +An optimized spin lock implementation that uses the first approach is +presented below: + +.. slide:: Optimized spin lock (KeAcquireSpinLock) + :inline-contents: True + :level: 2 + + |_| + + .. code-block:: asm + + spin_lock: + rep ; nop + test lock_addr, 1 + jnz spin_lock + lock bts lock_addr + jc spin_lock + + + * we first test the lock read only, using a non atomic + instructions, to avoid writes and thus invalidate operations + while we spin + + * only when the lock *might* be free, we try to acquire it + +The implementation also use the **PAUSE** instruction to avoid +pipeline flushes due to (false positive) memory order violations and +to add a small delay (proportional with the memory bus frequency) to +reduce power consumption. + +A similar implementation with support for fairness (the CPU cores are +allowed in the critical section based on the time of arrival) is used +in the Linux kernel (the `ticket spin lock <https://lwn.net/Articles/267968/>`_) +for many architectures. + +However, for the x86 architecture, the current spin lock +implementation uses a queued spin lock where the CPU cores spin on +different locks (hopefully distributed in different cache lines) to +avoid cache invalidation operations: + +.. slide:: Queued Spin Locks + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + +-------------------------------------------+ + | Queued Spin Lock cEEE | + | | + | +---+ +---+ +---+ +---+ | + | | |----->| |----->| |----->| | | + | +---+ +---+ +---+ +---+ | + | ^ ^ ^ ^ | + | | | | | | + +-------------------------------------------+ + | | | | + CPU10 CPU17 CPU99 CPU0 + owns the spins on spins on spins on + lock private private private + lock lock lock + + + +Conceptually, when a new CPU core tries to acquire the lock and it +fails it will add its private lock to the list of waiting CPU +cores. When the lock owner exits the critical section it unlocks the +next lock in the list, if any. + +While a read spin optimized spin lock reduces most of the cache +invalidation operations, the lock owner can still generate cache +invalidate operations due to writes to data structures close to the +lock and thus part of the same cache line. This in turn generates +memory traffic on subsequent reads on the spinning cores. + +Hence, queued spin locks scale much better for large number of cores +as is the case for NUMA systems. And since they have similar fairness +properties as the ticket lock it is the preferred implementation on +the x86 architecture. + + +Process and Interrupt Context Synchronization +============================================= + +Accessing shared data from both process and interrupt context is a +relatively common scenario. On single core systems we can do this by +disabling interrupts, but that won't work on multi-core systems, +as we can have the process running on one CPU core and the interrupt +context running on a different CPU core. + +Using a spin lock, which was designed for multi-processor systems, +seems like the right solution, but doing so can cause common +deadlock conditions, as detailed by the following scenario: + + +.. slide:: Process and Interrupt Handler Synchronization Deadlock + :inline-contents: True + :level: 2 + + * In the process context we take the spin lock + + * An interrupt occurs and it is scheduled on the same CPU core + + * The interrupt handler runs and tries to take the spin lock + + * The current CPU will deadlock + + +To avoid this issue a two fold approach is used: + + +.. slide:: Interrupt Synchronization for SMP + :inline-contents: True + :level: 2 + + * In process context: disable interrupts and acquire a spin lock; + this will protect both against interrupt or other CPU cores race + conditions (:c:func:`spin_lock_irqsave` and + :c:func:`spin_lock_restore` combine the two operations) + + * In interrupt context: take a spin lock; this will will protect + against race conditions with other interrupt handlers or process + context running on different processors + + +We have the same issue for other interrupt context handlers such as +softirqs, tasklets or timers and while disabling interrupts might +work, it is recommended to use dedicated APIs: + +.. slide:: Bottom-Half Synchronization for SMP + :inline-contents: True + :level: 2 + + * In process context use :c:func:`spin_lock_bh` (which combines + :c:func:`local_bh_disable` and :c:func:`spin_lock`) and + :c:func:`spin_unlock_bh` (which combines :c:func:`spin_unlock` and + :c:func:`local_bh_enable`) + + * In bottom half context use: :c:func:`spin_lock` and + :c:func:`spin_unlock` (or :c:func:`spin_lock_irqsave` and + :c:func:`spin_lock_irqrestore` if sharing data with interrupt + handlers) + + +As mentioned before, another source of concurrency in the Linux kernel +can be other processes, due to preemption. + +.. slide:: Preemption + :inline-contents: True + :level: 2 + + |_| + + Preemption is configurable: when active it provides better latency + and response time, while when deactivated it provides better + throughput. + + Preemption is disabled by spin locks and mutexes but it can be + manually disabled as well (by core kernel code). + + +As for local interrupt enabling and disabling APIs, the bottom half +and preemption APIs allows them to be used in overlapping critical +sections. A counter is used to track the state of bottom half and +preemption. In fact the same counter is used, with different increment +values: + +.. slide:: Preemption and Bottom-Half Masking + :inline-contents: True + :level: 2 + + .. code-block:: c + + #define PREEMPT_BITS 8 + #define SOFTIRQ_BITS 8 + #define HARDIRQ_BITS 4 + #define NMI_BITS 1 + + #define preempt_disable() preempt_count_inc() + + #define local_bh_disable() add_preempt_count(SOFTIRQ_OFFSET) + + #define local_bh_enable() sub_preempt_count(SOFTIRQ_OFFSET) + + #define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK)) + + #define in_interrupt() irq_count() + + asmlinkage void do_softirq(void) + { + if (in_interrupt()) return; + ... + + +Mutexes +======= + +Mutexes are used to protect against race conditions from other CPU +cores but they can only be used in **process context**. As opposed to +spin locks, while a thread is waiting to enter the critical section it +will not use CPU time, but instead it will be added to a waiting queue +until the critical section is vacated. + +Since mutexes and spin locks usage intersect, it is useful to compare +the two: + +.. slide:: Mutexes + :inline-contents: True + :level: 2 + + * They don't "waste" CPU cycles; system throughput is better than + spin locks if context switch overhead is lower than medium + spinning time + + * They can't be used in interrupt context + + * They have a higher latency than spin locks + +Conceptually, the :c:func:`mutex_lock` operation is relatively simple: +if the mutex is not acquired we can take the fast path via an atomic +exchange operation: + + +.. slide:: :c:func:`mutex_lock` fast path + :inline-contents: True + :level: 2 + + .. code-block:: c + + void __sched mutex_lock(struct mutex *lock) + { + might_sleep(); + + if (!__mutex_trylock_fast(lock)) + __mutex_lock_slowpath(lock); + } + + static __always_inline bool __mutex_trylock_fast(struct mutex *lock) + { + unsigned long curr = (unsigned long)current; + + if (!atomic_long_cmpxchg_acquire(&lock->owner, 0UL, curr)) + return true; + + return false; + } + + +otherwise we take the slow path where we add ourselves to the mutex +waiting list and put ourselves to sleep: + +.. slide:: :c:func:`mutex_lock` slow path + :inline-contents: True + :level: 2 + + .. code-block:: c + + ... + spin_lock(&lock->wait_lock); + ... + /* add waiting tasks to the end of the waitqueue (FIFO): */ + list_add_tail(&waiter.list, &lock->wait_list); + ... + waiter.task = current; + ... + for (;;) { + if (__mutex_trylock(lock)) + goto acquired; + ... + spin_unlock(&lock->wait_lock); + ... + set_current_state(state); + spin_lock(&lock->wait_lock); + } + spin_lock(&lock->wait_lock); + acquired: + __set_current_state(TASK_RUNNING); + mutex_remove_waiter(lock, &waiter, current); + spin_lock(&lock->wait_lock); + ... + +The full implementation is a bit more complex: instead of going to +sleep immediately it optimistic spinning if it detects that the lock +owner is currently running on a different CPU as chances are the owner +will release the lock soon. It also checks for signals and handles +mutex debugging for locking dependency engine debug feature. + + +The :c:func:`mutex_unlock` operation is symmetric: if there are no +waiters on the mutex then we can take the fast path via an atomic exchange +operation: + +.. slide:: :c:func:`mutex_unlock` fast path + :inline-contents: True + :level: 2 + + .. code-block:: c + + void __sched mutex_unlock(struct mutex *lock) + { + if (__mutex_unlock_fast(lock)) + return; + __mutex_unlock_slowpath(lock, _RET_IP_); + } + + static __always_inline bool __mutex_unlock_fast(struct mutex *lock) + { + unsigned long curr = (unsigned long)current; + + if (atomic_long_cmpxchg_release(&lock->owner, curr, 0UL) == curr) + return true; + + return false; + } + + void __mutex_lock_slowpath(struct mutex *lock) + { + ... + if (__mutex_waiter_is_first(lock, &waiter)) + __mutex_set_flag(lock, MUTEX_FLAG_WAITERS); + ... + + +.. note:: Because :c:type:`struct task_struct` is cached aligned the 7 + lower bits of the owner field can be used for various flags, + such as :c:type:`MUTEX_FLAG_WAITERS`. + + +Otherwise we take the slow path where we pick up first waiter from the +list and wake it up: + +.. slide:: :c:func:`mutex_unlock` slow path + :inline-contents: True + :level: 2 + + .. code-block:: c + + ... + spin_lock(&lock->wait_lock); + if (!list_empty(&lock->wait_list)) { + /* get the first entry from the wait-list: */ + struct mutex_waiter *waiter; + waiter = list_first_entry(&lock->wait_list, struct mutex_waiter, + list); + next = waiter->task; + wake_q_add(&wake_q, next); + } + ... + spin_unlock(&lock->wait_lock); + ... + wake_up_q(&wake_q); + + + +Per CPU data +============ + +Per CPU data avoids race conditions by avoiding to use shared +data. Instead, an array sized to the maximum possible CPU cores is +used and each core will use its own array entry to read and write +data. This approach certainly has advantages: + + +.. slide:: Per CPU data + :inline-contents: True + :level: 2 + + * No need to synchronize to access the data + + * No contention, no performance impact + + * Well suited for distributed processing where aggregation is only + seldom necessary (e.g. statistics counters) + + +Memory Ordering and Barriers +============================ + +Modern processors and compilers employ out-of-order execution to +improve performance. For example, processors can execute "future" +instructions while waiting for current instruction data to be fetched +from memory. + +Here is an example of out of order compiler generated code: + +.. slide:: Out of Order Compiler Generated Code + :inline-contents: True + :level: 2 + + +-------------------+-------------------------+ + | C code | Compiler generated code | + +-------------------+-------------------------+ + |.. code-block:: c |.. code-block:: asm | + | | | + | a = 1; | MOV R10, 1 | + | b = 2; | MOV R11, 2 | + | | STORE R11, b | + | | STORE R10, a | + +-------------------+-------------------------+ + + +.. note:: When executing instructions out of order the processor makes + sure that data dependency is observed, i.e. it won't execute + instructions whose input depend on the output of a previous + instruction that has not been executed. + +In most cases out of order execution is not an issue. However, in +certain situations (e.g. communicating via shared memory between +processors or between processors and hardware) we must issue some +instructions before others even without data dependency between them. + +For this purpose we can use barriers to order memory operations: + +.. slide:: Barriers + :inline-contents: True + :level: 2 + + * A read barrier (:c:func:`rmb()`, :c:func:`smp_rmb()`) is used to + make sure that no read operation crosses the barrier; that is, + all read operation before the barrier are complete before + executing the first instruction after the barrier + + * A write barrier (:c:func:`wmb()`, :c:func:`smp_wmb()`) is used to + make sure that no write operation crosses the barrier + + * A simple barrier (:c:func:`mb()`, :c:func:`smp_mb()`) is used + to make sure that no write or read operation crosses the barrier + + +Read Copy Update (RCU) +====================== + +Read Copy Update is a special synchronization mechanism similar with +read-write locks but with significant improvements over it (and some +limitations): + +.. slide:: Read Copy Update (RCU) + :level: 2 + :inline-contents: True + + * **Read-only** lock-less access at the same time with write access + + * Write accesses still requires locks in order to avoid races + between writers + + * Requires unidirectional traversal by readers + + +In fact, the read-write locks in the Linux kernel have been deprecated +and then removed, in favor of RCU. + +Implementing RCU for a new data structure is difficult, but a few +common data structures (lists, queues, trees) do have RCU APIs that +can be used. + +RCU splits removal updates to the data structures in two phases: + +.. slide:: Removal and Reclamation + :inline-contents: True + :level: 2 + + * **Removal**: removes references to elements. Some old readers may + still see the old reference so we can't free the element. + + * **Elimination**: free the element. This action is postponed until + all existing readers finish traversal (quiescent cycle). New + readers won't affect the quiescent cycle. + + +As an example, lets take a look on how to delete an element from a +list using RCU: + +.. slide:: RCU List Delete + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + (1) List Traversal (2) Removal + +-----------+ + +-----+ +-----+ +-----+ +-----+ | +-----+ | +-----+ + | | | | | | | | | | | | | | + | A |---->| B |---->| C | | A |--+ | B |--+->| C | + | | | | | | | | | | | | + +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ + ^ ^ ^ ^ ^ ^ + | | | | | | + + + + + + + + (3) Quiescent cycle over (4) Reclamation + +-----------+ + +-----+ | +-----+ | +-----+ +-----+ +-----+ + | | | | | | | | | | | | + | A |--+ | B | +->| C | | A |---------------->| C | + | | | | | | | | | | + +-----+ +-----+ +-----+ +-----+ +-----+ + ^ ^ ^ ^ + | | | | + + +In the first step it can be seen that while readers traverse the list +all elements are referenced. In step two a writer removes +element B. Reclamation is postponed since there are still readers that +hold references to it. In step three a quiescent cycle just expired +and it can be noticed that there are no more references to +element B. Other elements still have references from readers that +started the list traversal after the element was removed. In step 4 we +finally perform reclamation (free the element). + + +Now that we covered how RCU functions at the high level, lets looks at +the APIs for traversing the list as well as adding and removing an +element to the list: + + +.. slide:: RCU list APIs cheat sheet + :inline-contents: True + :level: 2 + + .. code-block:: c + + /* list traversal */ + rcu_read_lock(); + list_for_each_entry_rcu(i, head) { + /* no sleeping, blocking calls or context switch allowed */ + } + rcu_read_unlock(); + + + /* list element delete */ + spin_lock(&lock); + list_del_rcu(&node->list); + spin_unlock(&lock); + synchronize_rcu(); + kfree(node); + + /* list element add */ + spin_lock(&lock); + list_add_rcu(head, &node->list); + spin_unlock(&lock); + diff --git a/refs/pull/405/merge/_sources/lectures/syscalls.rst.txt b/refs/pull/405/merge/_sources/lectures/syscalls.rst.txt new file mode 100644 index 00000000..49d864f3 --- /dev/null +++ b/refs/pull/405/merge/_sources/lectures/syscalls.rst.txt @@ -0,0 +1,611 @@ +============ +System Calls +============ + +`View slides <syscalls-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +Lecture objectives: +=================== + +.. slide:: System Calls + :inline-contents: True + :level: 2 + + * Linux system calls implementation + + * VDSO and virtual syscalls + + * Accessing user space from system calls + + + +Linux system calls implementation +================================= + +At a high level system calls are "services" offered by the kernel to +user applications and they resemble library APIs in that they are +described as a function call with a name, parameters, and return value. + +.. slide:: System Calls as Kernel services + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + +-------------+ +-------------+ + | Application | | Application | + +-------------+ +-------------+ + | | + |read(fd, buff, len) |fork() + | | + v v + +---------------------------------------+ + | Kernel | + +---------------------------------------+ + + +However, on a closer look, we can see that system calls are actually +not function calls, but specific assembly instructions (architecture +and kernel specific) that do the following: + +.. slide:: System Call Setup + :inline-contents: True + :level: 2 + + * setup information to identify the system call and its parameters + + * trigger a kernel mode switch + + * retrieve the result of the system call + +In Linux, system calls are identified by numbers and the parameters +for system calls are machine word sized (32 or 64 bit). There can be a +maximum of 6 system call parameters. Both the system call number and +the parameters are stored in certain registers. + +For example, on 32bit x86 architecture, the system call identifier is +stored in the EAX register, while parameters in registers EBX, ECX, +EDX, ESI, EDI, EBP. + +.. slide:: Linux system call setup + :inline-contents: False + :level: 2 + + * System calls are identified by numbers + + * The parameters for system calls are machine word sized (32 or 64 + bit) and they are limited to a maximum of 6 + + * Uses registers to store them both (e.g. for 32bit x86: EAX for + system call and EBX, ECX, EDX, ESI, EDI, EBP for parameters) + +System libraries (e.g. libc) offers functions that implement the +actual system calls in order to make it easier for applications to use +them. + +When a user to kernel mode transition occurs, the execution flow is +interrupted and it is transferred to a kernel entry point. This is +similar to how interrupts and exceptions are handled (in fact on some +architectures this transition happens as a result of an exception). + +The system call entry point will save registers (which contains values +from user space, including system call number and system call +parameters) on stack and then it will continue with executing the +system call dispatcher. + +.. note:: During the user - kernel mode transition the stack is also + switched from the user stack to the kernel stack. This is + explained in more details in the interrupts lecture. + +.. slide:: Example of Linux system call setup and handling + :inline-contents: True + :level: 2 + + .. ditaa:: + + +-------------+ dup2 +-----------------------------+ + | Application |-----+ | libc | + +-------------+ | | | + +---->| C7590 dup2: | + | ... | + | C7592 movl 0x8(%esp),%ecx | + | C7596 movl 0x4(%esp),%ebx | + | C759a movl $0x3f,%eax | + +------------------------------+ C759f int $0x80 | + | | ... +<-----+ + | +-----------------------------+ | + | | + | | + | | + | | + | +------------------------------------------------------------+ | + | | Kernel | | + | | | | + +--->|ENTRY(entry_INT80_32) | | + | ASM_CLAC | | + | pushl %eax # pt_regs->orig_ax | | + | SAVE_ALL pt_regs_ax=$-ENOSYS # save rest | | + | ... | | + | movl %esp, %eax | | + | call do_int80_syscall_32 | | + | .... | | + | RESTORE_REGS 4 # skip orig_eax/error_code | | + | ... | | + | INTERRUPT_RETURN +-+ + +------------------------------------------------------------+ + + +The purpose of the system call dispatcher is to verify the system call +number and run the kernel function associated with the system call. + +.. slide:: Linux System Call Dispatcher + :inline-contents: True + :level: 2 + + .. code-block:: c + + /* Handles int $0x80 */ + __visible void do_int80_syscall_32(struct pt_regs *regs) + { + enter_from_user_mode(); + local_irq_enable(); + do_syscall_32_irqs_on(regs); + } + + /* simplified version of the Linux x86 32bit System Call Dispatcher */ + static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs) + { + unsigned int nr = regs->orig_ax; + + if (nr < IA32_NR_syscalls) + regs->ax = ia32_sys_call_table[nr](regs->bx, regs->cx, + regs->dx, regs->si, + regs->di, regs->bp); + syscall_return_slowpath(regs); + } + + + +To demonstrate the system call flow we are going to use the virtual +machine setup, attach gdb to a running kernel, add a breakpoint to the +dup2 system call and inspect the state. + +.. slide:: Inspecting dup2 system call + :inline-contents: True + :level: 2 + + |_| + + .. asciicast:: ../res/syscalls-inspection.cast + + +In summary, this is what happens during a system call: + +.. slide:: System Call Flow Summary + :inline-contents: True + :level: 2 + + * The application is setting up the system call number and + parameters and it issues a trap instruction + + * The execution mode switches from user to kernel; the CPU switches + to a kernel stack; the user stack and the return address to user + space is saved on the kernel stack + + * The kernel entry point saves registers on the kernel stack + + * The system call dispatcher identifies the system call function + and runs it + + * The user space registers are restored and execution is switched + back to user (e.g. calling IRET) + + * The user space application resumes + + +System call table +----------------- + +The system call table is what the system call dispatcher uses to map +system call numbers to kernel functions: + +.. slide:: System Call Table + :inline-contents: True + :level: 2 + + .. code-block:: c + + #define __SYSCALL_I386(nr, sym, qual) [nr] = sym, + + const sys_call_ptr_t ia32_sys_call_table[] = { + [0 ... __NR_syscall_compat_max] = &sys_ni_syscall, + #include <asm/syscalls_32.h> + }; + + .. code-block:: c + + __SYSCALL_I386(0, sys_restart_syscall) + __SYSCALL_I386(1, sys_exit) + __SYSCALL_I386(2, sys_fork) + __SYSCALL_I386(3, sys_read) + __SYSCALL_I386(4, sys_write) + #ifdef CONFIG_X86_32 + __SYSCALL_I386(5, sys_open) + #else + __SYSCALL_I386(5, compat_sys_open) + #endif + __SYSCALL_I386(6, sys_close) + + + +System call parameters handling +------------------------------- + +Handling system call parameters is tricky. Since these values are +setup by user space, the kernel can not assume correctness and must +always verify them thoroughly. + +Pointers have a few important special cases that must be checked: + +.. slide:: System Calls Pointer Parameters + :inline-contents: True + :level: 2 + + * Never allow pointers to kernel-space + + * Check for invalid pointers + + +Since system calls are executed in kernel mode, they have access to +kernel space and if pointers are not properly checked user +applications might get read or write access to kernel space. + +For example, let's consider the case where such a check is not made for +the read or write system calls. If the user passes a kernel-space +pointer to a write system call then it can get access to kernel data +by later reading the file. If it passes a kernel-space pointer to a +read system call then it can corrupt kernel memory. + + +.. slide:: Pointers to Kernel Space + :level: 2 + + * User access to kernel data if allowed in a write system call + + * User corrupting kernel data if allowed in a read system call + + +Likewise, if a pointer passed by the application is invalid +(e.g. unmapped, read-only for cases where it is used for writing), it +could "crash" the kernel. Two approaches could be used: + +.. slide:: Invalid pointers handling approaches + :inline-contents: True + :level: 2 + + * Check the pointer against the user address space before using it, + or + + * Avoid checking the pointer and rely on the MMU to detect when the + pointer is invalid and use the page fault handler to determine + that the pointer was invalid + + +Although it sounds tempting, the second approach is not that easy to +implement. The page fault handler uses the fault address (the address +that was accessed), the faulting address (the address of the +instruction that did the access) and information from the user address +space to determine the cause: + +.. slide:: Page fault handling + :inline-contents: True + :level: 2 + + * Copy on write, demand paging, swapping: both the fault and + faulting addresses are in user space; the fault address is + valid (checked against the user address space) + + * Invalid pointer used in system call: the faulting address is + in kernel space; the fault address is in user space and it is + invalid + + * Kernel bug (kernel accesses invalid pointer): same as above + +But in the last two cases we don't have enough information to +determine the cause of the fault. + +In order to solve this issue, Linux uses special APIs (e.g +:c:func:`copy_to_user`) to accesses user space that are specially +crafted: + +.. slide:: Marking kernel code that accesses user space + :inline-contents: True + :level: 2 + + * The exact instructions that access user space are recorded in a + table (exception table) + + * When a page fault occurs the faulting address is checked against + this table + + +Although the fault handling case may be more costly overall depending +on the address space vs exception table size, and it is more complex, +it is optimized for the common case and that is why it is preferred +and used in Linux. + + +.. slide:: Cost analysis for pointer checks vs fault handling + :inline-contents: True + :level: 2 + + +------------------+-----------------------+------------------------+ + | Cost | Pointer checks | Fault handling | + +==================+=======================+========================+ + | Valid address | address space search | negligible | + +------------------+-----------------------+------------------------+ + | Invalid address | address space search | exception table search | + +------------------+-----------------------+------------------------+ + + +Virtual Dynamic Shared Object (VDSO) +==================================== + +The VDSO mechanism was born out of the necessity of optimizing the +system call implementation, in a way that does not impact libc with +having to track the CPU capabilities in conjunction with the kernel +version. + +For example, x86 has two ways of issuing system calls: int 0x80 and +sysenter. The latter is significantly faster so it should be used when +available. However, it is only available for processors newer than +Pentium II and only for kernel versions greater than 2.6. + +With VDSO the system call interface is decided by the kernel: + +.. slide:: Virtual Dynamic Shared Object (VDSO) + :inline-contents: True + :level: 2 + + * a stream of instructions to issue the system call is generated by + the kernel in a special memory area (formatted as an ELF shared + object) + + * that memory area is mapped towards the end of the user address + space + + * libc searches for VDSO and if present will use it to issue the + system call + + +.. slide:: Inspecting VDSO + :inline-contents: True + :level: 2 + + |_| + + .. asciicast:: ../res/syscalls-vdso.cast + + + +An interesting development of the VDSO is the virtual system calls +(vsyscalls) which run directly from user space. These vsyscalls are +also part of VDSO and they are accessing data from the VDSO page that +is either static or modified by the kernel in a separate read-write +map of the VDSO page. Examples of system calls that can be implemented +as vsyscalls are: getpid or gettimeofday. + + +.. slide:: Virtual System Calls (vsyscalls) + :inline-contents: True + :level: 2 + + * "System calls" that run directly from user space, part of the VDSO + + * Static data (e.g. getpid()) + + * Dynamic data update by the kernel a in RW map of the VDSO + (e.g. gettimeofday(), time(), ) + + +Accessing user space from system calls +====================================== + +As we mentioned earlier, user space must be accessed with special APIs +(:c:func:`get_user`, :c:func:`put_user`, :c:func:`copy_from_user`, +:c:func:`copy_to_user`) that check whether the pointer is in user space +and also handle the fault if the pointer is invalid. In case of invalid +pointers, they return a non-zero value. + +.. slide:: Accessing user space from system calls + :inline-contents: True + :level: 2 + + .. code-block:: c + + /* OK: return -EFAULT if user_ptr is invalid */ + if (copy_from_user(&kernel_buffer, user_ptr, size)) + return -EFAULT; + + /* NOK: only works if user_ptr is valid otherwise crashes kernel */ + memcpy(&kernel_buffer, user_ptr, size); + + +Let's examine the simplest API, get_user, as implemented for x86: + +.. slide:: get_user implementation + :inline-contents: True + :level: 2 + + .. code-block:: c + + #define get_user(x, ptr) \ + ({ \ + int __ret_gu; \ + register __inttype(*(ptr)) __val_gu asm("%"_ASM_DX); \ + __chk_user_ptr(ptr); \ + might_fault(); \ + asm volatile("call __get_user_%P4" \ + : "=a" (__ret_gu), "=r" (__val_gu), \ + ASM_CALL_CONSTRAINT \ + : "0" (ptr), "i" (sizeof(*(ptr)))); \ + (x) = (__force __typeof__(*(ptr))) __val_gu; \ + __builtin_expect(__ret_gu, 0); \ + }) + + +The implementation uses inline assembly, which allows inserting ASM +sequences in C code and also handles access to/from variables in the +ASM code. + +Based on the type size of the x variable, one of __get_user_1, +__get_user_2 or __get_user_4 will be called. Also, before executing +the assembly call, ptr will be moved to the first register EAX while +after the completion of assembly part the value of EAX will be moved +to __ret_gu and the EDX register will be moved to __val_gu. + +It is equivalent to the following pseudo code: + + +.. slide:: get_user pseudo code + :inline-contents: True + :level: 2 + + .. code-block:: c + + #define get_user(x, ptr) \ + movl ptr, %eax \ + call __get_user_1 \ + movl %edx, x \ + movl %eax, result \ + + + +The __get_user_1 implementation for x86 is the following: + +.. slide:: get_user_1 implementation + :inline-contents: True + :level: 2 + + .. code-block:: none + + .text + ENTRY(__get_user_1) + mov PER_CPU_VAR(current_task), %_ASM_DX + cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX + jae bad_get_user + ASM_STAC + 1: movzbl (%_ASM_AX),%edx + xor %eax,%eax + ASM_CLAC + ret + ENDPROC(__get_user_1) + + bad_get_user: + xor %edx,%edx + mov $(-EFAULT),%_ASM_AX + ASM_CLAC + ret + END(bad_get_user) + + _ASM_EXTABLE(1b,bad_get_user) + +The first two statements check the pointer (which is stored in EDX) +with the addr_limit field of the current task (process) descriptor to +make sure that we don't have a pointer to kernel space. + +Then, SMAP is disabled, to allow access to user from kernel, and the +access to user space is done with the instruction at the 1: label. EAX +is then zeroed to mark success, SMAP is enabled, and the call returns. + +The movzbl instruction is the one that does the access to user space +and its address is captured with the 1: label and stored in a special +section: + +.. slide:: Exception table entry + :inline-contents: True + :level: 2 + + .. code-block:: c + + /* Exception table entry */ + # define _ASM_EXTABLE_HANDLE(from, to, handler) \ + .pushsection "__ex_table","a" ; \ + .balign 4 ; \ + .long (from) - . ; \ + .long (to) - . ; \ + .long (handler) - . ; \ + .popsection + + # define _ASM_EXTABLE(from, to) \ + _ASM_EXTABLE_HANDLE(from, to, ex_handler_default) + + +For each address that accesses user space we have an entry in the +exception table, that is made up of: the faulting address(from), where +to jump to in case of a fault, and a handler function (that implements +the jump logic). All of these addresses are stored on 32bit in +relative format to the exception table, so that they work for both 32 +and 64 bit kernels. + + +All of the exception table entries are then collected in the +__ex_table section by the linker script: + +.. slide:: Exception table building + :inline-contents: True + :level: 2 + + .. code-block:: c + + #define EXCEPTION_TABLE(align) \ + . = ALIGN(align); \ + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ex_table) = .; \ + KEEP(*(__ex_table)) \ + VMLINUX_SYMBOL(__stop___ex_table) = .; \ + } + + +The section is guarded with __start___ex_table and __stop___ex_table +symbols, so that it is easy to find the data from C code. This table +is accessed by the fault handler: + + +.. slide:: Exception table handling + :inline-contents: True + :level: 2 + + .. code-block:: c + + bool ex_handler_default(const struct exception_table_entry *fixup, + struct pt_regs *regs, int trapnr) + { + regs->ip = ex_fixup_addr(fixup); + return true; + } + + int fixup_exception(struct pt_regs *regs, int trapnr) + { + const struct exception_table_entry *e; + ex_handler_t handler; + + e = search_exception_tables(regs->ip); + if (!e) + return 0; + + handler = ex_fixup_handler(e); + return handler(e, regs, trapnr); + } + + +All it does is to set the return address to the one in the field of +the exception table entry which, in case of the get_user exception +table entry, is bad_get_user which return -EFAULT to the caller. + diff --git a/refs/pull/405/merge/_sources/lectures/virt.rst.txt b/refs/pull/405/merge/_sources/lectures/virt.rst.txt new file mode 100644 index 00000000..78040391 --- /dev/null +++ b/refs/pull/405/merge/_sources/lectures/virt.rst.txt @@ -0,0 +1,651 @@ +============== +Virtualization +============== + +`View slides <virt-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +Lecture objectives: +=================== + +.. slide:: Virtualization + :inline-contents: True + :level: 2 + + * Emulation basics + + * Virtualization basics + + * Paravirtualization basics + + * Hardware support for virtualization + + * Overview of the Xen hypervisor + + * Overview of the KVM hypervisor + + +Emulation basics +================ + +.. slide:: Emulation basics + :inline-contents: True + :level: 2 + + * Instructions are emulated (each time they are executed) + + * The other system components are also emulated: + + * MMU + + * Physical memory access + + * Peripherals + + * Target architecture - the architecture that it is emulated + + * Host architecture - the architecture that the emulator runs on + + * For emulation target and host architectures can be different + + +Virtualization basics +===================== + +.. slide:: Virtualization basics + :inline-contents: True + :level: 2 + + * Defined in a paper by Popek & Goldberg in 1974 + + * Fidelity + + * Performance + + * Security + + .. ditaa:: + + +----+ +----+ +----+ + | VM | | VM | ... | VM | + +----+ +----+ +----+ + + +-------------------------+ + | Virtual Machine Monitor | + +-------------------------+ + + +-------------------------+ + | Hardware | + +-------------------------+ + + +Classic virtualization +====================== + +.. slide:: Classic virtualization + :inline-contents: True + :level: 2 + + * Trap & Emulate + + * Same architecture for host and target + + * Most of the target instructions are natively executed + + * Target OS runs in non-privilege mode on the host + + * Privileged instructions are trapped and emulated + + * Two machine states: host and guest + + +Software virtualization +======================= + +.. slide:: Software virtualization + :inline-contents: True + :level: 2 + + * Not all architecture can be virtualized; e.g. x86: + + * CS register encodes the CPL + + * Some instructions don't generate a trap (e.g. popf) + + * Solution: emulate instructions using binary translation + + +MMU virtualization +================== + +.. slide:: MMU virtualization + :inline-contents: True + :level: 2 + + * "Fake" VM physical addresses are translated by the host to actual + physical addresses + + * Guest virtual address -> Guest physical address -> Host Physical Address + + * The guest page tables are not directly used by the host hardware + + * VM page tables are verified then translated into a new set of page + tables on the host (shadow page tables) + + +Shadow page tables +------------------ + +.. slide:: Shadow page tables + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + PGD PMD PT + +----------+ +----------+ +----------+ + | | | | | | Guest Physical Page + +----------+ +----------+ +----------+ +----------+ + | | | | | |----+ | | + +-----+ +----------+ +----------+ +----------+ | | | + | CR3 | | |----+ | |---+ | | | | | + +-----+ +----------+ | +----------+ | +----------+ +--->+----------+ + | | | | | | | | | + +---------> +----------+ +------>+----------+ +---->+----------+ + Write Protected Write Protected Write Protected + | + | + Guest (VM) | + | trap access + | + ---------------------+------------------------------------------------------------------------------ + | + | check access, transform GPP to HPP + | + v + + Shadow PGD Shadow PMD Shadow PT + +----------+ +----------+ +----------+ + | | | | | | Host Physical Page + +----------+ +----------+ +----------+ +----------+ + | | | | | |----+ | | + +----------+ +----------+ +----------+ | | | + | |----+ | |---+ | | | | | + +----------+ | +----------+ | +----------+ +--->+----------+ + | | | | | | | | + +----------+ +------>+----------+ +---->+----------+ + + + +Lazy shadow sync +---------------- + +.. slide:: Lazy shadow sync + :inline-contents: True + :level: 2 + + * Guest page tables changes are typically batched + + * To avoid repeated traps, checks and transformations map guest + page table entries with write access + + * Update the shadow page table when + + * The TLB is flushed + + * In the host page fault handler + + +I/O emulation +============= + +.. slide:: I/O emulation + :inline-contents: True + :level: 2 + + |_| + + .. ditaa:: + + +---------------------+ + | Guest OS | + | +---------------+ | + | | Guest Driver | | + | +---------------+ | + | | ^ | + | | | | + +----+-----------+----+ + | trap | + | access | + +---+-----------+----+ + | | VMM | | + | v | | + | +----------------+ | + | | Virtual Device | | + | +----------------+ | + | | ^ | + | | | | + +--+------------+----+ + | | + v | + +-----------------+ + | Physical Device | + +-----------------+ + + +.. slide:: Example: qemu SiFive UART emulation + :inline-contents: True + :level: 2 + + .. literalinclude:: ../res/sifive_uart.c + :language: c + + +Paravirtualization +================== + +.. slide:: Paravirtualization + :inline-contents: True + :level: 2 + + * Change the guest OS so that it cooperates with the VMM + + * CPU paravirtualization + + * MMU paravirtualization + + * I/O paravirtualization + + * VMM exposes hypercalls for: + + * activate / deactivate the interrupts + + * changing page tables + + * accessing virtualized peripherals + + * VMM uses events to trigger interrupts in the VM + + +Intel VT-x +========== + +.. slide:: Intel VT-x + :inline-contents: True + :level: 2 + + + * Hardware extension to transform x86 to the point it can be + virtualized "classically" + + * New execution mode: non-root mode + + * Each non-root mode instance uses a Virtual Machine Control + Structure (VMCS) to store its state + + * VMM runs in root mode + + * VM-entry and VM-exit are used to transition between the two modes + + +Virtual Machine Control Structure +--------------------------------- + +.. slide:: Virtual Machine Control Structure + :inline-contents: True + :level: 2 + + * Guest information: state of the virtual CPU + + * Host information: state of the physical CPU + + * Saved information: + + * visible state: segment registers, CR3, IDTR, etc. + + * internal state + + * VMCS can not be accessed directly but certain information can be + accessed with special instructions + +VM entry & exit +--------------- + +.. slide:: VM entry & exit + :inline-contents: True + :level: 2 + + * VM entry - new instructions that switches the CPU in non-root + mode and loads the VM state from a VMCS; host state is saved in + VMCS + + * Allows injecting interrupts and exceptions in the guest + + * VM exit will be automatically triggered based on the VMCS + configuration + + * When VM exit occurs host state is loaded from VMCS, guest state + is saved in VMCS + +VM execution control fields +--------------------------- + +.. slide:: VM execution control fields + :inline-contents: True + :level: 2 + + * Selects conditions which triggers a VM exit; examples: + + * If an external interrupt is generated + + * If an external interrupt is generated and EFLAGS.IF is set + + * If CR0-CR4 registers are modified + + * Exception bitmap - selects which exceptions will generate a VM + exit + + * IO bitmap - selects which I/O addresses (IN/OUT accesses) + generates a VM exit + + * MSR bitmaps - selects which RDMSR or WRMSR instructions will + generate a VM exit + + +Extend Page Tables +================== + +.. slide:: Extend Page Tables + :inline-contents: True + :level: 2 + + * Reduces the complexity of MMU virtualization and improves + performance + + * Access to CR3, INVLPG and page faults do not require VM exit + anymore + + * The EPT page table is controlled by the VMM + + .. ditaa:: + + +-----+ +-----+ + | CR3 | | EPT | + +-----+ +-----+ + | +------------------+ | +----------------+ + | | | | | | + +--------> | Guest Page Table | +-------> | EPT Page Table | ---------------> + | | | | + ------------> +------------------+ ------------> +----------------+ + + Guest Virtual Guest Physical Host Physical + Address Address Address + + +VPID +---- + +.. slide:: VPID + :inline-contents: True + :level: 2 + + * VM entry and VM exit forces a TLB flush - loses VMM / VM translations + + * To avoid this issue a VPID (Virtual Processor ID) tag is + associated with each VM (VPID 0 is reserved for the VMM) + + * All TLB entries are tagged + + * At VM entry and exit just the entries associated with the tags + are flushed + + * When searching the TLB just the current VPID is used + + +I/O virtualization +================== + + * Direct access to hardware from a VM - in a controlled fashion + + * Map the MMIO host directly to the guest + + * Forward interrupts + +.. slide:: I/O virtualization + :inline-contents: True + :level: 2 + + .. ditaa:: + + +---------------------+ +---------------------+ + | Guest OS | | Guest OS | + | +---------------+ | | +---------------+ | + | | Guest Driver | | | | Guest Driver | | + | +---------------+ | | +---------------+ | + | | ^ | | | ^ | + | | | | | | | | + +----+-----------+----+ +----+-----------+----+ + | traped | | mapped | + | access | | access | + +---+-----------+----+ +---+-----------+-----+ But how do we deal with DMA? + | | VMM | | | | VMM | | + | v | | | | | | + | +----------------+ | | | +---------+ | + | | Virtual Device | | | | | IRQ | | + | +----------------+ | | | | Mapping | | + | | ^ | | | +---------+ | + | | | | | | | | + +--+------------+----+ +---+-----------+-----+ + | | | | + v | v | + +-----------------+ +-----------------+ + | Physical Device | | Physical Device | + +-----------------+ +-----------------+ + +Instead of trapping MMIO as with emulated devices we can allow the +guest to access the MMIO directly by mapping through its page tables. + +Interrupts from the device are handled by the host kernel and a signal +is send to the VMM which injects the interrupt to the guest just as +for the emulated devices. + + +.. slide:: I/O MMU + :inline-contents: True + :level: 2 + + VT-d protects and translates VM physical addresses using an I/O + MMU (DMA remaping) + + .. ditaa:: + + +------+ +------+ + | | | | + | CPU | | DMA | + | | | | + +------+ +------+ + | + | + v + +-----+ +-----+ + | CR3 | | EPT | + +-----+ +-----+ + | +------------------+ | +----------------+ + | | | | | | + +--------> | Guest Page Table | +-------> | EPT Page Table | ---------------> + | | | | + ------------> +------------------+ ------------> +----------------+ + + Guest Virtual Guest Physical Host Physical + Address Address Address + + +.. slide:: Interrupt posting + :inline-contents: True + :level: 2 + + * Messsage Signaled Interrupts (MSI) = DMA writes to the host + address range of the IRQ controller (e.g. 0xFEExxxxx) + + * Low bits of the address and the data indicate which interrupt + vector to deliver to which CPU + + * Interrupt remapping table points to the virtual CPU (VMCS) that + should receive the interrupt + + * I/O MMU will trap the IRQ controller write and look it up in the + interrupt remmaping table + + * if that virtual CPU is currently running it will take the + interrupt directly + + * otherwise a bit is set in a table (Posted Interrupt Descriptor + table) and the interrupt will be inject next time that vCPU is + run + + +.. slide:: I/O virtualization + :inline-contents: True + :level: 2 + + .. ditaa:: + + +---------------------+ +---------------------+ +---------------------+ + | Guest OS | | Guest OS | | Guest OS | + | +---------------+ | | +---------------+ | | +---------------+ | + | | Guest Driver | | | | Guest Driver | | | | Guest Driver | | + | +---------------+ | | +---------------+ | | +---------------+ | + | | ^ | | | ^ | | | ^ | + | | | | | | | | | | | | + +----+-----------+----+ +----+-----------+----+ +----+-----------+----+ + | traped | | mapped | | mapped | interrupt + | access | | access | | access | posting + +---+-----------+----+ +---+-----------+-----+ +---+-----------+-----+ + | | VMM | | | | VMM | | | | VMM | | + | v | | | | | | | | | | + | +----------------+ | | | +---------+ | | | | | + | | Virtual Device | | | | | IRQ | | | | | | + | +----------------+ | | | | Mapping | | | | | | + | | ^ | | | +---------+ | | | | | + | | | | | | | | | | | | + +--+------------+----+ +---+-----------+-----+ +---+-----------+-----+ + | | | | | | + v | v | v | + +-----------------+ +-----------------+ +-----------------+ + | Physical Device | | Physical Device | | Physical Device | + +-----------------+ +-----------------+ +-----------------+ + + + +.. slide:: SR-IOV + :inline-contents: True + :level: 2 + + * Single Root - Input Output Virtualization + + * Physical device with multiple Ethernet ports will be shown as + multiple device on the PCI bus + + * Physical Function is used for the control and can be configured + + * to present itself as a new PCI device + + * which VLAN to use + + * The new virtual function is enumerated on the bus and can be + assigned to a particular guest + + +qemu +==== + +.. slide:: qemu + :inline-contents: True + :level: 2 + + * Uses binary translation via Tiny Code Generator (TCG) for + efficient emulation + + * Supports different target and host architectures (e.g. running + ARM VMs on x86) + + * Both process and full system level emulation + + * MMU emulation + + * I/O emulation + + * Can be used with KVM for accelerated virtualization + +KVM +=== + +.. slide:: KVM + :inline-contents: True + :level: 2 + + .. ditaa:: + + VM1 (qemu) VM2 (qemu) + +---------------------+ +---------------------+ + | +------+ +------+ | | +------+ +------+ | + | | App1 | | App2 | | | | App1 | | App2 | | + | +------+ +------+ | | +------+ +------+ | + | +-----------------+ | | +-----------------+ | + | | Guest Kernel | | | | Guest Kernel | | + | +-----------------+ | | +-----------------+ | + +---------------------+ +---------------------+ + + +----------------------------------------------------+ + | +-----+ | + | | KVM | Host Linux Kernel | + | +-----+ | + +----------------------------------------------------+ + + +----------------------------------------------------+ + | Hardware with virtualization support | + +----------------------------------------------------+ + + +.. slide:: KVM + :inline-contents: True + :level: 2 + + * Linux device driver for hardware virtualization (e.g. Intel VT-x, SVM) + + * IOCTL based interface for managing and running virtual CPUs + + * VMM components implemented inside the Linux kernel + (e.g. interrupt controller, timers) + + * Shadow page tables or EPT if present + + * Uses qemu or virtio for I/O virtualization + + + +Type 1 vs Type 2 Hypervisors +============================ + +.. slide:: Xen + :inline-contents: True + :level: 2 + + * Type 1 = Bare Metal Hypervisor + + * Type 2 = Hypervisor embedded in an exist kernel / OS + + +Xen +=== + +.. slide:: Xen + :inline-contents: True + :level: 2 + + .. image:: ../res/xen-overview.png diff --git a/refs/pull/405/merge/_sources/so2/assign-collaboration.rst.txt b/refs/pull/405/merge/_sources/so2/assign-collaboration.rst.txt new file mode 100644 index 00000000..188c18bc --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/assign-collaboration.rst.txt @@ -0,0 +1,144 @@ +============= +Collaboration +============= + +Collaboration is essential in open source world and we encourage you +to pick a team partner to work on selected assignments. + +Here is a simple guide to get you started: + +1. Use Github / Gitlab +---------------------- + +Best way to share your work inside the team is to use a version control system (VCS) +in order to track each change. Mind that you must make your repo private and only allow +read/write access rights to team members. + +2. Start with a skeleton for the assignment +------------------------------------------- + +Add `init`/`exit` functions, driver operations and global structures that you driver might need. + +.. code-block:: c + + // SPDX-License-Identifier: GPL-2.0 + /* + * uart16550.c - UART16550 driver + * + * Author: John Doe <john.doe@mail.com> + * Author: Ionut Popescu <ionut.popescu@mail.com> + */ + struct uart16550_dev { + struct cdev cdev; + /*TODO */ + }; + + static struct uart16550_dev devs[MAX_NUMBER_DEVICES]; + + static int uart16550_open(struct inode *inode, struct file *file) + { + /*TODO */ + return 0; + } + + static int uart16550_release(struct inode *inode, struct file *file) + { + /*TODO */ + return 0; + } + + static ssize_t uart16550_read(struct file *file, char __user *user_buffer, + size_t size, loff_t *offset) + { + /*TODO */ + } + + static ssize_t uart16550_write(struct file *file, + const char __user *user_buffer, + size_t size, loff_t *offset) + { + /*TODO */ + } + + static long + uart16550_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + { + /*TODO */ + return 0; + } + + static const struct file_operations uart16550_fops = { + .owner = THIS_MODULE, + .open = uart16550_open, + .release = uart16550_release, + .read = uart16550_read, + .write = uart16550_write, + .unlocked_ioctl = uart16550_ioctl + }; + + static int __init uart16550_init(void) + { + /* TODO: */ + } + + static void __exit uart16550_exit(void) + { + /* TODO: */ + } + + module_init(uart16550_init); + module_exit(uart16550_exit); + + MODULE_DESCRIPTION("UART16550 Driver"); + MODULE_AUTHOR("John Doe <john.doe@mail.com"); + MODULE_AUTHOR("Ionut Popescu <ionut.popescu@mail.com"); + +3. Add a commit for each individual change +------------------------------------------ + +First commit must always be the skeleton file. And the rest of the code should be on top of skeleton file. +Please write a good commit mesage. Explain briefly what the commit does and *why* it is necessary. + +Follow the seven rules of writing a good commit message: https://cbea.ms/git-commit/#seven-rules + +.. code-block:: console + + Commit 3c92a02cc52700d2cd7c50a20297eef8553c207a (HEAD -> tema2) + Author: John Doe <john.doe@mail.com> + Date: Mon Apr 4 11:54:39 2022 +0300 + + uart16550: Add initial skeleton for ssignment #2 + + This adds simple skeleton file for uart16550 assignment. Notice + module init/exit callbacks and file_operations dummy implementation + for open/release/read/write/ioctl. + + Signed-off-by: John Doe <john.doe@mail.com> + +4. Split the work inside the team +--------------------------------- + +Add `TODOs` with each team member tasks. Try to split the work evenly. + +Before starting to code, make a plan. On top of your skeleton file, add TODOs with each member tasks. Agree on global +structures and the overall driver design. Then start coding. + +5. Do reviews +------------- + +Create Pull Requests with your commits and go through review rounds with your team members. You can follow `How to create a PR` `video <https://www.youtube.com/watch?v=YvoHJJWvn98>`_. + +6. Merge the work +----------------- + +The final work is the result of merging all the pull requests. Following the commit messages +one should clearly understand the progress of the code and how the work was managed inside the team. + +.. code-block:: console + + f5118b873294 uart16550: Add uart16550_interrupt implementation + 2115503fc3e3 uart16550: Add uart16550_ioctl implementation + b31a257fd8b8 uart16550: Add uart16550_write implementation + ac1af6d88a25 uart16550: Add uart16550_read implementation + 9f680e8136bf uart16550: Add uart16550_open/release implementation + 3c92a02cc527 uart16550: Add skeleton for SO2 assignment #2 diff --git a/refs/pull/405/merge/_sources/so2/assign0-kernel-api.rst.txt b/refs/pull/405/merge/_sources/so2/assign0-kernel-api.rst.txt new file mode 100644 index 00000000..835eccef --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/assign0-kernel-api.rst.txt @@ -0,0 +1,111 @@ +========================= +Assignment 0 - Kernel API +========================= + +- Deadline: :command:`Monday, 25 March 2024, 23:59` + +Assignment's Objectives +======================= + +* getting familiar with the qemu setup +* loading/unloading kernel modules +* getting familiar with the list API implemented in the kernel +* have fun :) + +Statement +========= + +Write a kernel module called `list` (the resulting file must be called `list.ko`) which stores data (strings) +in an internal list. + +It is mandatory to use `the list API <https://github.com/torvalds/linux/blob/master/include/linux/list.h>`__ +implemented in the kernel. +For details you can take a look at `the laboratory 2 <https://linux-kernel-labs.github.io/refs/heads/master/so2/lab2-kernel-api.html>`__. + +The module exports a directory named :command:`list` to procfs. The directory contains two files: + +- :command:`management`: with write-only access; is the interface for transmitting commands to the kernel module +- :command:`preview`: with read-only access; is the interface through which the internal contents of the kernel list can be viewed. + +`The code skeleton <https://github.com/linux-kernel-labs/linux/blob/master/tools/labs/templates/assignments/0-list/list.c>`__ implements the two procfs files. +You will need to create a list and implement support for `adding` and `reading` data. Follow the TODOs in the code for details. + +To interact with the kernel list, you must write commands (using the `echo` command) in the `/proc/list/management` file: + +- `addf name`: adds the `name` element to the top of the list +- `adde name`: adds the `name` element to the end of the list +- `delf name`: deletes the first appearance of the `name` item from the list +- `dela name`: deletes all occurrences of the `name` element in the list + +Viewing the contents of the list is done by viewing the contents of the `/proc/list/preview` file (use the` cat` command). +The format contains one element on each line. + +Testing +======= + +In order to simplify the assignment evaluation process, but also to reduce the mistakes of the submitted assignments, +the assignment evaluation will be done automatically with the help of a +`test script <https://github.com/linux-kernel-labs/linux/blob/master/tools/labs/templates/assignments/0-list/checker/_checker>`__ called `_checker`. +The test script assumes that the kernel module is called `list.ko`. + +QuickStart +========== + +It is mandatory to start the implementation of the assignment from the code skeleton found in the `list.c <https://gitlab.cs.pub.ro/so2/0-list/-/blob/master/src/list.c>`__ file. +You should follow the instructions in the `README.md file <https://gitlab.cs.pub.ro/so2/0-list/-/blob/master/README.md>`__ of the `assignment's repo <https://gitlab.cs.pub.ro/so2/0-list>`__. + +Tips +---- + +To increase your chances of getting the highest grade, read and follow the Linux kernel +coding style described in the `Coding Style document <https://elixir.bootlin.com/linux/v4.19.19/source/Documentation/process/coding-style.rst>`__. + +Also, use the following static analysis tools to verify the code: + +- checkpatch.pl + +.. code-block:: console + + $ linux/scripts/checkpatch.pl --no-tree --terse -f /path/to/your/list.c + +- sparse + +.. code-block:: console + + $ sudo apt-get install sparse + $ cd linux + $ make C=2 /path/to/your/list.c + +- cppcheck + +.. code-block:: console + + $ sudo apt-get install cppcheck + $ cppcheck /path/to/your/list.c + +Penalties +--------- +Information about assigments penalties can be found on the +`General Directions page <https://ocw.cs.pub.ro/courses/so2/teme/general>`__. + +In exceptional cases (the assigment passes the tests by not complying with the requirements) +and if the assigment does not pass all the tests, the grade will may decrease more than mentioned above. + +Submitting the assigment +------------------------ + +The assignment will be graded automatically using the `vmchecker-next <https://github.com/systems-cs-pub-ro/vmchecker-next/wiki/Student-Handbook>`__ infrastructure. +The submission will be made on moodle on the `course's page <https://curs.upb.ro/2022/course/view.php?id=5121>`__ to the related assignment. +You will find the submission details in the `README.md file <https://gitlab.cs.pub.ro/so2/0-list/-/blob/master/README.md>`__ of the `repo <https://gitlab.cs.pub.ro/so2/0-list/-/blob/master>`__. + +Resources +========= + +We recommend that you use gitlab to store your homework. Follow the directions in +`README.md file <https://gitlab.cs.pub.ro/so2/0-list/-/blob/master/README.md>`__. + +Questions +========= + +For questions about the topic, you can consult the mailing `list archives <http://cursuri.cs.pub.ro/pipermail/so2/>`__ +or you can write a question on the dedicated Teams channel. diff --git a/refs/pull/405/merge/_sources/so2/assign1-kprobe-based-tracer.rst.txt b/refs/pull/405/merge/_sources/so2/assign1-kprobe-based-tracer.rst.txt new file mode 100644 index 00000000..c419a0fb --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/assign1-kprobe-based-tracer.rst.txt @@ -0,0 +1,182 @@ +================================== +Assignment 1 - Kprobe based tracer +================================== + +- Deadline: :command:`Monday, 8 April 2024, 23:59` + +Assignment's Objectives +======================= + +* gaining knowledge related to the instrumentation of functions in the Linux kernel (``kretprobes`` mechanism) +* gaining knowledge regarding the ``/proc`` file system from the Linux kernel +* get familiar with data structures specific to the Linux kernel (``hash table`` and ``list``) + +Statement +========= + +Build a kernel operations surveillant. + +With this surveillant, we aim to intercept: + +* ``kmalloc`` and ``kfree`` calls +* ``schedule`` calls +* ``up`` and ``down_interruptible`` calls +* ``mutex_lock`` and ``mutex_unlock`` calls + +The surveillant will hold, at the process level, the number of calls for each of the above functions. +For the ``kmalloc`` and ``kfree`` calls the total quantity of allocated and deallocated memory will be +shown. + +The surveillant will be implemented as a kernel module with the name ``tracer.ko``. + +Implementation details +---------------------- + +The interception will be done by recording a sample (``kretprobe``) for each of the above functions. The +surveillant will retain a list/hashtable with the monitored processes and will account for +the above information for these processes. + +For the control of the list/hashtable with the monitored processes, a char device called ``/dev/tracer`` +will be used, with major `10` and minor `42`. It will expose an ``ioctl`` interface with two arguments: + +* the first argument is the request to the monitoring subsystem: + + * ``TRACER_ADD_PROCESS`` + * ``TRACER_REMOVE_PROCESS`` + +* the second argument is the PID of the process for which the monitoring request will be executed + +In order to create a char device with major `10` you will need to use the `miscdevice <https://elixir.bootlin.com/linux/latest/source/include/linux/miscdevice.h>`__ interface in the kernel. +Definitions of related macros can be found in the `tracer.h header <https://gitlab.cs.pub.ro/so2/1-tracer/-/blob/master/src/tracer.h>`__. + +Since the ``kmalloc`` function is inline for instrumenting the allocated amount of memory, the ``__kmalloc`` +function will be inspected as follows: + +* a ``kretprobe`` will be used, which will retain the amount of memory allocated and the address of the allocated memory area. +* the ``.entry_handler`` and ``.handler`` fields in the ``kretprobe`` structure will be used to retain information about the amount of memory allocated and the address from which the allocated memory starts. + +.. code-block:: C + + static struct kretprobe kmalloc_probe = { + .entry_handler = kmalloc_probe_entry_handler, /* entry handler */ + .handler = kmalloc_probe_handler, /* return probe handler */ + .maxactive = 32, + }; + +Since the ``kfree`` function only receives the address of the memory area to be freed, in order to determine +the total amount of memory freed, we will need to determine its size based on the address of the area. +This is possible because there is an address-size association made when inspecting the ``__kmalloc`` function. + +For the rest of the instrumentation functions it is enough to use a ``kretprobe``. + +.. code-block:: C + + static struct kretprobe up_probe = { + .entry_handler = up_probe_handler, + .maxactive = 32, + }; + +The virtual machine kernel has the ``CONFIG_DEBUG_LOCK_ALLOC`` option enabled where the ``mutex_lock`` symbol +is a macro that expands to ``mutex_lock_nested``. Thus, in order to obtain information about the ``mutex_lock`` +function you will have to instrument the ``mutex_lock_nested`` function. + +Processes that have been added to the list/hashtable and that end their execution will be removed +from the list/hashtable. Also, a process will be removed from the dispatch list/hashtable following +the ``TRACER_REMOVE_PROCESS`` operation. + +The information retained by the surveillant will be displayed via the procfs file system, in the ``/proc/tracer`` file. +For each monitored process an entry is created in the ``/proc/tracer`` file having as first field the process PID. +The entry will be read-only, and a read operation on it will display the retained results. An example of +displaying the contents of the entry is: + +.. code-block:: console + + $cat /proc/tracer + PID kmalloc kfree kmalloc_mem kfree_mem sched up down lock unlock + 42 12 12 2048 2048 124 2 2 9 9 + 1099 0 0 0 0 1984 0 0 0 0 + 1244 0 0 0 0 1221 100 1023 1023 1002 + 1337 123 99 125952 101376 193821 992 81921 7421 6392 + +Testing +======= + +In order to simplify the assignment evaluation process, but also to reduce the mistakes of the submitted assignments, +the assignment evaluation will be done automatically with the help of a +`test script <https://github.com/linux-kernel-labs/linux/blob/master/tools/labs/templates/assignments/1-tracer/checker/_checker>`__ called `_checker`. +The test script assumes that the kernel module is called `tracer.ko`. + +QuickStart +========== + +It is mandatory to start the implementation of the assignment from the code skeleton found in the `src <https://gitlab.cs.pub.ro/so2/1-tracer/-/tree/master/src>`__ directory. +There is only one header in the skeleton called `tracer.h <https://gitlab.cs.pub.ro/so2/1-tracer/-/blob/master/src/tracer.h>`__. +You will provide the rest of the implementation. You can add as many `*.c`` sources and additional `*.h`` headers. +You should also provide a Kbuild file that will compile the kernel module called `tracer.ko`. +Follow the instructions in the `README.md file <https://gitlab.cs.pub.ro/so2/1-tracer/-/blob/master/README.md>`__ of the `assignment's repo <https://gitlab.cs.pub.ro/so2/1-tracer>`__. + + +Tips +---- + +To increase your chances of getting the highest grade, read and follow the Linux kernel +coding style described in the `Coding Style document <https://elixir.bootlin.com/linux/v4.19.19/source/Documentation/process/coding-style.rst>`__. + +Also, use the following static analysis tools to verify the code: + +- checkpatch.pl + +.. code-block:: console + + $ linux/scripts/checkpatch.pl --no-tree --terse -f /path/to/your/tracer.c + +- sparse + +.. code-block:: console + + $ sudo apt-get install sparse + $ cd linux + $ make C=2 /path/to/your/tracer.c + +- cppcheck + +.. code-block:: console + + $ sudo apt-get install cppcheck + $ cppcheck /path/to/your/tracer.c + +Penalties +--------- + +Information about assigments penalties can be found on the +`General Directions page <https://ocw.cs.pub.ro/courses/so2/teme/general>`__. In addition, the following +elements will be taken into account: + +* *-2*: missing of proper disposal of resources (``kretprobes``, entries in ``/proc``) +* *-2*: data synchronization issues for data used by multiple executing instances (e.g. the list/hashtable) + +In exceptional cases (the assigment passes the tests but it is not complying with the requirements) +and if the assigment does not pass all the tests, the grade may decrease more than mentioned above. + +Submitting the assigment +------------------------ + +The assignment will be graded automatically using the `vmchecker-next <https://github.com/systems-cs-pub-ro/vmchecker-next/wiki/Student-Handbook>`__ infrastructure. +The submission will be made on moodle on the `course's page <https://curs.upb.ro/2022/course/view.php?id=5121>`__ to the related assignment. +You will find the submission details in the `README.md file <https://gitlab.cs.pub.ro/so2/1-tracer/-/blob/master/README.md>`__ of the `repo <https://gitlab.cs.pub.ro/so2/1-tracer>`__. + + +Resources +========= + +* `Documentation/kprobes.txt <https://www.kernel.org/doc/Documentation/kprobes.txt>`__ - description of the ``kprobes`` subsystem from Linux kernel sources. +* `samples/kprobes/ <https://elixir.bootlin.com/linux/latest/source/samples/kprobes>`__ - some examples of using ``kprobes`` from Linux kernel sources. + +We recommend that you use gitlab to store your homework. Follow the directions in +`README <https://gitlab.cs.pub.ro/so2/1-tracer/-/blob/master/README.md>`__. + +Questions +========= + +For questions about the topic, you can consult the mailing `list archives <http://cursuri.cs.pub.ro/pipermail/so2/>`__ +or you can write a question on the dedicated Teams channel. diff --git a/refs/pull/405/merge/_sources/so2/assign2-driver-uart.rst.txt b/refs/pull/405/merge/_sources/so2/assign2-driver-uart.rst.txt new file mode 100644 index 00000000..0622965b --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/assign2-driver-uart.rst.txt @@ -0,0 +1,152 @@ +========================== +Assignment 2 - Driver UART +========================== + +- Deadline: :command:`Monday, 22 April 2024, 23:59` +- The assigment is individual + +Assignment's Objectives +======================= + +* consolidating the knowledge of device drivers +* read hardware documentation and track the desired functionality in the documentation +* work with interrupts; use of non-blocking functions in interrupt context +* use of buffers; synchronization +* kernel modules with parameters + +Statement +========= + +Write a kernel module that implements a driver for the serial port (`UART16550`). +The device driver must support the two standard serial ports in a PC, `COM1` and `COM2` (`0x3f8` and `0x2f8`, +in fact the entire range of `8` addresses `0x3f8-0x3ff` and `0x2f8-0x2ff` specific to the two ports). +In addition to the standard routines (`open`, `read`, `write`, `close`), +the driver must also have support for changing communication parameters using an `ioctl` operation (`UART16550_IOCTL_SET_LINE`). + +The driver must use interrupts for both reception and transmission to reduce latency and CPU usage time. +`Read` and `write` calls must also be blocking. :command:`Assignments that do not meet these requirements will not be considered.` +It is recommended that you use a buffer for the read routine and another buffer for the write routine for each serial port in the driver. + +A blocking read call means that the read routine called from the user-space will be blocked until :command:`at least` one byte is read +(the read buffer in the kernel is empty and no data can be read). +A blocking write call means that the write routine called from the user-space will be blocked until :command:`at least` one byte is written +(the write buffer in the kernel is full and no data can be written). + +Buffers Scheme +-------------- + +.. image:: ../img/buffers-scheme.png + +Data transfer between the various buffers is a `Producer-Consumer <https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem>`__ problem. Example: + +- The process is the producer and the device is the consumer if it is written from the process to the device; the process will block until there is at least one free space in the consumer's buffer + +- The process is the consumer and the device is the producer if it is read from a process from the device; the process will block until there is at least one element in the producer's buffer. + +Implementation Details +====================== + +- the driver will be implemented as a kernel module named :command:`uart16550.ko` +- the driver will be accessed as a character device driver, with different functions depending on the parameters transmitted to the load module: + + - the `major` parameter will specify the major with which the device must be registered + - the `option` parameter will specify how it works: + + - OPTION_BOTH: will also register COM1 and COM2, with the major given by the `major` parameter and the minors 0 (for COM1) and 1 (for COM2); + - OPTION_COM1: will only register COM1, with the major `major` and minor 0; + - OPTION_COM2: will only register COM2, with the major `major` and minor 1; + - to learn how to pass parameters in Linux, see `tldp <https://tldp.org/LDP/lkmpg/2.6/html/x323.html>`__ + - the default values are `major=42` and `option=OPTION_BOTH`. +- the interrupt number associated with COM1 is 4 (`IRQ_COM1`) and the interrupt number associated with COM2 is 3 (`IRQ_COM2`) +- `the header <https://gitlab.cs.pub.ro/so2/2-uart/-/blob/master/src/uart16550.h>`__ with the definitions needed for special operations; +- a starting point in implementing read / write routines is the `example <https://ocw.cs.pub.ro/courses/so2/laboratoare/lab04?&#sincronizare_-_cozi_de_asteptare>`__ of uppercase / lowercase character device driver; the only difference is that you have to use two buffers, one for read and one for write; +- you can use `kfifo <https://lwn.net/Articles/347619/>`__ for buffers; +- you do not have to use deferred functions to read / write data from / to ports (you can do everything from interrupt context); +- you will need to synchronize the read / write routines with the interrupt handling routine for the routines to be blocking; it is recommended to use `synchronization with waiting queues <https://ocw.cs.pub.ro/courses/so2/laboratoare/lab04?&#sincronizare_-_cozi_de_asteptare>`__ +- In order for the assigment to work, the `default serial driver` must be disabled: + + - `cat /proc/ioports | grep serial` will detect the presence of the default driver on the regions where COM1 and COM2 are defined + - in order to deactivate it, the kernel must be recompiled, either by setting the serial driver as the module, or by deactivating it completely (this modification is already made on the virtual machine) + + - `Device Drivers -> Character devices -> Serial driver -> 8250/16550 and compatible serial support.` + +Testing +======= +In order to simplify the assignment evaluation process, but also to reduce the mistakes of the submitted assignments, +the assignment evaluation will be done automatically with the help of a +`test script <https://gitlab.cs.pub.ro/so2/2-uart/-/blob/master/checker/2-uart-checker/_checker>`__ called `_checker`. +The test script assumes that the kernel module is called `uart16550.ko`. + +QuickStart +========== + +It is mandatory to start the implementation of the assignment from the code skeleton found in the `src <https://gitlab.cs.pub.ro/so2/2-uart/-/tree/master/src>`__ directory. +There is only one header in the skeleton called `uart16550.h <https://gitlab.cs.pub.ro/so2/2-uart/-/blob/master/src/uart16550.h>`__. +You will provide the rest of the implementation. You can add as many `*.c`` sources and additional `*.h`` headers. +You should also provide a Kbuild file that will compile the kernel module called `uart16550.ko`. +Follow the instructions in the `README.md file <https://gitlab.cs.pub.ro/so2/2-uart/-/blob/master/README.md>`__ of the `assignment's repo <https://gitlab.cs.pub.ro/so2/2-uart>`__. + + +Tips +---- + +To increase your chances of getting the highest grade, read and follow the Linux kernel +coding style described in the `Coding Style document <https://elixir.bootlin.com/linux/v4.19.19/source/Documentation/process/coding-style.rst>`__. + +Also, use the following static analysis tools to verify the code: + +- checkpatch.pl + +.. code-block:: console + + $ linux/scripts/checkpatch.pl --no-tree --terse -f /path/to/your/list.c + +- sparse + +.. code-block:: console + + $ sudo apt-get install sparse + $ cd linux + $ make C=2 /path/to/your/list.c + +- cppcheck + +.. code-block:: console + + $ sudo apt-get install cppcheck + $ cppcheck /path/to/your/list.c + +Penalties +--------- + +Information about assigments penalties can be found on the +`General Directions page <https://ocw.cs.pub.ro/courses/so2/teme/general>`__. + +In exceptional cases (the assigment passes the tests by not complying with the requirements) +and if the assigment does not pass all the tests, the grade will may decrease more than mentioned above. + +Submitting the assigment +------------------------ + +The assignment will be graded automatically using the `vmchecker-next <https://github.com/systems-cs-pub-ro/vmchecker-next/wiki/Student-Handbook>`__ infrastructure. +The submission will be made on moodle on the `course's page <https://curs.upb.ro/2022/course/view.php?id=5121>`__ to the related assignment. +You will find the submission details in the `README.md file <https://gitlab.cs.pub.ro/so2/2-uart/-/blob/master/README.md>`__ of the `repo <https://gitlab.cs.pub.ro/so2/2-uart>`__. + + +Resources +========= + +- serial port documentation can be found on `tldp <https://tldp.org/HOWTO/Serial-HOWTO-19.html>`__ +- `table with registers <http://www.byterunner.com/16550.html>`__ +- `datasheet 16550 <https://pdf1.alldatasheet.com/datasheet-pdf/view/9301/NSC/PC16550D.html>`__ +- `alternative documentation <https://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming>`__ + +We recommend that you use gitlab to store your homework. Follow the directions in +`README <https://gitlab.cs.pub.ro/so2/2-uart/-/blob/master/README.md>`__. + + +Questions +========= + +For questions about the topic, you can consult the mailing `list archives <http://cursuri.cs.pub.ro/pipermail/so2/>`__ +or you can write a question on the dedicated Teams channel. diff --git a/refs/pull/405/merge/_sources/so2/assign3-software-raid.rst.txt b/refs/pull/405/merge/_sources/so2/assign3-software-raid.rst.txt new file mode 100644 index 00000000..e0b574a8 --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/assign3-software-raid.rst.txt @@ -0,0 +1,174 @@ +=========================== +Assignment 3 - Software RAID +=========================== + +- Deadline: :command:`Thursday, 16 May 2024, 23:59` + +Implementing a software RAID module that uses a logical block device that will read and write data from two physical devices, +ensuring the consistency and synchronization of data from the two physical devices. The type of RAID implemented will be similar to a `RAID 1`. + +Assignment's Objectives +======================= + +* in-depth understanding of how the I/O subsystem works. +* acquire advanced skills working with `bio` structures. +* work with the block / disk devices in the Linux kernel. +* acquire skills to navigate and understand the code and API dedicated to the I/O subsystem in Linux. + + +Statement +========= + +Write a kernel module that implements the RAID software functionality. `Software RAID <https://en.wikipedia.org/wiki/RAID#Software-based_RAID>`__ provides an abstraction between +the logical device and the physical devices. The implementation will use `RAID scheme 1 <https://en.wikipedia.org/wiki/RAID#Standard_levels>`__. + +The virtual machine has two hard disks that will represent the physical devices: `/dev/vdb` and `/dev/vdc`. The operating system +will provide a logical device (block type) that will interface the access from the user space. Writing requests to the logical device +will result in two writes, one for each hard disk. Hard disks are not partitioned. It will be considered that each hard disk has a +single partition that covers the entire disk. + +Each partition will store a sector along with an associated checksum (CRC32) to ensure error recovery. At each reading, the related +information from both partitions is read. If a sector of the first partition has corrupt data (CRC value is wrong) then the sector +on the second partition will be read; at the same time the sector of the first partition will be corrected. Similar in the case of +a reading of a corrupt sector on the second partition. If a sector has incorrect CRC values on both partitions, an appropriate error +code will be returned. + +Important to know +----------------- + +To ensure error recovery, a CRC code is associated with each sector. CRC codes are stored by LOGICAL_DISK_SIZE byte of the partition +(macro defined in the assignment `header <https://gitlab.cs.pub.ro/so2/3-raid/-/blob/master/src/ssr.h>`__). The disk structure will have the following layout: + + +.. code-block:: console + + +-----------+-----------+-----------+ +---+---+---+ + | sector1 | sector2 | sector3 |.....|C1 |C2 |C3 | + +-----------+-----------+-----------+ +---+---+---+ + +where ``C1``, ``C2``, ``C3`` are the values CRC sectors ``sector1``, ``sector2``, ``sector3``. The CRC area is found immediately after the ``LOGICAL_DISK_SIZE`` bytes of the partition. + +As a seed for CRC use 0(zero). + +Implementation Details +====================== + +- the kernel module will be named ``ssr.ko`` +- the logical device will be accessed as a block device with the major ``SSR_MAJOR`` and minor ``SSR_FIRST_MINOR`` under the name ``/dev/ssr`` (via the macro ``LOGICAL_DISK_NAME``) +- the virtual device (``LOGICAL_DISK_NAME`` - ``/dev/ssr``) will have the capacity of ``LOGICAL_DISK_SECTORS`` (use ``set_capacity`` with the ``struct gendisk`` structure) +- the two disks are represented by the devices ``/dev/vdb``, respectively ``/dev/vdc``, defined by means of macros ``PHYSICAL_DISK1_NAME``, respectively ``PHYSICAL_DISK2_NAME`` +- to work with the ``struct block _device`` structure associated with a physical device, you can use the ``blkdev_get_by_path`` and ``blkdev_put`` functions +- for the handling of requests from the user space, we recommend not to use a ``request_queue``, but to do processing at :c:type:`struct bio` level + using the ``submit_bio`` field of :c:type:`struct block_device_operations` +- since data sectors are separated from CRC sectors you will have to build separate ``bio`` structures for data and CRC values +- to allocate a :c:type:`struct bio` for physical disks you can use :c:func:`bio_alloc`; to add data pages to bio use :c:func:`alloc_page` and :c:func:`bio_add_page` +- to free up the space allocated for a :c:type:`struct bio` you need to release the pages allocated to the bio (using the :c:func:`__free_page` macro ) and call + :c:func:`bio_put` +- when generating a :c:type:`struct bio` structure, consider that its size must be multiple of the disk sector size (``KERNEL_SECTOR_SIZE``) +- to send a request to a block device and wait for it to end, you can use the :c:func:`submit_bio_wait` function +- use :c:func:`bio_endio` to signal the completion of processing a ``bio`` structure +- for the CRC32 calculation you can use the :c:func:`crc32` macro provided by the kernel +- useful macro definitions can be found in the assignment support `header <https://gitlab.cs.pub.ro/so2/3-raid/-/blob/master/src/ssr.h>`__ +- a single request processing function for block devices can be active at one time in a call stack (more details `here <https://elixir.bootlin.com/linux/v5.10/source/block/blk-core.c#L1048>`__). + You will need to submit requests for physical devices in a kernel thread; we recommend using ``workqueues``. +- For a quick run, use a single bio to batch send the read/write request for CRC values for adjacent sectors. For example, + if you need to send requests for CRCs in sectors 0, 1, ..., 7, use a single bio, not 8 bios. +- our recommendations are not mandatory (any solution that meets the requirements of the assignment is accepted) +Testing +======= +In order to simplify the assignment evaluation process, but also to reduce the mistakes of the submitted assignments, +the assignment evaluation will be done automatically with the help of a +`test script <https://gitlab.cs.pub.ro/so2/3-raid/-/blob/master/checker/3-raid-checker/_checker>`__ called `_checker`. +The test script assumes that the kernel module is called `ssr.ko`. + +If, as a result of the testing process, the sectors on both disks contain invalid data, resulting in +read errors that make the module impossible to use, you will need to redo the two disks in the +virtual machine using the commands: + +.. code-block:: console + + $ dd if=/dev/zero of=/dev/vdb bs=1M + $ dd if=/dev/zero of=/dev/vdc bs=1M + +You can also get the same result using the following command to start the virtual machine: + +.. code-block:: console + + $ rm disk{1,2}.img; make console # or rm disk{1,2}.img; make boot + +QuickStart +========== + +It is mandatory to start the implementation of the assignment from the code skeleton found in the `src <https://gitlab.cs.pub.ro/so2/3-raid/-/tree/master/src>`__ directory. +There is only one header in the skeleton called `ssr.h <https://gitlab.cs.pub.ro/so2/3-raid/-/blob/master/src/ssr.h>`__. +You will provide the rest of the implementation. You can add as many `*.c`` sources and additional `*.h`` headers. +You should also provide a Kbuild file that will compile the kernel module called `ssr.ko`. +Follow the instructions in the `README.md file <https://gitlab.cs.pub.ro/so2/3-raid/-/blob/master/README.md>`__ of the `assignment's repo <https://gitlab.cs.pub.ro/so2/3-raid>`__. + + +Tips +---- + +To increase your chances of getting the highest grade, read and follow the Linux kernel +coding style described in the `Coding Style document <https://elixir.bootlin.com/linux/v4.19.19/source/Documentation/process/coding-style.rst>`__. + +Also, use the following static analysis tools to verify the code: + +- checkpatch.pl + +.. code-block:: console + + $ linux/scripts/checkpatch.pl --no-tree --terse -f /path/to/your/file.c + +- sparse + +.. code-block:: console + + $ sudo apt-get install sparse + $ cd linux + $ make C=2 /path/to/your/file.c + +- cppcheck + +.. code-block:: console + + $ sudo apt-get install cppcheck + $ cppcheck /path/to/your/file.c + +Penalties +--------- + +Information about assigments penalties can be found on the +`General Directions page <https://ocw.cs.pub.ro/courses/so2/teme/general>`__. + +In exceptional cases (the assigment passes the tests by not complying with the requirements) +and if the assigment does not pass all the tests, the grade will may decrease more than mentioned above. + +Submitting the assigment +------------------------ + +The assignment will be graded automatically using the `vmchecker-next <https://github.com/systems-cs-pub-ro/vmchecker-next/wiki/Student-Handbook>`__ infrastructure. +The submission will be made on moodle on the `course's page <https://curs.upb.ro/2022/course/view.php?id=5121>`__ to the related assignment. +You will find the submission details in the `README.md file <https://gitlab.cs.pub.ro/so2/3-raid/-/blob/master/README.md>`__ of the `repo <https://gitlab.cs.pub.ro/so2/3-raid>`__. + + +Resources +========= + +- implementation of the `RAID <https://elixir.bootlin.com/linux/v5.10/source/drivers/md>`__ software in the Linux kernel + +We recommend that you use gitlab to store your homework. Follow the directions in +`README <https://gitlab.cs.pub.ro/so2/3-raid/-/blob/master/README.md>`__. + + +Questions +========= + +For questions about the topic, you can consult the mailing `list archives <http://cursuri.cs.pub.ro/pipermail/so2/>`__ +or you can write a question on the dedicated Teams channel. + +Before you ask a question, make sure that: + + - you have read the statement of the assigment well + - the question is not already presented on the `FAQ page <https://ocw.cs.pub.ro/courses/so2/teme/tema2/faq>`__ + - the answer cannot be found in the `mailing list archives <http://cursuri.cs.pub.ro/pipermail/so2/>`__ diff --git a/refs/pull/405/merge/_sources/so2/assign4-transport-protocol.rst.txt b/refs/pull/405/merge/_sources/so2/assign4-transport-protocol.rst.txt new file mode 100644 index 00000000..192dc842 --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/assign4-transport-protocol.rst.txt @@ -0,0 +1,253 @@ +===================================== +Assignment 4 - SO2 Transport Protocol +===================================== + +- Deadline: :command:`Monday, 29 May 2023, 23:00` +- This assignment can be made in teams (max 2). Only one of them must submit the assignment, and the names of the student should be listed in a README file. + +Implement a simple datagram transport protocol - STP (*SO2 Transport Protocol*). + +Assignment's Objectives +======================= + +* gaining knowledge about the operation of the networking subsystem in the Linux kernel +* obtaining skills to work with the basic structures of the networking subsystem in Linux +* deepening the notions related to communication and networking protocols by implementing a protocol in an existing protocol stack + +Statement +========= + +Implement, in the Linux kernel, a protocol called STP (*SO2 Transport Protocol*), at network and transport level, that works using datagrams (it is not connection-oriented and does not use flow-control elements). + +The STP protocol acts as a Transport layer protocol (port-based multiplexing) but operates at level 3 (Network) of `the OSI stack <http://en.wikipedia.org/wiki/OSI_model>`__, above the Data Link level. + +The STP header is defined by the ``struct stp_header`` structure: + +.. code-block:: c + + struct stp_header { + __be16 dst; + __be16 src; + __be16 len; + __u8 flags; + __u8 csum; + }; + + +where: + + * ``len`` is the length of the packet in bytes (including the header); + * ``dst`` and ``src`` are the destination and source ports, respectively; + * ``flags`` contains various flags, currently unused (marked *reserved*); + * ``csum`` is the checksum of the entire package including the header; the checksum is calculated by exclusive OR (XOR) between all bytes. + +Sockets using this protocol will use the ``AF_STP`` family. + +The protocol must work directly over Ethernet. The ports used are between ``1`` and ``65535``. Port ``0`` is not used. + +The definition of STP-related structures and macros can be found in the `assignment support header <https://gitlab.cs.pub.ro/so2/4-stp/-/blob/master/src/stp.h>`__. + +Implementation Details +====================== + +The kernel module will be named **af_stp.ko**. + +You have to define a structure of type `net_proto_family <http://elixir.free-electrons.com/linux/v5.10/source/include/linux/net.h#L211>`__, which provides the operation to create STP sockets. +Newly created sockets are not associated with any port or interface and cannot receive / send packets. +You must initialize the `socket ops field <http://elixir.free-electrons.com/linux/v5.10/source/include/linux/net.h#L125>`__ with the list of operations specific to the STP family. +This field refers to a structure `proto_ops <http://elixir.free-electrons.com/linux/v5.10/source/include/linux/net.h#L139>`__ which must include the following functions: + +* ``release``: releases an STP socket +* ``bind``: associates a socket with a port (possibly also an interface) on which packets will be received / sent: + + * there may be bind sockets only on one port (not on an interface) + * sockets associated with only one port will be able to receive packets sent to that port on all interfaces (analogous to UDP sockets associated with only one port); these sockets cannot send packets because the interface from which they can be sent via the standard sockets API cannot be specified + * two sockets cannot be binded to the same port-interface combination: + + * if there is a socket already binded with a port and an interface then a second socket cannot be binded to the same port and the same interface or without a specified interface + * if there is a socket already binded to a port but without a specified interface then a second socket cannot be binded to the same port (with or without a specified interface) + + * we recommend using a hash table for bind instead of other data structures (list, array); in the kernel there is a hash table implementation in the `hashtable.h header <http://elixir.free-electrons.com/linux/v4.9.11/source/include/linux/hashtable.h>`__ + +* ``connect``: associates a socket with a remote port and hardware address (MAC address) to which packets will be sent / received: + + * this should allow ``send`` / ``recv`` operations on the socket instead of ``sendmsg`` / ``recvmsg`` or ``sendto`` / ``recvfrom`` + * once connected to a host, sockets will only accept packets from that host + * once connected, the sockets can no longer be disconnected + +* ``sendmsg``, ``recvmsg``: send or receive a datagram on an STP socket: + + * for the *receive* part, metainformation about the host that sent the packet can be stored in the `cb field in sk_buff <http://elixir.free-electrons.com/linux/v5.10/source/include/linux/skbuff.h#L742>`__ + +* ``poll``: the default function ``datagram_poll`` will have to be used +* for the rest of the operations the predefined stubs in the kernel will have to be used (``sock_no_*``) + +.. code-block:: c + + static const struct proto_ops stp_ops = { + .family = PF_STP, + .owner = THIS_MODULE, + .release = stp_release, + .bind = stp_bind, + .connect = stp_connect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .getname = sock_no_getname, + .poll = datagram_poll, + .ioctl = sock_no_ioctl, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .setsockopt = sock_no_setsockopt, + .getsockopt = sock_no_getsockopt, + .sendmsg = stp_sendmsg, + .recvmsg = stp_recvmsg, + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, + }; + +Socket operations use a type of address called ``sockaddr_stp``, a type defined in the `assignment support header <https://github.com/linux-kernel-labs/linux/blob/master/tools/labs/templates/assignments/4-stp/stp.h>`__. +For the *bind* operation, only the port and the index of the interface on which the socket is bind will be considered. +For the *receive* operation, only the ``addr`` and ``port`` fields in the structure will be filled in with the MAC address of the host that sent the packet and with the port from which it was sent. +Also, when sending a packet, the destination host will be obtained from the ``addr`` and ``port`` fields of this structure. + +You need to register a structure `packet_type <http://elixir.free-electrons.com/linux/v5.10/source/include/linux/netdevice.h#L2501>`__, using the call `dev_add_pack <http://elixir.free-electrons.com/linux/v5.10/source/net/core/dev.c#L521>`__ to be able to receive STP packets from the network layer. + +The protocol will need to provide an interface through the *procfs* file system for statistics on sent / received packets. +The file must be named ``/proc/net/stp_stats``, specified by the ``STP_PROC_FULL_FILENAME`` macro in `assignment support header <https://gitlab.cs.pub.ro/so2/4-stp/-/blob/master/src/stp.h>`__. +The format must be of simple table type with ``2`` rows: on the first row the header of the table, and on the second row the statistics corresponding to the columns. +The columns of the table must be in order: + +.. code:: + + RxPkts HdrErr CsumErr NoSock NoBuffs TxPkts + +where: + +* ``RxPkts`` - the number of packets received +* ``HdrErr`` - the number of packets received with header errors (packets too short or with source or destination 0 ports) +* ``CsumErr`` - the number of packets received with checksum errors +* ``NoSock`` - the number of received packets for which no destination socket was found +* ``NoBuffs`` - the number of received packets that could not be received because the socket queue was full +* ``TxPkts`` - the number of packets sent + +To create or delete the entry specified by ``STP_PROC_FULL_FILENAME`` we recommend using the functions `proc_create <http://elixir.free-electrons.com/linux/v5.10/source/include/linux/proc_fs.h#L108>`__ and `proc_remove <http://elixir.free-electrons.com/linux/v5.10/source/fs/proc/generic.c#L772>`__. + +Sample Protocol Implementations +------------------------------- + +For examples of protocol implementation, we recommend the implementation of `PF_PACKET <http://elixir.free-electrons.com/linux/v5.10/source/net/packet/af_packet.c>`__ sockets and the various functions in `UDP implementation <http://elixir.free-electrons.com/linux/v5.10/source/net/ipv4/udp.c>`__ or `IP implementation <http://elixir.free-electrons.com/linux/v5.10/source/net/ipv4/af_inet.c>`__. + +Testing +======= + +In order to simplify the assignment evaluation process, but also to reduce the mistakes of the submitted assignments, +the assignment evaluation will be done automatically with the help of a +`test script <https://gitlab.cs.pub.ro/so2/3-raid/-/blob/master/checker/4-stp-checker/_checker>`__ called `_checker`. +The test script assumes that the kernel module is called `af_stp.ko`. + +tcpdump +------- + +You can use the ``tcpdump`` utility to troubleshoot sent packets. +The tests use the loopback interface; to track sent packets you can use a command line of the form: + +.. code:: console + + tcpdump -i lo -XX + +You can use a static version of `tcpdump <http://elf.cs.pub.ro/so2/res/teme/tcpdump>`__. +To add to the ``PATH`` environment variable in the virtual machine, copy this file to ``/linux/tools/labs/rootfs/bin``. +Create the directory if it does not exist. Remember to give the ``tcpdump`` file execution permissions: + +.. code:: console + + # Connect to the docker using ./local.sh docker interactive + cd /linux/tools/labs/rootfs/bin + wget http://elf.cs.pub.ro/so2/res/teme/tcpdump + chmod +x tcpdump + +QuickStart +========== + +It is mandatory to start the implementation of the assignment from the code skeleton found in the `src <https://gitlab.cs.pub.ro/so2/4-stp/-/tree/master/src>`__ directory. +There is only one header in the skeleton called `stp.h <https://gitlab.cs.pub.ro/so2/4-stp/-/blob/master/src/stp.h>`__. +You will provide the rest of the implementation. You can add as many `*.c`` sources and additional `*.h`` headers. +You should also provide a Kbuild file that will compile the kernel module called `af_stp.ko`. +Follow the instructions in the `README.md file <https://gitlab.cs.pub.ro/so2/4-stp/-/blob/master/README.md>`__ of the `assignment's repo <https://gitlab.cs.pub.ro/so2/4-stp>`__. + + + +Tips +---- + +To increase your chances of getting the highest grade, read and follow the Linux kernel coding style described in the `Coding Style document <https://elixir.bootlin.com/linux/v5.10/source/Documentation/process/coding-style.rst>`__. + +Also, use the following static analysis tools to verify the code: + +* checkpatch.pl + + .. code-block:: console + + $ linux/scripts/checkpatch.pl --no-tree --terse -f /path/to/your/file.c + +* sparse + + .. code-block:: console + + $ sudo apt-get install sparse + $ cd linux + $ make C=2 /path/to/your/file.c + +* cppcheck + + .. code-block:: console + + $ sudo apt-get install cppcheck + $ cppcheck /path/to/your/file.c + +Penalties +--------- + +Information about assigments penalties can be found on the `General Directions page <https://ocw.cs.pub.ro/courses/so2/teme/general>`__. + +In exceptional cases (the assigment passes the tests by not complying with the requirements) and if the assigment does not pass all the tests, the grade will may decrease more than mentioned above. + +Submitting the assigment +------------------------ + +The assignment will be graded automatically using the `vmchecker-next <https://github.com/systems-cs-pub-ro/vmchecker-next/wiki/Student-Handbook>`__ infrastructure. +The submission will be made on moodle on the `course's page <https://curs.upb.ro/2022/course/view.php?id=5121>`__ to the related assignment. +You will find the submission details in the `README.md file <https://gitlab.cs.pub.ro/so2/4-stp/-/blob/master/README.md>`__ of the `repo <https://gitlab.cs.pub.ro/so2/4-stp>`__. + + +Resources +========= + +* `Lecture 10 - Networking <https://linux-kernel-labs.github.io/refs/heads/master/so2/lec10-networking.html>`__ +* `Lab 10 - Networking <https://linux-kernel-labs.github.io/refs/heads/master/so2/lab10-networking.html>`__ +* Linux kernel sources + + * `Implementing PF_PACKET sockets <http://elixir.free-electrons.com/linux/v5.10/source/net/packet/af_packet.c>`__ + * `Implementation of the UDP protocol <http://elixir.free-electrons.com/linux/v5.10/source/net/ipv4/udp.c>`__ + * `Implementation of the IP protocol <http://elixir.free-electrons.com/linux/v5.10/source/net/ipv4/af_inet.c>`__ + +* Understanding Linux Network Internals + + * chapters 8-13 + +* `assignment support header <https://gitlab.cs.pub.ro/so2/4-stp/-/blob/master/src/stp.h>`__ + +We recommend that you use gitlab to store your homework. Follow the directions in `README <https://gitlab.cs.pub.ro/so2/4-stp/-/blob/master/README.md>`__. + +Questions +========= + +For questions about the topic, you can consult the mailing `list archives <http://cursuri.cs.pub.ro/pipermail/so2/>`__ +or you can write a question on the dedicated Teams channel. + +Before you ask a question, make sure that: + + - you have read the statement of the assigment well + - the question is not already presented on the `FAQ page <https://ocw.cs.pub.ro/courses/so2/teme/tema2/faq>`__ + - the answer cannot be found in the `mailing list archives <http://cursuri.cs.pub.ro/pipermail/so2/>`__ + diff --git a/refs/pull/405/merge/_sources/so2/assign5-pitix.rst.txt b/refs/pull/405/merge/_sources/so2/assign5-pitix.rst.txt new file mode 100644 index 00000000..ef61918b --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/assign5-pitix.rst.txt @@ -0,0 +1,231 @@ +=================================== +Assignment 5 - PITIX Filesystem +=================================== + +Deadline: :command:`Tuesday, 24 May 2022, 23:00` + +Statement +========= + +Write a kernel module to implement the **PITIX** file system, version 2. +This file system will only support files and directories. +Support operations for hard or symbolic links will not be implemented. +Also, support operations for special files (pipes, character devices, or blocks) will not be implemented. +Basically you need to implement the following: + * for directories: ``lookup``, ``unlink``, ``mkdir``, ``rmdir``, ``iterate`` + * for files: ``create``, ``truncate``, bitmap functions, see `minix_get_block <https://elixir.bootlin.com/linux/v4.15/source/fs/minix/inode.c#L375>`__. + +The rest of the functions either have generic kernel implementations, or you don't have to implement them. + +The disk structure of the file system is: + +.. code-block:: console + + +--------------+-----------+-----------+------------+-----------------------+ + | | | | | | + | superblock | imap | dmap | izone | dzone | + +--------------+-----------+-----------+------------+-----------------------+ + 4096 bytes 1 block 1 block 32 blocks 8*block_size blocks + + +where: + +* ``Superblock`` is the superblock (``4096`` bytes) +* ``Imap`` contains the bitmap of the blocks occupied by the inodes (``1`` block) +* ``Dmap`` contains the bitmap of the blocks occupied by the data (``1`` block) +* ``Izone`` contains inodes (``32`` blocks) +* ``Dzone`` contains the data (the actual contents of the files) (``8 * block_size`` blocks) + +The superblock (**on disk**) is described by the following structure: + +.. code-block:: c + + struct pitix_super_block { + unsigned long magic; + __u8 version; + __u8 block_size_bits; + __u8 imap_block; + __u8 dmap_block; + __u8 izone_block; + __u8 dzone_block; + __u16 bfree; + __u16 ffree; + }; + +where: + +* ``magic`` must be initialized with ``PITIX_MAGIC`` +* ``version`` must be initialized with ``2`` (``PITIX_VERSION``) +* ``block_size_bits`` is the block size of two; the block size can be ``512``, ``1024``, ``2048``, or ``4096`` +* ``Imap_block`` is the block number (relative to the device) to the bit vector used for the allocation / release sites inode +* ``dmap_block`` is the block number (relative to the device) for the bit vector used to allocate / release data blocks +* ``izone_block`` is the number of the first block (relative to the device) of the inode area +* ``dzone_block`` is the number of the first block (relative to the device) of the data area +* ``bfree`` is the number of free blocks (unallocated) +* ``ffree`` is the number of free (unallocated) inodes + +The inodes will be stored in the inode area and are described by the following structure: + +.. code-block:: c + + struct pitix_inode { + __u32 mode; + uid_t uid; + gid_t gid; + __u32 size; + __u32 time; + __u16 direct_data_blocks [INODE_DIRECT_DATA_BLOCKS]; + __u16 indirect_data_block; + }; + +where: + +* ``mode`` represents the access rights and inode type (file or directory) as represented in the kernel +* ``uid`` represents the UID as it is represented in the kernel +* ``gid`` represents the GID as it is represented in the kernel +* ``size`` is the size of the file / directory +* ``time`` represents the modification time as it is represented in the kernel +* ``direct_data_blocks`` is a vector (size ``INODE_DIRECT_DATA_BLOCKS`` ) that contains indexes of direct data blocks +* ``indirect_data_block`` is the index of a data block that contains the indexes of indirect data blocks + +The index of a data block (direct or indirect) indicates the number of that data block relative to the data area (``Dzone``). +The size of an index is ``2`` bytes. + +As can be seen from its structure, the inode uses a simple routing scheme for data blocks. +Blocks in the range ``[0, INODE_DIRECT_DATA_BLOCKS)`` are blocks of direct data and are referenced by elements of the vector ``direct_data_blocks`` and blocks in the range ``[INODE_DIRECT_DATA_BLOCKS, INODE_DIRECT_DATA_BL)`` are indirect data blocks and are referred to by indices within the data block indicated by ``indirect_data_block``. + +The data block indicated by ``indirect_data_block`` must be allocated when we have to refer to a first block of indirect data and must be released when there are no more blocks of indirect data. + +Unused indexes must be set to ``0``. +The first block, the one with index ``0``, is always allocated when formatting. This block cannot be used and, consequently, the value ``0``: + +* in an element of the vector, ``direct_data_blocks`` means free slot (that element does not refer to a block of data directly) +* ``indirect_data_block`` means that no data block is allocated to keep track of indirect data blocks (when no indirect data blocks are needed) +* an index within the data block referred to as ``indirect_data_block`` means free slot (that index does not refer to an indirect data block) + +It is guaranteed that the number of bytes occupied by an inode on the disk is a divisor of the block size. + +Directories have associated a single block of data (referred to as ``direct_data_block [0]``) in which directory entries will be stored. These are described by the following structure: + +.. code-block:: c + + struct pitix_dir_entry { + __u32 ino; + char name [PITIX_NAME_LEN]; + }; + +where + +* ``inoi`` is the inode number of the file or directory; this number is an index in the inode area +* ``name`` is the name of the file or directory; maximum name length is ``16`` bytes (``PITIX_NAME_LEN``); if the name length is less than 16 bytes, then the name will end with the ASCII character that has the code ``0`` (same as for strings) + +The root directory will be assigned inode ``0`` and data block ``0``. + +For simplicity, at ``mkdir`` it is not necessary to create the entries ``.`` (*dot*) and ``..`` (*dot dot*) in the new directory; the checker uses this assumption. + +All numeric values are stored on disk in byte-order CPU. + +In the `assignment header <https://github.com/linux-kernel-labs/linux/blob/master/tools/labs/templates/assignments/5-pitix/pitix.h`__ you will find the structures described above together with useful macros and statements of the main functions to be implemented. + +The kernel module will be named ``pitix.ko``. + +Testing +======= + +.. note:: + + Enable ``Loop Devices`` support using ``make menuconfig``. ``Device drivers -> Block devices -> Loopback device support`` + +In order to simplify the assignment evaluation process, but also to reduce the mistakes of the submitted assignments, the assignment evaluation will be done automatically with with the help of public tests that are in the new infrastructure. + +For local testing, use the following commands: + +.. code-block:: console + + $ git clone https://github.com/linux-kernel-labs/linux.git + $ cd linux/tools/labs + $ LABS=assignments/5-pitix make skels + $ #the development of the assignment will be written in the 5-pitix directory + $ make build + $ make copy + $ make boot + +Instructions for using the test suite can be found in the ``README`` file. + +Tips +---- + +To increase your chances of getting the highest grade, read and follow the Linux kernel coding style described in the `Coding Style document <https://elixir.bootlin.com/linux/v4.19.19/source/Documentation/process/coding-style.rst>`__. + +Also, use the following static analysis tools to verify the code: + +- checkpatch.pl + +.. code-block:: console + + $ linux/scripts/checkpatch.pl --no-tree --terse -f /path/to/your/file.c + +- sparse + +.. code-block:: console + + $ sudo apt-get install sparse + $ cd linux + $ make C=2 /path/to/your/file.c + +- cppcheck + +.. code-block:: console + + $ sudo apt-get install cppcheck + $ cppcheck /path/to/your/file.c + +Penalties +--------- + +As a more difficult assignment, it is worth 2 points. + +Information about assigments penalties can be found on the +`General Directions page <https://ocw.cs.pub.ro/courses/so2/teme/general>`__. + +In exceptional cases (the assigment passes the tests by not complying with the requirements) +and if the assigment does not pass all the tests, the grade will may decrease more than mentioned above. + +Submitting the assigment +------------------------ + +The assignment archive will be submitted to vmchecker, according to the rules on the +`rules page <https://ocw.cs.pub.ro/courses/so2/reguli-notare#reguli_de_trimitere_a_temelor>`__. + +In the vmchecker interface choose the ``Google Challenge - Sistem de fișiere`` option for this assignment. + +Resources +========= + +* `assignment header <https://github.com/linux-kernel-labs/linux/blob/master/tools/labs/templates/assignments/5-pitix/pitix.h>`__ +* `Lab 08: File system drivers (Part 1) <https://linux-kernel-labs.github.io/refs/heads/master/so2/lab8-filesystems-part1.html>`__ +* `Lab 09: File system drivers (Part 2) <https://linux-kernel-labs.github.io/refs/heads/master/so2/lab9-filesystems-part2.html>`__ +* `Minix filesystem source code <https://elixir.bootlin.com/linux/v4.15/source/fs/minix>`__ + +We recommend that you use GitLab to store your homework. Follow the directions in +`README <https://github.com/systems-cs-pub-ro/so2-assignments/blob/master/README.md>`__ +and on the dedicated `Git wiki page <https://ocw.cs.pub.ro/courses/so2/teme/folosire-gitlab>`__. + +The resources for the assignment can also be found in the `so2-assignments <https://github.com/systems-cs-pub-ro/so2-assignments>`__ repo on GitHub. +The repo contains a `Bash script <https://github.com/systems-cs-pub-ro/so2-assignments/blob/master/so2-create-repo.sh>`__ +that helps you create a private repository on the faculty `GitLab <https://gitlab.cs.pub.ro/users/sign_in>`__ instance. +Follow the tips from the `README <https://github.com/systems-cs-pub-ro/so2-assignments/blob/master/README.md>`__ and +on the dedicated `Wiki page <https://ocw.cs.pub.ro/courses/so2/teme/folosire-gitlab>`__. + +Questions +========= + +For questions about the assigment, you can consult the mailing `list archives <http://cursuri.cs.pub.ro/pipermail/so2/>`__ +or send an e-mail (you must be `registered <http://cursuri.cs.pub.ro/cgi-bin/mailman/listinfo/so2>`__). +Please follow and follow `the tips for use of the list <https://ocw.cs.pub.ro/courses/so2/resurse/lista-discutii#mailing-list-guidelines>`__. + +Before you ask a question, make sure that: + +* you have read the statement of the assigment well +* the question is not already presented on the `FAQ page <https://ocw.cs.pub.ro/courses/so2/teme/tema2/faq>`__ +* the answer cannot be found in the `mailing list archives <http://cursuri.cs.pub.ro/pipermail/so2/>`__ diff --git a/refs/pull/405/merge/_sources/so2/assign7-kvm-vmm.rst.txt b/refs/pull/405/merge/_sources/so2/assign7-kvm-vmm.rst.txt new file mode 100644 index 00000000..3eb0b20c --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/assign7-kvm-vmm.rst.txt @@ -0,0 +1,295 @@ +===================================================== +Assignment 7 - SO2 Virtual Machine Manager with KVM +===================================================== + +- Deadline: :command:`Tuesday, 29 May 2023, 23:00` +- This assignment can be made in teams (max 2). Only one of them must submit the assignment, and the names of the student should be listed in a README file. + +In this assignment we will work on a simple Virtual Machine Manager (VMM). We will be using the KVM API +from the Linux kernel. + +The assignment has two components: the VM code and the VMM code. We will be using a very simple protocol +to enable the communication between the two components. The protocol is called SIMVIRTIO. + + +I. Virtual Machine Manager +========================== + +In general, to build a VMM from scratch we will have to implement three main functionalities: initialize the VMM, initialize the virtual CPU and run the guest code. We will split the implementation of the VMM in these three phases. + +1. Initialize the VMM +------------------------- + +A VM will be represented in general by three elements, a file descriptor used to interact with the KVM API, a file descriptor per VM used to configure it (e.g. set its memory) and a pointer to the VM's memory. We provide you with the following structure to start from when working with a VM. + +.. code-block:: c + + typedef struct vm { + int sys_fd; + int fd; + char *mem; + } virtual_machine; + + +The first step in initializing the KVM VM is to interract with the [KVM_API](https://www.kernel.org/doc/html/latest/virt/kvm/api.html]. The KVM API is exposed via ``/dev/kvm``. We will be using ioctl calls to call the API. + +The snippet below shows how one can call ``KVM_GET_API_VERSION`` to get the KVM API Version + +.. code-block:: c + + int kvm_fd = open("/dev/kvm", O_RDWR); + if (kvm_fd < 0) { + perror("open /dev/kvm"); + exit(1); + } + + int api_ver = ioctl(kvm_fd, KVM_GET_API_VERSION, 0); + if (api_ver < 0) { + perror("KVM_GET_API_VERSION"); + exit(1); + } + +Let us now go briefly through how a VMM initializes a VM. This is only the bare bones, a VMM may do lots of other things during VM initialization. + +1. We first use KVM_GET_API_VERSION to check that we are running the expected version of KVM, ``KVM_API_VERSION``. +2. We now create the VM using ``KVM_CREATE_VM``. Note that calling ``KVM_CREATE_VM`` returns a file descriptor. We will be using this file descriptor for the next phases of the setup. +3. (Optional) On Intel based CPUs we will have to call ``KVM_SET_TSS_ADDR`` with address ``0xfffbd000`` +4. Next, we allocate the memory for the VM, we will be using ``mmap`` for this with ``PROT_WRITE``, ``MAP_PRIVATE``, ``MAP_ANONYMOUS`` and ``MAP_NORESERVE``. We recommend allocating 0x100000 bytes for the VM. +5. We flag the memory as ``MADV_MERGEABLE`` using ``madvise`` +6. Finally, we use ``KVM_SET_USER_MEMORY_REGION`` to assign the memory to the VM. + +**Make sure you understand what file descriptor to use and when, we use the KVM fd when calling KVM_CREATE_VM, but when interacting with the vm such as calling KVM_SET_USER_MEMORY_REGION we use the VMs +file descriptor** + +TLDR: API used for VM initialization: + +* KVM_GET_API_VERSION +* KVM_CREATE_VM +* KVM_SET_TSS_ADDR +* KVM_SET_USER_MEMORY_REGION. + +2. Initialize a virtual CPU +___________________________ + +We need a Virtual CPU (VCPU) to store registers. + +.. code-block:: c + + typedef struct vcpu { + int fd; + struct kvm_run *kvm_run; + } virtual_cpu; + +To create a virtual CPU we will do the following: +1. Call ``KVM_CREATE_VCPU`` to create the virtual CPU. This call returns a file descriptor. +2. Use ``KVM_GET_VCPU_MMAP_SIZE`` to get the size of the shared memory +3. Allocated the necessary VCPU mem size with ``mmap``. We will be passing the VCPU file descriptor to the ``mmap`` call. We can store the result in ``kvm_run``. + + +TLDR: API used for VM + +* KVM_CREATE_VCPU +* KVM_GET_VCPU_MMAP_SIZE + +**We recommend using 2MB pages to simplify the translation process** + +Running the VM +============== + + +Setup real mode +--------------- + +At first, the CPU will start in Protected mode. To do run any meaningful code, we will switch the CPU to [Real mode](https://wiki.osdev.org/Real_Mode). To do this we will +need to configure several CPU registers. + +1. First, we will use ``KVM_GET_SREGS`` to get the registers. We use ``struct kvm_regs`` for this task. +2. We will need to set ``cs.selector`` and ``cs.base`` to 0. We will use ``KVM_SET_SREGS`` to set the registers. +3. Next we will clear all ``FLAGS`` bits via the ``rflags`` register, this means setting ``rflags`` to 2 since bit 1 must always be to 1. We alo set the ``RIP`` register to 0. + +Setup long mode +--------------- + +Read mode is all right for very simple guests, such as the one found in the folder `guest_16_bits`. But, +most programs nowdays need 64 bits addresses, and such we will need to switch to long mode. The following article from OSDev presents all the necessary information about [Setting Up Long Mode](https://wiki.osdev.org/Setting_Up_Long_Mode). + +In ``vcpu.h``, you may found helpful macros such as CR0_PE, CR0_MP, CR0_ET, etc. + +Since we will running a more complex program, we will also create a small stack for our program +``regs.rsp = 1 << 20;``. Don't forget to set the RIP and RFLAGS registers. + +Running +------- + +After we setup our VCPU in real or long mode we can finally start running code on the VM. + +1. We copy to the vm memory the guest code, `memcpy(vm->mem, guest_code, guest_code_size)` The guest code will be available in two variables which will be discussed below. +2. In a infinite loop we run the following: + * We call ``KVM_RUN`` on the VCPU file descriptor to run the VPCU + * Through the shared memory of the VCPU we check the ``exit_reason`` parameter to see if the guest has made any requests: + * We will handle the following VMEXITs: `KVM_EXIT_MMIO`, `KVM_EXIT_IO` and ``KVM_EXIT_HLT``. ``KVM_EXIT_MMIO`` is triggered when the VM writes to a MMIO address. ``KVM_EXIT_IO`` is called when the VM calls ``inb`` or ``outb``. ``KVM_EXIT_HLT`` is called when the user does a ``hlt`` instruction. + +Guest code +---------- + +The VM that is running is also called guest. We will be using the guest to test our implementation. + +1. To test the implementation before implementing SIMVIRTIO. The guest will write at address 400 and the RAX register the value 42. +2. To test a more complicated implementation,we will extend the previous program to also write "Hello, world!\n" on port `0xE9` using the `outb` instruction. +3. To test the implementation of `SIMVIRTIO`, we will + +How do we get the guest code? The guest code is available at the following static pointers guest16, guest16_end-guest16. The linker script is populating them. + + +## SIMVIRTIO: +From the communication between the guest and the VMM we will implement a very simple protocol called ``SIMVIRTIO``. It's a simplified version of the real protocol used in the real world called virtio. + +Configuration space: + ++--------------+----------------+----------------+----------------+------------------+-------------+-------------+ +| u32 | u16 | u8 | u8 | u8 | u8 | u8 | ++==============+================+================+================+==================+=============+=============+ +| magic value | max queue len | device status | driver status | queue selector | Q0(TX) CTL | Q1(RX) CTL | +| R | R | R | R/W | R/W | R/W | R/w | ++--------------+----------------+----------------+----------------+------------------+-------------+-------------+ + + +Controller queues +----------------- + +We provide you with the following structures and methods for the ``SIMVIRTIO`` implementation. + +.. code-block:: c + + typedef uint8_t q_elem_t; + typedef struct queue_control { + // Ptr to current available head/producer index in 'buffer'. + unsigned head; + // Ptr to last index in 'buffer' used by consumer. + unsigned tail; + } queue_control_t; + typedef struct simqueue { + // MMIO queue control. + volatile queue_control_t *q_ctrl; + // Size of the queue buffer/data. + unsigned maxlen; + // Queue data buffer. + q_elem_t *buffer; + } simqueue_t; + int circ_bbuf_push(simqueue_t *q, q_elem_t data) + { + } + int circ_bbuf_pop(simqueue_t *q, q_elem_t *data) + { + } + + +Device structures +----------------- + +.. code-block:: c + + #define MAGIC_VALUE 0x74726976 + #define DEVICE_RESET 0x0 + #define DEVICE_CONFIG 0x2 + #define DEVICE_READY 0x4 + #define DRIVER_ACK 0x0 + #define DRIVER 0x2 + #define DRIVER_OK 0x4 + #define DRIVER_RESET 0x8000 + typedef struct device { + uint32_t magic; + uint8_t device_status; + uint8_t driver_status; + uint8_t max_queue_len; + } device_t; + typedef struct device_table { + uint16_t count; + uint64_t device_addresses[10]; + } device_table_t; + + +We will be implementing the following handles: +* MMIO (read/write) VMEXIT +* PIO (read/write) VMEXIT + +Using the skeleton +================== + +Debugging +========= + + +Tasks +===== +1. 30p Implement a simple VMM that runs the code from `guest_16_bits`. We will be running the VCPU in read mode for this task +2. 20p Extend the previous implementation to run the VCPU in real mode. We will be running the `guest_32_bits` example +3. 30p Implement the `SIMVIRTIO` protocol. +4. 10p Implement pooling as opposed to VMEXIT. We will use the macro `USE_POOLING` to switch this option on and off. +5. 10p Add profiling code. Measure the number of VMEXITs triggered by the VMM. + +Submitting the assigment +------------------------ + +The assignment archive will be submitted on **Moodle**, according to the rules on the `rules page <https://ocw.cs.pub.ro/courses/so2/reguli-notare#reguli_de_trimitere_a_temelor>`__. + + +Tips +---- + +To increase your chances of getting the highest grade, read and follow the Linux kernel coding style described in the `Coding Style document <https://elixir.bootlin.com/linux/v4.19.19/source/Documentation/process/coding-style.rst>`__. + +Also, use the following static analysis tools to verify the code: + +* checkpatch.pl + + .. code-block:: console + + $ linux/scripts/checkpatch.pl --no-tree --terse -f /path/to/your/file.c + +* sparse + + .. code-block:: console + + $ sudo apt-get install sparse + $ cd linux + $ make C=2 /path/to/your/file.c + +* cppcheck + + .. code-block:: console + + $ sudo apt-get install cppcheck + $ cppcheck /path/to/your/file.c + +Penalties +--------- + +Information about assigments penalties can be found on the `General Directions page <https://ocw.cs.pub.ro/courses/so2/teme/general>`__. + +In exceptional cases (the assigment passes the tests by not complying with the requirements) and if the assigment does not pass all the tests, the grade will may decrease more than mentioned above. + +## References +We recommend you the following readings before starting to work on the homework: +* [KVM host in a few lines of code](https://zserge.com/posts/kvm/) + + +TLDR +---- + +1. The VMM creates and initializes a virtual machine and a virtual CPU +2. We switch to real mode and check run the simple guest code from `guest_16_bits` +3. We switch to long mode and run the more complex guest from `guest_32_bits` +4. We implement the SIMVIRTIO protocol. We will describe how it behaves in the following subtasks. +5. The guest writes in the TX queue (queue 0) the ascii code for `R` which will result in a `VMEXIT` +6. the VMM will handle the VMEXIT caused by the previous write in the queue. When the guests receiver the +`R` letter it will initiate the reser procedure of the device and set the device status to `DEVICE_RESET` +7. After the reset handling, the guest must set the status of the device to `DRIVER_ACK`. After this, the guest will write to the TX queue the letter `C` +8. In the VMM we will initialize the config process when letter `C` is received.It will set the device status to `DEVICE_CONFIG` and add a new entry in the device_table +9. After the configuration process is finished, the guest will set the driver status to `DRIVER_OK` +10. Nex, the VMM will set the device status to `DEVICE_READY` +11. The guest will write in the TX queue "Ana are mere" and will execute a halt +12. The VMM will print to the STDOUT the message received and execute the halt request +13. Finally, the VMM will verify that at address 0x400 and in register RAX is stored the value 42 + + diff --git a/refs/pull/405/merge/_sources/so2/grading.rst.txt b/refs/pull/405/merge/_sources/so2/grading.rst.txt new file mode 100644 index 00000000..ab728e12 --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/grading.rst.txt @@ -0,0 +1,207 @@ +=============================== +SO2 - General Rules and Grading +=============================== + +General Rules +============= + +1. Laboratory +------------- +There is no formal rule for dividing students; everyone can participate in any laboratory as long as the following rules are respected. +Priority for participation is given to students from the respective group (34xC3 or optional). +The limit of students in a laboratory is 14 people. +Starting from the third week, the participation list in the laboratory is "frozen". +Students who have a retake can participate in any laboratory as long as there are available spots. +Like other students, the participation list is "frozen" starting from the third week. +The division is done on the laboratory hours division page. +You can make up for a maximum of 2 laboratories (you can attend another subgroup) (in those laboratories where there are available spots). +Laboratories cannot be made up retroactively. You cannot make up a laboratory from the previous week within the same laboratory week. +Laboratory activities take place only in the laboratory room. +We encourage you to go through the brief and laboratory exercises at home. +You can solve exercises at home, but you will have to start from scratch in the laboratory. + +2. Final deadline for submitting assignments +-------------------------------------------- +The final deadline for submitting SO2 assignments is **Wednesday, May 29, 2024, 23:59.**. +Beyond this date, assignments cannot be submitted anymore. +Please ensure timely submission of assignments with complete information to be graded. +We will not accept assignments submitted after this date or assignments not submitted on vmchecker-next. +For the testing part, assignments will receive the score indicated from testing on vmchecker-next; tests failed due to reasons unrelated to vmchecker-next will not be graded. +Assignments cannot be submitted for the special June 2023 exam session. +Assignments can be resubmitted after TODO for the September 2024 exam session. +The deadline for submitting assignments for the Fall 2024 session is TODO. + +3. Assignment Presentations +--------------------------- +The SO2 team reserves the right to request presentations for some homework assignments. +A presentation involves a discussion with at least two assistants about the completion of the assignment, the solution used, and any encountered issues. +The purpose of the assignment presentation sessions is to clarify any uncertainties regarding the completion of the assignment and to verify its correctness. +Individuals who will present an assignment will be contacted at least 24 hours in advance by the laboratory assistant. +Most likely, a 15-minute slot before/after the SO2 class or at the end of the SO2 laboratory session will be used. + +4. Rules on Assignments +------------------------ +The assignments for Operating Systems 2 are individual, except when explicitly stated that an assignment can be solved in a team. +This is because the primary objective of the assignments is for you to acquire or deepen your practical skills. +If the level of collaboration is too high or if you seek solutions online, this objective will not be achieved. +Each assignment is to be completed by a student without consulting the source code of their peers. + +We understand that teamwork is important, but we do not have the environment to carry out team projects in the Operating Systems 2 course. +If you encounter any problems in completing an assignment, use the discussion list or ask the laboratory assistants or course instructors. +Our role is to help you solve them. +Feel free to rely on the SO2 team. + +You can discuss among yourselves within the bounds of common sense; that is, you should not dictate a solution to someone, but you can offer a general idea. +If you are the one being asked and providing explanations, please consider redirecting to the discussion list and the SO2 team. +It is not allowed to request the solution to an assignment on a site like StackExchange, Rent a Coder, ChatGPT etc. +You can ask more generic questions, but do not request the solution to the assignment. + +You can freely use code from the laboratory, skeletons provided by us. +You can use external resources (GitHub, open-source code, or others) as long as they do not represent obvious solutions to the assignments, publicly available with or without intention. +See also the next paragraph. + +It is not allowed to publish assignment solutions (even after the end of the course). +If you find assignment solutions on GitHub or elsewhere, report them to the discussion list or privately to the laboratory assistant or course instructor. +We reiterate that if you need clarification that you would address to older colleagues or other forums, StackExchange, or other sources, use the discussion list and the SO2 team. +It is the safest and most honest way to solve problems. + +It is not allowed to transfer files between yourselves. +In general, we recommend not to screen-share with another colleague, whether for inspiration or to help them with their assignment. +Avoid testing an assignment on a colleague's system. +There may be exceptions; you can help someone troubleshoot, but please ensure that it does not transition from "let's solve this problem together" to "let me solve your assignment for you". +However, we recommend using the discussion list or the SO2 team to ask questions. + +5. Penalties for Plagiarized Assignments +----------------------------------- + +In general, we consider punitive measures as a last resort. +As long as the assignment is completed individually, without problematic source code contribution from external sources, then it is not a plagiarized assignment. + +The notion of a plagiarized assignment refers to, without limitation, situations such as: + + * Two assignments that are similar enough to draw this conclusion; + * Using source code from the internet that is an obvious solution to the assignment; + * Using pieces of code from another colleague; + * Accessing another colleague's code during the assignment; + * Modifying an existing assignment; + * Following another colleague's code; + * Direct assistance in completing the assignment (someone else wrote or dictated the code); + * Someone else wrote the assignment (voluntarily, for payment, or other benefits). + * If two assignments are considered plagiarized, both the source and destination will be penalized equally, without discussions about who plagiarized from whom and whose fault it is. + +.. warning:: + + Plagiarizing an assignment results in the elimination of points for the assignments completed up to that session. + Any assignment submitted until that session receives a score of 0 and cannot be resubmitted during the current academic year. + If there were instances of plagiarized assignments during the semester, it will be possible to obtain points in the summer, for the September session, from assignments **not yet** submitted. + We reiterate that our goal is not and will not be penalization for plagiarism. + We consider cheating to be dishonest behavior that will be punished if it occurs. + However, our goal is to prevent cheating; for this purpose, we offer support and resources from the team in all its forms (discussion list, face-to-face discussions with the SO2 team). + Please use them with confidence; we believe that an honest approach to completing assignments will also result in a gain of knowledge and skills for you. + +6. Retake/Grade Increase +------------------------- + +In the retake/grade increase session in September, only assignments can be submitted, only the final exam can be retaken, or both. +You can continue to submit assignments with the deadlines from the semester, meaning you can achieve a maximum grade of 7 for each assignment. +Assignments are submitted using the vmchecker-next interface. +If you did not have plagiarized assignments during the semester, you can (re)submit any assignments. +If there were instances of plagiarized assignments during the semester, you can submit only assignments not yet submitted during the semester. +The submission deadline is TODO + +If you do not wish to retake the final exam, you can choose not to participate in the exam. +Grades will be recorded in the official catalog, according to the SO2 catalog. + +In the special retake/grade increase session in June, only the final exam can be retaken, and no homework assignments can be submitted. + +The exam in the retake session will consist of 11 equally weighted topics (for a total of 3 points - one topic is a bonus). Passing the exam is conditional on obtaining 1 point out of the 3 points assigned to the course. In practice, this means correctly solving 3 out of the 11 topics in the exam. + +In the case of retaking the final exam, the higher grade will be retained (between the semester grade and the grade from the retake session). + +You can participate in only one exam during a session. + +7. Class Redo +------------------- + +If you prefer, you can keep the score from the previous academic year for the entire semester's activity (labs, assignments, course work), and only retake the final exam. +You cannot keep the score for individual components of the semester (only assignments or only course work). + +If you want to keep the score from the previous academic year for the entire semester's activity, you must announce this at the begining of the semester. +Otherwise, the score from the previous academic year's semester will be reset according to the default mode. + +By default, the score for the academic year will be reset on October 1. +If you do not graduate from the course during the current academic year, you will need to retake it completely during the next academic year. + +Grading +======= + +You must achieve at least 4.5 points out of 10 to pass. + +1. Lectures (3 points) +---------------------- +* Completion of the course is conditioned by obtaining 30% (3 out of 10) of the course score. +* The lecture score will be obtained from 11 lecture quizzes to be completed before each class (one quiz is a bonus). +* Each course assignment contains a set of 4 questions from the material covered in the previous class (one question is a bonus). + * There will be no final exam. + * Each question is scored with 0 or 1. + * A question is scored only if it is fully and correctly answered. + * A question answered incompletely or one answered completely but with incorrect specifications or errors will not be scored. + * Course assignments cannot be redone. + * Each assignment lasts 3 minutes. + * The score is obtained from the formula min(sum_of_assignment_scores / 10 * 4/3, 10). + * The assignments are closed book. +* For those who cannot attend the course assignments or wish to improve their course score, an assignment will be given at the end of the semester (during the last class) covering all the course material. + * The end-of-semester assignment (last class) consists of 11 questions for the 3 course points and lasts 60 minutes. + * The end-of-semester assignment is open-book. You are allowed to use class notes, books, slides, laptops, or tablets without internet access. + * Access with mobile phones is not permitted. Phones must be turned off/silent/deactivated during the exam. + * You may download course materials, labs, or other resources for offline use. + + +2. Laboratory (2 points) +------------------------ +* The laboratories are held in EG106, EG306, and PR706. +* Completion of the laboratory exercises leads to obtaining 10 or 11 points allocated for the laboratory. +* The final grade for the laboratory is calculated using the formula (sum(l1:l12) / 12). + + +3. Assignments (5 points + Extra) +--------------------------------- +* There are 4 Assignments: + * Assignment 0 - "Kernel API" - 0.5 points + * Assignment 1 - "Kprobe based tracer" - 1.5 points + * Assignment 2 - "Driver UART" 1.5 points + * Assignment 3 - "Software RAID" - 1.5 points +* Extra activities: + * SO2 transport protocol - 2 points + * SO2 Virtual Machine Manager with KVM - 2 points +* In case the total score for assignments + "Extra" activities exceeds 5 points, the following procedure will be followed: + * 5 points are considered as part of the total score. + * The difference between the total score and 5 points will be proportionally adjusted relative to the grade obtained in the lecture. + +.. code-block:: c + + S = A0 + A1 + A2 + A3 + Extra; + if (S <= 5) + assignment_grade = S; + else + assignment_grade = 5 + (S - 5) * course_grade / 3; // 0 <= course_grade <=3 + +* The verification and scoring of assignments: + * Assignments are tested against plagiarism. + * Assignments will be automatically verified using the `vmchecker-next <https://github.com/systems-cs-pub-ro/vmchecker-next/wiki/Student-Handbook>`__ infrastructure integrated with moodle. + * The verification tests are public. + * Students who upload their assignments on Moodle must wait for the checker's feedback in the feedback section of the assignment upload page. + * The grade listed in the feedback section will be the final grade for the assigment. + * There may be exceptional situations where this rule is not considered (for example, if the assignment is implemented solely to pass the tests and does not meet the assignment requirements). + * The verification system deducts points (automatically) for certain situations (segmentation faults, unhandled exceptions, compilation errors, or warnings) regardless of the test results. + * Deductions are specified in the instructions list and in the assignment statement. + * Deductions are subtracted from the assignment grade (maximum of 10) not from the assignment score. + +* Late assignments + * Each assignment has a deadline of 2 weeks from the publication date. (exception! Assignment 0) + * After the deadline, 0.25 points per day (out of 10, the maximum grade for each assignment) will be deducted for 12 days (up to a maximum grade of 7). + * The deduction is from the grade (maximum 10), not from the score. An assignment incurs deductions of 0.25 points per day from the maximum grade (10), regardless of its score. + * For example, if for assignment 3 (scored with 1.5 points) the delay is 4 days, you will receive a deduction of 4 * 0.25 = 1 point from the grade, resulting in a maximum grade of 9, equivalent to a maximum score of 1.35 points. + * After 12 days, no further deductions will be made; a maximum grade of 7 can be obtained for an assignment submitted 13 days after the deadline expiration, or 50 days, or more, including during the retake session. + + diff --git a/refs/pull/405/merge/_sources/so2/index.rst.txt b/refs/pull/405/merge/_sources/so2/index.rst.txt new file mode 100644 index 00000000..80188277 --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/index.rst.txt @@ -0,0 +1,57 @@ +=================== +Operating Systems 2 +=================== + +.. toctree:: + :caption: Good To Know + :maxdepth: 1 + + grading.rst + +.. toctree:: + :caption: Lectures + :maxdepth: 1 + + lec1-intro.rst + lec2-syscalls.rst + lec3-processes.rst + lec4-interrupts.rst + lec5-smp.rst + lec6-address-space.rst + lec7-memory-management.rst + lec8-filesystems.rst + lec9-debugging.rst + lec10-networking.rst + lec11-arch.rst + lec12-virtualization.rst + +.. toctree:: + :caption: Labs + :maxdepth: 1 + + lab1-intro.rst + lab2-kernel-api.rst + lab3-device-drivers.rst + lab4-interrupts.rst + lab5-deferred-work.rst + lab6-memory-mapping.rst + lab7-block-device-drivers.rst + lab8-filesystems-part1.rst + lab9-filesystems-part2.rst + lab10-networking.rst + lab11-arm-kernel-development.rst + lab12-kernel-profiling.rst + +.. toctree:: + :caption: Assignments + :maxdepth: 1 + + assign-collaboration.rst + assign0-kernel-api.rst + assign1-kprobe-based-tracer.rst + assign2-driver-uart.rst + assign3-software-raid.rst + assign4-transport-protocol.rst + .. uncoment next line for pitix to be available in Docs + .. assign5-pitix.rst + assign7-kvm-vmm.rst diff --git a/refs/pull/405/merge/_sources/so2/lab1-intro.rst.txt b/refs/pull/405/merge/_sources/so2/lab1-intro.rst.txt new file mode 100644 index 00000000..461148a9 --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lab1-intro.rst.txt @@ -0,0 +1,112 @@ +========================= +SO2 Lab 01 - Introduction +========================= + +Lab objectives +============== + +* presenting the rules and objectives of the Operating Systems 2 lab +* introducing the lab documentation +* introducing the Linux kernel and related resources +* creating simple modules +* describing the process of kernel module compilation +* presenting how a module can be used with a kernel +* simple kernel debugging methods + +.. include:: ../labs/introduction.rst + :start-after: [SECTION-ABOUT-BEGIN] + :end-before: [SECTION-ABOUT-END] + +.. include:: ../labs/introduction.rst + :start-after: [SECTION-REFERENCES-BEGIN] + :end-before: [SECTION-REFERENCES-END] + +.. include:: ../labs/introduction.rst + :start-after: [SECTION-DOCUMENTATION-BEGIN] + :end-before: [SECTION-DOCUMENTATION-END] + +.. include:: ../labs/kernel_modules.rst + :start-after: [SECTION-OVERVIEW-BEGIN] + :end-before: [SECTION-OVERVIEW-END] + +.. include:: ../labs/kernel_modules.rst + :start-after: [SECTION-MODULE-EXAMPLE-BEGIN] + :end-before: [SECTION-MODULE-EXAMPLE-END] + +.. include:: ../labs/kernel_modules.rst + :start-after: [SECTION-COMPILE-MODULES-BEGIN] + :end-before: [SECTION-COMPILE-MODULES-END] + +.. include:: ../labs/kernel_modules.rst + :start-after: [SECTION-LOAD-MODULES-BEGIN] + :end-before: [SECTION-LOAD-MODULES-END] + +.. include:: ../labs/kernel_modules.rst + :start-after: [SECTION-DEBUG-MODULES-BEGIN] + :end-before: [SECTION-DEBUG-MODULES-END] + +.. note:: + + If you want to learn how to easily browse through the Linux source code + and how to debug kernel code, read the `Good to know <#good-to-know>`__ + section. + +Exercises +========= + +.. include:: ../labs/introduction.rst + :start-after: [SECTION-EXERCISES-REMARKS-BEGIN] + :end-before: [SECTION-EXERCISES-REMARKS-END] + +.. _exercises_summary: + +.. include:: ../labs/exercises-summary.hrst +.. |LAB_NAME| replace:: kernel_modules + +.. .. include:: ../labs/introduction.rst +.. :start-after: [EXERCISE1-BEGIN] +.. :end-before: [EXERCISE1-END] + +.. include:: ../labs/kernel_modules.rst + :start-after: [EXERCISE1-BEGIN] + :end-before: [EXERCISE1-END] + +.. include:: ../labs/kernel_modules.rst + :start-after: [EXERCISE2-BEGIN] + :end-before: [EXERCISE2-END] + +.. include:: ../labs/kernel_modules.rst + :start-after: [EXERCISE3-BEGIN] + :end-before: [EXERCISE3-END] + +.. include:: ../labs/kernel_modules.rst + :start-after: [EXERCISE4-BEGIN] + :end-before: [EXERCISE4-END] + +.. include:: ../labs/kernel_modules.rst + :start-after: [EXERCISE5-BEGIN] + :end-before: [EXERCISE5-END] + +.. include:: ../labs/kernel_modules.rst + :start-after: [EXERCISE6-BEGIN] + :end-before: [EXERCISE6-END] + +.. include:: ../labs/kernel_modules.rst + :start-after: [EXERCISE7-BEGIN] + :end-before: [EXERCISE7-END] + +.. _good-to-know: + +Good to know +============ + +The following sections contain useful information for getitng used to the Linux +kernel code and debugging techniques. + +.. include:: ../labs/introduction.rst + :start-after: [SECTION-CODE-NAVIGATION-BEGIN] + :end-before: [SECTION-CODE-NAVIGATION-END] + +.. include:: ../labs/introduction.rst + :start-after: [SECTION-DEBUGGING-BEGIN] + :end-before: [SECTION-DEBUGGING-END] diff --git a/refs/pull/405/merge/_sources/so2/lab10-networking.rst.txt b/refs/pull/405/merge/_sources/so2/lab10-networking.rst.txt new file mode 100644 index 00000000..0f9675cb --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lab10-networking.rst.txt @@ -0,0 +1,6 @@ +======================= +SO2 Lab 10 - Networking +======================= + +.. include:: ../labs/networking.rst + :start-line: 4 diff --git a/refs/pull/405/merge/_sources/so2/lab11-arm-kernel-development.rst.txt b/refs/pull/405/merge/_sources/so2/lab11-arm-kernel-development.rst.txt new file mode 100644 index 00000000..6f59f8cc --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lab11-arm-kernel-development.rst.txt @@ -0,0 +1,6 @@ +====================================== +SO2 Lab 11 - Kernel Development on ARM +====================================== + +.. include:: ../labs/arm_kernel_development.rst + :start-line: 4 diff --git a/refs/pull/405/merge/_sources/so2/lab12-kernel-profiling.rst.txt b/refs/pull/405/merge/_sources/so2/lab12-kernel-profiling.rst.txt new file mode 100644 index 00000000..ce8f1358 --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lab12-kernel-profiling.rst.txt @@ -0,0 +1,6 @@ +============================= +SO2 Lab 12 - Kernel Profiling +============================= + +.. include:: ../labs/kernel_profiling.rst + :start-line: 4 diff --git a/refs/pull/405/merge/_sources/so2/lab2-kernel-api.rst.txt b/refs/pull/405/merge/_sources/so2/lab2-kernel-api.rst.txt new file mode 100644 index 00000000..379601db --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lab2-kernel-api.rst.txt @@ -0,0 +1,6 @@ +======================= +SO2 Lab 02 - Kernel API +======================= + +.. include:: ../labs/kernel_api.rst + :start-line: 4 diff --git a/refs/pull/405/merge/_sources/so2/lab3-device-drivers.rst.txt b/refs/pull/405/merge/_sources/so2/lab3-device-drivers.rst.txt new file mode 100644 index 00000000..6a3c77b0 --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lab3-device-drivers.rst.txt @@ -0,0 +1,6 @@ +===================================== +SO2 Lab 03 - Character device drivers +===================================== + +.. include:: ../labs/device_drivers.rst + :start-line: 4 diff --git a/refs/pull/405/merge/_sources/so2/lab4-interrupts.rst.txt b/refs/pull/405/merge/_sources/so2/lab4-interrupts.rst.txt new file mode 100644 index 00000000..5375f6cc --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lab4-interrupts.rst.txt @@ -0,0 +1,6 @@ +====================================== +SO2 Lab 04 - I/O access and Interrupts +====================================== + +.. include:: ../labs/interrupts.rst + :start-line: 4 diff --git a/refs/pull/405/merge/_sources/so2/lab5-deferred-work.rst.txt b/refs/pull/405/merge/_sources/so2/lab5-deferred-work.rst.txt new file mode 100644 index 00000000..bf763d7f --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lab5-deferred-work.rst.txt @@ -0,0 +1,6 @@ +========================== +SO2 Lab 05 - Deferred work +========================== + +.. include:: ../labs/deferred_work.rst + :start-line: 4 diff --git a/refs/pull/405/merge/_sources/so2/lab6-memory-mapping.rst.txt b/refs/pull/405/merge/_sources/so2/lab6-memory-mapping.rst.txt new file mode 100644 index 00000000..53bc205e --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lab6-memory-mapping.rst.txt @@ -0,0 +1,6 @@ +=========================== +SO2 Lab 06 - Memory Mapping +=========================== + +.. include:: ../labs/memory_mapping.rst + :start-line: 4 diff --git a/refs/pull/405/merge/_sources/so2/lab7-block-device-drivers.rst.txt b/refs/pull/405/merge/_sources/so2/lab7-block-device-drivers.rst.txt new file mode 100644 index 00000000..2bbad421 --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lab7-block-device-drivers.rst.txt @@ -0,0 +1,6 @@ +================================= +SO2 Lab 07 - Block Device Drivers +================================= + +.. include:: ../labs/block_device_drivers.rst + :start-line: 4 diff --git a/refs/pull/405/merge/_sources/so2/lab8-filesystems-part1.rst.txt b/refs/pull/405/merge/_sources/so2/lab8-filesystems-part1.rst.txt new file mode 100644 index 00000000..d4d8516f --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lab8-filesystems-part1.rst.txt @@ -0,0 +1,19 @@ +========================================= +SO2 Lab 08 - File system drivers (Part 1) +========================================= + +.. include:: ../labs/filesystems_part1.rst + :start-line: 4 + :end-before: [SURVEY-LABEL] + +.. important:: + In order to have a better understanding of what we do well and we can do + better, what factors affect your implication in teaching, extracurricular + but also professional activities, we ask you to complete `this survey + <https://forms.office.com/r/SqBF2kfzk5>`_. The survey is a short one, + having answers with check marks, with an estimated completion time of + 3-5 minutes. Obviously, we will send you the analysis of the survey and + use it to improve the teaching activities. + +.. include:: ../labs/filesystems_part1.rst + :start-after: [SURVEY-LABEL] diff --git a/refs/pull/405/merge/_sources/so2/lab9-filesystems-part2.rst.txt b/refs/pull/405/merge/_sources/so2/lab9-filesystems-part2.rst.txt new file mode 100644 index 00000000..5ef61803 --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lab9-filesystems-part2.rst.txt @@ -0,0 +1,6 @@ +========================================= +SO2 Lab 09 - File system drivers (Part 2) +========================================= + +.. include:: ../labs/filesystems_part2.rst + :start-line: 4 diff --git a/refs/pull/405/merge/_sources/so2/lec1-intro.rst.txt b/refs/pull/405/merge/_sources/so2/lec1-intro.rst.txt new file mode 100644 index 00000000..2a011341 --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lec1-intro.rst.txt @@ -0,0 +1,260 @@ +============================================================== +SO2 Lecture 01 - Course overview and Linux kernel introduction +============================================================== + +`View slides <lec1-intro-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +.. slide:: SO2 Lecture 01 - Course overview and Linux kernel introduction + :inline-contents: False + :level: 1 + + +Echipa +====== + +.. slide:: Echipa + :inline-contents: True + :level: 2 + + * Daniel Băluță (Daniel), Răzvan Deaconescu (Răzvan, RD), Claudiu + Ghioc (Claudiu), Valentin Ghiță (Vali), Sergiu Weisz (Sergiu), + Octavian Purdilă (Tavi) + + * Alexandru Militaru (Alex), Teodora Șerbănescu (Teo), Ștefan + Teodorescu (Ștefan, Fane), Mihai Popescu (Mihai, Mișu), + Constantin Răducanu, Daniel Dinca, Laurențiu Ștefan + + * Mult succes în noul semestru! + +Poziționare curs +================ + +.. slide:: Poziționare curs + :inline-contents: True + :level: 2 + + .. ditaa:: + + +---------------------------------------------------------+ + | application programming (EGC, SPG, PP, SPRC, IOC, etc.) | + +---------------------------------------------------------+ + + +----------------------------------+ + | system programming (PC, SO, CPL) | + +----------------------------------+ + user space + ----------------------------------------------------------=- + kernel space + +--------------------------+ + | kernel programming (SO2) | + +--------------------------+ + + ----------------------------------------------------------=- + + +----------------------------------+ + | hardware (PM, CN1, CN2, PL ) | + +----------------------------------+ + +Resurse +======= + +.. slide:: Resurse + :inline-contents: True + :level: 2 + + * Linux Kernel Labs: https://linux-kernel-labs.github.io/ + * mailing list: so2@cursuri.cs.pub.ro + * Facebook + * vmchecker + * catalog Google, calendar Google + * LXR: https://elixir.bootlin.com/linux/v5.10.14/source + * cs.curs.pub.ro - rol de portal + * karma awards + +Comunitate +========== + +.. slide:: Comunitate + :inline-contents: True + :level: 2 + + * tutorial contribuții: https://linux-kernel-labs.github.io/refs/heads/master/info/contributing.html + * corecții, ajustări, precizări, informații utile + * listă de discuții + * răspundeți la întrebările colegilor voștri + * propuneți subiecte de discuție care au legătură cu disciplina + * Facebook + * sugestii, propuneri, feedback + * Primiți puncte de karma + +Notare +======= + +.. slide:: Notare + :inline-contents: True + :level: 2 + + * 2 puncte activitate la laborator + * 3 puncte „examen”, notare pe parcurs + * 5 puncte teme de casă + * Activități "extra" + * Punctajul din teme de casă + activitați extra ce depăsește 5 + puncte e corelat direct proportional cu nota de la examen + * Tema 0 - 0,5 puncte + * Temele 1, 2, 3 - câte 1,5 puncte fiecare + * Condiţii de promovare: nota finală 4.5, nota minimă examen 3 + +Obiectivele cursului +==================== + +.. slide:: Obiectivele cursului + :inline-contents: True + :level: 2 + + * Prezentarea structurii interne a unui sistem de operare + * Target: sisteme de operare de uz general + * Structura și componentele unui kernel monolitic + * Procese, FS, Networking + * Memory management + * Exemplificare pe Linux + +Obiectivele laboratorului si a temelor +====================================== + +.. slide:: Obiectivele laboratorului si a temelor + :inline-contents: True + :level: 2 + + * Însușirea cunoștințelor necesare implementării de device drivere + + * Înțelegerea în profunzime a cunoștințelor prin rezolvarea de + exerciții + +Cursuri necesare +================ + +.. slide:: Cursuri necesare + :inline-contents: True + :level: 2 + + * Programare: C + * SD: tabele de dispersie, arbori echilibrați + * IOCLA: lucrul cu registre și instrucțiuni de bază (adunări, comparaţii, salturi) + * CN: TLB/CAM, memorie, procesor, I/O + * PC, RL: ethernet, IP, sockeți + * SO: procese, fișiere, thread-uri, memorie virtuală + +Despre curs +=========== + +.. slide:: Despre curs + :inline-contents: True + :level: 2 + + * 12 cursuri + * interactiv + * participaţi la discuţii + * întrebaţi atunci când nu aţi înţeles + * destul de “dens”, se recomandă călduros parcurgerea suportului bibliografic înainte şi după curs + * 1h:20 prezentare + 20min teste si discutii pe marginea testului + +Lista cursuri +============= + +.. slide:: Lista cursuri + :inline-contents: True + :level: 2 + + .. hlist:: + :columns: 2 + + * Introducere + * Apeluri de sistem + * Procese + * Întreruperi + * Sincronizare + * Adresarea memoriei + * Gestiunea memoriei + * Gestiunea fișierelor + * Kernel debugging + * Gestiunea rețelei + * Virtualizare + * Kernel profiling + + +Despre laborator +================ + +.. slide:: Despre laborator + :inline-contents: True + :level: 2 + + * Kernel Modules and Device Drivers + * 15 min prezentare / 80 de minute lucru + * se punctează activitatea + * learn by doing + +Despre teme +=========== + +.. slide:: Despre teme + :inline-contents: True + :level: 2 + + * necesare: aprofundare API (laborator) și concepte (curs) + * teste publice + * suport de testare (vmchecker) + * relativ puţin cod de scris dar relativ dificile + * dificultatea constă în acomodarea cu noul mediu + +Lista teme +========== + +.. slide:: Lista teme + :inline-contents: True + :level: 2 + + * Tema 0 - Kernel API + * Kprobe based tracer + * Driver pentru portul serial + * Software RAID + * SO2 Transport Protocol + + +Bibliografie curs +================= + +.. slide:: Bibliografie curs + :inline-contents: True + :level: 2 + + * Linux Kernel Development, 3rd edition, Robert Love, Addison + Wesley, 2010 + + * Understanding the Linux Kernel, 3rd edition, Daniel P. Bovet & + Marco Cesati, O'Reilly 2005 + + * Linux Networking Architecture, Klaus Wehrle, Frank Pahlke, + Hartmut Ritter, Daniel Muller, Marc Bechler, Prentice Hall 2004 + + * Understanding Linux Network Internals, Christian Benvenuti, O'Reilly 2005 + +Bibliografie laborator +====================== + +.. slide:: Bibliografie laborator + :inline-contents: True + :level: 2 + + * Linux Device Drivers, 3nd edition, Alessandro Rubini & Jonathan + Corbet, O'Reilly 2006 + + * Linux Kernel in a Nutshell, Greg Kroah-Hartman, O'Reilly 2005 + + +.. include:: ../lectures/intro.rst + :start-line: 6 diff --git a/refs/pull/405/merge/_sources/so2/lec10-networking.rst.txt b/refs/pull/405/merge/_sources/so2/lec10-networking.rst.txt new file mode 100644 index 00000000..aec4b414 --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lec10-networking.rst.txt @@ -0,0 +1,16 @@ +=========================== +SO2 Lecture 10 - Networking +=========================== + +`View slides <lec10-networking-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +.. slide:: SO2 Lecture 10 - Networking + :inline-contents: False + :level: 1 + +.. include:: ../lectures/networking.rst + :start-line: 6 diff --git a/refs/pull/405/merge/_sources/so2/lec11-arch.rst.txt b/refs/pull/405/merge/_sources/so2/lec11-arch.rst.txt new file mode 100644 index 00000000..fa160b27 --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lec11-arch.rst.txt @@ -0,0 +1,17 @@ +=================================== +SO2 Lecture 11 - Architecture Layer +=================================== + +`View slides <lec11-arch-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +.. slide:: SO2 Lecture 11 - Architecture Layer + :inline-contents: False + :level: 1 + +.. include:: ../lectures/arch.rst + :start-line: 6 + diff --git a/refs/pull/405/merge/_sources/so2/lec12-profiling.rst.txt b/refs/pull/405/merge/_sources/so2/lec12-profiling.rst.txt new file mode 100644 index 00000000..8a854414 --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lec12-profiling.rst.txt @@ -0,0 +1,13 @@ +========================== +SO2 Lecture 12 - Profiling +========================== + +`View slides <lec12-profiling-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +.. slide:: SO2 Lecture 12 - Profiling + :inline-contents: False + :level: 1 diff --git a/refs/pull/405/merge/_sources/so2/lec12-virtualization.rst.txt b/refs/pull/405/merge/_sources/so2/lec12-virtualization.rst.txt new file mode 100644 index 00000000..9ababa1d --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lec12-virtualization.rst.txt @@ -0,0 +1,16 @@ +=============================== +SO2 Lecture 12 - Virtualization +=============================== + +`View slides <lec12-virtualization-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +.. slide:: SO2 Lecture 12 - Virtualization + :inline-contents: False + :level: 1 + +.. include:: ../lectures/virt.rst + :start-line: 6 diff --git a/refs/pull/405/merge/_sources/so2/lec2-syscalls.rst.txt b/refs/pull/405/merge/_sources/so2/lec2-syscalls.rst.txt new file mode 100644 index 00000000..bcf3bb6b --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lec2-syscalls.rst.txt @@ -0,0 +1,16 @@ +============================= +SO2 Lecture 02 - System calls +============================= + +`View slides <lec2-syscalls-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +.. slide:: SO2 Lecture 02 - System calls + :inline-contents: False + :level: 1 + +.. include:: ../lectures/syscalls.rst + :start-line: 6 diff --git a/refs/pull/405/merge/_sources/so2/lec3-processes.rst.txt b/refs/pull/405/merge/_sources/so2/lec3-processes.rst.txt new file mode 100644 index 00000000..394e3306 --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lec3-processes.rst.txt @@ -0,0 +1,16 @@ +========================== +SO2 Lecture 03 - Processes +========================== + +`View slides <lec3-processes-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +.. slide:: SO2 Lecture 03 - Processes + :inline-contents: False + :level: 1 + +.. include:: ../lectures/processes.rst + :start-line: 6 diff --git a/refs/pull/405/merge/_sources/so2/lec4-interrupts.rst.txt b/refs/pull/405/merge/_sources/so2/lec4-interrupts.rst.txt new file mode 100644 index 00000000..3fba6c5b --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lec4-interrupts.rst.txt @@ -0,0 +1,16 @@ +============================= +SO2 Lecture 04 - Interrupts +============================= + +`View slides <lec4-interrupts-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +.. slide:: SO2 Lecture 04 - Interrupts + :inline-contents: False + :level: 1 + +.. include:: ../lectures/interrupts.rst + :start-line: 6 diff --git a/refs/pull/405/merge/_sources/so2/lec5-smp.rst.txt b/refs/pull/405/merge/_sources/so2/lec5-smp.rst.txt new file mode 100644 index 00000000..a0ef6425 --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lec5-smp.rst.txt @@ -0,0 +1,16 @@ +=========================================== +SO2 Lecture 05 - Symmetric Multi-Processing +=========================================== + +`View slides <lec5-smp-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +.. slide:: SO2 Lecture 05 - Symmetric Multi-Processing + :inline-contents: False + :level: 1 + +.. include:: ../lectures/smp.rst + :start-line: 6 diff --git a/refs/pull/405/merge/_sources/so2/lec6-address-space.rst.txt b/refs/pull/405/merge/_sources/so2/lec6-address-space.rst.txt new file mode 100644 index 00000000..b0237be0 --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lec6-address-space.rst.txt @@ -0,0 +1,16 @@ +============================== +SO2 Lecture 06 - Address Space +============================== + +`View slides <lec6-address-space-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +.. slide:: SO2 Lecture 06 - Address Space + :inline-contents: False + :level: 1 + +.. include:: ../lectures/address-space.rst + :start-line: 6 diff --git a/refs/pull/405/merge/_sources/so2/lec7-memory-management.rst.txt b/refs/pull/405/merge/_sources/so2/lec7-memory-management.rst.txt new file mode 100644 index 00000000..05e2e3b0 --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lec7-memory-management.rst.txt @@ -0,0 +1,16 @@ +================================== +SO2 Lecture 07 - Memory Management +================================== + +`View slides <lec7-memory-management-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +.. slide:: SO2 Lecture 07 - Memory Management + :inline-contents: False + :level: 1 + +.. include:: ../lectures/memory-management.rst + :start-line: 6 diff --git a/refs/pull/405/merge/_sources/so2/lec8-filesystems.rst.txt b/refs/pull/405/merge/_sources/so2/lec8-filesystems.rst.txt new file mode 100644 index 00000000..6029d651 --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lec8-filesystems.rst.txt @@ -0,0 +1,17 @@ +====================================== +SO2 Lecture 08 - Filesystem Management +====================================== + +`View slides <lec8-filesystems-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +.. slide:: SO2 Lecture 08 - Filesystem Management + :inline-contents: False + :level: 1 + +.. include:: ../lectures/fs.rst + :start-line: 6 + diff --git a/refs/pull/405/merge/_sources/so2/lec9-debugging.rst.txt b/refs/pull/405/merge/_sources/so2/lec9-debugging.rst.txt new file mode 100644 index 00000000..02b4ed6d --- /dev/null +++ b/refs/pull/405/merge/_sources/so2/lec9-debugging.rst.txt @@ -0,0 +1,16 @@ +================================= +SO2 Lecture 09 - Kernel debugging +================================= + +`View slides <lec9-debugging-slides.html>`_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +.. slide:: SO2 Lecture 09 - Kernel debugging + :inline-contents: False + :level: 1 + +.. include:: ../lectures/debugging.rst + :start-line: 6 diff --git a/refs/pull/405/merge/_static/ajax-loader.gif b/refs/pull/405/merge/_static/ajax-loader.gif new file mode 100644 index 00000000..61faf8ca Binary files /dev/null and b/refs/pull/405/merge/_static/ajax-loader.gif differ diff --git a/refs/pull/405/merge/_static/asciinema-player.css b/refs/pull/405/merge/_static/asciinema-player.css new file mode 100644 index 00000000..20b6974f --- /dev/null +++ b/refs/pull/405/merge/_static/asciinema-player.css @@ -0,0 +1,2563 @@ +.asciinema-player-wrapper { + position: relative; + text-align: center; + outline: none; +} +.asciinema-player-wrapper .title-bar { + display: none; + top: -78px; + transition: top 0.15s linear; + position: absolute; + left: 0; + right: 0; + box-sizing: content-box; + font-size: 20px; + line-height: 1em; + padding: 15px; + font-family: sans-serif; + color: white; + background-color: rgba(0, 0, 0, 0.8); +} +.asciinema-player-wrapper .title-bar img { + vertical-align: middle; + height: 48px; + margin-right: 16px; +} +.asciinema-player-wrapper .title-bar a { + color: white; + text-decoration: underline; +} +.asciinema-player-wrapper .title-bar a:hover { + text-decoration: none; +} +.asciinema-player-wrapper:fullscreen { + background-color: #000; + width: 100%; + height: 100%; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-justify-content: center; + justify-content: center; + -webkit-align-items: center; + align-items: center; +} +.asciinema-player-wrapper:fullscreen .asciinema-player { + position: static; +} +.asciinema-player-wrapper:fullscreen .title-bar { + display: initial; +} +.asciinema-player-wrapper:fullscreen.hud .title-bar { + top: 0; +} +.asciinema-player-wrapper:-webkit-full-screen { + background-color: #000; + width: 100%; + height: 100%; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-justify-content: center; + justify-content: center; + -webkit-align-items: center; + align-items: center; +} +.asciinema-player-wrapper:-webkit-full-screen .asciinema-player { + position: static; +} +.asciinema-player-wrapper:-webkit-full-screen .title-bar { + display: initial; +} +.asciinema-player-wrapper:-webkit-full-screen.hud .title-bar { + top: 0; +} +.asciinema-player-wrapper:-moz-full-screen { + background-color: #000; + width: 100%; + height: 100%; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-justify-content: center; + justify-content: center; + -webkit-align-items: center; + align-items: center; +} +.asciinema-player-wrapper:-moz-full-screen .asciinema-player { + position: static; +} +.asciinema-player-wrapper:-moz-full-screen .title-bar { + display: initial; +} +.asciinema-player-wrapper:-moz-full-screen.hud .title-bar { + top: 0; +} +.asciinema-player-wrapper:-ms-fullscreen { + background-color: #000; + width: 100%; + height: 100%; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-justify-content: center; + justify-content: center; + -webkit-align-items: center; + align-items: center; +} +.asciinema-player-wrapper:-ms-fullscreen .asciinema-player { + position: static; +} +.asciinema-player-wrapper:-ms-fullscreen .title-bar { + display: initial; +} +.asciinema-player-wrapper:-ms-fullscreen.hud .title-bar { + top: 0; +} +.asciinema-player-wrapper .asciinema-player { + text-align: left; + display: inline-block; + padding: 0px; + position: relative; + box-sizing: content-box; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + overflow: hidden; + max-width: 100%; +} +.asciinema-terminal { + box-sizing: content-box; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + overflow: hidden; + padding: 0; + margin: 0px; + display: block; + white-space: pre; + border: 0; + word-wrap: normal; + word-break: normal; + border-radius: 0; + border-style: solid; + cursor: text; + border-width: 0.5em; + font-family: Consolas, Menlo, 'Bitstream Vera Sans Mono', monospace, 'Powerline Symbols'; + line-height: 1.3333333333em; +} +.asciinema-terminal .line { + letter-spacing: normal; + overflow: hidden; + height: 1.3333333333em; +} +.asciinema-terminal .line span { + padding: 0; + display: inline-block; + height: 1.3333333333em; +} +.asciinema-terminal .line { + display: block; + width: 200%; +} +.asciinema-terminal .bright { + font-weight: bold; +} +.asciinema-terminal .underline { + text-decoration: underline; +} +.asciinema-terminal .italic { + font-style: italic; +} +.asciinema-terminal.font-small { + font-size: 12px; +} +.asciinema-terminal.font-medium { + font-size: 18px; +} +.asciinema-terminal.font-big { + font-size: 24px; +} +.asciinema-player .control-bar { + width: 100%; + height: 32px; + background: rgba(0, 0, 0, 0.8); + /* no gradient fallback */ + background: -moz-linear-gradient(top, rgba(0, 0, 0, 0.5) 0%, #000000 25%, #000000 100%); + /* FF3.6-15 */ + background: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.5) 0%, #000000 25%, #000000 100%); + /* Chrome10-25,Safari5.1-6 */ + background: linear-gradient(to bottom, rgba(0, 0, 0, 0.5) 0%, #000000 25%, #000000 100%); + /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ + color: #bbbbbb; + box-sizing: content-box; + line-height: 1; + /* position: absolute; */ + bottom: -35px; + left: 0; + transition: bottom 0.15s linear; +} +.asciinema-player .control-bar * { + box-sizing: inherit; + font-size: 0; +} +.asciinema-player .control-bar svg.icon path { + fill: #bbbbbb; +} +.asciinema-player .control-bar .playback-button { + display: block; + float: left; + cursor: pointer; + height: 12px; + width: 12px; + padding: 10px; +} +.asciinema-player .control-bar .playback-button svg { + height: 12px; + width: 12px; +} +.asciinema-player .control-bar .timer { + display: block; + float: left; + width: 50px; + height: 100%; + text-align: center; + font-family: Helvetica, Arial, sans-serif; + font-size: 11px; + font-weight: bold; + line-height: 32px; + cursor: default; +} +.asciinema-player .control-bar .timer span { + display: inline-block; + font-size: inherit; +} +.asciinema-player .control-bar .timer .time-remaining { + display: none; +} +.asciinema-player .control-bar .timer:hover .time-elapsed { + display: none; +} +.asciinema-player .control-bar .timer:hover .time-remaining { + display: inline; +} +.asciinema-player .control-bar .progressbar { + display: block; + overflow: hidden; + height: 100%; + padding: 0 10px; +} +.asciinema-player .control-bar .progressbar .bar { + display: block; + cursor: pointer; + height: 100%; + padding-top: 15px; + font-size: 0; +} +.asciinema-player .control-bar .progressbar .bar .gutter { + display: block; + height: 3px; + background-color: #333; +} +.asciinema-player .control-bar .progressbar .bar .gutter span { + display: inline-block; + height: 100%; + background-color: #bbbbbb; + border-radius: 3px; +} +.asciinema-player .control-bar.live .progressbar .bar { + cursor: default; +} +.asciinema-player .control-bar .fullscreen-button { + display: block; + float: right; + width: 14px; + height: 14px; + padding: 9px; + cursor: pointer; +} +.asciinema-player .control-bar .fullscreen-button svg { + width: 14px; + height: 14px; +} +.asciinema-player .control-bar .fullscreen-button svg:first-child { + display: inline; +} +.asciinema-player .control-bar .fullscreen-button svg:last-child { + display: none; +} +.asciinema-player-wrapper.hud .control-bar { + bottom: 0px; +} +.asciinema-player-wrapper:fullscreen .fullscreen-button svg:first-child { + display: none; +} +.asciinema-player-wrapper:fullscreen .fullscreen-button svg:last-child { + display: inline; +} +.asciinema-player-wrapper:-webkit-full-screen .fullscreen-button svg:first-child { + display: none; +} +.asciinema-player-wrapper:-webkit-full-screen .fullscreen-button svg:last-child { + display: inline; +} +.asciinema-player-wrapper:-moz-full-screen .fullscreen-button svg:first-child { + display: none; +} +.asciinema-player-wrapper:-moz-full-screen .fullscreen-button svg:last-child { + display: inline; +} +.asciinema-player-wrapper:-ms-fullscreen .fullscreen-button svg:first-child { + display: none; +} +.asciinema-player-wrapper:-ms-fullscreen .fullscreen-button svg:last-child { + display: inline; +} +.asciinema-player .loading { + z-index: 10; + background-repeat: no-repeat; + background-position: center; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 32px; + background-color: rgba(0, 0, 0, 0.5); +} +.asciinema-player .start-prompt { + z-index: 10; + background-repeat: no-repeat; + background-position: center; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 32px; + z-index: 20; + cursor: pointer; +} +.asciinema-player .start-prompt .play-button { + font-size: 0px; +} +.asciinema-player .start-prompt .play-button { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + text-align: center; + color: white; + display: table; + width: 100%; + height: 100%; +} +.asciinema-player .start-prompt .play-button div { + vertical-align: middle; + display: table-cell; +} +.asciinema-player .start-prompt .play-button div span { + width: 96px; + height: 96px; + display: inline-block; +} +@-webkit-keyframes expand { + 0% { + -webkit-transform: scale(0); + } + 50% { + -webkit-transform: scale(1); + } + 100% { + z-index: 1; + } +} +@-moz-keyframes expand { + 0% { + -moz-transform: scale(0); + } + 50% { + -moz-transform: scale(1); + } + 100% { + z-index: 1; + } +} +@-o-keyframes expand { + 0% { + -o-transform: scale(0); + } + 50% { + -o-transform: scale(1); + } + 100% { + z-index: 1; + } +} +@keyframes expand { + 0% { + transform: scale(0); + } + 50% { + transform: scale(1); + } + 100% { + z-index: 1; + } +} +.loader { + position: absolute; + left: 50%; + top: 50%; + margin: -20px 0 0 -20px; + background-color: white; + border-radius: 50%; + box-shadow: 0 0 0 6.66667px #141414; + width: 40px; + height: 40px; +} +.loader:before, +.loader:after { + content: ""; + position: absolute; + left: 50%; + top: 50%; + display: block; + margin: -21px 0 0 -21px; + border-radius: 50%; + z-index: 2; + width: 42px; + height: 42px; +} +.loader:before { + background-color: #141414; + -webkit-animation: expand 1.6s linear infinite both; + -moz-animation: expand 1.6s linear infinite both; + animation: expand 1.6s linear infinite both; +} +.loader:after { + background-color: white; + -webkit-animation: expand 1.6s linear 0.8s infinite both; + -moz-animation: expand 1.6s linear 0.8s infinite both; + animation: expand 1.6s linear 0.8s infinite both; +} +.asciinema-terminal .fg-16 { + color: #000000; +} +.asciinema-terminal .bg-16 { + background-color: #000000; +} +.asciinema-terminal .fg-17 { + color: #00005f; +} +.asciinema-terminal .bg-17 { + background-color: #00005f; +} +.asciinema-terminal .fg-18 { + color: #000087; +} +.asciinema-terminal .bg-18 { + background-color: #000087; +} +.asciinema-terminal .fg-19 { + color: #0000af; +} +.asciinema-terminal .bg-19 { + background-color: #0000af; +} +.asciinema-terminal .fg-20 { + color: #0000d7; +} +.asciinema-terminal .bg-20 { + background-color: #0000d7; +} +.asciinema-terminal .fg-21 { + color: #0000ff; +} +.asciinema-terminal .bg-21 { + background-color: #0000ff; +} +.asciinema-terminal .fg-22 { + color: #005f00; +} +.asciinema-terminal .bg-22 { + background-color: #005f00; +} +.asciinema-terminal .fg-23 { + color: #005f5f; +} +.asciinema-terminal .bg-23 { + background-color: #005f5f; +} +.asciinema-terminal .fg-24 { + color: #005f87; +} +.asciinema-terminal .bg-24 { + background-color: #005f87; +} +.asciinema-terminal .fg-25 { + color: #005faf; +} +.asciinema-terminal .bg-25 { + background-color: #005faf; +} +.asciinema-terminal .fg-26 { + color: #005fd7; +} +.asciinema-terminal .bg-26 { + background-color: #005fd7; +} +.asciinema-terminal .fg-27 { + color: #005fff; +} +.asciinema-terminal .bg-27 { + background-color: #005fff; +} +.asciinema-terminal .fg-28 { + color: #008700; +} +.asciinema-terminal .bg-28 { + background-color: #008700; +} +.asciinema-terminal .fg-29 { + color: #00875f; +} +.asciinema-terminal .bg-29 { + background-color: #00875f; +} +.asciinema-terminal .fg-30 { + color: #008787; +} +.asciinema-terminal .bg-30 { + background-color: #008787; +} +.asciinema-terminal .fg-31 { + color: #0087af; +} +.asciinema-terminal .bg-31 { + background-color: #0087af; +} +.asciinema-terminal .fg-32 { + color: #0087d7; +} +.asciinema-terminal .bg-32 { + background-color: #0087d7; +} +.asciinema-terminal .fg-33 { + color: #0087ff; +} +.asciinema-terminal .bg-33 { + background-color: #0087ff; +} +.asciinema-terminal .fg-34 { + color: #00af00; +} +.asciinema-terminal .bg-34 { + background-color: #00af00; +} +.asciinema-terminal .fg-35 { + color: #00af5f; +} +.asciinema-terminal .bg-35 { + background-color: #00af5f; +} +.asciinema-terminal .fg-36 { + color: #00af87; +} +.asciinema-terminal .bg-36 { + background-color: #00af87; +} +.asciinema-terminal .fg-37 { + color: #00afaf; +} +.asciinema-terminal .bg-37 { + background-color: #00afaf; +} +.asciinema-terminal .fg-38 { + color: #00afd7; +} +.asciinema-terminal .bg-38 { + background-color: #00afd7; +} +.asciinema-terminal .fg-39 { + color: #00afff; +} +.asciinema-terminal .bg-39 { + background-color: #00afff; +} +.asciinema-terminal .fg-40 { + color: #00d700; +} +.asciinema-terminal .bg-40 { + background-color: #00d700; +} +.asciinema-terminal .fg-41 { + color: #00d75f; +} +.asciinema-terminal .bg-41 { + background-color: #00d75f; +} +.asciinema-terminal .fg-42 { + color: #00d787; +} +.asciinema-terminal .bg-42 { + background-color: #00d787; +} +.asciinema-terminal .fg-43 { + color: #00d7af; +} +.asciinema-terminal .bg-43 { + background-color: #00d7af; +} +.asciinema-terminal .fg-44 { + color: #00d7d7; +} +.asciinema-terminal .bg-44 { + background-color: #00d7d7; +} +.asciinema-terminal .fg-45 { + color: #00d7ff; +} +.asciinema-terminal .bg-45 { + background-color: #00d7ff; +} +.asciinema-terminal .fg-46 { + color: #00ff00; +} +.asciinema-terminal .bg-46 { + background-color: #00ff00; +} +.asciinema-terminal .fg-47 { + color: #00ff5f; +} +.asciinema-terminal .bg-47 { + background-color: #00ff5f; +} +.asciinema-terminal .fg-48 { + color: #00ff87; +} +.asciinema-terminal .bg-48 { + background-color: #00ff87; +} +.asciinema-terminal .fg-49 { + color: #00ffaf; +} +.asciinema-terminal .bg-49 { + background-color: #00ffaf; +} +.asciinema-terminal .fg-50 { + color: #00ffd7; +} +.asciinema-terminal .bg-50 { + background-color: #00ffd7; +} +.asciinema-terminal .fg-51 { + color: #00ffff; +} +.asciinema-terminal .bg-51 { + background-color: #00ffff; +} +.asciinema-terminal .fg-52 { + color: #5f0000; +} +.asciinema-terminal .bg-52 { + background-color: #5f0000; +} +.asciinema-terminal .fg-53 { + color: #5f005f; +} +.asciinema-terminal .bg-53 { + background-color: #5f005f; +} +.asciinema-terminal .fg-54 { + color: #5f0087; +} +.asciinema-terminal .bg-54 { + background-color: #5f0087; +} +.asciinema-terminal .fg-55 { + color: #5f00af; +} +.asciinema-terminal .bg-55 { + background-color: #5f00af; +} +.asciinema-terminal .fg-56 { + color: #5f00d7; +} +.asciinema-terminal .bg-56 { + background-color: #5f00d7; +} +.asciinema-terminal .fg-57 { + color: #5f00ff; +} +.asciinema-terminal .bg-57 { + background-color: #5f00ff; +} +.asciinema-terminal .fg-58 { + color: #5f5f00; +} +.asciinema-terminal .bg-58 { + background-color: #5f5f00; +} +.asciinema-terminal .fg-59 { + color: #5f5f5f; +} +.asciinema-terminal .bg-59 { + background-color: #5f5f5f; +} +.asciinema-terminal .fg-60 { + color: #5f5f87; +} +.asciinema-terminal .bg-60 { + background-color: #5f5f87; +} +.asciinema-terminal .fg-61 { + color: #5f5faf; +} +.asciinema-terminal .bg-61 { + background-color: #5f5faf; +} +.asciinema-terminal .fg-62 { + color: #5f5fd7; +} +.asciinema-terminal .bg-62 { + background-color: #5f5fd7; +} +.asciinema-terminal .fg-63 { + color: #5f5fff; +} +.asciinema-terminal .bg-63 { + background-color: #5f5fff; +} +.asciinema-terminal .fg-64 { + color: #5f8700; +} +.asciinema-terminal .bg-64 { + background-color: #5f8700; +} +.asciinema-terminal .fg-65 { + color: #5f875f; +} +.asciinema-terminal .bg-65 { + background-color: #5f875f; +} +.asciinema-terminal .fg-66 { + color: #5f8787; +} +.asciinema-terminal .bg-66 { + background-color: #5f8787; +} +.asciinema-terminal .fg-67 { + color: #5f87af; +} +.asciinema-terminal .bg-67 { + background-color: #5f87af; +} +.asciinema-terminal .fg-68 { + color: #5f87d7; +} +.asciinema-terminal .bg-68 { + background-color: #5f87d7; +} +.asciinema-terminal .fg-69 { + color: #5f87ff; +} +.asciinema-terminal .bg-69 { + background-color: #5f87ff; +} +.asciinema-terminal .fg-70 { + color: #5faf00; +} +.asciinema-terminal .bg-70 { + background-color: #5faf00; +} +.asciinema-terminal .fg-71 { + color: #5faf5f; +} +.asciinema-terminal .bg-71 { + background-color: #5faf5f; +} +.asciinema-terminal .fg-72 { + color: #5faf87; +} +.asciinema-terminal .bg-72 { + background-color: #5faf87; +} +.asciinema-terminal .fg-73 { + color: #5fafaf; +} +.asciinema-terminal .bg-73 { + background-color: #5fafaf; +} +.asciinema-terminal .fg-74 { + color: #5fafd7; +} +.asciinema-terminal .bg-74 { + background-color: #5fafd7; +} +.asciinema-terminal .fg-75 { + color: #5fafff; +} +.asciinema-terminal .bg-75 { + background-color: #5fafff; +} +.asciinema-terminal .fg-76 { + color: #5fd700; +} +.asciinema-terminal .bg-76 { + background-color: #5fd700; +} +.asciinema-terminal .fg-77 { + color: #5fd75f; +} +.asciinema-terminal .bg-77 { + background-color: #5fd75f; +} +.asciinema-terminal .fg-78 { + color: #5fd787; +} +.asciinema-terminal .bg-78 { + background-color: #5fd787; +} +.asciinema-terminal .fg-79 { + color: #5fd7af; +} +.asciinema-terminal .bg-79 { + background-color: #5fd7af; +} +.asciinema-terminal .fg-80 { + color: #5fd7d7; +} +.asciinema-terminal .bg-80 { + background-color: #5fd7d7; +} +.asciinema-terminal .fg-81 { + color: #5fd7ff; +} +.asciinema-terminal .bg-81 { + background-color: #5fd7ff; +} +.asciinema-terminal .fg-82 { + color: #5fff00; +} +.asciinema-terminal .bg-82 { + background-color: #5fff00; +} +.asciinema-terminal .fg-83 { + color: #5fff5f; +} +.asciinema-terminal .bg-83 { + background-color: #5fff5f; +} +.asciinema-terminal .fg-84 { + color: #5fff87; +} +.asciinema-terminal .bg-84 { + background-color: #5fff87; +} +.asciinema-terminal .fg-85 { + color: #5fffaf; +} +.asciinema-terminal .bg-85 { + background-color: #5fffaf; +} +.asciinema-terminal .fg-86 { + color: #5fffd7; +} +.asciinema-terminal .bg-86 { + background-color: #5fffd7; +} +.asciinema-terminal .fg-87 { + color: #5fffff; +} +.asciinema-terminal .bg-87 { + background-color: #5fffff; +} +.asciinema-terminal .fg-88 { + color: #870000; +} +.asciinema-terminal .bg-88 { + background-color: #870000; +} +.asciinema-terminal .fg-89 { + color: #87005f; +} +.asciinema-terminal .bg-89 { + background-color: #87005f; +} +.asciinema-terminal .fg-90 { + color: #870087; +} +.asciinema-terminal .bg-90 { + background-color: #870087; +} +.asciinema-terminal .fg-91 { + color: #8700af; +} +.asciinema-terminal .bg-91 { + background-color: #8700af; +} +.asciinema-terminal .fg-92 { + color: #8700d7; +} +.asciinema-terminal .bg-92 { + background-color: #8700d7; +} +.asciinema-terminal .fg-93 { + color: #8700ff; +} +.asciinema-terminal .bg-93 { + background-color: #8700ff; +} +.asciinema-terminal .fg-94 { + color: #875f00; +} +.asciinema-terminal .bg-94 { + background-color: #875f00; +} +.asciinema-terminal .fg-95 { + color: #875f5f; +} +.asciinema-terminal .bg-95 { + background-color: #875f5f; +} +.asciinema-terminal .fg-96 { + color: #875f87; +} +.asciinema-terminal .bg-96 { + background-color: #875f87; +} +.asciinema-terminal .fg-97 { + color: #875faf; +} +.asciinema-terminal .bg-97 { + background-color: #875faf; +} +.asciinema-terminal .fg-98 { + color: #875fd7; +} +.asciinema-terminal .bg-98 { + background-color: #875fd7; +} +.asciinema-terminal .fg-99 { + color: #875fff; +} +.asciinema-terminal .bg-99 { + background-color: #875fff; +} +.asciinema-terminal .fg-100 { + color: #878700; +} +.asciinema-terminal .bg-100 { + background-color: #878700; +} +.asciinema-terminal .fg-101 { + color: #87875f; +} +.asciinema-terminal .bg-101 { + background-color: #87875f; +} +.asciinema-terminal .fg-102 { + color: #878787; +} +.asciinema-terminal .bg-102 { + background-color: #878787; +} +.asciinema-terminal .fg-103 { + color: #8787af; +} +.asciinema-terminal .bg-103 { + background-color: #8787af; +} +.asciinema-terminal .fg-104 { + color: #8787d7; +} +.asciinema-terminal .bg-104 { + background-color: #8787d7; +} +.asciinema-terminal .fg-105 { + color: #8787ff; +} +.asciinema-terminal .bg-105 { + background-color: #8787ff; +} +.asciinema-terminal .fg-106 { + color: #87af00; +} +.asciinema-terminal .bg-106 { + background-color: #87af00; +} +.asciinema-terminal .fg-107 { + color: #87af5f; +} +.asciinema-terminal .bg-107 { + background-color: #87af5f; +} +.asciinema-terminal .fg-108 { + color: #87af87; +} +.asciinema-terminal .bg-108 { + background-color: #87af87; +} +.asciinema-terminal .fg-109 { + color: #87afaf; +} +.asciinema-terminal .bg-109 { + background-color: #87afaf; +} +.asciinema-terminal .fg-110 { + color: #87afd7; +} +.asciinema-terminal .bg-110 { + background-color: #87afd7; +} +.asciinema-terminal .fg-111 { + color: #87afff; +} +.asciinema-terminal .bg-111 { + background-color: #87afff; +} +.asciinema-terminal .fg-112 { + color: #87d700; +} +.asciinema-terminal .bg-112 { + background-color: #87d700; +} +.asciinema-terminal .fg-113 { + color: #87d75f; +} +.asciinema-terminal .bg-113 { + background-color: #87d75f; +} +.asciinema-terminal .fg-114 { + color: #87d787; +} +.asciinema-terminal .bg-114 { + background-color: #87d787; +} +.asciinema-terminal .fg-115 { + color: #87d7af; +} +.asciinema-terminal .bg-115 { + background-color: #87d7af; +} +.asciinema-terminal .fg-116 { + color: #87d7d7; +} +.asciinema-terminal .bg-116 { + background-color: #87d7d7; +} +.asciinema-terminal .fg-117 { + color: #87d7ff; +} +.asciinema-terminal .bg-117 { + background-color: #87d7ff; +} +.asciinema-terminal .fg-118 { + color: #87ff00; +} +.asciinema-terminal .bg-118 { + background-color: #87ff00; +} +.asciinema-terminal .fg-119 { + color: #87ff5f; +} +.asciinema-terminal .bg-119 { + background-color: #87ff5f; +} +.asciinema-terminal .fg-120 { + color: #87ff87; +} +.asciinema-terminal .bg-120 { + background-color: #87ff87; +} +.asciinema-terminal .fg-121 { + color: #87ffaf; +} +.asciinema-terminal .bg-121 { + background-color: #87ffaf; +} +.asciinema-terminal .fg-122 { + color: #87ffd7; +} +.asciinema-terminal .bg-122 { + background-color: #87ffd7; +} +.asciinema-terminal .fg-123 { + color: #87ffff; +} +.asciinema-terminal .bg-123 { + background-color: #87ffff; +} +.asciinema-terminal .fg-124 { + color: #af0000; +} +.asciinema-terminal .bg-124 { + background-color: #af0000; +} +.asciinema-terminal .fg-125 { + color: #af005f; +} +.asciinema-terminal .bg-125 { + background-color: #af005f; +} +.asciinema-terminal .fg-126 { + color: #af0087; +} +.asciinema-terminal .bg-126 { + background-color: #af0087; +} +.asciinema-terminal .fg-127 { + color: #af00af; +} +.asciinema-terminal .bg-127 { + background-color: #af00af; +} +.asciinema-terminal .fg-128 { + color: #af00d7; +} +.asciinema-terminal .bg-128 { + background-color: #af00d7; +} +.asciinema-terminal .fg-129 { + color: #af00ff; +} +.asciinema-terminal .bg-129 { + background-color: #af00ff; +} +.asciinema-terminal .fg-130 { + color: #af5f00; +} +.asciinema-terminal .bg-130 { + background-color: #af5f00; +} +.asciinema-terminal .fg-131 { + color: #af5f5f; +} +.asciinema-terminal .bg-131 { + background-color: #af5f5f; +} +.asciinema-terminal .fg-132 { + color: #af5f87; +} +.asciinema-terminal .bg-132 { + background-color: #af5f87; +} +.asciinema-terminal .fg-133 { + color: #af5faf; +} +.asciinema-terminal .bg-133 { + background-color: #af5faf; +} +.asciinema-terminal .fg-134 { + color: #af5fd7; +} +.asciinema-terminal .bg-134 { + background-color: #af5fd7; +} +.asciinema-terminal .fg-135 { + color: #af5fff; +} +.asciinema-terminal .bg-135 { + background-color: #af5fff; +} +.asciinema-terminal .fg-136 { + color: #af8700; +} +.asciinema-terminal .bg-136 { + background-color: #af8700; +} +.asciinema-terminal .fg-137 { + color: #af875f; +} +.asciinema-terminal .bg-137 { + background-color: #af875f; +} +.asciinema-terminal .fg-138 { + color: #af8787; +} +.asciinema-terminal .bg-138 { + background-color: #af8787; +} +.asciinema-terminal .fg-139 { + color: #af87af; +} +.asciinema-terminal .bg-139 { + background-color: #af87af; +} +.asciinema-terminal .fg-140 { + color: #af87d7; +} +.asciinema-terminal .bg-140 { + background-color: #af87d7; +} +.asciinema-terminal .fg-141 { + color: #af87ff; +} +.asciinema-terminal .bg-141 { + background-color: #af87ff; +} +.asciinema-terminal .fg-142 { + color: #afaf00; +} +.asciinema-terminal .bg-142 { + background-color: #afaf00; +} +.asciinema-terminal .fg-143 { + color: #afaf5f; +} +.asciinema-terminal .bg-143 { + background-color: #afaf5f; +} +.asciinema-terminal .fg-144 { + color: #afaf87; +} +.asciinema-terminal .bg-144 { + background-color: #afaf87; +} +.asciinema-terminal .fg-145 { + color: #afafaf; +} +.asciinema-terminal .bg-145 { + background-color: #afafaf; +} +.asciinema-terminal .fg-146 { + color: #afafd7; +} +.asciinema-terminal .bg-146 { + background-color: #afafd7; +} +.asciinema-terminal .fg-147 { + color: #afafff; +} +.asciinema-terminal .bg-147 { + background-color: #afafff; +} +.asciinema-terminal .fg-148 { + color: #afd700; +} +.asciinema-terminal .bg-148 { + background-color: #afd700; +} +.asciinema-terminal .fg-149 { + color: #afd75f; +} +.asciinema-terminal .bg-149 { + background-color: #afd75f; +} +.asciinema-terminal .fg-150 { + color: #afd787; +} +.asciinema-terminal .bg-150 { + background-color: #afd787; +} +.asciinema-terminal .fg-151 { + color: #afd7af; +} +.asciinema-terminal .bg-151 { + background-color: #afd7af; +} +.asciinema-terminal .fg-152 { + color: #afd7d7; +} +.asciinema-terminal .bg-152 { + background-color: #afd7d7; +} +.asciinema-terminal .fg-153 { + color: #afd7ff; +} +.asciinema-terminal .bg-153 { + background-color: #afd7ff; +} +.asciinema-terminal .fg-154 { + color: #afff00; +} +.asciinema-terminal .bg-154 { + background-color: #afff00; +} +.asciinema-terminal .fg-155 { + color: #afff5f; +} +.asciinema-terminal .bg-155 { + background-color: #afff5f; +} +.asciinema-terminal .fg-156 { + color: #afff87; +} +.asciinema-terminal .bg-156 { + background-color: #afff87; +} +.asciinema-terminal .fg-157 { + color: #afffaf; +} +.asciinema-terminal .bg-157 { + background-color: #afffaf; +} +.asciinema-terminal .fg-158 { + color: #afffd7; +} +.asciinema-terminal .bg-158 { + background-color: #afffd7; +} +.asciinema-terminal .fg-159 { + color: #afffff; +} +.asciinema-terminal .bg-159 { + background-color: #afffff; +} +.asciinema-terminal .fg-160 { + color: #d70000; +} +.asciinema-terminal .bg-160 { + background-color: #d70000; +} +.asciinema-terminal .fg-161 { + color: #d7005f; +} +.asciinema-terminal .bg-161 { + background-color: #d7005f; +} +.asciinema-terminal .fg-162 { + color: #d70087; +} +.asciinema-terminal .bg-162 { + background-color: #d70087; +} +.asciinema-terminal .fg-163 { + color: #d700af; +} +.asciinema-terminal .bg-163 { + background-color: #d700af; +} +.asciinema-terminal .fg-164 { + color: #d700d7; +} +.asciinema-terminal .bg-164 { + background-color: #d700d7; +} +.asciinema-terminal .fg-165 { + color: #d700ff; +} +.asciinema-terminal .bg-165 { + background-color: #d700ff; +} +.asciinema-terminal .fg-166 { + color: #d75f00; +} +.asciinema-terminal .bg-166 { + background-color: #d75f00; +} +.asciinema-terminal .fg-167 { + color: #d75f5f; +} +.asciinema-terminal .bg-167 { + background-color: #d75f5f; +} +.asciinema-terminal .fg-168 { + color: #d75f87; +} +.asciinema-terminal .bg-168 { + background-color: #d75f87; +} +.asciinema-terminal .fg-169 { + color: #d75faf; +} +.asciinema-terminal .bg-169 { + background-color: #d75faf; +} +.asciinema-terminal .fg-170 { + color: #d75fd7; +} +.asciinema-terminal .bg-170 { + background-color: #d75fd7; +} +.asciinema-terminal .fg-171 { + color: #d75fff; +} +.asciinema-terminal .bg-171 { + background-color: #d75fff; +} +.asciinema-terminal .fg-172 { + color: #d78700; +} +.asciinema-terminal .bg-172 { + background-color: #d78700; +} +.asciinema-terminal .fg-173 { + color: #d7875f; +} +.asciinema-terminal .bg-173 { + background-color: #d7875f; +} +.asciinema-terminal .fg-174 { + color: #d78787; +} +.asciinema-terminal .bg-174 { + background-color: #d78787; +} +.asciinema-terminal .fg-175 { + color: #d787af; +} +.asciinema-terminal .bg-175 { + background-color: #d787af; +} +.asciinema-terminal .fg-176 { + color: #d787d7; +} +.asciinema-terminal .bg-176 { + background-color: #d787d7; +} +.asciinema-terminal .fg-177 { + color: #d787ff; +} +.asciinema-terminal .bg-177 { + background-color: #d787ff; +} +.asciinema-terminal .fg-178 { + color: #d7af00; +} +.asciinema-terminal .bg-178 { + background-color: #d7af00; +} +.asciinema-terminal .fg-179 { + color: #d7af5f; +} +.asciinema-terminal .bg-179 { + background-color: #d7af5f; +} +.asciinema-terminal .fg-180 { + color: #d7af87; +} +.asciinema-terminal .bg-180 { + background-color: #d7af87; +} +.asciinema-terminal .fg-181 { + color: #d7afaf; +} +.asciinema-terminal .bg-181 { + background-color: #d7afaf; +} +.asciinema-terminal .fg-182 { + color: #d7afd7; +} +.asciinema-terminal .bg-182 { + background-color: #d7afd7; +} +.asciinema-terminal .fg-183 { + color: #d7afff; +} +.asciinema-terminal .bg-183 { + background-color: #d7afff; +} +.asciinema-terminal .fg-184 { + color: #d7d700; +} +.asciinema-terminal .bg-184 { + background-color: #d7d700; +} +.asciinema-terminal .fg-185 { + color: #d7d75f; +} +.asciinema-terminal .bg-185 { + background-color: #d7d75f; +} +.asciinema-terminal .fg-186 { + color: #d7d787; +} +.asciinema-terminal .bg-186 { + background-color: #d7d787; +} +.asciinema-terminal .fg-187 { + color: #d7d7af; +} +.asciinema-terminal .bg-187 { + background-color: #d7d7af; +} +.asciinema-terminal .fg-188 { + color: #d7d7d7; +} +.asciinema-terminal .bg-188 { + background-color: #d7d7d7; +} +.asciinema-terminal .fg-189 { + color: #d7d7ff; +} +.asciinema-terminal .bg-189 { + background-color: #d7d7ff; +} +.asciinema-terminal .fg-190 { + color: #d7ff00; +} +.asciinema-terminal .bg-190 { + background-color: #d7ff00; +} +.asciinema-terminal .fg-191 { + color: #d7ff5f; +} +.asciinema-terminal .bg-191 { + background-color: #d7ff5f; +} +.asciinema-terminal .fg-192 { + color: #d7ff87; +} +.asciinema-terminal .bg-192 { + background-color: #d7ff87; +} +.asciinema-terminal .fg-193 { + color: #d7ffaf; +} +.asciinema-terminal .bg-193 { + background-color: #d7ffaf; +} +.asciinema-terminal .fg-194 { + color: #d7ffd7; +} +.asciinema-terminal .bg-194 { + background-color: #d7ffd7; +} +.asciinema-terminal .fg-195 { + color: #d7ffff; +} +.asciinema-terminal .bg-195 { + background-color: #d7ffff; +} +.asciinema-terminal .fg-196 { + color: #ff0000; +} +.asciinema-terminal .bg-196 { + background-color: #ff0000; +} +.asciinema-terminal .fg-197 { + color: #ff005f; +} +.asciinema-terminal .bg-197 { + background-color: #ff005f; +} +.asciinema-terminal .fg-198 { + color: #ff0087; +} +.asciinema-terminal .bg-198 { + background-color: #ff0087; +} +.asciinema-terminal .fg-199 { + color: #ff00af; +} +.asciinema-terminal .bg-199 { + background-color: #ff00af; +} +.asciinema-terminal .fg-200 { + color: #ff00d7; +} +.asciinema-terminal .bg-200 { + background-color: #ff00d7; +} +.asciinema-terminal .fg-201 { + color: #ff00ff; +} +.asciinema-terminal .bg-201 { + background-color: #ff00ff; +} +.asciinema-terminal .fg-202 { + color: #ff5f00; +} +.asciinema-terminal .bg-202 { + background-color: #ff5f00; +} +.asciinema-terminal .fg-203 { + color: #ff5f5f; +} +.asciinema-terminal .bg-203 { + background-color: #ff5f5f; +} +.asciinema-terminal .fg-204 { + color: #ff5f87; +} +.asciinema-terminal .bg-204 { + background-color: #ff5f87; +} +.asciinema-terminal .fg-205 { + color: #ff5faf; +} +.asciinema-terminal .bg-205 { + background-color: #ff5faf; +} +.asciinema-terminal .fg-206 { + color: #ff5fd7; +} +.asciinema-terminal .bg-206 { + background-color: #ff5fd7; +} +.asciinema-terminal .fg-207 { + color: #ff5fff; +} +.asciinema-terminal .bg-207 { + background-color: #ff5fff; +} +.asciinema-terminal .fg-208 { + color: #ff8700; +} +.asciinema-terminal .bg-208 { + background-color: #ff8700; +} +.asciinema-terminal .fg-209 { + color: #ff875f; +} +.asciinema-terminal .bg-209 { + background-color: #ff875f; +} +.asciinema-terminal .fg-210 { + color: #ff8787; +} +.asciinema-terminal .bg-210 { + background-color: #ff8787; +} +.asciinema-terminal .fg-211 { + color: #ff87af; +} +.asciinema-terminal .bg-211 { + background-color: #ff87af; +} +.asciinema-terminal .fg-212 { + color: #ff87d7; +} +.asciinema-terminal .bg-212 { + background-color: #ff87d7; +} +.asciinema-terminal .fg-213 { + color: #ff87ff; +} +.asciinema-terminal .bg-213 { + background-color: #ff87ff; +} +.asciinema-terminal .fg-214 { + color: #ffaf00; +} +.asciinema-terminal .bg-214 { + background-color: #ffaf00; +} +.asciinema-terminal .fg-215 { + color: #ffaf5f; +} +.asciinema-terminal .bg-215 { + background-color: #ffaf5f; +} +.asciinema-terminal .fg-216 { + color: #ffaf87; +} +.asciinema-terminal .bg-216 { + background-color: #ffaf87; +} +.asciinema-terminal .fg-217 { + color: #ffafaf; +} +.asciinema-terminal .bg-217 { + background-color: #ffafaf; +} +.asciinema-terminal .fg-218 { + color: #ffafd7; +} +.asciinema-terminal .bg-218 { + background-color: #ffafd7; +} +.asciinema-terminal .fg-219 { + color: #ffafff; +} +.asciinema-terminal .bg-219 { + background-color: #ffafff; +} +.asciinema-terminal .fg-220 { + color: #ffd700; +} +.asciinema-terminal .bg-220 { + background-color: #ffd700; +} +.asciinema-terminal .fg-221 { + color: #ffd75f; +} +.asciinema-terminal .bg-221 { + background-color: #ffd75f; +} +.asciinema-terminal .fg-222 { + color: #ffd787; +} +.asciinema-terminal .bg-222 { + background-color: #ffd787; +} +.asciinema-terminal .fg-223 { + color: #ffd7af; +} +.asciinema-terminal .bg-223 { + background-color: #ffd7af; +} +.asciinema-terminal .fg-224 { + color: #ffd7d7; +} +.asciinema-terminal .bg-224 { + background-color: #ffd7d7; +} +.asciinema-terminal .fg-225 { + color: #ffd7ff; +} +.asciinema-terminal .bg-225 { + background-color: #ffd7ff; +} +.asciinema-terminal .fg-226 { + color: #ffff00; +} +.asciinema-terminal .bg-226 { + background-color: #ffff00; +} +.asciinema-terminal .fg-227 { + color: #ffff5f; +} +.asciinema-terminal .bg-227 { + background-color: #ffff5f; +} +.asciinema-terminal .fg-228 { + color: #ffff87; +} +.asciinema-terminal .bg-228 { + background-color: #ffff87; +} +.asciinema-terminal .fg-229 { + color: #ffffaf; +} +.asciinema-terminal .bg-229 { + background-color: #ffffaf; +} +.asciinema-terminal .fg-230 { + color: #ffffd7; +} +.asciinema-terminal .bg-230 { + background-color: #ffffd7; +} +.asciinema-terminal .fg-231 { + color: #ffffff; +} +.asciinema-terminal .bg-231 { + background-color: #ffffff; +} +.asciinema-terminal .fg-232 { + color: #080808; +} +.asciinema-terminal .bg-232 { + background-color: #080808; +} +.asciinema-terminal .fg-233 { + color: #121212; +} +.asciinema-terminal .bg-233 { + background-color: #121212; +} +.asciinema-terminal .fg-234 { + color: #1c1c1c; +} +.asciinema-terminal .bg-234 { + background-color: #1c1c1c; +} +.asciinema-terminal .fg-235 { + color: #262626; +} +.asciinema-terminal .bg-235 { + background-color: #262626; +} +.asciinema-terminal .fg-236 { + color: #303030; +} +.asciinema-terminal .bg-236 { + background-color: #303030; +} +.asciinema-terminal .fg-237 { + color: #3a3a3a; +} +.asciinema-terminal .bg-237 { + background-color: #3a3a3a; +} +.asciinema-terminal .fg-238 { + color: #444444; +} +.asciinema-terminal .bg-238 { + background-color: #444444; +} +.asciinema-terminal .fg-239 { + color: #4e4e4e; +} +.asciinema-terminal .bg-239 { + background-color: #4e4e4e; +} +.asciinema-terminal .fg-240 { + color: #585858; +} +.asciinema-terminal .bg-240 { + background-color: #585858; +} +.asciinema-terminal .fg-241 { + color: #626262; +} +.asciinema-terminal .bg-241 { + background-color: #626262; +} +.asciinema-terminal .fg-242 { + color: #6c6c6c; +} +.asciinema-terminal .bg-242 { + background-color: #6c6c6c; +} +.asciinema-terminal .fg-243 { + color: #767676; +} +.asciinema-terminal .bg-243 { + background-color: #767676; +} +.asciinema-terminal .fg-244 { + color: #808080; +} +.asciinema-terminal .bg-244 { + background-color: #808080; +} +.asciinema-terminal .fg-245 { + color: #8a8a8a; +} +.asciinema-terminal .bg-245 { + background-color: #8a8a8a; +} +.asciinema-terminal .fg-246 { + color: #949494; +} +.asciinema-terminal .bg-246 { + background-color: #949494; +} +.asciinema-terminal .fg-247 { + color: #9e9e9e; +} +.asciinema-terminal .bg-247 { + background-color: #9e9e9e; +} +.asciinema-terminal .fg-248 { + color: #a8a8a8; +} +.asciinema-terminal .bg-248 { + background-color: #a8a8a8; +} +.asciinema-terminal .fg-249 { + color: #b2b2b2; +} +.asciinema-terminal .bg-249 { + background-color: #b2b2b2; +} +.asciinema-terminal .fg-250 { + color: #bcbcbc; +} +.asciinema-terminal .bg-250 { + background-color: #bcbcbc; +} +.asciinema-terminal .fg-251 { + color: #c6c6c6; +} +.asciinema-terminal .bg-251 { + background-color: #c6c6c6; +} +.asciinema-terminal .fg-252 { + color: #d0d0d0; +} +.asciinema-terminal .bg-252 { + background-color: #d0d0d0; +} +.asciinema-terminal .fg-253 { + color: #dadada; +} +.asciinema-terminal .bg-253 { + background-color: #dadada; +} +.asciinema-terminal .fg-254 { + color: #e4e4e4; +} +.asciinema-terminal .bg-254 { + background-color: #e4e4e4; +} +.asciinema-terminal .fg-255 { + color: #eeeeee; +} +.asciinema-terminal .bg-255 { + background-color: #eeeeee; +} +.asciinema-theme-asciinema .asciinema-terminal { + color: #cccccc; + background-color: #121314; + border-color: #121314; +} +.asciinema-theme-asciinema .fg-bg { + color: #121314; +} +.asciinema-theme-asciinema .bg-fg { + background-color: #cccccc; +} +.asciinema-theme-asciinema .fg-0 { + color: #000000; +} +.asciinema-theme-asciinema .bg-0 { + background-color: #000000; +} +.asciinema-theme-asciinema .fg-1 { + color: #dd3c69; +} +.asciinema-theme-asciinema .bg-1 { + background-color: #dd3c69; +} +.asciinema-theme-asciinema .fg-2 { + color: #4ebf22; +} +.asciinema-theme-asciinema .bg-2 { + background-color: #4ebf22; +} +.asciinema-theme-asciinema .fg-3 { + color: #ddaf3c; +} +.asciinema-theme-asciinema .bg-3 { + background-color: #ddaf3c; +} +.asciinema-theme-asciinema .fg-4 { + color: #26b0d7; +} +.asciinema-theme-asciinema .bg-4 { + background-color: #26b0d7; +} +.asciinema-theme-asciinema .fg-5 { + color: #b954e1; +} +.asciinema-theme-asciinema .bg-5 { + background-color: #b954e1; +} +.asciinema-theme-asciinema .fg-6 { + color: #54e1b9; +} +.asciinema-theme-asciinema .bg-6 { + background-color: #54e1b9; +} +.asciinema-theme-asciinema .fg-7 { + color: #d9d9d9; +} +.asciinema-theme-asciinema .bg-7 { + background-color: #d9d9d9; +} +.asciinema-theme-asciinema .fg-8 { + color: #4d4d4d; +} +.asciinema-theme-asciinema .bg-8 { + background-color: #4d4d4d; +} +.asciinema-theme-asciinema .fg-9 { + color: #dd3c69; +} +.asciinema-theme-asciinema .bg-9 { + background-color: #dd3c69; +} +.asciinema-theme-asciinema .fg-10 { + color: #4ebf22; +} +.asciinema-theme-asciinema .bg-10 { + background-color: #4ebf22; +} +.asciinema-theme-asciinema .fg-11 { + color: #ddaf3c; +} +.asciinema-theme-asciinema .bg-11 { + background-color: #ddaf3c; +} +.asciinema-theme-asciinema .fg-12 { + color: #26b0d7; +} +.asciinema-theme-asciinema .bg-12 { + background-color: #26b0d7; +} +.asciinema-theme-asciinema .fg-13 { + color: #b954e1; +} +.asciinema-theme-asciinema .bg-13 { + background-color: #b954e1; +} +.asciinema-theme-asciinema .fg-14 { + color: #54e1b9; +} +.asciinema-theme-asciinema .bg-14 { + background-color: #54e1b9; +} +.asciinema-theme-asciinema .fg-15 { + color: #ffffff; +} +.asciinema-theme-asciinema .bg-15 { + background-color: #ffffff; +} +.asciinema-theme-asciinema .fg-8, +.asciinema-theme-asciinema .fg-9, +.asciinema-theme-asciinema .fg-10, +.asciinema-theme-asciinema .fg-11, +.asciinema-theme-asciinema .fg-12, +.asciinema-theme-asciinema .fg-13, +.asciinema-theme-asciinema .fg-14, +.asciinema-theme-asciinema .fg-15 { + font-weight: bold; +} +.asciinema-theme-tango .asciinema-terminal { + color: #cccccc; + background-color: #121314; + border-color: #121314; +} +.asciinema-theme-tango .fg-bg { + color: #121314; +} +.asciinema-theme-tango .bg-fg { + background-color: #cccccc; +} +.asciinema-theme-tango .fg-0 { + color: #000000; +} +.asciinema-theme-tango .bg-0 { + background-color: #000000; +} +.asciinema-theme-tango .fg-1 { + color: #cc0000; +} +.asciinema-theme-tango .bg-1 { + background-color: #cc0000; +} +.asciinema-theme-tango .fg-2 { + color: #4e9a06; +} +.asciinema-theme-tango .bg-2 { + background-color: #4e9a06; +} +.asciinema-theme-tango .fg-3 { + color: #c4a000; +} +.asciinema-theme-tango .bg-3 { + background-color: #c4a000; +} +.asciinema-theme-tango .fg-4 { + color: #3465a4; +} +.asciinema-theme-tango .bg-4 { + background-color: #3465a4; +} +.asciinema-theme-tango .fg-5 { + color: #75507b; +} +.asciinema-theme-tango .bg-5 { + background-color: #75507b; +} +.asciinema-theme-tango .fg-6 { + color: #06989a; +} +.asciinema-theme-tango .bg-6 { + background-color: #06989a; +} +.asciinema-theme-tango .fg-7 { + color: #d3d7cf; +} +.asciinema-theme-tango .bg-7 { + background-color: #d3d7cf; +} +.asciinema-theme-tango .fg-8 { + color: #555753; +} +.asciinema-theme-tango .bg-8 { + background-color: #555753; +} +.asciinema-theme-tango .fg-9 { + color: #ef2929; +} +.asciinema-theme-tango .bg-9 { + background-color: #ef2929; +} +.asciinema-theme-tango .fg-10 { + color: #8ae234; +} +.asciinema-theme-tango .bg-10 { + background-color: #8ae234; +} +.asciinema-theme-tango .fg-11 { + color: #fce94f; +} +.asciinema-theme-tango .bg-11 { + background-color: #fce94f; +} +.asciinema-theme-tango .fg-12 { + color: #729fcf; +} +.asciinema-theme-tango .bg-12 { + background-color: #729fcf; +} +.asciinema-theme-tango .fg-13 { + color: #ad7fa8; +} +.asciinema-theme-tango .bg-13 { + background-color: #ad7fa8; +} +.asciinema-theme-tango .fg-14 { + color: #34e2e2; +} +.asciinema-theme-tango .bg-14 { + background-color: #34e2e2; +} +.asciinema-theme-tango .fg-15 { + color: #eeeeec; +} +.asciinema-theme-tango .bg-15 { + background-color: #eeeeec; +} +.asciinema-theme-tango .fg-8, +.asciinema-theme-tango .fg-9, +.asciinema-theme-tango .fg-10, +.asciinema-theme-tango .fg-11, +.asciinema-theme-tango .fg-12, +.asciinema-theme-tango .fg-13, +.asciinema-theme-tango .fg-14, +.asciinema-theme-tango .fg-15 { + font-weight: bold; +} +.asciinema-theme-solarized-dark .asciinema-terminal { + color: #839496; + background-color: #002b36; + border-color: #002b36; +} +.asciinema-theme-solarized-dark .fg-bg { + color: #002b36; +} +.asciinema-theme-solarized-dark .bg-fg { + background-color: #839496; +} +.asciinema-theme-solarized-dark .fg-0 { + color: #073642; +} +.asciinema-theme-solarized-dark .bg-0 { + background-color: #073642; +} +.asciinema-theme-solarized-dark .fg-1 { + color: #dc322f; +} +.asciinema-theme-solarized-dark .bg-1 { + background-color: #dc322f; +} +.asciinema-theme-solarized-dark .fg-2 { + color: #859900; +} +.asciinema-theme-solarized-dark .bg-2 { + background-color: #859900; +} +.asciinema-theme-solarized-dark .fg-3 { + color: #b58900; +} +.asciinema-theme-solarized-dark .bg-3 { + background-color: #b58900; +} +.asciinema-theme-solarized-dark .fg-4 { + color: #268bd2; +} +.asciinema-theme-solarized-dark .bg-4 { + background-color: #268bd2; +} +.asciinema-theme-solarized-dark .fg-5 { + color: #d33682; +} +.asciinema-theme-solarized-dark .bg-5 { + background-color: #d33682; +} +.asciinema-theme-solarized-dark .fg-6 { + color: #2aa198; +} +.asciinema-theme-solarized-dark .bg-6 { + background-color: #2aa198; +} +.asciinema-theme-solarized-dark .fg-7 { + color: #eee8d5; +} +.asciinema-theme-solarized-dark .bg-7 { + background-color: #eee8d5; +} +.asciinema-theme-solarized-dark .fg-8 { + color: #002b36; +} +.asciinema-theme-solarized-dark .bg-8 { + background-color: #002b36; +} +.asciinema-theme-solarized-dark .fg-9 { + color: #cb4b16; +} +.asciinema-theme-solarized-dark .bg-9 { + background-color: #cb4b16; +} +.asciinema-theme-solarized-dark .fg-10 { + color: #586e75; +} +.asciinema-theme-solarized-dark .bg-10 { + background-color: #586e75; +} +.asciinema-theme-solarized-dark .fg-11 { + color: #657b83; +} +.asciinema-theme-solarized-dark .bg-11 { + background-color: #657b83; +} +.asciinema-theme-solarized-dark .fg-12 { + color: #839496; +} +.asciinema-theme-solarized-dark .bg-12 { + background-color: #839496; +} +.asciinema-theme-solarized-dark .fg-13 { + color: #6c71c4; +} +.asciinema-theme-solarized-dark .bg-13 { + background-color: #6c71c4; +} +.asciinema-theme-solarized-dark .fg-14 { + color: #93a1a1; +} +.asciinema-theme-solarized-dark .bg-14 { + background-color: #93a1a1; +} +.asciinema-theme-solarized-dark .fg-15 { + color: #fdf6e3; +} +.asciinema-theme-solarized-dark .bg-15 { + background-color: #fdf6e3; +} +.asciinema-theme-solarized-light .asciinema-terminal { + color: #657b83; + background-color: #fdf6e3; + border-color: #fdf6e3; +} +.asciinema-theme-solarized-light .fg-bg { + color: #fdf6e3; +} +.asciinema-theme-solarized-light .bg-fg { + background-color: #657b83; +} +.asciinema-theme-solarized-light .fg-0 { + color: #073642; +} +.asciinema-theme-solarized-light .bg-0 { + background-color: #073642; +} +.asciinema-theme-solarized-light .fg-1 { + color: #dc322f; +} +.asciinema-theme-solarized-light .bg-1 { + background-color: #dc322f; +} +.asciinema-theme-solarized-light .fg-2 { + color: #859900; +} +.asciinema-theme-solarized-light .bg-2 { + background-color: #859900; +} +.asciinema-theme-solarized-light .fg-3 { + color: #b58900; +} +.asciinema-theme-solarized-light .bg-3 { + background-color: #b58900; +} +.asciinema-theme-solarized-light .fg-4 { + color: #268bd2; +} +.asciinema-theme-solarized-light .bg-4 { + background-color: #268bd2; +} +.asciinema-theme-solarized-light .fg-5 { + color: #d33682; +} +.asciinema-theme-solarized-light .bg-5 { + background-color: #d33682; +} +.asciinema-theme-solarized-light .fg-6 { + color: #2aa198; +} +.asciinema-theme-solarized-light .bg-6 { + background-color: #2aa198; +} +.asciinema-theme-solarized-light .fg-7 { + color: #eee8d5; +} +.asciinema-theme-solarized-light .bg-7 { + background-color: #eee8d5; +} +.asciinema-theme-solarized-light .fg-8 { + color: #002b36; +} +.asciinema-theme-solarized-light .bg-8 { + background-color: #002b36; +} +.asciinema-theme-solarized-light .fg-9 { + color: #cb4b16; +} +.asciinema-theme-solarized-light .bg-9 { + background-color: #cb4b16; +} +.asciinema-theme-solarized-light .fg-10 { + color: #586e75; +} +.asciinema-theme-solarized-light .bg-10 { + background-color: #586e75; +} +.asciinema-theme-solarized-light .fg-11 { + color: #657c83; +} +.asciinema-theme-solarized-light .bg-11 { + background-color: #657c83; +} +.asciinema-theme-solarized-light .fg-12 { + color: #839496; +} +.asciinema-theme-solarized-light .bg-12 { + background-color: #839496; +} +.asciinema-theme-solarized-light .fg-13 { + color: #6c71c4; +} +.asciinema-theme-solarized-light .bg-13 { + background-color: #6c71c4; +} +.asciinema-theme-solarized-light .fg-14 { + color: #93a1a1; +} +.asciinema-theme-solarized-light .bg-14 { + background-color: #93a1a1; +} +.asciinema-theme-solarized-light .fg-15 { + color: #fdf6e3; +} +.asciinema-theme-solarized-light .bg-15 { + background-color: #fdf6e3; +} +.asciinema-theme-seti .asciinema-terminal { + color: #cacecd; + background-color: #111213; + border-color: #111213; +} +.asciinema-theme-seti .fg-bg { + color: #111213; +} +.asciinema-theme-seti .bg-fg { + background-color: #cacecd; +} +.asciinema-theme-seti .fg-0 { + color: #323232; +} +.asciinema-theme-seti .bg-0 { + background-color: #323232; +} +.asciinema-theme-seti .fg-1 { + color: #c22832; +} +.asciinema-theme-seti .bg-1 { + background-color: #c22832; +} +.asciinema-theme-seti .fg-2 { + color: #8ec43d; +} +.asciinema-theme-seti .bg-2 { + background-color: #8ec43d; +} +.asciinema-theme-seti .fg-3 { + color: #e0c64f; +} +.asciinema-theme-seti .bg-3 { + background-color: #e0c64f; +} +.asciinema-theme-seti .fg-4 { + color: #43a5d5; +} +.asciinema-theme-seti .bg-4 { + background-color: #43a5d5; +} +.asciinema-theme-seti .fg-5 { + color: #8b57b5; +} +.asciinema-theme-seti .bg-5 { + background-color: #8b57b5; +} +.asciinema-theme-seti .fg-6 { + color: #8ec43d; +} +.asciinema-theme-seti .bg-6 { + background-color: #8ec43d; +} +.asciinema-theme-seti .fg-7 { + color: #eeeeee; +} +.asciinema-theme-seti .bg-7 { + background-color: #eeeeee; +} +.asciinema-theme-seti .fg-8 { + color: #323232; +} +.asciinema-theme-seti .bg-8 { + background-color: #323232; +} +.asciinema-theme-seti .fg-9 { + color: #c22832; +} +.asciinema-theme-seti .bg-9 { + background-color: #c22832; +} +.asciinema-theme-seti .fg-10 { + color: #8ec43d; +} +.asciinema-theme-seti .bg-10 { + background-color: #8ec43d; +} +.asciinema-theme-seti .fg-11 { + color: #e0c64f; +} +.asciinema-theme-seti .bg-11 { + background-color: #e0c64f; +} +.asciinema-theme-seti .fg-12 { + color: #43a5d5; +} +.asciinema-theme-seti .bg-12 { + background-color: #43a5d5; +} +.asciinema-theme-seti .fg-13 { + color: #8b57b5; +} +.asciinema-theme-seti .bg-13 { + background-color: #8b57b5; +} +.asciinema-theme-seti .fg-14 { + color: #8ec43d; +} +.asciinema-theme-seti .bg-14 { + background-color: #8ec43d; +} +.asciinema-theme-seti .fg-15 { + color: #ffffff; +} +.asciinema-theme-seti .bg-15 { + background-color: #ffffff; +} +.asciinema-theme-seti .fg-8, +.asciinema-theme-seti .fg-9, +.asciinema-theme-seti .fg-10, +.asciinema-theme-seti .fg-11, +.asciinema-theme-seti .fg-12, +.asciinema-theme-seti .fg-13, +.asciinema-theme-seti .fg-14, +.asciinema-theme-seti .fg-15 { + font-weight: bold; +} +/* Based on Monokai from base16 collection - https://github.com/chriskempson/base16 */ +.asciinema-theme-monokai .asciinema-terminal { + color: #f8f8f2; + background-color: #272822; + border-color: #272822; +} +.asciinema-theme-monokai .fg-bg { + color: #272822; +} +.asciinema-theme-monokai .bg-fg { + background-color: #f8f8f2; +} +.asciinema-theme-monokai .fg-0 { + color: #272822; +} +.asciinema-theme-monokai .bg-0 { + background-color: #272822; +} +.asciinema-theme-monokai .fg-1 { + color: #f92672; +} +.asciinema-theme-monokai .bg-1 { + background-color: #f92672; +} +.asciinema-theme-monokai .fg-2 { + color: #a6e22e; +} +.asciinema-theme-monokai .bg-2 { + background-color: #a6e22e; +} +.asciinema-theme-monokai .fg-3 { + color: #f4bf75; +} +.asciinema-theme-monokai .bg-3 { + background-color: #f4bf75; +} +.asciinema-theme-monokai .fg-4 { + color: #66d9ef; +} +.asciinema-theme-monokai .bg-4 { + background-color: #66d9ef; +} +.asciinema-theme-monokai .fg-5 { + color: #ae81ff; +} +.asciinema-theme-monokai .bg-5 { + background-color: #ae81ff; +} +.asciinema-theme-monokai .fg-6 { + color: #a1efe4; +} +.asciinema-theme-monokai .bg-6 { + background-color: #a1efe4; +} +.asciinema-theme-monokai .fg-7 { + color: #f8f8f2; +} +.asciinema-theme-monokai .bg-7 { + background-color: #f8f8f2; +} +.asciinema-theme-monokai .fg-8 { + color: #75715e; +} +.asciinema-theme-monokai .bg-8 { + background-color: #75715e; +} +.asciinema-theme-monokai .fg-9 { + color: #f92672; +} +.asciinema-theme-monokai .bg-9 { + background-color: #f92672; +} +.asciinema-theme-monokai .fg-10 { + color: #a6e22e; +} +.asciinema-theme-monokai .bg-10 { + background-color: #a6e22e; +} +.asciinema-theme-monokai .fg-11 { + color: #f4bf75; +} +.asciinema-theme-monokai .bg-11 { + background-color: #f4bf75; +} +.asciinema-theme-monokai .fg-12 { + color: #66d9ef; +} +.asciinema-theme-monokai .bg-12 { + background-color: #66d9ef; +} +.asciinema-theme-monokai .fg-13 { + color: #ae81ff; +} +.asciinema-theme-monokai .bg-13 { + background-color: #ae81ff; +} +.asciinema-theme-monokai .fg-14 { + color: #a1efe4; +} +.asciinema-theme-monokai .bg-14 { + background-color: #a1efe4; +} +.asciinema-theme-monokai .fg-15 { + color: #f9f8f5; +} +.asciinema-theme-monokai .bg-15 { + background-color: #f9f8f5; +} +.asciinema-theme-monokai .fg-8, +.asciinema-theme-monokai .fg-9, +.asciinema-theme-monokai .fg-10, +.asciinema-theme-monokai .fg-11, +.asciinema-theme-monokai .fg-12, +.asciinema-theme-monokai .fg-13, +.asciinema-theme-monokai .fg-14, +.asciinema-theme-monokai .fg-15 { + font-weight: bold; +} diff --git a/refs/pull/405/merge/_static/asciinema-player.js b/refs/pull/405/merge/_static/asciinema-player.js new file mode 100644 index 00000000..5ad47e08 --- /dev/null +++ b/refs/pull/405/merge/_static/asciinema-player.js @@ -0,0 +1,1213 @@ +/** + * asciinema-player v2.6.1 + * + * Copyright 2011-2018, Marcin Kulik + * + */ + +// CustomEvent polyfill from MDN (https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent) + +(function () { + if (typeof window.CustomEvent === "function") return false; + + function CustomEvent ( event, params ) { + params = params || { bubbles: false, cancelable: false, detail: undefined }; + var evt = document.createEvent( 'CustomEvent'); + evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); + return evt; + } + + CustomEvent.prototype = window.Event.prototype; + + window.CustomEvent = CustomEvent; +})(); + +/** + * @license + * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. + * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt + * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt + * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt + * Code distributed by Google as part of the polymer project is also + * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt + */ +// @version 0.7.22 +"undefined"==typeof WeakMap&&!function(){var e=Object.defineProperty,t=Date.now()%1e9,n=function(){this.name="__st"+(1e9*Math.random()>>>0)+(t++ +"__")};n.prototype={set:function(t,n){var o=t[this.name];return o&&o[0]===t?o[1]=n:e(t,this.name,{value:[t,n],writable:!0}),this},get:function(e){var t;return(t=e[this.name])&&t[0]===e?t[1]:void 0},"delete":function(e){var t=e[this.name];return t&&t[0]===e?(t[0]=t[1]=void 0,!0):!1},has:function(e){var t=e[this.name];return t?t[0]===e:!1}},window.WeakMap=n}(),function(e){function t(e){E.push(e),b||(b=!0,w(o))}function n(e){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(e)||e}function o(){b=!1;var e=E;E=[],e.sort(function(e,t){return e.uid_-t.uid_});var t=!1;e.forEach(function(e){var n=e.takeRecords();r(e),n.length&&(e.callback_(n,e),t=!0)}),t&&o()}function r(e){e.nodes_.forEach(function(t){var n=v.get(t);n&&n.forEach(function(t){t.observer===e&&t.removeTransientObservers()})})}function i(e,t){for(var n=e;n;n=n.parentNode){var o=v.get(n);if(o)for(var r=0;r<o.length;r++){var i=o[r],a=i.options;if(n===e||a.subtree){var d=t(a);d&&i.enqueue(d)}}}}function a(e){this.callback_=e,this.nodes_=[],this.records_=[],this.uid_=++_}function d(e,t){this.type=e,this.target=t,this.addedNodes=[],this.removedNodes=[],this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function s(e){var t=new d(e.type,e.target);return t.addedNodes=e.addedNodes.slice(),t.removedNodes=e.removedNodes.slice(),t.previousSibling=e.previousSibling,t.nextSibling=e.nextSibling,t.attributeName=e.attributeName,t.attributeNamespace=e.attributeNamespace,t.oldValue=e.oldValue,t}function u(e,t){return y=new d(e,t)}function c(e){return N?N:(N=s(y),N.oldValue=e,N)}function l(){y=N=void 0}function f(e){return e===N||e===y}function p(e,t){return e===t?e:N&&f(e)?N:null}function m(e,t,n){this.observer=e,this.target=t,this.options=n,this.transientObservedNodes=[]}if(!e.JsMutationObserver){var w,v=new WeakMap;if(/Trident|Edge/.test(navigator.userAgent))w=setTimeout;else if(window.setImmediate)w=window.setImmediate;else{var h=[],g=String(Math.random());window.addEventListener("message",function(e){if(e.data===g){var t=h;h=[],t.forEach(function(e){e()})}}),w=function(e){h.push(e),window.postMessage(g,"*")}}var b=!1,E=[],_=0;a.prototype={observe:function(e,t){if(e=n(e),!t.childList&&!t.attributes&&!t.characterData||t.attributeOldValue&&!t.attributes||t.attributeFilter&&t.attributeFilter.length&&!t.attributes||t.characterDataOldValue&&!t.characterData)throw new SyntaxError;var o=v.get(e);o||v.set(e,o=[]);for(var r,i=0;i<o.length;i++)if(o[i].observer===this){r=o[i],r.removeListeners(),r.options=t;break}r||(r=new m(this,e,t),o.push(r),this.nodes_.push(e)),r.addListeners()},disconnect:function(){this.nodes_.forEach(function(e){for(var t=v.get(e),n=0;n<t.length;n++){var o=t[n];if(o.observer===this){o.removeListeners(),t.splice(n,1);break}}},this),this.records_=[]},takeRecords:function(){var e=this.records_;return this.records_=[],e}};var y,N;m.prototype={enqueue:function(e){var n=this.observer.records_,o=n.length;if(n.length>0){var r=n[o-1],i=p(r,e);if(i)return void(n[o-1]=i)}else t(this.observer);n[o]=e},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(e){var t=this.options;t.attributes&&e.addEventListener("DOMAttrModified",this,!0),t.characterData&&e.addEventListener("DOMCharacterDataModified",this,!0),t.childList&&e.addEventListener("DOMNodeInserted",this,!0),(t.childList||t.subtree)&&e.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(e){var t=this.options;t.attributes&&e.removeEventListener("DOMAttrModified",this,!0),t.characterData&&e.removeEventListener("DOMCharacterDataModified",this,!0),t.childList&&e.removeEventListener("DOMNodeInserted",this,!0),(t.childList||t.subtree)&&e.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(e){if(e!==this.target){this.addListeners_(e),this.transientObservedNodes.push(e);var t=v.get(e);t||v.set(e,t=[]),t.push(this)}},removeTransientObservers:function(){var e=this.transientObservedNodes;this.transientObservedNodes=[],e.forEach(function(e){this.removeListeners_(e);for(var t=v.get(e),n=0;n<t.length;n++)if(t[n]===this){t.splice(n,1);break}},this)},handleEvent:function(e){switch(e.stopImmediatePropagation(),e.type){case"DOMAttrModified":var t=e.attrName,n=e.relatedNode.namespaceURI,o=e.target,r=new u("attributes",o);r.attributeName=t,r.attributeNamespace=n;var a=e.attrChange===MutationEvent.ADDITION?null:e.prevValue;i(o,function(e){return!e.attributes||e.attributeFilter&&e.attributeFilter.length&&-1===e.attributeFilter.indexOf(t)&&-1===e.attributeFilter.indexOf(n)?void 0:e.attributeOldValue?c(a):r});break;case"DOMCharacterDataModified":var o=e.target,r=u("characterData",o),a=e.prevValue;i(o,function(e){return e.characterData?e.characterDataOldValue?c(a):r:void 0});break;case"DOMNodeRemoved":this.addTransientObserver(e.target);case"DOMNodeInserted":var d,s,f=e.target;"DOMNodeInserted"===e.type?(d=[f],s=[]):(d=[],s=[f]);var p=f.previousSibling,m=f.nextSibling,r=u("childList",e.target.parentNode);r.addedNodes=d,r.removedNodes=s,r.previousSibling=p,r.nextSibling=m,i(e.relatedNode,function(e){return e.childList?r:void 0})}l()}},e.JsMutationObserver=a,e.MutationObserver||(e.MutationObserver=a,a._isPolyfilled=!0)}}(self),function(e){"use strict";if(!window.performance){var t=Date.now();window.performance={now:function(){return Date.now()-t}}}window.requestAnimationFrame||(window.requestAnimationFrame=function(){var e=window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame;return e?function(t){return e(function(){t(performance.now())})}:function(e){return window.setTimeout(e,1e3/60)}}()),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(){return window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||function(e){clearTimeout(e)}}());var n=function(){var e=document.createEvent("Event");return e.initEvent("foo",!0,!0),e.preventDefault(),e.defaultPrevented}();if(!n){var o=Event.prototype.preventDefault;Event.prototype.preventDefault=function(){this.cancelable&&(o.call(this),Object.defineProperty(this,"defaultPrevented",{get:function(){return!0},configurable:!0}))}}var r=/Trident/.test(navigator.userAgent);if((!window.CustomEvent||r&&"function"!=typeof window.CustomEvent)&&(window.CustomEvent=function(e,t){t=t||{};var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,Boolean(t.bubbles),Boolean(t.cancelable),t.detail),n},window.CustomEvent.prototype=window.Event.prototype),!window.Event||r&&"function"!=typeof window.Event){var i=window.Event;window.Event=function(e,t){t=t||{};var n=document.createEvent("Event");return n.initEvent(e,Boolean(t.bubbles),Boolean(t.cancelable)),n},window.Event.prototype=i.prototype}}(window.WebComponents),window.CustomElements=window.CustomElements||{flags:{}},function(e){var t=e.flags,n=[],o=function(e){n.push(e)},r=function(){n.forEach(function(t){t(e)})};e.addModule=o,e.initializeModules=r,e.hasNative=Boolean(document.registerElement),e.isIE=/Trident/.test(navigator.userAgent),e.useNative=!t.register&&e.hasNative&&!window.ShadowDOMPolyfill&&(!window.HTMLImports||window.HTMLImports.useNative)}(window.CustomElements),window.CustomElements.addModule(function(e){function t(e,t){n(e,function(e){return t(e)?!0:void o(e,t)}),o(e,t)}function n(e,t,o){var r=e.firstElementChild;if(!r)for(r=e.firstChild;r&&r.nodeType!==Node.ELEMENT_NODE;)r=r.nextSibling;for(;r;)t(r,o)!==!0&&n(r,t,o),r=r.nextElementSibling;return null}function o(e,n){for(var o=e.shadowRoot;o;)t(o,n),o=o.olderShadowRoot}function r(e,t){i(e,t,[])}function i(e,t,n){if(e=window.wrap(e),!(n.indexOf(e)>=0)){n.push(e);for(var o,r=e.querySelectorAll("link[rel="+a+"]"),d=0,s=r.length;s>d&&(o=r[d]);d++)o["import"]&&i(o["import"],t,n);t(e)}}var a=window.HTMLImports?window.HTMLImports.IMPORT_LINK_TYPE:"none";e.forDocumentTree=r,e.forSubtree=t}),window.CustomElements.addModule(function(e){function t(e,t){return n(e,t)||o(e,t)}function n(t,n){return e.upgrade(t,n)?!0:void(n&&a(t))}function o(e,t){b(e,function(e){return n(e,t)?!0:void 0})}function r(e){N.push(e),y||(y=!0,setTimeout(i))}function i(){y=!1;for(var e,t=N,n=0,o=t.length;o>n&&(e=t[n]);n++)e();N=[]}function a(e){_?r(function(){d(e)}):d(e)}function d(e){e.__upgraded__&&!e.__attached&&(e.__attached=!0,e.attachedCallback&&e.attachedCallback())}function s(e){u(e),b(e,function(e){u(e)})}function u(e){_?r(function(){c(e)}):c(e)}function c(e){e.__upgraded__&&e.__attached&&(e.__attached=!1,e.detachedCallback&&e.detachedCallback())}function l(e){for(var t=e,n=window.wrap(document);t;){if(t==n)return!0;t=t.parentNode||t.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&t.host}}function f(e){if(e.shadowRoot&&!e.shadowRoot.__watched){g.dom&&console.log("watching shadow-root for: ",e.localName);for(var t=e.shadowRoot;t;)w(t),t=t.olderShadowRoot}}function p(e,n){if(g.dom){var o=n[0];if(o&&"childList"===o.type&&o.addedNodes&&o.addedNodes){for(var r=o.addedNodes[0];r&&r!==document&&!r.host;)r=r.parentNode;var i=r&&(r.URL||r._URL||r.host&&r.host.localName)||"";i=i.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",n.length,i||"")}var a=l(e);n.forEach(function(e){"childList"===e.type&&(M(e.addedNodes,function(e){e.localName&&t(e,a)}),M(e.removedNodes,function(e){e.localName&&s(e)}))}),g.dom&&console.groupEnd()}function m(e){for(e=window.wrap(e),e||(e=window.wrap(document));e.parentNode;)e=e.parentNode;var t=e.__observer;t&&(p(e,t.takeRecords()),i())}function w(e){if(!e.__observer){var t=new MutationObserver(p.bind(this,e));t.observe(e,{childList:!0,subtree:!0}),e.__observer=t}}function v(e){e=window.wrap(e),g.dom&&console.group("upgradeDocument: ",e.baseURI.split("/").pop());var n=e===window.wrap(document);t(e,n),w(e),g.dom&&console.groupEnd()}function h(e){E(e,v)}var g=e.flags,b=e.forSubtree,E=e.forDocumentTree,_=window.MutationObserver._isPolyfilled&&g["throttle-attached"];e.hasPolyfillMutations=_,e.hasThrottledAttached=_;var y=!1,N=[],M=Array.prototype.forEach.call.bind(Array.prototype.forEach),O=Element.prototype.createShadowRoot;O&&(Element.prototype.createShadowRoot=function(){var e=O.call(this);return window.CustomElements.watchShadow(this),e}),e.watchShadow=f,e.upgradeDocumentTree=h,e.upgradeDocument=v,e.upgradeSubtree=o,e.upgradeAll=t,e.attached=a,e.takeRecords=m}),window.CustomElements.addModule(function(e){function t(t,o){if("template"===t.localName&&window.HTMLTemplateElement&&HTMLTemplateElement.decorate&&HTMLTemplateElement.decorate(t),!t.__upgraded__&&t.nodeType===Node.ELEMENT_NODE){var r=t.getAttribute("is"),i=e.getRegisteredDefinition(t.localName)||e.getRegisteredDefinition(r);if(i&&(r&&i.tag==t.localName||!r&&!i["extends"]))return n(t,i,o)}}function n(t,n,r){return a.upgrade&&console.group("upgrade:",t.localName),n.is&&t.setAttribute("is",n.is),o(t,n),t.__upgraded__=!0,i(t),r&&e.attached(t),e.upgradeSubtree(t,r),a.upgrade&&console.groupEnd(),t}function o(e,t){Object.__proto__?e.__proto__=t.prototype:(r(e,t.prototype,t["native"]),e.__proto__=t.prototype)}function r(e,t,n){for(var o={},r=t;r!==n&&r!==HTMLElement.prototype;){for(var i,a=Object.getOwnPropertyNames(r),d=0;i=a[d];d++)o[i]||(Object.defineProperty(e,i,Object.getOwnPropertyDescriptor(r,i)),o[i]=1);r=Object.getPrototypeOf(r)}}function i(e){e.createdCallback&&e.createdCallback()}var a=e.flags;e.upgrade=t,e.upgradeWithDefinition=n,e.implementPrototype=o}),window.CustomElements.addModule(function(e){function t(t,o){var s=o||{};if(!t)throw new Error("document.registerElement: first argument `name` must not be empty");if(t.indexOf("-")<0)throw new Error("document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '"+String(t)+"'.");if(r(t))throw new Error("Failed to execute 'registerElement' on 'Document': Registration failed for type '"+String(t)+"'. The type name is invalid.");if(u(t))throw new Error("DuplicateDefinitionError: a type with name '"+String(t)+"' is already registered");return s.prototype||(s.prototype=Object.create(HTMLElement.prototype)),s.__name=t.toLowerCase(),s["extends"]&&(s["extends"]=s["extends"].toLowerCase()),s.lifecycle=s.lifecycle||{},s.ancestry=i(s["extends"]),a(s),d(s),n(s.prototype),c(s.__name,s),s.ctor=l(s),s.ctor.prototype=s.prototype,s.prototype.constructor=s.ctor,e.ready&&v(document),s.ctor}function n(e){if(!e.setAttribute._polyfilled){var t=e.setAttribute;e.setAttribute=function(e,n){o.call(this,e,n,t)};var n=e.removeAttribute;e.removeAttribute=function(e){o.call(this,e,null,n)},e.setAttribute._polyfilled=!0}}function o(e,t,n){e=e.toLowerCase();var o=this.getAttribute(e);n.apply(this,arguments);var r=this.getAttribute(e);this.attributeChangedCallback&&r!==o&&this.attributeChangedCallback(e,o,r)}function r(e){for(var t=0;t<_.length;t++)if(e===_[t])return!0}function i(e){var t=u(e);return t?i(t["extends"]).concat([t]):[]}function a(e){for(var t,n=e["extends"],o=0;t=e.ancestry[o];o++)n=t.is&&t.tag;e.tag=n||e.__name,n&&(e.is=e.__name)}function d(e){if(!Object.__proto__){var t=HTMLElement.prototype;if(e.is){var n=document.createElement(e.tag);t=Object.getPrototypeOf(n)}for(var o,r=e.prototype,i=!1;r;)r==t&&(i=!0),o=Object.getPrototypeOf(r),o&&(r.__proto__=o),r=o;i||console.warn(e.tag+" prototype not found in prototype chain for "+e.is),e["native"]=t}}function s(e){return g(M(e.tag),e)}function u(e){return e?y[e.toLowerCase()]:void 0}function c(e,t){y[e]=t}function l(e){return function(){return s(e)}}function f(e,t,n){return e===N?p(t,n):O(e,t)}function p(e,t){e&&(e=e.toLowerCase()),t&&(t=t.toLowerCase());var n=u(t||e);if(n){if(e==n.tag&&t==n.is)return new n.ctor;if(!t&&!n.is)return new n.ctor}var o;return t?(o=p(e),o.setAttribute("is",t),o):(o=M(e),e.indexOf("-")>=0&&b(o,HTMLElement),o)}function m(e,t){var n=e[t];e[t]=function(){var e=n.apply(this,arguments);return h(e),e}}var w,v=(e.isIE,e.upgradeDocumentTree),h=e.upgradeAll,g=e.upgradeWithDefinition,b=e.implementPrototype,E=e.useNative,_=["annotation-xml","color-profile","font-face","font-face-src","font-face-uri","font-face-format","font-face-name","missing-glyph"],y={},N="http://www.w3.org/1999/xhtml",M=document.createElement.bind(document),O=document.createElementNS.bind(document);w=Object.__proto__||E?function(e,t){return e instanceof t}:function(e,t){if(e instanceof t)return!0;for(var n=e;n;){if(n===t.prototype)return!0;n=n.__proto__}return!1},m(Node.prototype,"cloneNode"),m(document,"importNode"),document.registerElement=t,document.createElement=p,document.createElementNS=f,e.registry=y,e["instanceof"]=w,e.reservedTagList=_,e.getRegisteredDefinition=u,document.register=document.registerElement}),function(e){function t(){i(window.wrap(document)),window.CustomElements.ready=!0;var e=window.requestAnimationFrame||function(e){setTimeout(e,16)};e(function(){setTimeout(function(){window.CustomElements.readyTime=Date.now(),window.HTMLImports&&(window.CustomElements.elapsed=window.CustomElements.readyTime-window.HTMLImports.readyTime),document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})})}var n=e.useNative,o=e.initializeModules;e.isIE;if(n){var r=function(){};e.watchShadow=r,e.upgrade=r,e.upgradeAll=r,e.upgradeDocumentTree=r,e.upgradeSubtree=r,e.takeRecords=r,e["instanceof"]=function(e,t){return e instanceof t}}else o();var i=e.upgradeDocumentTree,a=e.upgradeDocument;if(window.wrap||(window.ShadowDOMPolyfill?(window.wrap=window.ShadowDOMPolyfill.wrapIfNeeded,window.unwrap=window.ShadowDOMPolyfill.unwrapIfNeeded):window.wrap=window.unwrap=function(e){return e}),window.HTMLImports&&(window.HTMLImports.__importsParsingHook=function(e){e["import"]&&a(wrap(e["import"]))}),"complete"===document.readyState||e.flags.eager)t();else if("interactive"!==document.readyState||window.attachEvent||window.HTMLImports&&!window.HTMLImports.ready){var d=window.HTMLImports&&!window.HTMLImports.ready?"HTMLImportsLoaded":"DOMContentLoaded";window.addEventListener(d,t)}else t()}(window.CustomElements); +if(typeof Math.imul == "undefined" || (Math.imul(0xffffffff,5) == 0)) { + Math.imul = function (a, b) { + var ah = (a >>> 16) & 0xffff; + var al = a & 0xffff; + var bh = (b >>> 16) & 0xffff; + var bl = b & 0xffff; + // the shift by 0 fixes the sign on the high part + // the final |0 converts the unsigned value into a signed value + return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0)|0); + } +} + +/** + * React v15.5.4 + * + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ +!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.React=t()}}(function(){return function t(e,n,r){function o(u,a){if(!n[u]){if(!e[u]){var s="function"==typeof require&&require;if(!a&&s)return s(u,!0);if(i)return i(u,!0);var c=new Error("Cannot find module '"+u+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[u]={exports:{}};e[u][0].call(l.exports,function(t){var n=e[u][1][t];return o(n||t)},l,l.exports,t,e,n,r)}return n[u].exports}for(var i="function"==typeof require&&require,u=0;u<r.length;u++)o(r[u]);return o}({1:[function(t,e,n){"use strict";function r(t){var e={"=":"=0",":":"=2"};return"$"+(""+t).replace(/[=:]/g,function(t){return e[t]})}function o(t){var e={"=0":"=","=2":":"};return(""+("."===t[0]&&"$"===t[1]?t.substring(2):t.substring(1))).replace(/(=0|=2)/g,function(t){return e[t]})}var i={escape:r,unescape:o};e.exports=i},{}],2:[function(t,e,n){"use strict";var r=t(20),o=(t(24),function(t){var e=this;if(e.instancePool.length){var n=e.instancePool.pop();return e.call(n,t),n}return new e(t)}),i=function(t,e){var n=this;if(n.instancePool.length){var r=n.instancePool.pop();return n.call(r,t,e),r}return new n(t,e)},u=function(t,e,n){var r=this;if(r.instancePool.length){var o=r.instancePool.pop();return r.call(o,t,e,n),o}return new r(t,e,n)},a=function(t,e,n,r){var o=this;if(o.instancePool.length){var i=o.instancePool.pop();return o.call(i,t,e,n,r),i}return new o(t,e,n,r)},s=function(t){var e=this;t instanceof e||r("25"),t.destructor(),e.instancePool.length<e.poolSize&&e.instancePool.push(t)},c=o,l=function(t,e){var n=t;return n.instancePool=[],n.getPooled=e||c,n.poolSize||(n.poolSize=10),n.release=s,n},f={addPoolingTo:l,oneArgumentPooler:o,twoArgumentPooler:i,threeArgumentPooler:u,fourArgumentPooler:a};e.exports=f},{20:20,24:24}],3:[function(t,e,n){"use strict";var r=t(26),o=t(4),i=t(6),u=t(14),a=t(5),s=t(8),c=t(9),l=t(13),f=t(16),p=t(19),d=(t(25),c.createElement),y=c.createFactory,h=c.cloneElement,v=r,m={Children:{map:o.map,forEach:o.forEach,count:o.count,toArray:o.toArray,only:p},Component:i,PureComponent:u,createElement:d,cloneElement:h,isValidElement:c.isValidElement,PropTypes:l,createClass:a.createClass,createFactory:y,createMixin:function(t){return t},DOM:s,version:f,__spread:v};e.exports=m},{13:13,14:14,16:16,19:19,25:25,26:26,4:4,5:5,6:6,8:8,9:9}],4:[function(t,e,n){"use strict";function r(t){return(""+t).replace(E,"$&/")}function o(t,e){this.func=t,this.context=e,this.count=0}function i(t,e,n){var r=t.func,o=t.context;r.call(o,e,t.count++)}function u(t,e,n){if(null==t)return t;var r=o.getPooled(e,n);m(t,i,r),o.release(r)}function a(t,e,n,r){this.result=t,this.keyPrefix=e,this.func=n,this.context=r,this.count=0}function s(t,e,n){var o=t.result,i=t.keyPrefix,u=t.func,a=t.context,s=u.call(a,e,t.count++);Array.isArray(s)?c(s,o,n,v.thatReturnsArgument):null!=s&&(h.isValidElement(s)&&(s=h.cloneAndReplaceKey(s,i+(!s.key||e&&e.key===s.key?"":r(s.key)+"/")+n)),o.push(s))}function c(t,e,n,o,i){var u="";null!=n&&(u=r(n)+"/");var c=a.getPooled(e,u,o,i);m(t,s,c),a.release(c)}function l(t,e,n){if(null==t)return t;var r=[];return c(t,r,null,e,n),r}function f(t,e,n){return null}function p(t,e){return m(t,f,null)}function d(t){var e=[];return c(t,e,null,v.thatReturnsArgument),e}var y=t(2),h=t(9),v=t(22),m=t(21),b=y.twoArgumentPooler,g=y.fourArgumentPooler,E=/\/+/g;o.prototype.destructor=function(){this.func=null,this.context=null,this.count=0},y.addPoolingTo(o,b),a.prototype.destructor=function(){this.result=null,this.keyPrefix=null,this.func=null,this.context=null,this.count=0},y.addPoolingTo(a,g);var x={forEach:u,map:l,mapIntoWithKeyPrefixInternal:c,count:p,toArray:d};e.exports=x},{2:2,21:21,22:22,9:9}],5:[function(t,e,n){"use strict";function r(t){return t}function o(t,e){var n=E.hasOwnProperty(e)?E[e]:null;_.hasOwnProperty(e)&&"OVERRIDE_BASE"!==n&&p("73",e),t&&"DEFINE_MANY"!==n&&"DEFINE_MANY_MERGED"!==n&&p("74",e)}function i(t,e){if(e){"function"==typeof e&&p("75"),h.isValidElement(e)&&p("76");var n=t.prototype,r=n.__reactAutoBindPairs;e.hasOwnProperty(b)&&x.mixins(t,e.mixins);for(var i in e)if(e.hasOwnProperty(i)&&i!==b){var u=e[i],a=n.hasOwnProperty(i);if(o(a,i),x.hasOwnProperty(i))x[i](t,u);else{var l=E.hasOwnProperty(i),f="function"==typeof u,d=f&&!l&&!a&&!1!==e.autobind;if(d)r.push(i,u),n[i]=u;else if(a){var y=E[i];(!l||"DEFINE_MANY_MERGED"!==y&&"DEFINE_MANY"!==y)&&p("77",y,i),"DEFINE_MANY_MERGED"===y?n[i]=s(n[i],u):"DEFINE_MANY"===y&&(n[i]=c(n[i],u))}else n[i]=u}}}}function u(t,e){if(e)for(var n in e){var r=e[n];if(e.hasOwnProperty(n)){var o=n in x;o&&p("78",n);var i=n in t;i&&p("79",n),t[n]=r}}}function a(t,e){t&&e&&"object"==typeof t&&"object"==typeof e||p("80");for(var n in e)e.hasOwnProperty(n)&&(void 0!==t[n]&&p("81",n),t[n]=e[n]);return t}function s(t,e){return function(){var n=t.apply(this,arguments),r=e.apply(this,arguments);if(null==n)return r;if(null==r)return n;var o={};return a(o,n),a(o,r),o}}function c(t,e){return function(){t.apply(this,arguments),e.apply(this,arguments)}}function l(t,e){return e.bind(t)}function f(t){for(var e=t.__reactAutoBindPairs,n=0;n<e.length;n+=2){var r=e[n],o=e[n+1];t[r]=l(t,o)}}var p=t(20),d=t(26),y=t(6),h=t(9),v=(t(12),t(11)),m=t(23),b=(t(24),t(25),"mixins"),g=[],E={mixins:"DEFINE_MANY",statics:"DEFINE_MANY",propTypes:"DEFINE_MANY",contextTypes:"DEFINE_MANY",childContextTypes:"DEFINE_MANY",getDefaultProps:"DEFINE_MANY_MERGED",getInitialState:"DEFINE_MANY_MERGED",getChildContext:"DEFINE_MANY_MERGED",render:"DEFINE_ONCE",componentWillMount:"DEFINE_MANY",componentDidMount:"DEFINE_MANY",componentWillReceiveProps:"DEFINE_MANY",shouldComponentUpdate:"DEFINE_ONCE",componentWillUpdate:"DEFINE_MANY",componentDidUpdate:"DEFINE_MANY",componentWillUnmount:"DEFINE_MANY",updateComponent:"OVERRIDE_BASE"},x={displayName:function(t,e){t.displayName=e},mixins:function(t,e){if(e)for(var n=0;n<e.length;n++)i(t,e[n])},childContextTypes:function(t,e){t.childContextTypes=d({},t.childContextTypes,e)},contextTypes:function(t,e){t.contextTypes=d({},t.contextTypes,e)},getDefaultProps:function(t,e){t.getDefaultProps?t.getDefaultProps=s(t.getDefaultProps,e):t.getDefaultProps=e},propTypes:function(t,e){t.propTypes=d({},t.propTypes,e)},statics:function(t,e){u(t,e)},autobind:function(){}},_={replaceState:function(t,e){this.updater.enqueueReplaceState(this,t),e&&this.updater.enqueueCallback(this,e,"replaceState")},isMounted:function(){return this.updater.isMounted(this)}},P=function(){};d(P.prototype,y.prototype,_);var w={createClass:function(t){var e=r(function(t,n,r){this.__reactAutoBindPairs.length&&f(this),this.props=t,this.context=n,this.refs=m,this.updater=r||v,this.state=null;var o=this.getInitialState?this.getInitialState():null;("object"!=typeof o||Array.isArray(o))&&p("82",e.displayName||"ReactCompositeComponent"),this.state=o});e.prototype=new P,e.prototype.constructor=e,e.prototype.__reactAutoBindPairs=[],g.forEach(i.bind(null,e)),i(e,t),e.getDefaultProps&&(e.defaultProps=e.getDefaultProps()),e.prototype.render||p("83");for(var n in E)e.prototype[n]||(e.prototype[n]=null);return e},injection:{injectMixin:function(t){g.push(t)}}};e.exports=w},{11:11,12:12,20:20,23:23,24:24,25:25,26:26,6:6,9:9}],6:[function(t,e,n){"use strict";function r(t,e,n){this.props=t,this.context=e,this.refs=u,this.updater=n||i}var o=t(20),i=t(11),u=(t(17),t(23));t(24),t(25);r.prototype.isReactComponent={},r.prototype.setState=function(t,e){"object"!=typeof t&&"function"!=typeof t&&null!=t&&o("85"),this.updater.enqueueSetState(this,t),e&&this.updater.enqueueCallback(this,e,"setState")},r.prototype.forceUpdate=function(t){this.updater.enqueueForceUpdate(this),t&&this.updater.enqueueCallback(this,t,"forceUpdate")};e.exports=r},{11:11,17:17,20:20,23:23,24:24,25:25}],7:[function(t,e,n){"use strict";var r={current:null};e.exports=r},{}],8:[function(t,e,n){"use strict";var r=t(9),o=r.createFactory,i={a:o("a"),abbr:o("abbr"),address:o("address"),area:o("area"),article:o("article"),aside:o("aside"),audio:o("audio"),b:o("b"),base:o("base"),bdi:o("bdi"),bdo:o("bdo"),big:o("big"),blockquote:o("blockquote"),body:o("body"),br:o("br"),button:o("button"),canvas:o("canvas"),caption:o("caption"),cite:o("cite"),code:o("code"),col:o("col"),colgroup:o("colgroup"),data:o("data"),datalist:o("datalist"),dd:o("dd"),del:o("del"),details:o("details"),dfn:o("dfn"),dialog:o("dialog"),div:o("div"),dl:o("dl"),dt:o("dt"),em:o("em"),embed:o("embed"),fieldset:o("fieldset"),figcaption:o("figcaption"),figure:o("figure"),footer:o("footer"),form:o("form"),h1:o("h1"),h2:o("h2"),h3:o("h3"),h4:o("h4"),h5:o("h5"),h6:o("h6"),head:o("head"),header:o("header"),hgroup:o("hgroup"),hr:o("hr"),html:o("html"),i:o("i"),iframe:o("iframe"),img:o("img"),input:o("input"),ins:o("ins"),kbd:o("kbd"),keygen:o("keygen"),label:o("label"),legend:o("legend"),li:o("li"),link:o("link"),main:o("main"),map:o("map"),mark:o("mark"),menu:o("menu"),menuitem:o("menuitem"),meta:o("meta"),meter:o("meter"),nav:o("nav"),noscript:o("noscript"),object:o("object"),ol:o("ol"),optgroup:o("optgroup"),option:o("option"),output:o("output"),p:o("p"),param:o("param"),picture:o("picture"),pre:o("pre"),progress:o("progress"),q:o("q"),rp:o("rp"),rt:o("rt"),ruby:o("ruby"),s:o("s"),samp:o("samp"),script:o("script"),section:o("section"),select:o("select"),small:o("small"),source:o("source"),span:o("span"),strong:o("strong"),style:o("style"),sub:o("sub"),summary:o("summary"),sup:o("sup"),table:o("table"),tbody:o("tbody"),td:o("td"),textarea:o("textarea"),tfoot:o("tfoot"),th:o("th"),thead:o("thead"),time:o("time"),title:o("title"),tr:o("tr"),track:o("track"),u:o("u"),ul:o("ul"),var:o("var"),video:o("video"),wbr:o("wbr"),circle:o("circle"),clipPath:o("clipPath"),defs:o("defs"),ellipse:o("ellipse"),g:o("g"),image:o("image"),line:o("line"),linearGradient:o("linearGradient"),mask:o("mask"),path:o("path"),pattern:o("pattern"),polygon:o("polygon"),polyline:o("polyline"),radialGradient:o("radialGradient"),rect:o("rect"),stop:o("stop"),svg:o("svg"),text:o("text"),tspan:o("tspan")};e.exports=i},{9:9}],9:[function(t,e,n){"use strict";function r(t){return void 0!==t.ref}function o(t){return void 0!==t.key}var i=t(26),u=t(7),a=(t(25),t(17),Object.prototype.hasOwnProperty),s=t(10),c={key:!0,ref:!0,__self:!0,__source:!0},l=function(t,e,n,r,o,i,u){return{$$typeof:s,type:t,key:e,ref:n,props:u,_owner:i}};l.createElement=function(t,e,n){var i,s={},f=null,p=null;if(null!=e){r(e)&&(p=e.ref),o(e)&&(f=""+e.key),void 0===e.__self?null:e.__self,void 0===e.__source?null:e.__source;for(i in e)a.call(e,i)&&!c.hasOwnProperty(i)&&(s[i]=e[i])}var d=arguments.length-2;if(1===d)s.children=n;else if(d>1){for(var y=Array(d),h=0;h<d;h++)y[h]=arguments[h+2];s.children=y}if(t&&t.defaultProps){var v=t.defaultProps;for(i in v)void 0===s[i]&&(s[i]=v[i])}return l(t,f,p,0,0,u.current,s)},l.createFactory=function(t){var e=l.createElement.bind(null,t);return e.type=t,e},l.cloneAndReplaceKey=function(t,e){return l(t.type,e,t.ref,t._self,t._source,t._owner,t.props)},l.cloneElement=function(t,e,n){var s,f=i({},t.props),p=t.key,d=t.ref,y=(t._self,t._source,t._owner);if(null!=e){r(e)&&(d=e.ref,y=u.current),o(e)&&(p=""+e.key);var h;t.type&&t.type.defaultProps&&(h=t.type.defaultProps);for(s in e)a.call(e,s)&&!c.hasOwnProperty(s)&&(void 0===e[s]&&void 0!==h?f[s]=h[s]:f[s]=e[s])}var v=arguments.length-2;if(1===v)f.children=n;else if(v>1){for(var m=Array(v),b=0;b<v;b++)m[b]=arguments[b+2];f.children=m}return l(t.type,p,d,0,0,y,f)},l.isValidElement=function(t){return"object"==typeof t&&null!==t&&t.$$typeof===s},e.exports=l},{10:10,17:17,25:25,26:26,7:7}],10:[function(t,e,n){"use strict";var r="function"==typeof Symbol&&Symbol.for&&Symbol.for("react.element")||60103;e.exports=r},{}],11:[function(t,e,n){"use strict";var r=(t(25),{isMounted:function(t){return!1},enqueueCallback:function(t,e){},enqueueForceUpdate:function(t){},enqueueReplaceState:function(t,e){},enqueueSetState:function(t,e){}});e.exports=r},{25:25}],12:[function(t,e,n){"use strict";var r={};e.exports=r},{}],13:[function(t,e,n){"use strict";var r=t(9),o=r.isValidElement,i=t(28);e.exports=i(o)},{28:28,9:9}],14:[function(t,e,n){"use strict";function r(t,e,n){this.props=t,this.context=e,this.refs=s,this.updater=n||a}function o(){}var i=t(26),u=t(6),a=t(11),s=t(23);o.prototype=u.prototype,r.prototype=new o,r.prototype.constructor=r,i(r.prototype,u.prototype),r.prototype.isPureReactComponent=!0,e.exports=r},{11:11,23:23,26:26,6:6}],15:[function(t,e,n){"use strict";var r=t(26),o=t(3),i=r(o,{__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED:{ReactCurrentOwner:t(7)}});e.exports=i},{26:26,3:3,7:7}],16:[function(t,e,n){"use strict";e.exports="15.5.4"},{}],17:[function(t,e,n){"use strict";e.exports=!1},{}],18:[function(t,e,n){"use strict";function r(t){var e=t&&(o&&t[o]||t[i]);if("function"==typeof e)return e}var o="function"==typeof Symbol&&Symbol.iterator,i="@@iterator";e.exports=r},{}],19:[function(t,e,n){"use strict";function r(t){return i.isValidElement(t)||o("143"),t}var o=t(20),i=t(9);t(24);e.exports=r},{20:20,24:24,9:9}],20:[function(t,e,n){"use strict";function r(t){for(var e=arguments.length-1,n="Minified React error #"+t+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant="+t,r=0;r<e;r++)n+="&args[]="+encodeURIComponent(arguments[r+1]);n+=" for the full message or use the non-minified dev environment for full errors and additional helpful warnings.";var o=new Error(n);throw o.name="Invariant Violation",o.framesToPop=1,o}e.exports=r},{}],21:[function(t,e,n){"use strict";function r(t,e){return t&&"object"==typeof t&&null!=t.key?c.escape(t.key):e.toString(36)}function o(t,e,n,i){var p=typeof t;if("undefined"!==p&&"boolean"!==p||(t=null),null===t||"string"===p||"number"===p||"object"===p&&t.$$typeof===a)return n(i,t,""===e?l+r(t,0):e),1;var d,y,h=0,v=""===e?l:e+f;if(Array.isArray(t))for(var m=0;m<t.length;m++)d=t[m],y=v+r(d,m),h+=o(d,y,n,i);else{var b=s(t);if(b){var g,E=b.call(t);if(b!==t.entries)for(var x=0;!(g=E.next()).done;)d=g.value,y=v+r(d,x++),h+=o(d,y,n,i);else for(;!(g=E.next()).done;){var _=g.value;_&&(d=_[1],y=v+c.escape(_[0])+f+r(d,0),h+=o(d,y,n,i))}}else if("object"===p){var P=String(t);u("31","[object Object]"===P?"object with keys {"+Object.keys(t).join(", ")+"}":P,"")}}return h}function i(t,e,n){return null==t?0:o(t,"",e,n)}var u=t(20),a=(t(7),t(10)),s=t(18),c=(t(24),t(1)),l=(t(25),"."),f=":";e.exports=i},{1:1,10:10,18:18,20:20,24:24,25:25,7:7}],22:[function(t,e,n){"use strict";function r(t){return function(){return t}}var o=function(){};o.thatReturns=r,o.thatReturnsFalse=r(!1),o.thatReturnsTrue=r(!0),o.thatReturnsNull=r(null),o.thatReturnsThis=function(){return this},o.thatReturnsArgument=function(t){return t},e.exports=o},{}],23:[function(t,e,n){"use strict";var r={};e.exports=r},{}],24:[function(t,e,n){"use strict";function r(t,e,n,r,i,u,a,s){if(o(e),!t){var c;if(void 0===e)c=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var l=[n,r,i,u,a,s],f=0;c=new Error(e.replace(/%s/g,function(){return l[f++]})),c.name="Invariant Violation"}throw c.framesToPop=1,c}}var o=function(t){};e.exports=r},{}],25:[function(t,e,n){"use strict";var r=t(22),o=r;e.exports=o},{22:22}],26:[function(t,e,n){"use strict";function r(t){if(null===t||void 0===t)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(t)}var o=Object.getOwnPropertySymbols,i=Object.prototype.hasOwnProperty,u=Object.prototype.propertyIsEnumerable;e.exports=function(){try{if(!Object.assign)return!1;var t=new String("abc");if(t[5]="de","5"===Object.getOwnPropertyNames(t)[0])return!1;for(var e={},n=0;n<10;n++)e["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(e).map(function(t){return e[t]}).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach(function(t){r[t]=t}),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(t){return!1}}()?Object.assign:function(t,e){for(var n,a,s=r(t),c=1;c<arguments.length;c++){n=Object(arguments[c]);for(var l in n)i.call(n,l)&&(s[l]=n[l]);if(o){a=o(n);for(var f=0;f<a.length;f++)u.call(n,a[f])&&(s[a[f]]=n[a[f]])}}return s}},{}],27:[function(t,e,n){"use strict";function r(t,e,n,r,o){}e.exports=r},{24:24,25:25,30:30}],28:[function(t,e,n){"use strict";var r=t(29);e.exports=function(t){return r(t,!1)}},{29:29}],29:[function(t,e,n){"use strict";var r=t(22),o=t(24),i=(t(25),t(30)),u=t(27);e.exports=function(t,e){function n(t){var e=t&&(_&&t[_]||t[P]);if("function"==typeof e)return e}function a(t,e){return t===e?0!==t||1/t==1/e:t!==t&&e!==e}function s(t){this.message=t,this.stack=""}function c(t){function n(n,r,u,a,c,l,f){if(a=a||w,l=l||u,f!==i)if(e)o(!1,"Calling PropTypes validators directly is not supported by the `prop-types` package. Use `PropTypes.checkPropTypes()` to call them. Read more at http://fb.me/use-check-prop-types");else;return null==r[u]?n?new s(null===r[u]?"The "+c+" `"+l+"` is marked as required in `"+a+"`, but its value is `null`.":"The "+c+" `"+l+"` is marked as required in `"+a+"`, but its value is `undefined`."):null:t(r,u,a,c,l)}var r=n.bind(null,!1);return r.isRequired=n.bind(null,!0),r}function l(t){function e(e,n,r,o,i,u){var a=e[n];if(g(a)!==t)return new s("Invalid "+o+" `"+i+"` of type `"+E(a)+"` supplied to `"+r+"`, expected `"+t+"`.");return null}return c(e)}function f(t){function e(e,n,r,o,u){if("function"!=typeof t)return new s("Property `"+u+"` of component `"+r+"` has invalid PropType notation inside arrayOf.");var a=e[n];if(!Array.isArray(a)){return new s("Invalid "+o+" `"+u+"` of type `"+g(a)+"` supplied to `"+r+"`, expected an array.")}for(var c=0;c<a.length;c++){var l=t(a,c,r,o,u+"["+c+"]",i);if(l instanceof Error)return l}return null}return c(e)}function p(t){function e(e,n,r,o,i){if(!(e[n]instanceof t)){var u=t.name||w;return new s("Invalid "+o+" `"+i+"` of type `"+x(e[n])+"` supplied to `"+r+"`, expected instance of `"+u+"`.")}return null}return c(e)}function d(t){function e(e,n,r,o,i){for(var u=e[n],c=0;c<t.length;c++)if(a(u,t[c]))return null;return new s("Invalid "+o+" `"+i+"` of value `"+u+"` supplied to `"+r+"`, expected one of "+JSON.stringify(t)+".")}return Array.isArray(t)?c(e):r.thatReturnsNull}function y(t){function e(e,n,r,o,u){if("function"!=typeof t)return new s("Property `"+u+"` of component `"+r+"` has invalid PropType notation inside objectOf.");var a=e[n],c=g(a);if("object"!==c)return new s("Invalid "+o+" `"+u+"` of type `"+c+"` supplied to `"+r+"`, expected an object.");for(var l in a)if(a.hasOwnProperty(l)){var f=t(a,l,r,o,u+"."+l,i);if(f instanceof Error)return f}return null}return c(e)}function h(t){function e(e,n,r,o,u){for(var a=0;a<t.length;a++){if(null==(0,t[a])(e,n,r,o,u,i))return null}return new s("Invalid "+o+" `"+u+"` supplied to `"+r+"`.")}return Array.isArray(t)?c(e):r.thatReturnsNull}function v(t){function e(e,n,r,o,u){var a=e[n],c=g(a);if("object"!==c)return new s("Invalid "+o+" `"+u+"` of type `"+c+"` supplied to `"+r+"`, expected `object`.");for(var l in t){var f=t[l];if(f){var p=f(a,l,r,o,u+"."+l,i);if(p)return p}}return null}return c(e)}function m(e){switch(typeof e){case"number":case"string":case"undefined":return!0;case"boolean":return!e;case"object":if(Array.isArray(e))return e.every(m);if(null===e||t(e))return!0;var r=n(e);if(!r)return!1;var o,i=r.call(e);if(r!==e.entries){for(;!(o=i.next()).done;)if(!m(o.value))return!1}else for(;!(o=i.next()).done;){var u=o.value;if(u&&!m(u[1]))return!1}return!0;default:return!1}}function b(t,e){return"symbol"===t||("Symbol"===e["@@toStringTag"]||"function"==typeof Symbol&&e instanceof Symbol)}function g(t){var e=typeof t;return Array.isArray(t)?"array":t instanceof RegExp?"object":b(e,t)?"symbol":e}function E(t){var e=g(t);if("object"===e){if(t instanceof Date)return"date";if(t instanceof RegExp)return"regexp"}return e}function x(t){return t.constructor&&t.constructor.name?t.constructor.name:w}var _="function"==typeof Symbol&&Symbol.iterator,P="@@iterator",w="<<anonymous>>",N={array:l("array"),bool:l("boolean"),func:l("function"),number:l("number"),object:l("object"),string:l("string"),symbol:l("symbol"),any:function(){return c(r.thatReturnsNull)}(),arrayOf:f,element:function(){function e(e,n,r,o,i){var u=e[n];if(!t(u)){return new s("Invalid "+o+" `"+i+"` of type `"+g(u)+"` supplied to `"+r+"`, expected a single ReactElement.")}return null}return c(e)}(),instanceOf:p,node:function(){function t(t,e,n,r,o){return m(t[e])?null:new s("Invalid "+r+" `"+o+"` supplied to `"+n+"`, expected a ReactNode.")}return c(t)}(),objectOf:y,oneOf:d,oneOfType:h,shape:v};return s.prototype=Error.prototype,N.checkPropTypes=u,N.PropTypes=N,N}},{22:22,24:24,25:25,27:27,30:30}],30:[function(t,e,n){"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},{}]},{},[15])(15)}); +!function(f){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=f();else if("function"==typeof define&&define.amd)define([],f);else{var g;if(g="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,void 0===g.React)throw Error("React module should be required before createClass");g.createReactClass=f()}}(function(){return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n||e)},l,l.exports,e,t,n,r)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;o<r.length;o++)s(r[o]);return s}({1:[function(require,module,exports){"use strict";function identity(fn){return fn}function factory(ReactComponent,isValidElement,ReactNoopUpdateQueue){function validateMethodOverride(isAlreadyDefined,name){var specPolicy=ReactClassInterface.hasOwnProperty(name)?ReactClassInterface[name]:null;ReactClassMixin.hasOwnProperty(name)&&_invariant("OVERRIDE_BASE"===specPolicy,"ReactClassInterface: You are attempting to override `%s` from your class specification. Ensure that your method names do not overlap with React methods.",name),isAlreadyDefined&&_invariant("DEFINE_MANY"===specPolicy||"DEFINE_MANY_MERGED"===specPolicy,"ReactClassInterface: You are attempting to define `%s` on your component more than once. This conflict may be due to a mixin.",name)}function mixSpecIntoComponent(Constructor,spec){if(spec){_invariant("function"!=typeof spec,"ReactClass: You're attempting to use a component class or function as a mixin. Instead, just use a regular object."),_invariant(!isValidElement(spec),"ReactClass: You're attempting to use a component as a mixin. Instead, just use a regular object.");var proto=Constructor.prototype,autoBindPairs=proto.__reactAutoBindPairs;spec.hasOwnProperty(MIXINS_KEY)&&RESERVED_SPEC_KEYS.mixins(Constructor,spec.mixins);for(var name in spec)if(spec.hasOwnProperty(name)&&name!==MIXINS_KEY){var property=spec[name],isAlreadyDefined=proto.hasOwnProperty(name);if(validateMethodOverride(isAlreadyDefined,name),RESERVED_SPEC_KEYS.hasOwnProperty(name))RESERVED_SPEC_KEYS[name](Constructor,property);else{var isReactClassMethod=ReactClassInterface.hasOwnProperty(name),isFunction="function"==typeof property,shouldAutoBind=isFunction&&!isReactClassMethod&&!isAlreadyDefined&&!1!==spec.autobind;if(shouldAutoBind)autoBindPairs.push(name,property),proto[name]=property;else if(isAlreadyDefined){var specPolicy=ReactClassInterface[name];_invariant(isReactClassMethod&&("DEFINE_MANY_MERGED"===specPolicy||"DEFINE_MANY"===specPolicy),"ReactClass: Unexpected spec policy %s for key %s when mixing in component specs.",specPolicy,name),"DEFINE_MANY_MERGED"===specPolicy?proto[name]=createMergedResultFunction(proto[name],property):"DEFINE_MANY"===specPolicy&&(proto[name]=createChainedFunction(proto[name],property))}else proto[name]=property}}}else;}function mixStaticSpecIntoComponent(Constructor,statics){if(statics)for(var name in statics){var property=statics[name];if(statics.hasOwnProperty(name)){var isReserved=name in RESERVED_SPEC_KEYS;_invariant(!isReserved,'ReactClass: You are attempting to define a reserved property, `%s`, that shouldn\'t be on the "statics" key. Define it as an instance property instead; it will still be accessible on the constructor.',name);var isInherited=name in Constructor;_invariant(!isInherited,"ReactClass: You are attempting to define `%s` on your component more than once. This conflict may be due to a mixin.",name),Constructor[name]=property}}}function mergeIntoWithNoDuplicateKeys(one,two){_invariant(one&&two&&"object"==typeof one&&"object"==typeof two,"mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.");for(var key in two)two.hasOwnProperty(key)&&(_invariant(void 0===one[key],"mergeIntoWithNoDuplicateKeys(): Tried to merge two objects with the same key: `%s`. This conflict may be due to a mixin; in particular, this may be caused by two getInitialState() or getDefaultProps() methods returning objects with clashing keys.",key),one[key]=two[key]);return one}function createMergedResultFunction(one,two){return function(){var a=one.apply(this,arguments),b=two.apply(this,arguments);if(null==a)return b;if(null==b)return a;var c={};return mergeIntoWithNoDuplicateKeys(c,a),mergeIntoWithNoDuplicateKeys(c,b),c}}function createChainedFunction(one,two){return function(){one.apply(this,arguments),two.apply(this,arguments)}}function bindAutoBindMethod(component,method){var boundMethod=method.bind(component);return boundMethod}function bindAutoBindMethods(component){for(var pairs=component.__reactAutoBindPairs,i=0;i<pairs.length;i+=2){var autoBindKey=pairs[i],method=pairs[i+1];component[autoBindKey]=bindAutoBindMethod(component,method)}}function createClass(spec){var Constructor=identity(function(props,context,updater){this.__reactAutoBindPairs.length&&bindAutoBindMethods(this),this.props=props,this.context=context,this.refs=emptyObject,this.updater=updater||ReactNoopUpdateQueue,this.state=null;var initialState=this.getInitialState?this.getInitialState():null;_invariant("object"==typeof initialState&&!Array.isArray(initialState),"%s.getInitialState(): must return an object or null",Constructor.displayName||"ReactCompositeComponent"),this.state=initialState});Constructor.prototype=new ReactClassComponent,Constructor.prototype.constructor=Constructor,Constructor.prototype.__reactAutoBindPairs=[],injectedMixins.forEach(mixSpecIntoComponent.bind(null,Constructor)),mixSpecIntoComponent(Constructor,IsMountedMixin),mixSpecIntoComponent(Constructor,spec),Constructor.getDefaultProps&&(Constructor.defaultProps=Constructor.getDefaultProps()),_invariant(Constructor.prototype.render,"createClass(...): Class specification must implement a `render` method.");for(var methodName in ReactClassInterface)Constructor.prototype[methodName]||(Constructor.prototype[methodName]=null);return Constructor}var injectedMixins=[],ReactClassInterface={mixins:"DEFINE_MANY",statics:"DEFINE_MANY",propTypes:"DEFINE_MANY",contextTypes:"DEFINE_MANY",childContextTypes:"DEFINE_MANY",getDefaultProps:"DEFINE_MANY_MERGED",getInitialState:"DEFINE_MANY_MERGED",getChildContext:"DEFINE_MANY_MERGED",render:"DEFINE_ONCE",componentWillMount:"DEFINE_MANY",componentDidMount:"DEFINE_MANY",componentWillReceiveProps:"DEFINE_MANY",shouldComponentUpdate:"DEFINE_ONCE",componentWillUpdate:"DEFINE_MANY",componentDidUpdate:"DEFINE_MANY",componentWillUnmount:"DEFINE_MANY",updateComponent:"OVERRIDE_BASE"},RESERVED_SPEC_KEYS={displayName:function(Constructor,displayName){Constructor.displayName=displayName},mixins:function(Constructor,mixins){if(mixins)for(var i=0;i<mixins.length;i++)mixSpecIntoComponent(Constructor,mixins[i])},childContextTypes:function(Constructor,childContextTypes){Constructor.childContextTypes=_assign({},Constructor.childContextTypes,childContextTypes)},contextTypes:function(Constructor,contextTypes){Constructor.contextTypes=_assign({},Constructor.contextTypes,contextTypes)},getDefaultProps:function(Constructor,getDefaultProps){Constructor.getDefaultProps?Constructor.getDefaultProps=createMergedResultFunction(Constructor.getDefaultProps,getDefaultProps):Constructor.getDefaultProps=getDefaultProps},propTypes:function(Constructor,propTypes){Constructor.propTypes=_assign({},Constructor.propTypes,propTypes)},statics:function(Constructor,statics){mixStaticSpecIntoComponent(Constructor,statics)},autobind:function(){}},IsMountedMixin={componentDidMount:function(){this.__isMounted=!0},componentWillUnmount:function(){this.__isMounted=!1}},ReactClassMixin={replaceState:function(newState,callback){this.updater.enqueueReplaceState(this,newState,callback)},isMounted:function(){return!!this.__isMounted}},ReactClassComponent=function(){};return _assign(ReactClassComponent.prototype,ReactComponent.prototype,ReactClassMixin),createClass}var _assign=require(7),emptyObject=require(4),_invariant=require(5),MIXINS_KEY="mixins";module.exports=factory},{4:4,5:5,6:6,7:7}],2:[function(require,module,exports){"use strict";var factory=require(1),ReactNoopUpdateQueue=(new React.Component).updater;module.exports=factory(React.Component,React.isValidElement,ReactNoopUpdateQueue)},{1:1}],3:[function(require,module,exports){"use strict";function makeEmptyFunction(arg){return function(){return arg}}var emptyFunction=function(){};emptyFunction.thatReturns=makeEmptyFunction,emptyFunction.thatReturnsFalse=makeEmptyFunction(!1),emptyFunction.thatReturnsTrue=makeEmptyFunction(!0),emptyFunction.thatReturnsNull=makeEmptyFunction(null),emptyFunction.thatReturnsThis=function(){return this},emptyFunction.thatReturnsArgument=function(arg){return arg},module.exports=emptyFunction},{}],4:[function(require,module,exports){"use strict";var emptyObject={};module.exports=emptyObject},{}],5:[function(require,module,exports){"use strict";function invariant(condition,format,a,b,c,d,e,f){if(validateFormat(format),!condition){var error;if(void 0===format)error=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var args=[a,b,c,d,e,f],argIndex=0;error=new Error(format.replace(/%s/g,function(){return args[argIndex++]})),error.name="Invariant Violation"}throw error.framesToPop=1,error}}var validateFormat=function(format){};module.exports=invariant},{}],6:[function(require,module,exports){"use strict";var emptyFunction=require(3),warning=emptyFunction;module.exports=warning},{3:3}],7:[function(require,module,exports){"use strict";function toObject(val){if(null===val||void 0===val)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(val)}var getOwnPropertySymbols=Object.getOwnPropertySymbols,hasOwnProperty=Object.prototype.hasOwnProperty,propIsEnumerable=Object.prototype.propertyIsEnumerable;module.exports=function(){try{if(!Object.assign)return!1;var test1=new String("abc");if(test1[5]="de","5"===Object.getOwnPropertyNames(test1)[0])return!1;for(var test2={},i=0;i<10;i++)test2["_"+String.fromCharCode(i)]=i;if("0123456789"!==Object.getOwnPropertyNames(test2).map(function(n){return test2[n]}).join(""))return!1;var test3={};return"abcdefghijklmnopqrst".split("").forEach(function(letter){test3[letter]=letter}),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},test3)).join("")}catch(err){return!1}}()?Object.assign:function(target,source){for(var from,symbols,to=toObject(target),s=1;s<arguments.length;s++){from=Object(arguments[s]);for(var key in from)hasOwnProperty.call(from,key)&&(to[key]=from[key]);if(getOwnPropertySymbols){symbols=getOwnPropertySymbols(from);for(var i=0;i<symbols.length;i++)propIsEnumerable.call(from,symbols[i])&&(to[symbols[i]]=from[symbols[i]])}}return to}},{}]},{},[2])(2)}); + +/** + * ReactDOM v15.5.4 + * + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e(require("react"));else if("function"==typeof define&&define.amd)define(["react"],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.ReactDOM=e(t.React)}}(function(e){return function(t){return function(){return function e(t,n,r){function o(a,s){if(!n[a]){if(!t[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(i)return i(a,!0);var l=new Error("Cannot find module '"+a+"'");throw l.code="MODULE_NOT_FOUND",l}var c=n[a]={exports:{}};t[a][0].call(c.exports,function(e){var n=t[a][1][e];return o(n||e)},c,c.exports,e,t,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;a<r.length;a++)o(r[a]);return o}({1:[function(e,t,n){"use strict";var r={Properties:{"aria-current":0,"aria-details":0,"aria-disabled":0,"aria-hidden":0,"aria-invalid":0,"aria-keyshortcuts":0,"aria-label":0,"aria-roledescription":0,"aria-autocomplete":0,"aria-checked":0,"aria-expanded":0,"aria-haspopup":0,"aria-level":0,"aria-modal":0,"aria-multiline":0,"aria-multiselectable":0,"aria-orientation":0,"aria-placeholder":0,"aria-pressed":0,"aria-readonly":0,"aria-required":0,"aria-selected":0,"aria-sort":0,"aria-valuemax":0,"aria-valuemin":0,"aria-valuenow":0,"aria-valuetext":0,"aria-atomic":0,"aria-busy":0,"aria-live":0,"aria-relevant":0,"aria-dropeffect":0,"aria-grabbed":0,"aria-activedescendant":0,"aria-colcount":0,"aria-colindex":0,"aria-colspan":0,"aria-controls":0,"aria-describedby":0,"aria-errormessage":0,"aria-flowto":0,"aria-labelledby":0,"aria-owns":0,"aria-posinset":0,"aria-rowcount":0,"aria-rowindex":0,"aria-rowspan":0,"aria-setsize":0},DOMAttributeNames:{},DOMPropertyNames:{}};t.exports=r},{}],2:[function(e,t,n){"use strict";var r=e(33),o=e(131),i={focusDOMComponent:function(){o(r.getNodeFromInstance(this))}};t.exports=i},{131:131,33:33}],3:[function(e,t,n){"use strict";function r(e){return(e.ctrlKey||e.altKey||e.metaKey)&&!(e.ctrlKey&&e.altKey)}function o(e){switch(e){case"topCompositionStart":return T.compositionStart;case"topCompositionEnd":return T.compositionEnd;case"topCompositionUpdate":return T.compositionUpdate}}function i(e,t){return"topKeyDown"===e&&t.keyCode===y}function a(e,t){switch(e){case"topKeyUp":return-1!==g.indexOf(t.keyCode);case"topKeyDown":return t.keyCode!==y;case"topKeyPress":case"topMouseDown":case"topBlur":return!0;default:return!1}}function s(e){var t=e.detail;return"object"==typeof t&&"data"in t?t.data:null}function u(e,t,n,r){var u,l;if(_?u=o(e):P?a(e,n)&&(u=T.compositionEnd):i(e,n)&&(u=T.compositionStart),!u)return null;E&&(P||u!==T.compositionStart?u===T.compositionEnd&&P&&(l=P.getData()):P=h.getPooled(r));var c=m.getPooled(u,t,n,r);if(l)c.data=l;else{var p=s(n);null!==p&&(c.data=p)}return d.accumulateTwoPhaseDispatches(c),c}function l(e,t){switch(e){case"topCompositionEnd":return s(t);case"topKeyPress":return t.which!==x?null:(k=!0,w);case"topTextInput":var n=t.data;return n===w&&k?null:n;default:return null}}function c(e,t){if(P){if("topCompositionEnd"===e||!_&&a(e,t)){var n=P.getData();return h.release(P),P=null,n}return null}switch(e){case"topPaste":return null;case"topKeyPress":return t.which&&!r(t)?String.fromCharCode(t.which):null;case"topCompositionEnd":return E?null:t.data;default:return null}}function p(e,t,n,r){var o;if(!(o=b?l(e,n):c(e,n)))return null;var i=v.getPooled(T.beforeInput,t,n,r);return i.data=o,d.accumulateTwoPhaseDispatches(i),i}var d=e(19),f=e(123),h=e(20),m=e(78),v=e(82),g=[9,13,27,32],y=229,_=f.canUseDOM&&"CompositionEvent"in window,C=null;f.canUseDOM&&"documentMode"in document&&(C=document.documentMode);var b=f.canUseDOM&&"TextEvent"in window&&!C&&!function(){var e=window.opera;return"object"==typeof e&&"function"==typeof e.version&&parseInt(e.version(),10)<=12}(),E=f.canUseDOM&&(!_||C&&C>8&&C<=11),x=32,w=String.fromCharCode(x),T={beforeInput:{phasedRegistrationNames:{bubbled:"onBeforeInput",captured:"onBeforeInputCapture"},dependencies:["topCompositionEnd","topKeyPress","topTextInput","topPaste"]},compositionEnd:{phasedRegistrationNames:{bubbled:"onCompositionEnd",captured:"onCompositionEndCapture"},dependencies:["topBlur","topCompositionEnd","topKeyDown","topKeyPress","topKeyUp","topMouseDown"]},compositionStart:{phasedRegistrationNames:{bubbled:"onCompositionStart",captured:"onCompositionStartCapture"},dependencies:["topBlur","topCompositionStart","topKeyDown","topKeyPress","topKeyUp","topMouseDown"]},compositionUpdate:{phasedRegistrationNames:{bubbled:"onCompositionUpdate",captured:"onCompositionUpdateCapture"},dependencies:["topBlur","topCompositionUpdate","topKeyDown","topKeyPress","topKeyUp","topMouseDown"]}},k=!1,P=null,S={eventTypes:T,extractEvents:function(e,t,n,r){return[u(e,t,n,r),p(e,t,n,r)]}};t.exports=S},{123:123,19:19,20:20,78:78,82:82}],4:[function(e,t,n){"use strict";function r(e,t){return e+t.charAt(0).toUpperCase()+t.substring(1)}var o={animationIterationCount:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridRow:!0,gridColumn:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},i=["Webkit","ms","Moz","O"];Object.keys(o).forEach(function(e){i.forEach(function(t){o[r(t,e)]=o[e]})});var a={background:{backgroundAttachment:!0,backgroundColor:!0,backgroundImage:!0,backgroundPositionX:!0,backgroundPositionY:!0,backgroundRepeat:!0},backgroundPosition:{backgroundPositionX:!0,backgroundPositionY:!0},border:{borderWidth:!0,borderStyle:!0,borderColor:!0},borderBottom:{borderBottomWidth:!0,borderBottomStyle:!0,borderBottomColor:!0},borderLeft:{borderLeftWidth:!0,borderLeftStyle:!0,borderLeftColor:!0},borderRight:{borderRightWidth:!0,borderRightStyle:!0,borderRightColor:!0},borderTop:{borderTopWidth:!0,borderTopStyle:!0,borderTopColor:!0},font:{fontStyle:!0,fontVariant:!0,fontWeight:!0,fontSize:!0,lineHeight:!0,fontFamily:!0},outline:{outlineWidth:!0,outlineStyle:!0,outlineColor:!0}},s={isUnitlessNumber:o,shorthandPropertyExpansions:a};t.exports=s},{}],5:[function(e,t,n){"use strict";var r=e(4),o=e(123),i=(e(58),e(125),e(94)),a=e(136),s=e(140),u=(e(142),s(function(e){return a(e)})),l=!1,c="cssFloat";if(o.canUseDOM){var p=document.createElement("div").style;try{p.font=""}catch(e){l=!0}void 0===document.documentElement.style.cssFloat&&(c="styleFloat")}var d={createMarkupForStyles:function(e,t){var n="";for(var r in e)if(e.hasOwnProperty(r)){var o=e[r];null!=o&&(n+=u(r)+":",n+=i(r,o,t)+";")}return n||null},setValueForStyles:function(e,t,n){var o=e.style;for(var a in t)if(t.hasOwnProperty(a)){var s=i(a,t[a],n);if("float"!==a&&"cssFloat"!==a||(a=c),s)o[a]=s;else{var u=l&&r.shorthandPropertyExpansions[a];if(u)for(var p in u)o[p]="";else o[a]=""}}}};t.exports=d},{123:123,125:125,136:136,140:140,142:142,4:4,58:58,94:94}],6:[function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=e(112),i=e(24),a=(e(137),function(){function e(t){r(this,e),this._callbacks=null,this._contexts=null,this._arg=t}return e.prototype.enqueue=function(e,t){this._callbacks=this._callbacks||[],this._callbacks.push(e),this._contexts=this._contexts||[],this._contexts.push(t)},e.prototype.notifyAll=function(){var e=this._callbacks,t=this._contexts,n=this._arg;if(e&&t){e.length!==t.length&&o("24"),this._callbacks=null,this._contexts=null;for(var r=0;r<e.length;r++)e[r].call(t[r],n);e.length=0,t.length=0}},e.prototype.checkpoint=function(){return this._callbacks?this._callbacks.length:0},e.prototype.rollback=function(e){this._callbacks&&this._contexts&&(this._callbacks.length=e,this._contexts.length=e)},e.prototype.reset=function(){this._callbacks=null,this._contexts=null},e.prototype.destructor=function(){this.reset()},e}());t.exports=i.addPoolingTo(a)},{112:112,137:137,24:24}],7:[function(e,t,n){"use strict";function r(e){var t=e.nodeName&&e.nodeName.toLowerCase();return"select"===t||"input"===t&&"file"===e.type}function o(e){var t=w.getPooled(S.change,M,e,T(e));C.accumulateTwoPhaseDispatches(t),x.batchedUpdates(i,t)}function i(e){_.enqueueEvents(e),_.processEventQueue(!1)}function a(e,t){N=e,M=t,N.attachEvent("onchange",o)}function s(){N&&(N.detachEvent("onchange",o),N=null,M=null)}function u(e,t){if("topChange"===e)return t}function l(e,t,n){"topFocus"===e?(s(),a(t,n)):"topBlur"===e&&s()}function c(e,t){N=e,M=t,I=e.value,O=Object.getOwnPropertyDescriptor(e.constructor.prototype,"value"),Object.defineProperty(N,"value",D),N.attachEvent?N.attachEvent("onpropertychange",d):N.addEventListener("propertychange",d,!1)}function p(){N&&(delete N.value,N.detachEvent?N.detachEvent("onpropertychange",d):N.removeEventListener("propertychange",d,!1),N=null,M=null,I=null,O=null)}function d(e){if("value"===e.propertyName){var t=e.srcElement.value;t!==I&&(I=t,o(e))}}function f(e,t){if("topInput"===e)return t}function h(e,t,n){"topFocus"===e?(p(),c(t,n)):"topBlur"===e&&p()}function m(e,t){if(("topSelectionChange"===e||"topKeyUp"===e||"topKeyDown"===e)&&N&&N.value!==I)return I=N.value,M}function v(e){return e.nodeName&&"input"===e.nodeName.toLowerCase()&&("checkbox"===e.type||"radio"===e.type)}function g(e,t){if("topClick"===e)return t}function y(e,t){if(null!=e){var n=e._wrapperState||t._wrapperState;if(n&&n.controlled&&"number"===t.type){var r=""+t.value;t.getAttribute("value")!==r&&t.setAttribute("value",r)}}}var _=e(16),C=e(19),b=e(123),E=e(33),x=e(71),w=e(80),T=e(102),k=e(109),P=e(110),S={change:{phasedRegistrationNames:{bubbled:"onChange",captured:"onChangeCapture"},dependencies:["topBlur","topChange","topClick","topFocus","topInput","topKeyDown","topKeyUp","topSelectionChange"]}},N=null,M=null,I=null,O=null,R=!1;b.canUseDOM&&(R=k("change")&&(!document.documentMode||document.documentMode>8));var A=!1;b.canUseDOM&&(A=k("input")&&(!document.documentMode||document.documentMode>11));var D={get:function(){return O.get.call(this)},set:function(e){I=""+e,O.set.call(this,e)}},L={eventTypes:S,extractEvents:function(e,t,n,o){var i,a,s=t?E.getNodeFromInstance(t):window;if(r(s)?R?i=u:a=l:P(s)?A?i=f:(i=m,a=h):v(s)&&(i=g),i){var c=i(e,t);if(c){var p=w.getPooled(S.change,c,n,o);return p.type="change",C.accumulateTwoPhaseDispatches(p),p}}a&&a(e,s,t),"topBlur"===e&&y(t,s)}};t.exports=L},{102:102,109:109,110:110,123:123,16:16,19:19,33:33,71:71,80:80}],8:[function(e,t,n){"use strict";function r(e,t){return Array.isArray(t)&&(t=t[1]),t?t.nextSibling:e.firstChild}function o(e,t,n){c.insertTreeBefore(e,t,n)}function i(e,t,n){Array.isArray(t)?s(e,t[0],t[1],n):m(e,t,n)}function a(e,t){if(Array.isArray(t)){var n=t[1];t=t[0],u(e,t,n),e.removeChild(n)}e.removeChild(t)}function s(e,t,n,r){for(var o=t;;){var i=o.nextSibling;if(m(e,o,r),o===n)break;o=i}}function u(e,t,n){for(;;){var r=t.nextSibling;if(r===n)break;e.removeChild(r)}}function l(e,t,n){var r=e.parentNode,o=e.nextSibling;o===t?n&&m(r,document.createTextNode(n),o):n?(h(o,n),u(r,o,t)):u(r,e,t)}var c=e(9),p=e(13),d=(e(33),e(58),e(93)),f=e(114),h=e(115),m=d(function(e,t,n){e.insertBefore(t,n)}),v=p.dangerouslyReplaceNodeWithMarkup,g={dangerouslyReplaceNodeWithMarkup:v,replaceDelimitedText:l,processUpdates:function(e,t){for(var n=0;n<t.length;n++){var s=t[n];switch(s.type){case"INSERT_MARKUP":o(e,s.content,r(e,s.afterNode));break;case"MOVE_EXISTING":i(e,s.fromNode,r(e,s.afterNode));break;case"SET_MARKUP":f(e,s.content);break;case"TEXT_CONTENT":h(e,s.content);break;case"REMOVE_NODE":a(e,s.fromNode)}}}};t.exports=g},{114:114,115:115,13:13,33:33,58:58,9:9,93:93}],9:[function(e,t,n){"use strict";function r(e){if(h){var t=e.node,n=e.children;if(n.length)for(var r=0;r<n.length;r++)m(t,n[r],null);else null!=e.html?p(t,e.html):null!=e.text&&f(t,e.text)}}function o(e,t){e.parentNode.replaceChild(t.node,e),r(t)}function i(e,t){h?e.children.push(t):e.node.appendChild(t.node)}function a(e,t){h?e.html=t:p(e.node,t)}function s(e,t){h?e.text=t:f(e.node,t)}function u(){return this.node.nodeName}function l(e){return{node:e,children:[],html:null,text:null,toString:u}}var c=e(10),p=e(114),d=e(93),f=e(115),h="undefined"!=typeof document&&"number"==typeof document.documentMode||"undefined"!=typeof navigator&&"string"==typeof navigator.userAgent&&/\bEdge\/\d/.test(navigator.userAgent),m=d(function(e,t,n){11===t.node.nodeType||1===t.node.nodeType&&"object"===t.node.nodeName.toLowerCase()&&(null==t.node.namespaceURI||t.node.namespaceURI===c.html)?(r(t),e.insertBefore(t.node,n)):(e.insertBefore(t.node,n),r(t))});l.insertTreeBefore=m,l.replaceChildWithTree=o,l.queueChild=i,l.queueHTML=a,l.queueText=s,t.exports=l},{10:10,114:114,115:115,93:93}],10:[function(e,t,n){"use strict";var r={html:"http://www.w3.org/1999/xhtml",mathml:"http://www.w3.org/1998/Math/MathML",svg:"http://www.w3.org/2000/svg"};t.exports=r},{}],11:[function(e,t,n){"use strict";function r(e,t){return(e&t)===t}var o=e(112),i=(e(137),{MUST_USE_PROPERTY:1,HAS_BOOLEAN_VALUE:4,HAS_NUMERIC_VALUE:8,HAS_POSITIVE_NUMERIC_VALUE:24,HAS_OVERLOADED_BOOLEAN_VALUE:32,injectDOMPropertyConfig:function(e){var t=i,n=e.Properties||{},a=e.DOMAttributeNamespaces||{},u=e.DOMAttributeNames||{},l=e.DOMPropertyNames||{},c=e.DOMMutationMethods||{};e.isCustomAttribute&&s._isCustomAttributeFunctions.push(e.isCustomAttribute);for(var p in n){s.properties.hasOwnProperty(p)&&o("48",p);var d=p.toLowerCase(),f=n[p],h={attributeName:d,attributeNamespace:null,propertyName:p,mutationMethod:null,mustUseProperty:r(f,t.MUST_USE_PROPERTY),hasBooleanValue:r(f,t.HAS_BOOLEAN_VALUE),hasNumericValue:r(f,t.HAS_NUMERIC_VALUE),hasPositiveNumericValue:r(f,t.HAS_POSITIVE_NUMERIC_VALUE),hasOverloadedBooleanValue:r(f,t.HAS_OVERLOADED_BOOLEAN_VALUE)};if(h.hasBooleanValue+h.hasNumericValue+h.hasOverloadedBooleanValue<=1||o("50",p),u.hasOwnProperty(p)){var m=u[p];h.attributeName=m}a.hasOwnProperty(p)&&(h.attributeNamespace=a[p]),l.hasOwnProperty(p)&&(h.propertyName=l[p]),c.hasOwnProperty(p)&&(h.mutationMethod=c[p]),s.properties[p]=h}}}),a=":A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD",s={ID_ATTRIBUTE_NAME:"data-reactid",ROOT_ATTRIBUTE_NAME:"data-reactroot",ATTRIBUTE_NAME_START_CHAR:a,ATTRIBUTE_NAME_CHAR:a+"\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040",properties:{},getPossibleStandardName:null,_isCustomAttributeFunctions:[],isCustomAttribute:function(e){for(var t=0;t<s._isCustomAttributeFunctions.length;t++)if((0,s._isCustomAttributeFunctions[t])(e))return!0;return!1},injection:i};t.exports=s},{112:112,137:137}],12:[function(e,t,n){"use strict";function r(e){return!!l.hasOwnProperty(e)||!u.hasOwnProperty(e)&&(s.test(e)?(l[e]=!0,!0):(u[e]=!0,!1))}function o(e,t){return null==t||e.hasBooleanValue&&!t||e.hasNumericValue&&isNaN(t)||e.hasPositiveNumericValue&&t<1||e.hasOverloadedBooleanValue&&!1===t}var i=e(11),a=(e(33),e(58),e(111)),s=(e(142),new RegExp("^["+i.ATTRIBUTE_NAME_START_CHAR+"]["+i.ATTRIBUTE_NAME_CHAR+"]*$")),u={},l={},c={createMarkupForID:function(e){return i.ID_ATTRIBUTE_NAME+"="+a(e)},setAttributeForID:function(e,t){e.setAttribute(i.ID_ATTRIBUTE_NAME,t)},createMarkupForRoot:function(){return i.ROOT_ATTRIBUTE_NAME+'=""'},setAttributeForRoot:function(e){e.setAttribute(i.ROOT_ATTRIBUTE_NAME,"")},createMarkupForProperty:function(e,t){var n=i.properties.hasOwnProperty(e)?i.properties[e]:null;if(n){if(o(n,t))return"";var r=n.attributeName;return n.hasBooleanValue||n.hasOverloadedBooleanValue&&!0===t?r+'=""':r+"="+a(t)}return i.isCustomAttribute(e)?null==t?"":e+"="+a(t):null},createMarkupForCustomAttribute:function(e,t){return r(e)&&null!=t?e+"="+a(t):""},setValueForProperty:function(e,t,n){var r=i.properties.hasOwnProperty(t)?i.properties[t]:null;if(r){var a=r.mutationMethod;if(a)a(e,n);else{if(o(r,n))return void this.deleteValueForProperty(e,t);if(r.mustUseProperty)e[r.propertyName]=n;else{var s=r.attributeName,u=r.attributeNamespace;u?e.setAttributeNS(u,s,""+n):r.hasBooleanValue||r.hasOverloadedBooleanValue&&!0===n?e.setAttribute(s,""):e.setAttribute(s,""+n)}}}else if(i.isCustomAttribute(t))return void c.setValueForAttribute(e,t,n)},setValueForAttribute:function(e,t,n){r(t)&&(null==n?e.removeAttribute(t):e.setAttribute(t,""+n))},deleteValueForAttribute:function(e,t){e.removeAttribute(t)},deleteValueForProperty:function(e,t){var n=i.properties.hasOwnProperty(t)?i.properties[t]:null;if(n){var r=n.mutationMethod;if(r)r(e,void 0);else if(n.mustUseProperty){var o=n.propertyName;n.hasBooleanValue?e[o]=!1:e[o]=""}else e.removeAttribute(n.attributeName)}else i.isCustomAttribute(t)&&e.removeAttribute(t)}};t.exports=c},{11:11,111:111,142:142,33:33,58:58}],13:[function(e,t,n){"use strict";var r=e(112),o=e(9),i=e(123),a=e(128),s=e(129),u=(e(137),{dangerouslyReplaceNodeWithMarkup:function(e,t){if(i.canUseDOM||r("56"),t||r("57"),"HTML"===e.nodeName&&r("58"),"string"==typeof t){var n=a(t,s)[0];e.parentNode.replaceChild(n,e)}else o.replaceChildWithTree(e,t)}});t.exports=u},{112:112,123:123,128:128,129:129,137:137,9:9}],14:[function(e,t,n){"use strict";var r=["ResponderEventPlugin","SimpleEventPlugin","TapEventPlugin","EnterLeaveEventPlugin","ChangeEventPlugin","SelectEventPlugin","BeforeInputEventPlugin"];t.exports=r},{}],15:[function(e,t,n){"use strict";var r=e(19),o=e(33),i=e(84),a={mouseEnter:{registrationName:"onMouseEnter",dependencies:["topMouseOut","topMouseOver"]},mouseLeave:{registrationName:"onMouseLeave",dependencies:["topMouseOut","topMouseOver"]}},s={eventTypes:a,extractEvents:function(e,t,n,s){if("topMouseOver"===e&&(n.relatedTarget||n.fromElement))return null;if("topMouseOut"!==e&&"topMouseOver"!==e)return null;var u;if(s.window===s)u=s;else{var l=s.ownerDocument;u=l?l.defaultView||l.parentWindow:window}var c,p;if("topMouseOut"===e){c=t;var d=n.relatedTarget||n.toElement;p=d?o.getClosestInstanceFromNode(d):null}else c=null,p=t;if(c===p)return null;var f=null==c?u:o.getNodeFromInstance(c),h=null==p?u:o.getNodeFromInstance(p),m=i.getPooled(a.mouseLeave,c,n,s);m.type="mouseleave",m.target=f,m.relatedTarget=h;var v=i.getPooled(a.mouseEnter,p,n,s);return v.type="mouseenter",v.target=h,v.relatedTarget=f,r.accumulateEnterLeaveDispatches(m,v,c,p),[m,v]}};t.exports=s},{19:19,33:33,84:84}],16:[function(e,t,n){"use strict";function r(e){return"button"===e||"input"===e||"select"===e||"textarea"===e}function o(e,t,n){switch(e){case"onClick":case"onClickCapture":case"onDoubleClick":case"onDoubleClickCapture":case"onMouseDown":case"onMouseDownCapture":case"onMouseMove":case"onMouseMoveCapture":case"onMouseUp":case"onMouseUpCapture":return!(!n.disabled||!r(t));default:return!1}}var i=e(112),a=e(17),s=e(18),u=e(50),l=e(91),c=e(98),p=(e(137),{}),d=null,f=function(e,t){e&&(s.executeDispatchesInOrder(e,t),e.isPersistent()||e.constructor.release(e))},h=function(e){return f(e,!0)},m=function(e){return f(e,!1)},v=function(e){return"."+e._rootNodeID},g={injection:{injectEventPluginOrder:a.injectEventPluginOrder,injectEventPluginsByName:a.injectEventPluginsByName},putListener:function(e,t,n){"function"!=typeof n&&i("94",t,typeof n);var r=v(e);(p[t]||(p[t]={}))[r]=n;var o=a.registrationNameModules[t];o&&o.didPutListener&&o.didPutListener(e,t,n)},getListener:function(e,t){var n=p[t];if(o(t,e._currentElement.type,e._currentElement.props))return null;var r=v(e);return n&&n[r]},deleteListener:function(e,t){var n=a.registrationNameModules[t];n&&n.willDeleteListener&&n.willDeleteListener(e,t);var r=p[t];r&&delete r[v(e)]},deleteAllListeners:function(e){var t=v(e);for(var n in p)if(p.hasOwnProperty(n)&&p[n][t]){var r=a.registrationNameModules[n];r&&r.willDeleteListener&&r.willDeleteListener(e,n),delete p[n][t]}},extractEvents:function(e,t,n,r){for(var o,i=a.plugins,s=0;s<i.length;s++){var u=i[s];if(u){var c=u.extractEvents(e,t,n,r);c&&(o=l(o,c))}}return o},enqueueEvents:function(e){e&&(d=l(d,e))},processEventQueue:function(e){var t=d;d=null,e?c(t,h):c(t,m),d&&i("95"),u.rethrowCaughtError()},__purge:function(){p={}},__getListenerBank:function(){return p}};t.exports=g},{112:112,137:137,17:17,18:18,50:50,91:91,98:98}],17:[function(e,t,n){"use strict";function r(){if(s)for(var e in u){var t=u[e],n=s.indexOf(e);if(n>-1||a("96",e),!l.plugins[n]){t.extractEvents||a("97",e),l.plugins[n]=t;var r=t.eventTypes;for(var i in r)o(r[i],t,i)||a("98",i,e)}}}function o(e,t,n){l.eventNameDispatchConfigs.hasOwnProperty(n)&&a("99",n),l.eventNameDispatchConfigs[n]=e;var r=e.phasedRegistrationNames;if(r){for(var o in r)if(r.hasOwnProperty(o)){var s=r[o];i(s,t,n)}return!0}return!!e.registrationName&&(i(e.registrationName,t,n),!0)}function i(e,t,n){l.registrationNameModules[e]&&a("100",e),l.registrationNameModules[e]=t,l.registrationNameDependencies[e]=t.eventTypes[n].dependencies}var a=e(112),s=(e(137),null),u={},l={plugins:[],eventNameDispatchConfigs:{},registrationNameModules:{},registrationNameDependencies:{},possibleRegistrationNames:null,injectEventPluginOrder:function(e){s&&a("101"),s=Array.prototype.slice.call(e),r()},injectEventPluginsByName:function(e){var t=!1;for(var n in e)if(e.hasOwnProperty(n)){var o=e[n];u.hasOwnProperty(n)&&u[n]===o||(u[n]&&a("102",n),u[n]=o,t=!0)}t&&r()},getPluginModuleForEvent:function(e){var t=e.dispatchConfig;if(t.registrationName)return l.registrationNameModules[t.registrationName]||null;if(void 0!==t.phasedRegistrationNames){var n=t.phasedRegistrationNames;for(var r in n)if(n.hasOwnProperty(r)){var o=l.registrationNameModules[n[r]];if(o)return o}}return null},_resetEventPlugins:function(){s=null;for(var e in u)u.hasOwnProperty(e)&&delete u[e];l.plugins.length=0;var t=l.eventNameDispatchConfigs;for(var n in t)t.hasOwnProperty(n)&&delete t[n];var r=l.registrationNameModules;for(var o in r)r.hasOwnProperty(o)&&delete r[o]}};t.exports=l},{112:112,137:137}],18:[function(e,t,n){"use strict";function r(e){return"topMouseUp"===e||"topTouchEnd"===e||"topTouchCancel"===e}function o(e){return"topMouseMove"===e||"topTouchMove"===e}function i(e){return"topMouseDown"===e||"topTouchStart"===e}function a(e,t,n,r){var o=e.type||"unknown-event";e.currentTarget=g.getNodeFromInstance(r),t?m.invokeGuardedCallbackWithCatch(o,n,e):m.invokeGuardedCallback(o,n,e),e.currentTarget=null}function s(e,t){var n=e._dispatchListeners,r=e._dispatchInstances;if(Array.isArray(n))for(var o=0;o<n.length&&!e.isPropagationStopped();o++)a(e,t,n[o],r[o]);else n&&a(e,t,n,r);e._dispatchListeners=null,e._dispatchInstances=null}function u(e){var t=e._dispatchListeners,n=e._dispatchInstances;if(Array.isArray(t)){for(var r=0;r<t.length&&!e.isPropagationStopped();r++)if(t[r](e,n[r]))return n[r]}else if(t&&t(e,n))return n;return null}function l(e){var t=u(e);return e._dispatchInstances=null,e._dispatchListeners=null,t}function c(e){var t=e._dispatchListeners,n=e._dispatchInstances;Array.isArray(t)&&h("103"),e.currentTarget=t?g.getNodeFromInstance(n):null;var r=t?t(e):null;return e.currentTarget=null,e._dispatchListeners=null,e._dispatchInstances=null,r}function p(e){return!!e._dispatchListeners}var d,f,h=e(112),m=e(50),v=(e(137),e(142),{injectComponentTree:function(e){d=e},injectTreeTraversal:function(e){f=e}}),g={isEndish:r,isMoveish:o,isStartish:i,executeDirectDispatch:c,executeDispatchesInOrder:s,executeDispatchesInOrderStopAtTrue:l,hasDispatches:p,getInstanceFromNode:function(e){return d.getInstanceFromNode(e)},getNodeFromInstance:function(e){return d.getNodeFromInstance(e)},isAncestor:function(e,t){return f.isAncestor(e,t)},getLowestCommonAncestor:function(e,t){return f.getLowestCommonAncestor(e,t)},getParentInstance:function(e){return f.getParentInstance(e)},traverseTwoPhase:function(e,t,n){return f.traverseTwoPhase(e,t,n)},traverseEnterLeave:function(e,t,n,r,o){return f.traverseEnterLeave(e,t,n,r,o)},injection:v};t.exports=g},{112:112,137:137,142:142,50:50}],19:[function(e,t,n){"use strict";function r(e,t,n){var r=t.dispatchConfig.phasedRegistrationNames[n];return g(e,r)}function o(e,t,n){var o=r(e,n,t);o&&(n._dispatchListeners=m(n._dispatchListeners,o),n._dispatchInstances=m(n._dispatchInstances,e))}function i(e){e&&e.dispatchConfig.phasedRegistrationNames&&h.traverseTwoPhase(e._targetInst,o,e)}function a(e){if(e&&e.dispatchConfig.phasedRegistrationNames){var t=e._targetInst,n=t?h.getParentInstance(t):null;h.traverseTwoPhase(n,o,e)}}function s(e,t,n){if(n&&n.dispatchConfig.registrationName){var r=n.dispatchConfig.registrationName,o=g(e,r);o&&(n._dispatchListeners=m(n._dispatchListeners,o),n._dispatchInstances=m(n._dispatchInstances,e))}}function u(e){e&&e.dispatchConfig.registrationName&&s(e._targetInst,null,e)}function l(e){v(e,i)}function c(e){v(e,a)}function p(e,t,n,r){h.traverseEnterLeave(n,r,s,e,t)}function d(e){v(e,u)}var f=e(16),h=e(18),m=e(91),v=e(98),g=(e(142),f.getListener),y={accumulateTwoPhaseDispatches:l,accumulateTwoPhaseDispatchesSkipTarget:c,accumulateDirectDispatches:d,accumulateEnterLeaveDispatches:p};t.exports=y},{142:142,16:16,18:18,91:91,98:98}],20:[function(e,t,n){"use strict";function r(e){this._root=e,this._startText=this.getText(),this._fallbackText=null}var o=e(143),i=e(24),a=e(106);o(r.prototype,{destructor:function(){this._root=null,this._startText=null,this._fallbackText=null},getText:function(){return"value"in this._root?this._root.value:this._root[a()]},getData:function(){if(this._fallbackText)return this._fallbackText;var e,t,n=this._startText,r=n.length,o=this.getText(),i=o.length;for(e=0;e<r&&n[e]===o[e];e++);var a=r-e;for(t=1;t<=a&&n[r-t]===o[i-t];t++);var s=t>1?1-t:void 0;return this._fallbackText=o.slice(e,s),this._fallbackText}}),i.addPoolingTo(r),t.exports=r},{106:106,143:143,24:24}],21:[function(e,t,n){"use strict";var r=e(11),o=r.injection.MUST_USE_PROPERTY,i=r.injection.HAS_BOOLEAN_VALUE,a=r.injection.HAS_NUMERIC_VALUE,s=r.injection.HAS_POSITIVE_NUMERIC_VALUE,u=r.injection.HAS_OVERLOADED_BOOLEAN_VALUE,l={isCustomAttribute:RegExp.prototype.test.bind(new RegExp("^(data|aria)-["+r.ATTRIBUTE_NAME_CHAR+"]*$")),Properties:{accept:0,acceptCharset:0,accessKey:0,action:0,allowFullScreen:i,allowTransparency:0,alt:0,as:0,async:i,autoComplete:0,autoPlay:i,capture:i,cellPadding:0,cellSpacing:0,charSet:0,challenge:0,checked:o|i,cite:0,classID:0,className:0,cols:s,colSpan:0,content:0,contentEditable:0,contextMenu:0,controls:i,coords:0,crossOrigin:0,data:0,dateTime:0,default:i,defer:i,dir:0,disabled:i,download:u,draggable:0,encType:0,form:0,formAction:0,formEncType:0,formMethod:0,formNoValidate:i,formTarget:0,frameBorder:0,headers:0,height:0,hidden:i,high:0,href:0,hrefLang:0,htmlFor:0,httpEquiv:0,icon:0,id:0,inputMode:0,integrity:0,is:0,keyParams:0,keyType:0,kind:0,label:0,lang:0,list:0,loop:i,low:0,manifest:0,marginHeight:0,marginWidth:0,max:0,maxLength:0,media:0,mediaGroup:0,method:0,min:0,minLength:0,multiple:o|i,muted:o|i,name:0,nonce:0,noValidate:i,open:i,optimum:0,pattern:0,placeholder:0,playsInline:i,poster:0,preload:0,profile:0,radioGroup:0,readOnly:i,referrerPolicy:0,rel:0,required:i,reversed:i,role:0,rows:s,rowSpan:a,sandbox:0,scope:0,scoped:i,scrolling:0,seamless:i,selected:o|i,shape:0,size:s,sizes:0,span:s,spellCheck:0,src:0,srcDoc:0,srcLang:0,srcSet:0,start:a,step:0,style:0,summary:0,tabIndex:0,target:0,title:0,type:0,useMap:0,value:0,width:0,wmode:0,wrap:0,about:0,datatype:0,inlist:0,prefix:0,property:0,resource:0,typeof:0,vocab:0,autoCapitalize:0,autoCorrect:0,autoSave:0,color:0,itemProp:0,itemScope:i,itemType:0,itemID:0,itemRef:0,results:0,security:0,unselectable:0},DOMAttributeNames:{acceptCharset:"accept-charset",className:"class",htmlFor:"for",httpEquiv:"http-equiv"},DOMPropertyNames:{},DOMMutationMethods:{value:function(e,t){if(null==t)return e.removeAttribute("value");"number"!==e.type||!1===e.hasAttribute("value")?e.setAttribute("value",""+t):e.validity&&!e.validity.badInput&&e.ownerDocument.activeElement!==e&&e.setAttribute("value",""+t)}}};t.exports=l},{11:11}],22:[function(e,t,n){"use strict";function r(e){var t={"=":"=0",":":"=2"};return"$"+(""+e).replace(/[=:]/g,function(e){return t[e]})}function o(e){var t={"=0":"=","=2":":"};return(""+("."===e[0]&&"$"===e[1]?e.substring(2):e.substring(1))).replace(/(=0|=2)/g,function(e){return t[e]})}var i={escape:r,unescape:o};t.exports=i},{}],23:[function(e,t,n){"use strict";function r(e){null!=e.checkedLink&&null!=e.valueLink&&s("87")}function o(e){r(e),(null!=e.value||null!=e.onChange)&&s("88")}function i(e){r(e),(null!=e.checked||null!=e.onChange)&&s("89")}function a(e){if(e){var t=e.getName();if(t)return" Check the render method of `"+t+"`."}return""}var s=e(112),u=e(64),l=e(145),c=e(120),p=l(c.isValidElement),d=(e(137),e(142),{button:!0,checkbox:!0,image:!0,hidden:!0,radio:!0,reset:!0,submit:!0}),f={value:function(e,t,n){return!e[t]||d[e.type]||e.onChange||e.readOnly||e.disabled?null:new Error("You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`.")},checked:function(e,t,n){return!e[t]||e.onChange||e.readOnly||e.disabled?null:new Error("You provided a `checked` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultChecked`. Otherwise, set either `onChange` or `readOnly`.")},onChange:p.func},h={},m={checkPropTypes:function(e,t,n){for(var r in f){if(f.hasOwnProperty(r))var o=f[r](t,r,e,"prop",null,u);o instanceof Error&&!(o.message in h)&&(h[o.message]=!0,a(n))}},getValue:function(e){return e.valueLink?(o(e),e.valueLink.value):e.value},getChecked:function(e){return e.checkedLink?(i(e),e.checkedLink.value):e.checked},executeOnChange:function(e,t){return e.valueLink?(o(e),e.valueLink.requestChange(t.target.value)):e.checkedLink?(i(e),e.checkedLink.requestChange(t.target.checked)):e.onChange?e.onChange.call(void 0,t):void 0}};t.exports=m},{112:112,120:120,137:137,142:142,145:145,64:64}],24:[function(e,t,n){"use strict";var r=e(112),o=(e(137),function(e){var t=this;if(t.instancePool.length){var n=t.instancePool.pop();return t.call(n,e),n}return new t(e)}),i=function(e,t){var n=this;if(n.instancePool.length){var r=n.instancePool.pop();return n.call(r,e,t),r}return new n(e,t)},a=function(e,t,n){var r=this;if(r.instancePool.length){var o=r.instancePool.pop();return r.call(o,e,t,n),o}return new r(e,t,n)},s=function(e,t,n,r){var o=this;if(o.instancePool.length){var i=o.instancePool.pop();return o.call(i,e,t,n,r),i}return new o(e,t,n,r)},u=function(e){var t=this;e instanceof t||r("25"),e.destructor(),t.instancePool.length<t.poolSize&&t.instancePool.push(e)},l=o,c=function(e,t){var n=e;return n.instancePool=[],n.getPooled=t||l,n.poolSize||(n.poolSize=10),n.release=u,n},p={addPoolingTo:c,oneArgumentPooler:o,twoArgumentPooler:i,threeArgumentPooler:a,fourArgumentPooler:s};t.exports=p},{112:112,137:137}],25:[function(e,t,n){"use strict";function r(e){return Object.prototype.hasOwnProperty.call(e,m)||(e[m]=f++,p[e[m]]={}),p[e[m]]}var o,i=e(143),a=e(17),s=e(51),u=e(90),l=e(107),c=e(109),p={},d=!1,f=0,h={topAbort:"abort",topAnimationEnd:l("animationend")||"animationend",topAnimationIteration:l("animationiteration")||"animationiteration",topAnimationStart:l("animationstart")||"animationstart",topBlur:"blur",topCanPlay:"canplay",topCanPlayThrough:"canplaythrough",topChange:"change",topClick:"click",topCompositionEnd:"compositionend",topCompositionStart:"compositionstart",topCompositionUpdate:"compositionupdate",topContextMenu:"contextmenu",topCopy:"copy",topCut:"cut",topDoubleClick:"dblclick",topDrag:"drag",topDragEnd:"dragend",topDragEnter:"dragenter",topDragExit:"dragexit",topDragLeave:"dragleave",topDragOver:"dragover",topDragStart:"dragstart",topDrop:"drop",topDurationChange:"durationchange",topEmptied:"emptied",topEncrypted:"encrypted",topEnded:"ended",topError:"error", +topFocus:"focus",topInput:"input",topKeyDown:"keydown",topKeyPress:"keypress",topKeyUp:"keyup",topLoadedData:"loadeddata",topLoadedMetadata:"loadedmetadata",topLoadStart:"loadstart",topMouseDown:"mousedown",topMouseMove:"mousemove",topMouseOut:"mouseout",topMouseOver:"mouseover",topMouseUp:"mouseup",topPaste:"paste",topPause:"pause",topPlay:"play",topPlaying:"playing",topProgress:"progress",topRateChange:"ratechange",topScroll:"scroll",topSeeked:"seeked",topSeeking:"seeking",topSelectionChange:"selectionchange",topStalled:"stalled",topSuspend:"suspend",topTextInput:"textInput",topTimeUpdate:"timeupdate",topTouchCancel:"touchcancel",topTouchEnd:"touchend",topTouchMove:"touchmove",topTouchStart:"touchstart",topTransitionEnd:l("transitionend")||"transitionend",topVolumeChange:"volumechange",topWaiting:"waiting",topWheel:"wheel"},m="_reactListenersID"+String(Math.random()).slice(2),v=i({},s,{ReactEventListener:null,injection:{injectReactEventListener:function(e){e.setHandleTopLevel(v.handleTopLevel),v.ReactEventListener=e}},setEnabled:function(e){v.ReactEventListener&&v.ReactEventListener.setEnabled(e)},isEnabled:function(){return!(!v.ReactEventListener||!v.ReactEventListener.isEnabled())},listenTo:function(e,t){for(var n=t,o=r(n),i=a.registrationNameDependencies[e],s=0;s<i.length;s++){var u=i[s];o.hasOwnProperty(u)&&o[u]||("topWheel"===u?c("wheel")?v.ReactEventListener.trapBubbledEvent("topWheel","wheel",n):c("mousewheel")?v.ReactEventListener.trapBubbledEvent("topWheel","mousewheel",n):v.ReactEventListener.trapBubbledEvent("topWheel","DOMMouseScroll",n):"topScroll"===u?c("scroll",!0)?v.ReactEventListener.trapCapturedEvent("topScroll","scroll",n):v.ReactEventListener.trapBubbledEvent("topScroll","scroll",v.ReactEventListener.WINDOW_HANDLE):"topFocus"===u||"topBlur"===u?(c("focus",!0)?(v.ReactEventListener.trapCapturedEvent("topFocus","focus",n),v.ReactEventListener.trapCapturedEvent("topBlur","blur",n)):c("focusin")&&(v.ReactEventListener.trapBubbledEvent("topFocus","focusin",n),v.ReactEventListener.trapBubbledEvent("topBlur","focusout",n)),o.topBlur=!0,o.topFocus=!0):h.hasOwnProperty(u)&&v.ReactEventListener.trapBubbledEvent(u,h[u],n),o[u]=!0)}},trapBubbledEvent:function(e,t,n){return v.ReactEventListener.trapBubbledEvent(e,t,n)},trapCapturedEvent:function(e,t,n){return v.ReactEventListener.trapCapturedEvent(e,t,n)},supportsEventPageXY:function(){if(!document.createEvent)return!1;var e=document.createEvent("MouseEvent");return null!=e&&"pageX"in e},ensureScrollValueMonitoring:function(){if(void 0===o&&(o=v.supportsEventPageXY()),!o&&!d){var e=u.refreshScrollValues;v.ReactEventListener.monitorScrollValue(e),d=!0}}});t.exports=v},{107:107,109:109,143:143,17:17,51:51,90:90}],26:[function(e,t,n){(function(n){"use strict";function r(e,t,n,r){var o=void 0===e[n];null!=t&&o&&(e[n]=i(t,!0))}var o=e(66),i=e(108),a=(e(22),e(116)),s=e(117);e(142);void 0!==n&&n.env;var u={instantiateChildren:function(e,t,n,o){if(null==e)return null;var i={};return s(e,r,i),i},updateChildren:function(e,t,n,r,s,u,l,c,p){if(t||e){var d,f;for(d in t)if(t.hasOwnProperty(d)){f=e&&e[d];var h=f&&f._currentElement,m=t[d];if(null!=f&&a(h,m))o.receiveComponent(f,m,s,c),t[d]=f;else{f&&(r[d]=o.getHostNode(f),o.unmountComponent(f,!1));var v=i(m,!0);t[d]=v;var g=o.mountComponent(v,s,u,l,c,p);n.push(g)}}for(d in e)!e.hasOwnProperty(d)||t&&t.hasOwnProperty(d)||(f=e[d],r[d]=o.getHostNode(f),o.unmountComponent(f,!1))}},unmountChildren:function(e,t){for(var n in e)if(e.hasOwnProperty(n)){var r=e[n];o.unmountComponent(r,t)}}};t.exports=u}).call(this,void 0)},{108:108,116:116,117:117,142:142,22:22,66:66}],27:[function(e,t,n){"use strict";var r=e(8),o=e(37),i={processChildrenUpdates:o.dangerouslyProcessChildrenUpdates,replaceNodeWithMarkup:r.dangerouslyReplaceNodeWithMarkup};t.exports=i},{37:37,8:8}],28:[function(e,t,n){"use strict";var r=e(112),o=(e(137),!1),i={replaceNodeWithMarkup:null,processChildrenUpdates:null,injection:{injectEnvironment:function(e){o&&r("104"),i.replaceNodeWithMarkup=e.replaceNodeWithMarkup,i.processChildrenUpdates=e.processChildrenUpdates,o=!0}}};t.exports=i},{112:112,137:137}],29:[function(e,t,n){"use strict";function r(e){}function o(e){return!(!e.prototype||!e.prototype.isReactComponent)}function i(e){return!(!e.prototype||!e.prototype.isPureReactComponent)}var a=e(112),s=e(143),u=e(120),l=e(28),c=e(119),p=e(50),d=e(57),f=(e(58),e(62)),h=e(66),m=e(130),v=(e(137),e(141)),g=e(116),y=(e(142),{ImpureClass:0,PureClass:1,StatelessFunctional:2});r.prototype.render=function(){var e=d.get(this)._currentElement.type,t=e(this.props,this.context,this.updater);return t};var _=1,C={construct:function(e){this._currentElement=e,this._rootNodeID=0,this._compositeType=null,this._instance=null,this._hostParent=null,this._hostContainerInfo=null,this._updateBatchNumber=null,this._pendingElement=null,this._pendingStateQueue=null,this._pendingReplaceState=!1,this._pendingForceUpdate=!1,this._renderedNodeType=null,this._renderedComponent=null,this._context=null,this._mountOrder=0,this._topLevelWrapper=null,this._pendingCallbacks=null,this._calledComponentWillUnmount=!1},mountComponent:function(e,t,n,s){this._context=s,this._mountOrder=_++,this._hostParent=t,this._hostContainerInfo=n;var l,c=this._currentElement.props,p=this._processContext(s),f=this._currentElement.type,h=e.getUpdateQueue(),v=o(f),g=this._constructComponent(v,c,p,h);v||null!=g&&null!=g.render?i(f)?this._compositeType=y.PureClass:this._compositeType=y.ImpureClass:(l=g,null===g||!1===g||u.isValidElement(g)||a("105",f.displayName||f.name||"Component"),g=new r(f),this._compositeType=y.StatelessFunctional),g.props=c,g.context=p,g.refs=m,g.updater=h,this._instance=g,d.set(g,this);var C=g.state;void 0===C&&(g.state=C=null),("object"!=typeof C||Array.isArray(C))&&a("106",this.getName()||"ReactCompositeComponent"),this._pendingStateQueue=null,this._pendingReplaceState=!1,this._pendingForceUpdate=!1;var b;return b=g.unstable_handleError?this.performInitialMountWithErrorHandling(l,t,n,e,s):this.performInitialMount(l,t,n,e,s),g.componentDidMount&&e.getReactMountReady().enqueue(g.componentDidMount,g),b},_constructComponent:function(e,t,n,r){return this._constructComponentWithoutOwner(e,t,n,r)},_constructComponentWithoutOwner:function(e,t,n,r){var o=this._currentElement.type;return e?new o(t,n,r):o(t,n,r)},performInitialMountWithErrorHandling:function(e,t,n,r,o){var i,a=r.checkpoint();try{i=this.performInitialMount(e,t,n,r,o)}catch(s){r.rollback(a),this._instance.unstable_handleError(s),this._pendingStateQueue&&(this._instance.state=this._processPendingState(this._instance.props,this._instance.context)),a=r.checkpoint(),this._renderedComponent.unmountComponent(!0),r.rollback(a),i=this.performInitialMount(e,t,n,r,o)}return i},performInitialMount:function(e,t,n,r,o){var i=this._instance;i.componentWillMount&&(i.componentWillMount(),this._pendingStateQueue&&(i.state=this._processPendingState(i.props,i.context))),void 0===e&&(e=this._renderValidatedComponent());var a=f.getType(e);this._renderedNodeType=a;var s=this._instantiateReactComponent(e,a!==f.EMPTY);return this._renderedComponent=s,h.mountComponent(s,r,t,n,this._processChildContext(o),0)},getHostNode:function(){return h.getHostNode(this._renderedComponent)},unmountComponent:function(e){if(this._renderedComponent){var t=this._instance;if(t.componentWillUnmount&&!t._calledComponentWillUnmount)if(t._calledComponentWillUnmount=!0,e){var n=this.getName()+".componentWillUnmount()";p.invokeGuardedCallback(n,t.componentWillUnmount.bind(t))}else t.componentWillUnmount();this._renderedComponent&&(h.unmountComponent(this._renderedComponent,e),this._renderedNodeType=null,this._renderedComponent=null,this._instance=null),this._pendingStateQueue=null,this._pendingReplaceState=!1,this._pendingForceUpdate=!1,this._pendingCallbacks=null,this._pendingElement=null,this._context=null,this._rootNodeID=0,this._topLevelWrapper=null,d.remove(t)}},_maskContext:function(e){var t=this._currentElement.type,n=t.contextTypes;if(!n)return m;var r={};for(var o in n)r[o]=e[o];return r},_processContext:function(e){return this._maskContext(e)},_processChildContext:function(e){var t,n=this._currentElement.type,r=this._instance;if(r.getChildContext&&(t=r.getChildContext()),t){"object"!=typeof n.childContextTypes&&a("107",this.getName()||"ReactCompositeComponent");for(var o in t)o in n.childContextTypes||a("108",this.getName()||"ReactCompositeComponent",o);return s({},e,t)}return e},_checkContextTypes:function(e,t,n){},receiveComponent:function(e,t,n){var r=this._currentElement,o=this._context;this._pendingElement=null,this.updateComponent(t,r,e,o,n)},performUpdateIfNecessary:function(e){null!=this._pendingElement?h.receiveComponent(this,this._pendingElement,e,this._context):null!==this._pendingStateQueue||this._pendingForceUpdate?this.updateComponent(e,this._currentElement,this._currentElement,this._context,this._context):this._updateBatchNumber=null},updateComponent:function(e,t,n,r,o){var i=this._instance;null==i&&a("136",this.getName()||"ReactCompositeComponent");var s,u=!1;this._context===o?s=i.context:(s=this._processContext(o),u=!0);var l=t.props,c=n.props;t!==n&&(u=!0),u&&i.componentWillReceiveProps&&i.componentWillReceiveProps(c,s);var p=this._processPendingState(c,s),d=!0;this._pendingForceUpdate||(i.shouldComponentUpdate?d=i.shouldComponentUpdate(c,p,s):this._compositeType===y.PureClass&&(d=!v(l,c)||!v(i.state,p))),this._updateBatchNumber=null,d?(this._pendingForceUpdate=!1,this._performComponentUpdate(n,c,p,s,e,o)):(this._currentElement=n,this._context=o,i.props=c,i.state=p,i.context=s)},_processPendingState:function(e,t){var n=this._instance,r=this._pendingStateQueue,o=this._pendingReplaceState;if(this._pendingReplaceState=!1,this._pendingStateQueue=null,!r)return n.state;if(o&&1===r.length)return r[0];for(var i=s({},o?r[0]:n.state),a=o?1:0;a<r.length;a++){var u=r[a];s(i,"function"==typeof u?u.call(n,i,e,t):u)}return i},_performComponentUpdate:function(e,t,n,r,o,i){var a,s,u,l=this._instance,c=Boolean(l.componentDidUpdate);c&&(a=l.props,s=l.state,u=l.context),l.componentWillUpdate&&l.componentWillUpdate(t,n,r),this._currentElement=e,this._context=i,l.props=t,l.state=n,l.context=r,this._updateRenderedComponent(o,i),c&&o.getReactMountReady().enqueue(l.componentDidUpdate.bind(l,a,s,u),l)},_updateRenderedComponent:function(e,t){var n=this._renderedComponent,r=n._currentElement,o=this._renderValidatedComponent();if(g(r,o))h.receiveComponent(n,o,e,this._processChildContext(t));else{var i=h.getHostNode(n);h.unmountComponent(n,!1);var a=f.getType(o);this._renderedNodeType=a;var s=this._instantiateReactComponent(o,a!==f.EMPTY);this._renderedComponent=s;var u=h.mountComponent(s,e,this._hostParent,this._hostContainerInfo,this._processChildContext(t),0);this._replaceNodeWithMarkup(i,u,n)}},_replaceNodeWithMarkup:function(e,t,n){l.replaceNodeWithMarkup(e,t,n)},_renderValidatedComponentWithoutOwnerOrContext:function(){return this._instance.render()},_renderValidatedComponent:function(){var e;if(this._compositeType!==y.StatelessFunctional){c.current=this;try{e=this._renderValidatedComponentWithoutOwnerOrContext()}finally{c.current=null}}else e=this._renderValidatedComponentWithoutOwnerOrContext();return null===e||!1===e||u.isValidElement(e)||a("109",this.getName()||"ReactCompositeComponent"),e},attachRef:function(e,t){var n=this.getPublicInstance();null==n&&a("110");var r=t.getPublicInstance();(n.refs===m?n.refs={}:n.refs)[e]=r},detachRef:function(e){delete this.getPublicInstance().refs[e]},getName:function(){var e=this._currentElement.type,t=this._instance&&this._instance.constructor;return e.displayName||t&&t.displayName||e.name||t&&t.name||null},getPublicInstance:function(){var e=this._instance;return this._compositeType===y.StatelessFunctional?null:e},_instantiateReactComponent:null};t.exports=C},{112:112,116:116,119:119,120:120,130:130,137:137,141:141,142:142,143:143,28:28,50:50,57:57,58:58,62:62,66:66}],30:[function(e,t,n){"use strict";var r=e(33),o=e(47),i=e(60),a=e(66),s=e(71),u=e(72),l=e(96),c=e(103),p=e(113);e(142);o.inject();var d={findDOMNode:l,render:i.render,unmountComponentAtNode:i.unmountComponentAtNode,version:u,unstable_batchedUpdates:s.batchedUpdates,unstable_renderSubtreeIntoContainer:p};"undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject&&__REACT_DEVTOOLS_GLOBAL_HOOK__.inject({ComponentTree:{getClosestInstanceFromNode:r.getClosestInstanceFromNode,getNodeFromInstance:function(e){return e._renderedComponent&&(e=c(e)),e?r.getNodeFromInstance(e):null}},Mount:i,Reconciler:a});t.exports=d},{103:103,113:113,142:142,33:33,47:47,60:60,66:66,71:71,72:72,96:96}],31:[function(e,t,n){"use strict";function r(e){if(e){var t=e._currentElement._owner||null;if(t){var n=t.getName();if(n)return" This DOM node was rendered by `"+n+"`."}}return""}function o(e,t){t&&(Y[e._tag]&&(null!=t.children||null!=t.dangerouslySetInnerHTML)&&m("137",e._tag,e._currentElement._owner?" Check the render method of "+e._currentElement._owner.getName()+".":""),null!=t.dangerouslySetInnerHTML&&(null!=t.children&&m("60"),"object"==typeof t.dangerouslySetInnerHTML&&B in t.dangerouslySetInnerHTML||m("61")),null!=t.style&&"object"!=typeof t.style&&m("62",r(e)))}function i(e,t,n,r){if(!(r instanceof R)){var o=e._hostContainerInfo,i=o._node&&o._node.nodeType===H,s=i?o._node:o._ownerDocument;F(t,s),r.getReactMountReady().enqueue(a,{inst:e,registrationName:t,listener:n})}}function a(){var e=this;x.putListener(e.inst,e.registrationName,e.listener)}function s(){var e=this;S.postMountWrapper(e)}function u(){var e=this;I.postMountWrapper(e)}function l(){var e=this;N.postMountWrapper(e)}function c(){var e=this;e._rootNodeID||m("63");var t=U(e);switch(t||m("64"),e._tag){case"iframe":case"object":e._wrapperState.listeners=[T.trapBubbledEvent("topLoad","load",t)];break;case"video":case"audio":e._wrapperState.listeners=[];for(var n in q)q.hasOwnProperty(n)&&e._wrapperState.listeners.push(T.trapBubbledEvent(n,q[n],t));break;case"source":e._wrapperState.listeners=[T.trapBubbledEvent("topError","error",t)];break;case"img":e._wrapperState.listeners=[T.trapBubbledEvent("topError","error",t),T.trapBubbledEvent("topLoad","load",t)];break;case"form":e._wrapperState.listeners=[T.trapBubbledEvent("topReset","reset",t),T.trapBubbledEvent("topSubmit","submit",t)];break;case"input":case"select":case"textarea":e._wrapperState.listeners=[T.trapBubbledEvent("topInvalid","invalid",t)]}}function p(){M.postUpdateWrapper(this)}function d(e){G.call(Q,e)||(X.test(e)||m("65",e),Q[e]=!0)}function f(e,t){return e.indexOf("-")>=0||null!=t.is}function h(e){var t=e.type;d(t),this._currentElement=e,this._tag=t.toLowerCase(),this._namespaceURI=null,this._renderedChildren=null,this._previousStyle=null,this._previousStyleCopy=null,this._hostNode=null,this._hostParent=null,this._rootNodeID=0,this._domID=0,this._hostContainerInfo=null,this._wrapperState=null,this._topLevelWrapper=null,this._flags=0}var m=e(112),v=e(143),g=e(2),y=e(5),_=e(9),C=e(10),b=e(11),E=e(12),x=e(16),w=e(17),T=e(25),k=e(32),P=e(33),S=e(38),N=e(39),M=e(40),I=e(43),O=(e(58),e(61)),R=e(68),A=(e(129),e(95)),D=(e(137),e(109),e(141),e(118),e(142),k),L=x.deleteListener,U=P.getNodeFromInstance,F=T.listenTo,j=w.registrationNameModules,V={string:!0,number:!0},B="__html",W={children:null,dangerouslySetInnerHTML:null,suppressContentEditableWarning:null},H=11,q={topAbort:"abort",topCanPlay:"canplay",topCanPlayThrough:"canplaythrough",topDurationChange:"durationchange",topEmptied:"emptied",topEncrypted:"encrypted",topEnded:"ended",topError:"error",topLoadedData:"loadeddata",topLoadedMetadata:"loadedmetadata",topLoadStart:"loadstart",topPause:"pause",topPlay:"play",topPlaying:"playing",topProgress:"progress",topRateChange:"ratechange",topSeeked:"seeked",topSeeking:"seeking",topStalled:"stalled",topSuspend:"suspend",topTimeUpdate:"timeupdate",topVolumeChange:"volumechange",topWaiting:"waiting"},K={area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0},z={listing:!0,pre:!0,textarea:!0},Y=v({menuitem:!0},K),X=/^[a-zA-Z][a-zA-Z:_\.\-\d]*$/,Q={},G={}.hasOwnProperty,$=1;h.displayName="ReactDOMComponent",h.Mixin={mountComponent:function(e,t,n,r){this._rootNodeID=$++,this._domID=n._idCounter++,this._hostParent=t,this._hostContainerInfo=n;var i=this._currentElement.props;switch(this._tag){case"audio":case"form":case"iframe":case"img":case"link":case"object":case"source":case"video":this._wrapperState={listeners:null},e.getReactMountReady().enqueue(c,this);break;case"input":S.mountWrapper(this,i,t),i=S.getHostProps(this,i),e.getReactMountReady().enqueue(c,this);break;case"option":N.mountWrapper(this,i,t),i=N.getHostProps(this,i);break;case"select":M.mountWrapper(this,i,t),i=M.getHostProps(this,i),e.getReactMountReady().enqueue(c,this);break;case"textarea":I.mountWrapper(this,i,t),i=I.getHostProps(this,i),e.getReactMountReady().enqueue(c,this)}o(this,i);var a,p;null!=t?(a=t._namespaceURI,p=t._tag):n._tag&&(a=n._namespaceURI,p=n._tag),(null==a||a===C.svg&&"foreignobject"===p)&&(a=C.html),a===C.html&&("svg"===this._tag?a=C.svg:"math"===this._tag&&(a=C.mathml)),this._namespaceURI=a;var d;if(e.useCreateElement){var f,h=n._ownerDocument;if(a===C.html)if("script"===this._tag){var m=h.createElement("div"),v=this._currentElement.type;m.innerHTML="<"+v+"></"+v+">",f=m.removeChild(m.firstChild)}else f=i.is?h.createElement(this._currentElement.type,i.is):h.createElement(this._currentElement.type);else f=h.createElementNS(a,this._currentElement.type);P.precacheNode(this,f),this._flags|=D.hasCachedChildNodes,this._hostParent||E.setAttributeForRoot(f),this._updateDOMProperties(null,i,e);var y=_(f);this._createInitialChildren(e,i,r,y),d=y}else{var b=this._createOpenTagMarkupAndPutListeners(e,i),x=this._createContentMarkup(e,i,r);d=!x&&K[this._tag]?b+"/>":b+">"+x+"</"+this._currentElement.type+">"}switch(this._tag){case"input":e.getReactMountReady().enqueue(s,this),i.autoFocus&&e.getReactMountReady().enqueue(g.focusDOMComponent,this);break;case"textarea":e.getReactMountReady().enqueue(u,this),i.autoFocus&&e.getReactMountReady().enqueue(g.focusDOMComponent,this);break;case"select":case"button":i.autoFocus&&e.getReactMountReady().enqueue(g.focusDOMComponent,this);break;case"option":e.getReactMountReady().enqueue(l,this)}return d},_createOpenTagMarkupAndPutListeners:function(e,t){var n="<"+this._currentElement.type;for(var r in t)if(t.hasOwnProperty(r)){var o=t[r];if(null!=o)if(j.hasOwnProperty(r))o&&i(this,r,o,e);else{"style"===r&&(o&&(o=this._previousStyleCopy=v({},t.style)),o=y.createMarkupForStyles(o,this));var a=null;null!=this._tag&&f(this._tag,t)?W.hasOwnProperty(r)||(a=E.createMarkupForCustomAttribute(r,o)):a=E.createMarkupForProperty(r,o),a&&(n+=" "+a)}}return e.renderToStaticMarkup?n:(this._hostParent||(n+=" "+E.createMarkupForRoot()),n+=" "+E.createMarkupForID(this._domID))},_createContentMarkup:function(e,t,n){var r="",o=t.dangerouslySetInnerHTML;if(null!=o)null!=o.__html&&(r=o.__html);else{var i=V[typeof t.children]?t.children:null,a=null!=i?null:t.children;if(null!=i)r=A(i);else if(null!=a){var s=this.mountChildren(a,e,n);r=s.join("")}}return z[this._tag]&&"\n"===r.charAt(0)?"\n"+r:r},_createInitialChildren:function(e,t,n,r){var o=t.dangerouslySetInnerHTML;if(null!=o)null!=o.__html&&_.queueHTML(r,o.__html);else{var i=V[typeof t.children]?t.children:null,a=null!=i?null:t.children;if(null!=i)""!==i&&_.queueText(r,i);else if(null!=a)for(var s=this.mountChildren(a,e,n),u=0;u<s.length;u++)_.queueChild(r,s[u])}},receiveComponent:function(e,t,n){var r=this._currentElement;this._currentElement=e,this.updateComponent(t,r,e,n)},updateComponent:function(e,t,n,r){var i=t.props,a=this._currentElement.props;switch(this._tag){case"input":i=S.getHostProps(this,i),a=S.getHostProps(this,a);break;case"option":i=N.getHostProps(this,i),a=N.getHostProps(this,a);break;case"select":i=M.getHostProps(this,i),a=M.getHostProps(this,a);break;case"textarea":i=I.getHostProps(this,i),a=I.getHostProps(this,a)}switch(o(this,a),this._updateDOMProperties(i,a,e),this._updateDOMChildren(i,a,e,r),this._tag){case"input":S.updateWrapper(this);break;case"textarea":I.updateWrapper(this);break;case"select":e.getReactMountReady().enqueue(p,this)}},_updateDOMProperties:function(e,t,n){var r,o,a;for(r in e)if(!t.hasOwnProperty(r)&&e.hasOwnProperty(r)&&null!=e[r])if("style"===r){var s=this._previousStyleCopy;for(o in s)s.hasOwnProperty(o)&&(a=a||{},a[o]="");this._previousStyleCopy=null}else j.hasOwnProperty(r)?e[r]&&L(this,r):f(this._tag,e)?W.hasOwnProperty(r)||E.deleteValueForAttribute(U(this),r):(b.properties[r]||b.isCustomAttribute(r))&&E.deleteValueForProperty(U(this),r);for(r in t){var u=t[r],l="style"===r?this._previousStyleCopy:null!=e?e[r]:void 0;if(t.hasOwnProperty(r)&&u!==l&&(null!=u||null!=l))if("style"===r)if(u?u=this._previousStyleCopy=v({},u):this._previousStyleCopy=null,l){for(o in l)!l.hasOwnProperty(o)||u&&u.hasOwnProperty(o)||(a=a||{},a[o]="");for(o in u)u.hasOwnProperty(o)&&l[o]!==u[o]&&(a=a||{},a[o]=u[o])}else a=u;else if(j.hasOwnProperty(r))u?i(this,r,u,n):l&&L(this,r);else if(f(this._tag,t))W.hasOwnProperty(r)||E.setValueForAttribute(U(this),r,u);else if(b.properties[r]||b.isCustomAttribute(r)){var c=U(this);null!=u?E.setValueForProperty(c,r,u):E.deleteValueForProperty(c,r)}}a&&y.setValueForStyles(U(this),a,this)},_updateDOMChildren:function(e,t,n,r){var o=V[typeof e.children]?e.children:null,i=V[typeof t.children]?t.children:null,a=e.dangerouslySetInnerHTML&&e.dangerouslySetInnerHTML.__html,s=t.dangerouslySetInnerHTML&&t.dangerouslySetInnerHTML.__html,u=null!=o?null:e.children,l=null!=i?null:t.children,c=null!=o||null!=a,p=null!=i||null!=s;null!=u&&null==l?this.updateChildren(null,n,r):c&&!p&&this.updateTextContent(""),null!=i?o!==i&&this.updateTextContent(""+i):null!=s?a!==s&&this.updateMarkup(""+s):null!=l&&this.updateChildren(l,n,r)},getHostNode:function(){return U(this)},unmountComponent:function(e){switch(this._tag){case"audio":case"form":case"iframe":case"img":case"link":case"object":case"source":case"video":var t=this._wrapperState.listeners;if(t)for(var n=0;n<t.length;n++)t[n].remove();break;case"html":case"head":case"body":m("66",this._tag)}this.unmountChildren(e),P.uncacheNode(this),x.deleteAllListeners(this),this._rootNodeID=0,this._domID=0,this._wrapperState=null},getPublicInstance:function(){return U(this)}},v(h.prototype,h.Mixin,O.Mixin),t.exports=h},{10:10,109:109,11:11,112:112,118:118,12:12,129:129,137:137,141:141,142:142,143:143,16:16,17:17,2:2,25:25,32:32,33:33,38:38,39:39,40:40,43:43,5:5,58:58,61:61,68:68,9:9,95:95}],32:[function(e,t,n){"use strict";var r={hasCachedChildNodes:1};t.exports=r},{}],33:[function(e,t,n){"use strict";function r(e,t){return 1===e.nodeType&&e.getAttribute(h)===String(t)||8===e.nodeType&&e.nodeValue===" react-text: "+t+" "||8===e.nodeType&&e.nodeValue===" react-empty: "+t+" "}function o(e){for(var t;t=e._renderedComponent;)e=t;return e}function i(e,t){var n=o(e);n._hostNode=t,t[v]=n}function a(e){var t=e._hostNode;t&&(delete t[v],e._hostNode=null)}function s(e,t){if(!(e._flags&m.hasCachedChildNodes)){var n=e._renderedChildren,a=t.firstChild;e:for(var s in n)if(n.hasOwnProperty(s)){var u=n[s],l=o(u)._domID;if(0!==l){for(;null!==a;a=a.nextSibling)if(r(a,l)){i(u,a);continue e}p("32",l)}}e._flags|=m.hasCachedChildNodes}}function u(e){if(e[v])return e[v];for(var t=[];!e[v];){if(t.push(e),!e.parentNode)return null;e=e.parentNode}for(var n,r;e&&(r=e[v]);e=t.pop())n=r,t.length&&s(r,e);return n}function l(e){var t=u(e);return null!=t&&t._hostNode===e?t:null}function c(e){if(void 0===e._hostNode&&p("33"),e._hostNode)return e._hostNode;for(var t=[];!e._hostNode;)t.push(e),e._hostParent||p("34"),e=e._hostParent;for(;t.length;e=t.pop())s(e,e._hostNode);return e._hostNode}var p=e(112),d=e(11),f=e(32),h=(e(137),d.ID_ATTRIBUTE_NAME),m=f,v="__reactInternalInstance$"+Math.random().toString(36).slice(2),g={getClosestInstanceFromNode:u,getInstanceFromNode:l,getNodeFromInstance:c,precacheChildNodes:s,precacheNode:i,uncacheNode:a};t.exports=g},{11:11,112:112,137:137,32:32}],34:[function(e,t,n){"use strict";function r(e,t){return{_topLevelWrapper:e,_idCounter:1,_ownerDocument:t?t.nodeType===o?t:t.ownerDocument:null,_node:t,_tag:t?t.nodeName.toLowerCase():null,_namespaceURI:t?t.namespaceURI:null}}var o=(e(118),9);t.exports=r},{118:118}],35:[function(e,t,n){"use strict";var r=e(143),o=e(9),i=e(33),a=function(e){this._currentElement=null,this._hostNode=null,this._hostParent=null,this._hostContainerInfo=null,this._domID=0};r(a.prototype,{mountComponent:function(e,t,n,r){var a=n._idCounter++;this._domID=a,this._hostParent=t,this._hostContainerInfo=n;var s=" react-empty: "+this._domID+" ";if(e.useCreateElement){var u=n._ownerDocument,l=u.createComment(s);return i.precacheNode(this,l),o(l)}return e.renderToStaticMarkup?"":"<!--"+s+"-->"},receiveComponent:function(){},getHostNode:function(){return i.getNodeFromInstance(this)},unmountComponent:function(){i.uncacheNode(this)}}),t.exports=a},{143:143,33:33,9:9}],36:[function(e,t,n){"use strict";var r={useCreateElement:!0,useFiber:!1};t.exports=r},{}],37:[function(e,t,n){"use strict";var r=e(8),o=e(33),i={dangerouslyProcessChildrenUpdates:function(e,t){var n=o.getNodeFromInstance(e);r.processUpdates(n,t)}};t.exports=i},{33:33,8:8}],38:[function(e,t,n){"use strict";function r(){this._rootNodeID&&d.updateWrapper(this)}function o(e){return"checkbox"===e.type||"radio"===e.type?null!=e.checked:null!=e.value}function i(e){var t=this._currentElement.props,n=l.executeOnChange(t,e);p.asap(r,this);var o=t.name;if("radio"===t.type&&null!=o){for(var i=c.getNodeFromInstance(this),s=i;s.parentNode;)s=s.parentNode;for(var u=s.querySelectorAll("input[name="+JSON.stringify(""+o)+'][type="radio"]'),d=0;d<u.length;d++){var f=u[d];if(f!==i&&f.form===i.form){var h=c.getInstanceFromNode(f);h||a("90"),p.asap(r,h)}}}return n}var a=e(112),s=e(143),u=e(12),l=e(23),c=e(33),p=e(71),d=(e(137),e(142),{getHostProps:function(e,t){var n=l.getValue(t),r=l.getChecked(t);return s({type:void 0,step:void 0,min:void 0,max:void 0},t,{defaultChecked:void 0,defaultValue:void 0,value:null!=n?n:e._wrapperState.initialValue,checked:null!=r?r:e._wrapperState.initialChecked,onChange:e._wrapperState.onChange})},mountWrapper:function(e,t){var n=t.defaultValue;e._wrapperState={initialChecked:null!=t.checked?t.checked:t.defaultChecked,initialValue:null!=t.value?t.value:n,listeners:null,onChange:i.bind(e),controlled:o(t)}},updateWrapper:function(e){var t=e._currentElement.props,n=t.checked;null!=n&&u.setValueForProperty(c.getNodeFromInstance(e),"checked",n||!1);var r=c.getNodeFromInstance(e),o=l.getValue(t);if(null!=o)if(0===o&&""===r.value)r.value="0";else if("number"===t.type){var i=parseFloat(r.value,10)||0;o!=i&&(r.value=""+o)}else o!=r.value&&(r.value=""+o);else null==t.value&&null!=t.defaultValue&&r.defaultValue!==""+t.defaultValue&&(r.defaultValue=""+t.defaultValue),null==t.checked&&null!=t.defaultChecked&&(r.defaultChecked=!!t.defaultChecked)},postMountWrapper:function(e){var t=e._currentElement.props,n=c.getNodeFromInstance(e);switch(t.type){case"submit":case"reset":break;case"color":case"date":case"datetime":case"datetime-local":case"month":case"time":case"week":n.value="",n.value=n.defaultValue;break;default:n.value=n.value}var r=n.name;""!==r&&(n.name=""),n.defaultChecked=!n.defaultChecked,n.defaultChecked=!n.defaultChecked,""!==r&&(n.name=r)}});t.exports=d},{112:112,12:12,137:137,142:142,143:143,23:23,33:33,71:71}],39:[function(e,t,n){"use strict";function r(e){var t="";return i.Children.forEach(e,function(e){null!=e&&("string"==typeof e||"number"==typeof e?t+=e:u||(u=!0))}),t}var o=e(143),i=e(120),a=e(33),s=e(40),u=(e(142),!1),l={mountWrapper:function(e,t,n){var o=null;if(null!=n){var i=n;"optgroup"===i._tag&&(i=i._hostParent),null!=i&&"select"===i._tag&&(o=s.getSelectValueContext(i))}var a=null;if(null!=o){var u;if(u=null!=t.value?t.value+"":r(t.children),a=!1,Array.isArray(o)){for(var l=0;l<o.length;l++)if(""+o[l]===u){a=!0;break}}else a=""+o===u}e._wrapperState={selected:a}},postMountWrapper:function(e){var t=e._currentElement.props;null!=t.value&&a.getNodeFromInstance(e).setAttribute("value",t.value)},getHostProps:function(e,t){var n=o({selected:void 0,children:void 0},t);null!=e._wrapperState.selected&&(n.selected=e._wrapperState.selected);var i=r(t.children);return i&&(n.children=i),n}};t.exports=l},{120:120,142:142,143:143,33:33,40:40}],40:[function(e,t,n){"use strict";function r(){if(this._rootNodeID&&this._wrapperState.pendingUpdate){this._wrapperState.pendingUpdate=!1;var e=this._currentElement.props,t=s.getValue(e);null!=t&&o(this,Boolean(e.multiple),t)}}function o(e,t,n){var r,o,i=u.getNodeFromInstance(e).options;if(t){for(r={},o=0;o<n.length;o++)r[""+n[o]]=!0;for(o=0;o<i.length;o++){var a=r.hasOwnProperty(i[o].value);i[o].selected!==a&&(i[o].selected=a)}}else{for(r=""+n,o=0;o<i.length;o++)if(i[o].value===r)return void(i[o].selected=!0);i.length&&(i[0].selected=!0)}}function i(e){var t=this._currentElement.props,n=s.executeOnChange(t,e);return this._rootNodeID&&(this._wrapperState.pendingUpdate=!0),l.asap(r,this),n}var a=e(143),s=e(23),u=e(33),l=e(71),c=(e(142),!1),p={getHostProps:function(e,t){return a({},t,{onChange:e._wrapperState.onChange,value:void 0})},mountWrapper:function(e,t){var n=s.getValue(t);e._wrapperState={pendingUpdate:!1,initialValue:null!=n?n:t.defaultValue,listeners:null,onChange:i.bind(e),wasMultiple:Boolean(t.multiple)},void 0===t.value||void 0===t.defaultValue||c||(c=!0)},getSelectValueContext:function(e){return e._wrapperState.initialValue},postUpdateWrapper:function(e){var t=e._currentElement.props;e._wrapperState.initialValue=void 0;var n=e._wrapperState.wasMultiple;e._wrapperState.wasMultiple=Boolean(t.multiple);var r=s.getValue(t);null!=r?(e._wrapperState.pendingUpdate=!1,o(e,Boolean(t.multiple),r)):n!==Boolean(t.multiple)&&(null!=t.defaultValue?o(e,Boolean(t.multiple),t.defaultValue):o(e,Boolean(t.multiple),t.multiple?[]:""))}};t.exports=p},{142:142,143:143,23:23,33:33,71:71}],41:[function(e,t,n){"use strict";function r(e,t,n,r){return e===n&&t===r}function o(e){var t=document.selection,n=t.createRange(),r=n.text.length,o=n.duplicate();o.moveToElementText(e),o.setEndPoint("EndToStart",n);var i=o.text.length;return{start:i,end:i+r}}function i(e){var t=window.getSelection&&window.getSelection();if(!t||0===t.rangeCount)return null;var n=t.anchorNode,o=t.anchorOffset,i=t.focusNode,a=t.focusOffset,s=t.getRangeAt(0);try{s.startContainer.nodeType,s.endContainer.nodeType}catch(e){return null}var u=r(t.anchorNode,t.anchorOffset,t.focusNode,t.focusOffset),l=u?0:s.toString().length,c=s.cloneRange();c.selectNodeContents(e),c.setEnd(s.startContainer,s.startOffset);var p=r(c.startContainer,c.startOffset,c.endContainer,c.endOffset),d=p?0:c.toString().length,f=d+l,h=document.createRange();h.setStart(n,o),h.setEnd(i,a);var m=h.collapsed;return{start:m?f:d,end:m?d:f}}function a(e,t){var n,r,o=document.selection.createRange().duplicate();void 0===t.end?(n=t.start,r=n):t.start>t.end?(n=t.end,r=t.start):(n=t.start,r=t.end),o.moveToElementText(e),o.moveStart("character",n),o.setEndPoint("EndToStart",o),o.moveEnd("character",r-n),o.select()}function s(e,t){if(window.getSelection){var n=window.getSelection(),r=e[c()].length,o=Math.min(t.start,r),i=void 0===t.end?o:Math.min(t.end,r);if(!n.extend&&o>i){var a=i;i=o,o=a}var s=l(e,o),u=l(e,i);if(s&&u){var p=document.createRange();p.setStart(s.node,s.offset),n.removeAllRanges(),o>i?(n.addRange(p),n.extend(u.node,u.offset)):(p.setEnd(u.node,u.offset),n.addRange(p))}}}var u=e(123),l=e(105),c=e(106),p=u.canUseDOM&&"selection"in document&&!("getSelection"in window),d={getOffsets:p?o:i,setOffsets:p?a:s};t.exports=d},{105:105,106:106,123:123}],42:[function(e,t,n){"use strict";var r=e(112),o=e(143),i=e(8),a=e(9),s=e(33),u=e(95),l=(e(137),e(118),function(e){this._currentElement=e,this._stringText=""+e, +this._hostNode=null,this._hostParent=null,this._domID=0,this._mountIndex=0,this._closingComment=null,this._commentNodes=null});o(l.prototype,{mountComponent:function(e,t,n,r){var o=n._idCounter++,i=" react-text: "+o+" ";if(this._domID=o,this._hostParent=t,e.useCreateElement){var l=n._ownerDocument,c=l.createComment(i),p=l.createComment(" /react-text "),d=a(l.createDocumentFragment());return a.queueChild(d,a(c)),this._stringText&&a.queueChild(d,a(l.createTextNode(this._stringText))),a.queueChild(d,a(p)),s.precacheNode(this,c),this._closingComment=p,d}var f=u(this._stringText);return e.renderToStaticMarkup?f:"<!--"+i+"-->"+f+"<!-- /react-text -->"},receiveComponent:function(e,t){if(e!==this._currentElement){this._currentElement=e;var n=""+e;if(n!==this._stringText){this._stringText=n;var r=this.getHostNode();i.replaceDelimitedText(r[0],r[1],n)}}},getHostNode:function(){var e=this._commentNodes;if(e)return e;if(!this._closingComment)for(var t=s.getNodeFromInstance(this),n=t.nextSibling;;){if(null==n&&r("67",this._domID),8===n.nodeType&&" /react-text "===n.nodeValue){this._closingComment=n;break}n=n.nextSibling}return e=[this._hostNode,this._closingComment],this._commentNodes=e,e},unmountComponent:function(){this._closingComment=null,this._commentNodes=null,s.uncacheNode(this)}}),t.exports=l},{112:112,118:118,137:137,143:143,33:33,8:8,9:9,95:95}],43:[function(e,t,n){"use strict";function r(){this._rootNodeID&&c.updateWrapper(this)}function o(e){var t=this._currentElement.props,n=s.executeOnChange(t,e);return l.asap(r,this),n}var i=e(112),a=e(143),s=e(23),u=e(33),l=e(71),c=(e(137),e(142),{getHostProps:function(e,t){return null!=t.dangerouslySetInnerHTML&&i("91"),a({},t,{value:void 0,defaultValue:void 0,children:""+e._wrapperState.initialValue,onChange:e._wrapperState.onChange})},mountWrapper:function(e,t){var n=s.getValue(t),r=n;if(null==n){var a=t.defaultValue,u=t.children;null!=u&&(null!=a&&i("92"),Array.isArray(u)&&(u.length<=1||i("93"),u=u[0]),a=""+u),null==a&&(a=""),r=a}e._wrapperState={initialValue:""+r,listeners:null,onChange:o.bind(e)}},updateWrapper:function(e){var t=e._currentElement.props,n=u.getNodeFromInstance(e),r=s.getValue(t);if(null!=r){var o=""+r;o!==n.value&&(n.value=o),null==t.defaultValue&&(n.defaultValue=o)}null!=t.defaultValue&&(n.defaultValue=t.defaultValue)},postMountWrapper:function(e){var t=u.getNodeFromInstance(e),n=t.textContent;n===e._wrapperState.initialValue&&(t.value=n)}});t.exports=c},{112:112,137:137,142:142,143:143,23:23,33:33,71:71}],44:[function(e,t,n){"use strict";function r(e,t){"_hostNode"in e||u("33"),"_hostNode"in t||u("33");for(var n=0,r=e;r;r=r._hostParent)n++;for(var o=0,i=t;i;i=i._hostParent)o++;for(;n-o>0;)e=e._hostParent,n--;for(;o-n>0;)t=t._hostParent,o--;for(var a=n;a--;){if(e===t)return e;e=e._hostParent,t=t._hostParent}return null}function o(e,t){"_hostNode"in e||u("35"),"_hostNode"in t||u("35");for(;t;){if(t===e)return!0;t=t._hostParent}return!1}function i(e){return"_hostNode"in e||u("36"),e._hostParent}function a(e,t,n){for(var r=[];e;)r.push(e),e=e._hostParent;var o;for(o=r.length;o-- >0;)t(r[o],"captured",n);for(o=0;o<r.length;o++)t(r[o],"bubbled",n)}function s(e,t,n,o,i){for(var a=e&&t?r(e,t):null,s=[];e&&e!==a;)s.push(e),e=e._hostParent;for(var u=[];t&&t!==a;)u.push(t),t=t._hostParent;var l;for(l=0;l<s.length;l++)n(s[l],"bubbled",o);for(l=u.length;l-- >0;)n(u[l],"captured",i)}var u=e(112);e(137);t.exports={isAncestor:o,getLowestCommonAncestor:r,getParentInstance:i,traverseTwoPhase:a,traverseEnterLeave:s}},{112:112,137:137}],45:[function(e,t,n){"use strict";var r=e(120),o=e(30),i=o;r.addons&&(r.__SECRET_INJECTED_REACT_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=i),t.exports=i},{120:120,30:30}],46:[function(e,t,n){"use strict";function r(){this.reinitializeTransaction()}var o=e(143),i=e(71),a=e(89),s=e(129),u={initialize:s,close:function(){d.isBatchingUpdates=!1}},l={initialize:s,close:i.flushBatchedUpdates.bind(i)},c=[l,u];o(r.prototype,a,{getTransactionWrappers:function(){return c}});var p=new r,d={isBatchingUpdates:!1,batchedUpdates:function(e,t,n,r,o,i){var a=d.isBatchingUpdates;return d.isBatchingUpdates=!0,a?e(t,n,r,o,i):p.perform(e,null,t,n,r,o,i)}};t.exports=d},{129:129,143:143,71:71,89:89}],47:[function(e,t,n){"use strict";function r(){x||(x=!0,y.EventEmitter.injectReactEventListener(g),y.EventPluginHub.injectEventPluginOrder(s),y.EventPluginUtils.injectComponentTree(d),y.EventPluginUtils.injectTreeTraversal(h),y.EventPluginHub.injectEventPluginsByName({SimpleEventPlugin:E,EnterLeaveEventPlugin:u,ChangeEventPlugin:a,SelectEventPlugin:b,BeforeInputEventPlugin:i}),y.HostComponent.injectGenericComponentClass(p),y.HostComponent.injectTextComponentClass(m),y.DOMProperty.injectDOMPropertyConfig(o),y.DOMProperty.injectDOMPropertyConfig(l),y.DOMProperty.injectDOMPropertyConfig(C),y.EmptyComponent.injectEmptyComponentFactory(function(e){return new f(e)}),y.Updates.injectReconcileTransaction(_),y.Updates.injectBatchingStrategy(v),y.Component.injectEnvironment(c))}var o=e(1),i=e(3),a=e(7),s=e(14),u=e(15),l=e(21),c=e(27),p=e(31),d=e(33),f=e(35),h=e(44),m=e(42),v=e(46),g=e(52),y=e(55),_=e(65),C=e(73),b=e(74),E=e(75),x=!1;t.exports={inject:r}},{1:1,14:14,15:15,21:21,27:27,3:3,31:31,33:33,35:35,42:42,44:44,46:46,52:52,55:55,65:65,7:7,73:73,74:74,75:75}],48:[function(e,t,n){"use strict";var r="function"==typeof Symbol&&Symbol.for&&Symbol.for("react.element")||60103;t.exports=r},{}],49:[function(e,t,n){"use strict";var r,o={injectEmptyComponentFactory:function(e){r=e}},i={create:function(e){return r(e)}};i.injection=o,t.exports=i},{}],50:[function(e,t,n){"use strict";function r(e,t,n){try{t(n)}catch(e){null===o&&(o=e)}}var o=null,i={invokeGuardedCallback:r,invokeGuardedCallbackWithCatch:r,rethrowCaughtError:function(){if(o){var e=o;throw o=null,e}}};t.exports=i},{}],51:[function(e,t,n){"use strict";function r(e){o.enqueueEvents(e),o.processEventQueue(!1)}var o=e(16),i={handleTopLevel:function(e,t,n,i){r(o.extractEvents(e,t,n,i))}};t.exports=i},{16:16}],52:[function(e,t,n){"use strict";function r(e){for(;e._hostParent;)e=e._hostParent;var t=p.getNodeFromInstance(e),n=t.parentNode;return p.getClosestInstanceFromNode(n)}function o(e,t){this.topLevelType=e,this.nativeEvent=t,this.ancestors=[]}function i(e){var t=f(e.nativeEvent),n=p.getClosestInstanceFromNode(t),o=n;do{e.ancestors.push(o),o=o&&r(o)}while(o);for(var i=0;i<e.ancestors.length;i++)n=e.ancestors[i],m._handleTopLevel(e.topLevelType,n,e.nativeEvent,f(e.nativeEvent))}function a(e){e(h(window))}var s=e(143),u=e(122),l=e(123),c=e(24),p=e(33),d=e(71),f=e(102),h=e(134);s(o.prototype,{destructor:function(){this.topLevelType=null,this.nativeEvent=null,this.ancestors.length=0}}),c.addPoolingTo(o,c.twoArgumentPooler);var m={_enabled:!0,_handleTopLevel:null,WINDOW_HANDLE:l.canUseDOM?window:null,setHandleTopLevel:function(e){m._handleTopLevel=e},setEnabled:function(e){m._enabled=!!e},isEnabled:function(){return m._enabled},trapBubbledEvent:function(e,t,n){return n?u.listen(n,t,m.dispatchEvent.bind(null,e)):null},trapCapturedEvent:function(e,t,n){return n?u.capture(n,t,m.dispatchEvent.bind(null,e)):null},monitorScrollValue:function(e){var t=a.bind(null,e);u.listen(window,"scroll",t)},dispatchEvent:function(e,t){if(m._enabled){var n=o.getPooled(e,t);try{d.batchedUpdates(i,n)}finally{o.release(n)}}}};t.exports=m},{102:102,122:122,123:123,134:134,143:143,24:24,33:33,71:71}],53:[function(e,t,n){"use strict";var r={logTopLevelRenders:!1};t.exports=r},{}],54:[function(e,t,n){"use strict";function r(e){return s||a("111",e.type),new s(e)}function o(e){return new u(e)}function i(e){return e instanceof u}var a=e(112),s=(e(137),null),u=null,l={injectGenericComponentClass:function(e){s=e},injectTextComponentClass:function(e){u=e}},c={createInternalComponent:r,createInstanceForText:o,isTextComponent:i,injection:l};t.exports=c},{112:112,137:137}],55:[function(e,t,n){"use strict";var r=e(11),o=e(16),i=e(18),a=e(28),s=e(49),u=e(25),l=e(54),c=e(71),p={Component:a.injection,DOMProperty:r.injection,EmptyComponent:s.injection,EventPluginHub:o.injection,EventPluginUtils:i.injection,EventEmitter:u.injection,HostComponent:l.injection,Updates:c.injection};t.exports=p},{11:11,16:16,18:18,25:25,28:28,49:49,54:54,71:71}],56:[function(e,t,n){"use strict";function r(e){return i(document.documentElement,e)}var o=e(41),i=e(126),a=e(131),s=e(132),u={hasSelectionCapabilities:function(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&"text"===e.type||"textarea"===t||"true"===e.contentEditable)},getSelectionInformation:function(){var e=s();return{focusedElem:e,selectionRange:u.hasSelectionCapabilities(e)?u.getSelection(e):null}},restoreSelection:function(e){var t=s(),n=e.focusedElem,o=e.selectionRange;t!==n&&r(n)&&(u.hasSelectionCapabilities(n)&&u.setSelection(n,o),a(n))},getSelection:function(e){var t;if("selectionStart"in e)t={start:e.selectionStart,end:e.selectionEnd};else if(document.selection&&e.nodeName&&"input"===e.nodeName.toLowerCase()){var n=document.selection.createRange();n.parentElement()===e&&(t={start:-n.moveStart("character",-e.value.length),end:-n.moveEnd("character",-e.value.length)})}else t=o.getOffsets(e);return t||{start:0,end:0}},setSelection:function(e,t){var n=t.start,r=t.end;if(void 0===r&&(r=n),"selectionStart"in e)e.selectionStart=n,e.selectionEnd=Math.min(r,e.value.length);else if(document.selection&&e.nodeName&&"input"===e.nodeName.toLowerCase()){var i=e.createTextRange();i.collapse(!0),i.moveStart("character",n),i.moveEnd("character",r-n),i.select()}else o.setOffsets(e,t)}};t.exports=u},{126:126,131:131,132:132,41:41}],57:[function(e,t,n){"use strict";var r={remove:function(e){e._reactInternalInstance=void 0},get:function(e){return e._reactInternalInstance},has:function(e){return void 0!==e._reactInternalInstance},set:function(e,t){e._reactInternalInstance=t}};t.exports=r},{}],58:[function(e,t,n){"use strict";t.exports={debugTool:null}},{}],59:[function(e,t,n){"use strict";var r=e(92),o=/^<\!\-\-/,i={CHECKSUM_ATTR_NAME:"data-react-checksum",addChecksumToMarkup:function(e){var t=r(e);return o.test(e)?e:e.replace(/\/?>/," "+i.CHECKSUM_ATTR_NAME+'="'+t+'"$&')},canReuseMarkup:function(e,t){var n=t.getAttribute(i.CHECKSUM_ATTR_NAME);return n=n&&parseInt(n,10),r(e)===n}};t.exports=i},{92:92}],60:[function(e,t,n){"use strict";function r(e,t){for(var n=Math.min(e.length,t.length),r=0;r<n;r++)if(e.charAt(r)!==t.charAt(r))return r;return e.length===t.length?-1:n}function o(e){return e?e.nodeType===A?e.documentElement:e.firstChild:null}function i(e){return e.getAttribute&&e.getAttribute(I)||""}function a(e,t,n,r,o){var i;if(b.logTopLevelRenders){var a=e._currentElement.props.child,s=a.type;i="React mount: "+("string"==typeof s?s:s.displayName||s.name),console.time(i)}var u=w.mountComponent(e,n,null,_(e,t),o,0);i&&console.timeEnd(i),e._renderedComponent._topLevelWrapper=e,j._mountImageIntoNode(u,t,e,r,n)}function s(e,t,n,r){var o=k.ReactReconcileTransaction.getPooled(!n&&C.useCreateElement);o.perform(a,null,e,t,o,n,r),k.ReactReconcileTransaction.release(o)}function u(e,t,n){for(w.unmountComponent(e,n),t.nodeType===A&&(t=t.documentElement);t.lastChild;)t.removeChild(t.lastChild)}function l(e){var t=o(e);if(t){var n=y.getInstanceFromNode(t);return!(!n||!n._hostParent)}}function c(e){return!(!e||e.nodeType!==R&&e.nodeType!==A&&e.nodeType!==D)}function p(e){var t=o(e),n=t&&y.getInstanceFromNode(t);return n&&!n._hostParent?n:null}function d(e){var t=p(e);return t?t._hostContainerInfo._topLevelWrapper:null}var f=e(112),h=e(9),m=e(11),v=e(120),g=e(25),y=(e(119),e(33)),_=e(34),C=e(36),b=e(53),E=e(57),x=(e(58),e(59)),w=e(66),T=e(70),k=e(71),P=e(130),S=e(108),N=(e(137),e(114)),M=e(116),I=(e(142),m.ID_ATTRIBUTE_NAME),O=m.ROOT_ATTRIBUTE_NAME,R=1,A=9,D=11,L={},U=1,F=function(){this.rootID=U++};F.prototype.isReactComponent={},F.prototype.render=function(){return this.props.child},F.isReactTopLevelWrapper=!0;var j={TopLevelWrapper:F,_instancesByReactRootID:L,scrollMonitor:function(e,t){t()},_updateRootComponent:function(e,t,n,r,o){return j.scrollMonitor(r,function(){T.enqueueElementInternal(e,t,n),o&&T.enqueueCallbackInternal(e,o)}),e},_renderNewRootComponent:function(e,t,n,r){c(t)||f("37"),g.ensureScrollValueMonitoring();var o=S(e,!1);k.batchedUpdates(s,o,t,n,r);var i=o._instance.rootID;return L[i]=o,o},renderSubtreeIntoContainer:function(e,t,n,r){return null!=e&&E.has(e)||f("38"),j._renderSubtreeIntoContainer(e,t,n,r)},_renderSubtreeIntoContainer:function(e,t,n,r){T.validateCallback(r,"ReactDOM.render"),v.isValidElement(t)||f("39","string"==typeof t?" Instead of passing a string like 'div', pass React.createElement('div') or <div />.":"function"==typeof t?" Instead of passing a class like Foo, pass React.createElement(Foo) or <Foo />.":null!=t&&void 0!==t.props?" This may be caused by unintentionally loading two independent copies of React.":"");var a,s=v.createElement(F,{child:t});if(e){var u=E.get(e);a=u._processChildContext(u._context)}else a=P;var c=d(n);if(c){var p=c._currentElement,h=p.props.child;if(M(h,t)){var m=c._renderedComponent.getPublicInstance(),g=r&&function(){r.call(m)};return j._updateRootComponent(c,s,a,n,g),m}j.unmountComponentAtNode(n)}var y=o(n),_=y&&!!i(y),C=l(n),b=_&&!c&&!C,x=j._renderNewRootComponent(s,n,b,a)._renderedComponent.getPublicInstance();return r&&r.call(x),x},render:function(e,t,n){return j._renderSubtreeIntoContainer(null,e,t,n)},unmountComponentAtNode:function(e){c(e)||f("40");var t=d(e);return t?(delete L[t._instance.rootID],k.batchedUpdates(u,t,e,!1),!0):(l(e),1===e.nodeType&&e.hasAttribute(O),!1)},_mountImageIntoNode:function(e,t,n,i,a){if(c(t)||f("41"),i){var s=o(t);if(x.canReuseMarkup(e,s))return void y.precacheNode(n,s);var u=s.getAttribute(x.CHECKSUM_ATTR_NAME);s.removeAttribute(x.CHECKSUM_ATTR_NAME);var l=s.outerHTML;s.setAttribute(x.CHECKSUM_ATTR_NAME,u);var p=e,d=r(p,l),m=" (client) "+p.substring(d-20,d+20)+"\n (server) "+l.substring(d-20,d+20);t.nodeType===A&&f("42",m)}if(t.nodeType===A&&f("43"),a.useCreateElement){for(;t.lastChild;)t.removeChild(t.lastChild);h.insertTreeBefore(t,e,null)}else N(t,e),y.precacheNode(n,t.firstChild)}};t.exports=j},{108:108,11:11,112:112,114:114,116:116,119:119,120:120,130:130,137:137,142:142,25:25,33:33,34:34,36:36,53:53,57:57,58:58,59:59,66:66,70:70,71:71,9:9}],61:[function(e,t,n){"use strict";function r(e,t,n){return{type:"INSERT_MARKUP",content:e,fromIndex:null,fromNode:null,toIndex:n,afterNode:t}}function o(e,t,n){return{type:"MOVE_EXISTING",content:null,fromIndex:e._mountIndex,fromNode:d.getHostNode(e),toIndex:n,afterNode:t}}function i(e,t){return{type:"REMOVE_NODE",content:null,fromIndex:e._mountIndex,fromNode:t,toIndex:null,afterNode:null}}function a(e){return{type:"SET_MARKUP",content:e,fromIndex:null,fromNode:null,toIndex:null,afterNode:null}}function s(e){return{type:"TEXT_CONTENT",content:e,fromIndex:null,fromNode:null,toIndex:null,afterNode:null}}function u(e,t){return t&&(e=e||[],e.push(t)),e}function l(e,t){p.processChildrenUpdates(e,t)}var c=e(112),p=e(28),d=(e(57),e(58),e(119),e(66)),f=e(26),h=(e(129),e(97)),m=(e(137),{Mixin:{_reconcilerInstantiateChildren:function(e,t,n){return f.instantiateChildren(e,t,n)},_reconcilerUpdateChildren:function(e,t,n,r,o,i){var a;return a=h(t,0),f.updateChildren(e,a,n,r,o,this,this._hostContainerInfo,i,0),a},mountChildren:function(e,t,n){var r=this._reconcilerInstantiateChildren(e,t,n);this._renderedChildren=r;var o=[],i=0;for(var a in r)if(r.hasOwnProperty(a)){var s=r[a],u=d.mountComponent(s,t,this,this._hostContainerInfo,n,0);s._mountIndex=i++,o.push(u)}return o},updateTextContent:function(e){var t=this._renderedChildren;f.unmountChildren(t,!1);for(var n in t)t.hasOwnProperty(n)&&c("118");l(this,[s(e)])},updateMarkup:function(e){var t=this._renderedChildren;f.unmountChildren(t,!1);for(var n in t)t.hasOwnProperty(n)&&c("118");l(this,[a(e)])},updateChildren:function(e,t,n){this._updateChildren(e,t,n)},_updateChildren:function(e,t,n){var r=this._renderedChildren,o={},i=[],a=this._reconcilerUpdateChildren(r,e,i,o,t,n);if(a||r){var s,c=null,p=0,f=0,h=0,m=null;for(s in a)if(a.hasOwnProperty(s)){var v=r&&r[s],g=a[s];v===g?(c=u(c,this.moveChild(v,m,p,f)),f=Math.max(v._mountIndex,f),v._mountIndex=p):(v&&(f=Math.max(v._mountIndex,f)),c=u(c,this._mountChildAtIndex(g,i[h],m,p,t,n)),h++),p++,m=d.getHostNode(g)}for(s in o)o.hasOwnProperty(s)&&(c=u(c,this._unmountChild(r[s],o[s])));c&&l(this,c),this._renderedChildren=a}},unmountChildren:function(e){var t=this._renderedChildren;f.unmountChildren(t,e),this._renderedChildren=null},moveChild:function(e,t,n,r){if(e._mountIndex<r)return o(e,t,n)},createChild:function(e,t,n){return r(n,t,e._mountIndex)},removeChild:function(e,t){return i(e,t)},_mountChildAtIndex:function(e,t,n,r,o,i){return e._mountIndex=r,this.createChild(e,n,t)},_unmountChild:function(e,t){var n=this.removeChild(e,t);return e._mountIndex=null,n}}});t.exports=m},{112:112,119:119,129:129,137:137,26:26,28:28,57:57,58:58,66:66,97:97}],62:[function(e,t,n){"use strict";var r=e(112),o=e(120),i=(e(137),{HOST:0,COMPOSITE:1,EMPTY:2,getType:function(e){return null===e||!1===e?i.EMPTY:o.isValidElement(e)?"function"==typeof e.type?i.COMPOSITE:i.HOST:void r("26",e)}});t.exports=i},{112:112,120:120,137:137}],63:[function(e,t,n){"use strict";function r(e){return!(!e||"function"!=typeof e.attachRef||"function"!=typeof e.detachRef)}var o=e(112),i=(e(137),{addComponentAsRefTo:function(e,t,n){r(n)||o("119"),n.attachRef(t,e)},removeComponentAsRefFrom:function(e,t,n){r(n)||o("120");var i=n.getPublicInstance();i&&i.refs[t]===e.getPublicInstance()&&n.detachRef(t)}});t.exports=i},{112:112,137:137}],64:[function(e,t,n){"use strict";t.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},{}],65:[function(e,t,n){"use strict";function r(e){this.reinitializeTransaction(),this.renderToStaticMarkup=!1,this.reactMountReady=i.getPooled(null),this.useCreateElement=e}var o=e(143),i=e(6),a=e(24),s=e(25),u=e(56),l=(e(58),e(89)),c=e(70),p={initialize:u.getSelectionInformation,close:u.restoreSelection},d={initialize:function(){var e=s.isEnabled();return s.setEnabled(!1),e},close:function(e){s.setEnabled(e)}},f={initialize:function(){this.reactMountReady.reset()},close:function(){this.reactMountReady.notifyAll()}},h=[p,d,f],m={getTransactionWrappers:function(){return h},getReactMountReady:function(){return this.reactMountReady},getUpdateQueue:function(){return c},checkpoint:function(){return this.reactMountReady.checkpoint()},rollback:function(e){this.reactMountReady.rollback(e)},destructor:function(){i.release(this.reactMountReady),this.reactMountReady=null}};o(r.prototype,l,m),a.addPoolingTo(r),t.exports=r},{143:143,24:24,25:25,56:56,58:58,6:6,70:70,89:89}],66:[function(e,t,n){"use strict";function r(){o.attachRefs(this,this._currentElement)}var o=e(67),i=(e(58),e(142),{mountComponent:function(e,t,n,o,i,a){var s=e.mountComponent(t,n,o,i,a);return e._currentElement&&null!=e._currentElement.ref&&t.getReactMountReady().enqueue(r,e),s},getHostNode:function(e){return e.getHostNode()},unmountComponent:function(e,t){o.detachRefs(e,e._currentElement),e.unmountComponent(t)},receiveComponent:function(e,t,n,i){var a=e._currentElement;if(t!==a||i!==e._context){var s=o.shouldUpdateRefs(a,t);s&&o.detachRefs(e,a),e.receiveComponent(t,n,i),s&&e._currentElement&&null!=e._currentElement.ref&&n.getReactMountReady().enqueue(r,e)}},performUpdateIfNecessary:function(e,t,n){e._updateBatchNumber===n&&e.performUpdateIfNecessary(t)}});t.exports=i},{142:142,58:58,67:67}],67:[function(e,t,n){"use strict";function r(e,t,n){"function"==typeof e?e(t.getPublicInstance()):i.addComponentAsRefTo(t,e,n)}function o(e,t,n){"function"==typeof e?e(null):i.removeComponentAsRefFrom(t,e,n)}var i=e(63),a={};a.attachRefs=function(e,t){if(null!==t&&"object"==typeof t){var n=t.ref;null!=n&&r(n,e,t._owner)}},a.shouldUpdateRefs=function(e,t){var n=null,r=null;null!==e&&"object"==typeof e&&(n=e.ref,r=e._owner);var o=null,i=null;return null!==t&&"object"==typeof t&&(o=t.ref,i=t._owner),n!==o||"string"==typeof o&&i!==r},a.detachRefs=function(e,t){if(null!==t&&"object"==typeof t){var n=t.ref;null!=n&&o(n,e,t._owner)}},t.exports=a},{63:63}],68:[function(e,t,n){"use strict";function r(e){this.reinitializeTransaction(),this.renderToStaticMarkup=e,this.useCreateElement=!1,this.updateQueue=new s(this)}var o=e(143),i=e(24),a=e(89),s=(e(58),e(69)),u=[],l={enqueue:function(){}},c={getTransactionWrappers:function(){return u},getReactMountReady:function(){return l},getUpdateQueue:function(){return this.updateQueue},destructor:function(){},checkpoint:function(){},rollback:function(){}};o(r.prototype,a,c),i.addPoolingTo(r),t.exports=r},{143:143,24:24,58:58,69:69,89:89}],69:[function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=e(70),i=(e(142),function(){function e(t){r(this,e),this.transaction=t}return e.prototype.isMounted=function(e){return!1},e.prototype.enqueueCallback=function(e,t,n){this.transaction.isInTransaction()&&o.enqueueCallback(e,t,n)},e.prototype.enqueueForceUpdate=function(e){this.transaction.isInTransaction()&&o.enqueueForceUpdate(e)},e.prototype.enqueueReplaceState=function(e,t){this.transaction.isInTransaction()&&o.enqueueReplaceState(e,t)},e.prototype.enqueueSetState=function(e,t){this.transaction.isInTransaction()&&o.enqueueSetState(e,t)},e}());t.exports=i},{142:142,70:70}],70:[function(e,t,n){"use strict";function r(e){u.enqueueUpdate(e)}function o(e){var t=typeof e;if("object"!==t)return t;var n=e.constructor&&e.constructor.name||t,r=Object.keys(e);return r.length>0&&r.length<20?n+" (keys: "+r.join(", ")+")":n}function i(e,t){var n=s.get(e);return n||null}var a=e(112),s=(e(119),e(57)),u=(e(58),e(71)),l=(e(137),e(142),{isMounted:function(e){var t=s.get(e);return!!t&&!!t._renderedComponent},enqueueCallback:function(e,t,n){l.validateCallback(t,n);var o=i(e);if(!o)return null;o._pendingCallbacks?o._pendingCallbacks.push(t):o._pendingCallbacks=[t],r(o)},enqueueCallbackInternal:function(e,t){e._pendingCallbacks?e._pendingCallbacks.push(t):e._pendingCallbacks=[t],r(e)},enqueueForceUpdate:function(e){var t=i(e,"forceUpdate");t&&(t._pendingForceUpdate=!0,r(t))},enqueueReplaceState:function(e,t,n){var o=i(e,"replaceState");o&&(o._pendingStateQueue=[t],o._pendingReplaceState=!0,void 0!==n&&null!==n&&(l.validateCallback(n,"replaceState"),o._pendingCallbacks?o._pendingCallbacks.push(n):o._pendingCallbacks=[n]),r(o))},enqueueSetState:function(e,t){var n=i(e,"setState");n&&((n._pendingStateQueue||(n._pendingStateQueue=[])).push(t),r(n))},enqueueElementInternal:function(e,t,n){e._pendingElement=t,e._context=n,r(e)},validateCallback:function(e,t){e&&"function"!=typeof e&&a("122",t,o(e))}});t.exports=l},{112:112,119:119,137:137,142:142,57:57,58:58,71:71}],71:[function(e,t,n){"use strict";function r(){P.ReactReconcileTransaction&&b||c("123")}function o(){this.reinitializeTransaction(),this.dirtyComponentsLength=null,this.callbackQueue=d.getPooled(),this.reconcileTransaction=P.ReactReconcileTransaction.getPooled(!0)}function i(e,t,n,o,i,a){return r(),b.batchedUpdates(e,t,n,o,i,a)}function a(e,t){return e._mountOrder-t._mountOrder}function s(e){var t=e.dirtyComponentsLength;t!==g.length&&c("124",t,g.length),g.sort(a),y++;for(var n=0;n<t;n++){var r=g[n],o=r._pendingCallbacks;r._pendingCallbacks=null;var i;if(h.logTopLevelRenders){var s=r;r._currentElement.type.isReactTopLevelWrapper&&(s=r._renderedComponent),i="React update: "+s.getName(),console.time(i)}if(m.performUpdateIfNecessary(r,e.reconcileTransaction,y),i&&console.timeEnd(i),o)for(var u=0;u<o.length;u++)e.callbackQueue.enqueue(o[u],r.getPublicInstance())}}function u(e){if(r(),!b.isBatchingUpdates)return void b.batchedUpdates(u,e);g.push(e),null==e._updateBatchNumber&&(e._updateBatchNumber=y+1)}function l(e,t){b.isBatchingUpdates||c("125"),_.enqueue(e,t),C=!0}var c=e(112),p=e(143),d=e(6),f=e(24),h=e(53),m=e(66),v=e(89),g=(e(137),[]),y=0,_=d.getPooled(),C=!1,b=null,E={initialize:function(){this.dirtyComponentsLength=g.length},close:function(){this.dirtyComponentsLength!==g.length?(g.splice(0,this.dirtyComponentsLength),T()):g.length=0}},x={initialize:function(){this.callbackQueue.reset()},close:function(){this.callbackQueue.notifyAll()}},w=[E,x];p(o.prototype,v,{getTransactionWrappers:function(){return w},destructor:function(){this.dirtyComponentsLength=null,d.release(this.callbackQueue),this.callbackQueue=null,P.ReactReconcileTransaction.release(this.reconcileTransaction),this.reconcileTransaction=null},perform:function(e,t,n){return v.perform.call(this,this.reconcileTransaction.perform,this.reconcileTransaction,e,t,n)}}),f.addPoolingTo(o);var T=function(){for(;g.length||C;){if(g.length){var e=o.getPooled();e.perform(s,null,e),o.release(e)}if(C){C=!1;var t=_;_=d.getPooled(),t.notifyAll(),d.release(t)}}},k={injectReconcileTransaction:function(e){e||c("126"),P.ReactReconcileTransaction=e},injectBatchingStrategy:function(e){e||c("127"),"function"!=typeof e.batchedUpdates&&c("128"),"boolean"!=typeof e.isBatchingUpdates&&c("129"),b=e}},P={ReactReconcileTransaction:null,batchedUpdates:i,enqueueUpdate:u,flushBatchedUpdates:T,injection:k,asap:l};t.exports=P},{112:112,137:137,143:143,24:24,53:53,6:6,66:66,89:89}],72:[function(e,t,n){"use strict";t.exports="15.5.4"},{}],73:[function(e,t,n){"use strict";var r={xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace"},o={accentHeight:"accent-height",accumulate:0,additive:0,alignmentBaseline:"alignment-baseline",allowReorder:"allowReorder",alphabetic:0,amplitude:0,arabicForm:"arabic-form",ascent:0,attributeName:"attributeName",attributeType:"attributeType",autoReverse:"autoReverse",azimuth:0,baseFrequency:"baseFrequency",baseProfile:"baseProfile",baselineShift:"baseline-shift",bbox:0,begin:0,bias:0,by:0,calcMode:"calcMode",capHeight:"cap-height",clip:0,clipPath:"clip-path",clipRule:"clip-rule",clipPathUnits:"clipPathUnits",colorInterpolation:"color-interpolation",colorInterpolationFilters:"color-interpolation-filters",colorProfile:"color-profile",colorRendering:"color-rendering",contentScriptType:"contentScriptType",contentStyleType:"contentStyleType",cursor:0,cx:0,cy:0,d:0,decelerate:0,descent:0,diffuseConstant:"diffuseConstant",direction:0,display:0,divisor:0,dominantBaseline:"dominant-baseline",dur:0,dx:0,dy:0,edgeMode:"edgeMode",elevation:0,enableBackground:"enable-background",end:0,exponent:0,externalResourcesRequired:"externalResourcesRequired",fill:0,fillOpacity:"fill-opacity",fillRule:"fill-rule",filter:0,filterRes:"filterRes",filterUnits:"filterUnits",floodColor:"flood-color",floodOpacity:"flood-opacity",focusable:0,fontFamily:"font-family",fontSize:"font-size",fontSizeAdjust:"font-size-adjust",fontStretch:"font-stretch",fontStyle:"font-style",fontVariant:"font-variant",fontWeight:"font-weight",format:0,from:0,fx:0,fy:0,g1:0,g2:0,glyphName:"glyph-name",glyphOrientationHorizontal:"glyph-orientation-horizontal",glyphOrientationVertical:"glyph-orientation-vertical",glyphRef:"glyphRef",gradientTransform:"gradientTransform",gradientUnits:"gradientUnits",hanging:0,horizAdvX:"horiz-adv-x",horizOriginX:"horiz-origin-x",ideographic:0,imageRendering:"image-rendering",in:0,in2:0,intercept:0,k:0,k1:0,k2:0,k3:0,k4:0,kernelMatrix:"kernelMatrix",kernelUnitLength:"kernelUnitLength",kerning:0,keyPoints:"keyPoints",keySplines:"keySplines",keyTimes:"keyTimes",lengthAdjust:"lengthAdjust",letterSpacing:"letter-spacing",lightingColor:"lighting-color",limitingConeAngle:"limitingConeAngle",local:0,markerEnd:"marker-end",markerMid:"marker-mid",markerStart:"marker-start",markerHeight:"markerHeight",markerUnits:"markerUnits",markerWidth:"markerWidth",mask:0,maskContentUnits:"maskContentUnits",maskUnits:"maskUnits",mathematical:0,mode:0,numOctaves:"numOctaves",offset:0,opacity:0,operator:0,order:0,orient:0,orientation:0,origin:0,overflow:0,overlinePosition:"overline-position",overlineThickness:"overline-thickness",paintOrder:"paint-order",panose1:"panose-1",pathLength:"pathLength",patternContentUnits:"patternContentUnits",patternTransform:"patternTransform",patternUnits:"patternUnits",pointerEvents:"pointer-events",points:0,pointsAtX:"pointsAtX",pointsAtY:"pointsAtY",pointsAtZ:"pointsAtZ",preserveAlpha:"preserveAlpha",preserveAspectRatio:"preserveAspectRatio",primitiveUnits:"primitiveUnits",r:0,radius:0,refX:"refX",refY:"refY",renderingIntent:"rendering-intent",repeatCount:"repeatCount",repeatDur:"repeatDur",requiredExtensions:"requiredExtensions",requiredFeatures:"requiredFeatures",restart:0,result:0,rotate:0,rx:0,ry:0,scale:0,seed:0,shapeRendering:"shape-rendering",slope:0,spacing:0,specularConstant:"specularConstant",specularExponent:"specularExponent",speed:0,spreadMethod:"spreadMethod",startOffset:"startOffset",stdDeviation:"stdDeviation",stemh:0,stemv:0,stitchTiles:"stitchTiles",stopColor:"stop-color",stopOpacity:"stop-opacity",strikethroughPosition:"strikethrough-position",strikethroughThickness:"strikethrough-thickness",string:0,stroke:0,strokeDasharray:"stroke-dasharray",strokeDashoffset:"stroke-dashoffset",strokeLinecap:"stroke-linecap",strokeLinejoin:"stroke-linejoin",strokeMiterlimit:"stroke-miterlimit",strokeOpacity:"stroke-opacity",strokeWidth:"stroke-width",surfaceScale:"surfaceScale",systemLanguage:"systemLanguage",tableValues:"tableValues",targetX:"targetX",targetY:"targetY",textAnchor:"text-anchor",textDecoration:"text-decoration",textRendering:"text-rendering",textLength:"textLength",to:0,transform:0,u1:0,u2:0,underlinePosition:"underline-position",underlineThickness:"underline-thickness",unicode:0,unicodeBidi:"unicode-bidi",unicodeRange:"unicode-range",unitsPerEm:"units-per-em",vAlphabetic:"v-alphabetic",vHanging:"v-hanging",vIdeographic:"v-ideographic",vMathematical:"v-mathematical",values:0,vectorEffect:"vector-effect",version:0,vertAdvY:"vert-adv-y",vertOriginX:"vert-origin-x",vertOriginY:"vert-origin-y",viewBox:"viewBox",viewTarget:"viewTarget",visibility:0,widths:0,wordSpacing:"word-spacing",writingMode:"writing-mode",x:0,xHeight:"x-height",x1:0,x2:0,xChannelSelector:"xChannelSelector",xlinkActuate:"xlink:actuate",xlinkArcrole:"xlink:arcrole",xlinkHref:"xlink:href",xlinkRole:"xlink:role",xlinkShow:"xlink:show",xlinkTitle:"xlink:title",xlinkType:"xlink:type",xmlBase:"xml:base",xmlns:0,xmlnsXlink:"xmlns:xlink",xmlLang:"xml:lang",xmlSpace:"xml:space",y:0,y1:0,y2:0,yChannelSelector:"yChannelSelector",z:0,zoomAndPan:"zoomAndPan"},i={Properties:{},DOMAttributeNamespaces:{xlinkActuate:r.xlink,xlinkArcrole:r.xlink,xlinkHref:r.xlink,xlinkRole:r.xlink,xlinkShow:r.xlink,xlinkTitle:r.xlink,xlinkType:r.xlink,xmlBase:r.xml,xmlLang:r.xml,xmlSpace:r.xml},DOMAttributeNames:{}};Object.keys(o).forEach(function(e){i.Properties[e]=0,o[e]&&(i.DOMAttributeNames[e]=o[e])}),t.exports=i},{}],74:[function(e,t,n){"use strict";function r(e){if("selectionStart"in e&&u.hasSelectionCapabilities(e))return{start:e.selectionStart,end:e.selectionEnd};if(window.getSelection){var t=window.getSelection();return{anchorNode:t.anchorNode,anchorOffset:t.anchorOffset,focusNode:t.focusNode,focusOffset:t.focusOffset}}if(document.selection){var n=document.selection.createRange();return{parentElement:n.parentElement(),text:n.text,top:n.boundingTop,left:n.boundingLeft}}}function o(e,t){if(y||null==m||m!==c())return null;var n=r(m);if(!g||!d(g,n)){g=n;var o=l.getPooled(h.select,v,e,t);return o.type="select",o.target=m,i.accumulateTwoPhaseDispatches(o),o}return null}var i=e(19),a=e(123),s=e(33),u=e(56),l=e(80),c=e(132),p=e(110),d=e(141),f=a.canUseDOM&&"documentMode"in document&&document.documentMode<=11,h={select:{phasedRegistrationNames:{bubbled:"onSelect",captured:"onSelectCapture"},dependencies:["topBlur","topContextMenu","topFocus","topKeyDown","topKeyUp","topMouseDown","topMouseUp","topSelectionChange"]}},m=null,v=null,g=null,y=!1,_=!1,C={eventTypes:h,extractEvents:function(e,t,n,r){if(!_)return null;var i=t?s.getNodeFromInstance(t):window;switch(e){case"topFocus":(p(i)||"true"===i.contentEditable)&&(m=i,v=t,g=null);break +;case"topBlur":m=null,v=null,g=null;break;case"topMouseDown":y=!0;break;case"topContextMenu":case"topMouseUp":return y=!1,o(n,r);case"topSelectionChange":if(f)break;case"topKeyDown":case"topKeyUp":return o(n,r)}return null},didPutListener:function(e,t,n){"onSelect"===t&&(_=!0)}};t.exports=C},{110:110,123:123,132:132,141:141,19:19,33:33,56:56,80:80}],75:[function(e,t,n){"use strict";function r(e){return"."+e._rootNodeID}function o(e){return"button"===e||"input"===e||"select"===e||"textarea"===e}var i=e(112),a=e(122),s=e(19),u=e(33),l=e(76),c=e(77),p=e(80),d=e(81),f=e(83),h=e(84),m=e(79),v=e(85),g=e(86),y=e(87),_=e(88),C=e(129),b=e(99),E=(e(137),{}),x={};["abort","animationEnd","animationIteration","animationStart","blur","canPlay","canPlayThrough","click","contextMenu","copy","cut","doubleClick","drag","dragEnd","dragEnter","dragExit","dragLeave","dragOver","dragStart","drop","durationChange","emptied","encrypted","ended","error","focus","input","invalid","keyDown","keyPress","keyUp","load","loadedData","loadedMetadata","loadStart","mouseDown","mouseMove","mouseOut","mouseOver","mouseUp","paste","pause","play","playing","progress","rateChange","reset","scroll","seeked","seeking","stalled","submit","suspend","timeUpdate","touchCancel","touchEnd","touchMove","touchStart","transitionEnd","volumeChange","waiting","wheel"].forEach(function(e){var t=e[0].toUpperCase()+e.slice(1),n="on"+t,r="top"+t,o={phasedRegistrationNames:{bubbled:n,captured:n+"Capture"},dependencies:[r]};E[e]=o,x[r]=o});var w={},T={eventTypes:E,extractEvents:function(e,t,n,r){var o=x[e];if(!o)return null;var a;switch(e){case"topAbort":case"topCanPlay":case"topCanPlayThrough":case"topDurationChange":case"topEmptied":case"topEncrypted":case"topEnded":case"topError":case"topInput":case"topInvalid":case"topLoad":case"topLoadedData":case"topLoadedMetadata":case"topLoadStart":case"topPause":case"topPlay":case"topPlaying":case"topProgress":case"topRateChange":case"topReset":case"topSeeked":case"topSeeking":case"topStalled":case"topSubmit":case"topSuspend":case"topTimeUpdate":case"topVolumeChange":case"topWaiting":a=p;break;case"topKeyPress":if(0===b(n))return null;case"topKeyDown":case"topKeyUp":a=f;break;case"topBlur":case"topFocus":a=d;break;case"topClick":if(2===n.button)return null;case"topDoubleClick":case"topMouseDown":case"topMouseMove":case"topMouseUp":case"topMouseOut":case"topMouseOver":case"topContextMenu":a=h;break;case"topDrag":case"topDragEnd":case"topDragEnter":case"topDragExit":case"topDragLeave":case"topDragOver":case"topDragStart":case"topDrop":a=m;break;case"topTouchCancel":case"topTouchEnd":case"topTouchMove":case"topTouchStart":a=v;break;case"topAnimationEnd":case"topAnimationIteration":case"topAnimationStart":a=l;break;case"topTransitionEnd":a=g;break;case"topScroll":a=y;break;case"topWheel":a=_;break;case"topCopy":case"topCut":case"topPaste":a=c}a||i("86",e);var u=a.getPooled(o,t,n,r);return s.accumulateTwoPhaseDispatches(u),u},didPutListener:function(e,t,n){if("onClick"===t&&!o(e._tag)){var i=r(e),s=u.getNodeFromInstance(e);w[i]||(w[i]=a.listen(s,"click",C))}},willDeleteListener:function(e,t){if("onClick"===t&&!o(e._tag)){var n=r(e);w[n].remove(),delete w[n]}}};t.exports=T},{112:112,122:122,129:129,137:137,19:19,33:33,76:76,77:77,79:79,80:80,81:81,83:83,84:84,85:85,86:86,87:87,88:88,99:99}],76:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(80),i={animationName:null,elapsedTime:null,pseudoElement:null};o.augmentClass(r,i),t.exports=r},{80:80}],77:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(80),i={clipboardData:function(e){return"clipboardData"in e?e.clipboardData:window.clipboardData}};o.augmentClass(r,i),t.exports=r},{80:80}],78:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(80),i={data:null};o.augmentClass(r,i),t.exports=r},{80:80}],79:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(84),i={dataTransfer:null};o.augmentClass(r,i),t.exports=r},{84:84}],80:[function(e,t,n){"use strict";function r(e,t,n,r){this.dispatchConfig=e,this._targetInst=t,this.nativeEvent=n;var o=this.constructor.Interface;for(var i in o)if(o.hasOwnProperty(i)){var s=o[i];s?this[i]=s(n):"target"===i?this.target=r:this[i]=n[i]}var u=null!=n.defaultPrevented?n.defaultPrevented:!1===n.returnValue;return this.isDefaultPrevented=u?a.thatReturnsTrue:a.thatReturnsFalse,this.isPropagationStopped=a.thatReturnsFalse,this}var o=e(143),i=e(24),a=e(129),s=(e(142),["dispatchConfig","_targetInst","nativeEvent","isDefaultPrevented","isPropagationStopped","_dispatchListeners","_dispatchInstances"]),u={type:null,target:null,currentTarget:a.thatReturnsNull,eventPhase:null,bubbles:null,cancelable:null,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:null,isTrusted:null};o(r.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=a.thatReturnsTrue)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=a.thatReturnsTrue)},persist:function(){this.isPersistent=a.thatReturnsTrue},isPersistent:a.thatReturnsFalse,destructor:function(){var e=this.constructor.Interface;for(var t in e)this[t]=null;for(var n=0;n<s.length;n++)this[s[n]]=null}}),r.Interface=u,r.augmentClass=function(e,t){var n=this,r=function(){};r.prototype=n.prototype;var a=new r;o(a,e.prototype),e.prototype=a,e.prototype.constructor=e,e.Interface=o({},n.Interface,t),e.augmentClass=n.augmentClass,i.addPoolingTo(e,i.fourArgumentPooler)},i.addPoolingTo(r,i.fourArgumentPooler),t.exports=r},{129:129,142:142,143:143,24:24}],81:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(87),i={relatedTarget:null};o.augmentClass(r,i),t.exports=r},{87:87}],82:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(80),i={data:null};o.augmentClass(r,i),t.exports=r},{80:80}],83:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(87),i=e(99),a=e(100),s=e(101),u={key:a,location:null,ctrlKey:null,shiftKey:null,altKey:null,metaKey:null,repeat:null,locale:null,getModifierState:s,charCode:function(e){return"keypress"===e.type?i(e):0},keyCode:function(e){return"keydown"===e.type||"keyup"===e.type?e.keyCode:0},which:function(e){return"keypress"===e.type?i(e):"keydown"===e.type||"keyup"===e.type?e.keyCode:0}};o.augmentClass(r,u),t.exports=r},{100:100,101:101,87:87,99:99}],84:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(87),i=e(90),a=e(101),s={screenX:null,screenY:null,clientX:null,clientY:null,ctrlKey:null,shiftKey:null,altKey:null,metaKey:null,getModifierState:a,button:function(e){var t=e.button;return"which"in e?t:2===t?2:4===t?1:0},buttons:null,relatedTarget:function(e){return e.relatedTarget||(e.fromElement===e.srcElement?e.toElement:e.fromElement)},pageX:function(e){return"pageX"in e?e.pageX:e.clientX+i.currentScrollLeft},pageY:function(e){return"pageY"in e?e.pageY:e.clientY+i.currentScrollTop}};o.augmentClass(r,s),t.exports=r},{101:101,87:87,90:90}],85:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(87),i=e(101),a={touches:null,targetTouches:null,changedTouches:null,altKey:null,metaKey:null,ctrlKey:null,shiftKey:null,getModifierState:i};o.augmentClass(r,a),t.exports=r},{101:101,87:87}],86:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(80),i={propertyName:null,elapsedTime:null,pseudoElement:null};o.augmentClass(r,i),t.exports=r},{80:80}],87:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(80),i=e(102),a={view:function(e){if(e.view)return e.view;var t=i(e);if(t.window===t)return t;var n=t.ownerDocument;return n?n.defaultView||n.parentWindow:window},detail:function(e){return e.detail||0}};o.augmentClass(r,a),t.exports=r},{102:102,80:80}],88:[function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=e(84),i={deltaX:function(e){return"deltaX"in e?e.deltaX:"wheelDeltaX"in e?-e.wheelDeltaX:0},deltaY:function(e){return"deltaY"in e?e.deltaY:"wheelDeltaY"in e?-e.wheelDeltaY:"wheelDelta"in e?-e.wheelDelta:0},deltaZ:null,deltaMode:null};o.augmentClass(r,i),t.exports=r},{84:84}],89:[function(e,t,n){"use strict";var r=e(112),o=(e(137),{}),i={reinitializeTransaction:function(){this.transactionWrappers=this.getTransactionWrappers(),this.wrapperInitData?this.wrapperInitData.length=0:this.wrapperInitData=[],this._isInTransaction=!1},_isInTransaction:!1,getTransactionWrappers:null,isInTransaction:function(){return!!this._isInTransaction},perform:function(e,t,n,o,i,a,s,u){this.isInTransaction()&&r("27");var l,c;try{this._isInTransaction=!0,l=!0,this.initializeAll(0),c=e.call(t,n,o,i,a,s,u),l=!1}finally{try{if(l)try{this.closeAll(0)}catch(e){}else this.closeAll(0)}finally{this._isInTransaction=!1}}return c},initializeAll:function(e){for(var t=this.transactionWrappers,n=e;n<t.length;n++){var r=t[n];try{this.wrapperInitData[n]=o,this.wrapperInitData[n]=r.initialize?r.initialize.call(this):null}finally{if(this.wrapperInitData[n]===o)try{this.initializeAll(n+1)}catch(e){}}}},closeAll:function(e){this.isInTransaction()||r("28");for(var t=this.transactionWrappers,n=e;n<t.length;n++){var i,a=t[n],s=this.wrapperInitData[n];try{i=!0,s!==o&&a.close&&a.close.call(this,s),i=!1}finally{if(i)try{this.closeAll(n+1)}catch(e){}}}this.wrapperInitData.length=0}};t.exports=i},{112:112,137:137}],90:[function(e,t,n){"use strict";var r={currentScrollLeft:0,currentScrollTop:0,refreshScrollValues:function(e){r.currentScrollLeft=e.x,r.currentScrollTop=e.y}};t.exports=r},{}],91:[function(e,t,n){"use strict";function r(e,t){return null==t&&o("30"),null==e?t:Array.isArray(e)?Array.isArray(t)?(e.push.apply(e,t),e):(e.push(t),e):Array.isArray(t)?[e].concat(t):[e,t]}var o=e(112);e(137);t.exports=r},{112:112,137:137}],92:[function(e,t,n){"use strict";function r(e){for(var t=1,n=0,r=0,i=e.length,a=-4&i;r<a;){for(var s=Math.min(r+4096,a);r<s;r+=4)n+=(t+=e.charCodeAt(r))+(t+=e.charCodeAt(r+1))+(t+=e.charCodeAt(r+2))+(t+=e.charCodeAt(r+3));t%=o,n%=o}for(;r<i;r++)n+=t+=e.charCodeAt(r);return t%=o,n%=o,t|n<<16}var o=65521;t.exports=r},{}],93:[function(e,t,n){"use strict";var r=function(e){return"undefined"!=typeof MSApp&&MSApp.execUnsafeLocalFunction?function(t,n,r,o){MSApp.execUnsafeLocalFunction(function(){return e(t,n,r,o)})}:e};t.exports=r},{}],94:[function(e,t,n){"use strict";function r(e,t,n){return null==t||"boolean"==typeof t||""===t?"":isNaN(t)||0===t||i.hasOwnProperty(e)&&i[e]?""+t:("string"==typeof t&&(t=t.trim()),t+"px")}var o=e(4),i=(e(142),o.isUnitlessNumber);t.exports=r},{142:142,4:4}],95:[function(e,t,n){"use strict";function r(e){var t=""+e,n=i.exec(t);if(!n)return t;var r,o="",a=0,s=0;for(a=n.index;a<t.length;a++){switch(t.charCodeAt(a)){case 34:r=""";break;case 38:r="&";break;case 39:r="'";break;case 60:r="<";break;case 62:r=">";break;default:continue}s!==a&&(o+=t.substring(s,a)),s=a+1,o+=r}return s!==a?o+t.substring(s,a):o}function o(e){return"boolean"==typeof e||"number"==typeof e?""+e:r(e)}var i=/["'&<>]/;t.exports=o},{}],96:[function(e,t,n){"use strict";function r(e){if(null==e)return null;if(1===e.nodeType)return e;var t=a.get(e);if(t)return t=s(t),t?i.getNodeFromInstance(t):null;"function"==typeof e.render?o("44"):o("45",Object.keys(e))}var o=e(112),i=(e(119),e(33)),a=e(57),s=e(103);e(137),e(142);t.exports=r},{103:103,112:112,119:119,137:137,142:142,33:33,57:57}],97:[function(e,t,n){(function(n){"use strict";function r(e,t,n,r){if(e&&"object"==typeof e){var o=e;void 0===o[n]&&null!=t&&(o[n]=t)}}function o(e,t){if(null==e)return e;var n={};return i(e,r,n),n}var i=(e(22),e(117));e(142);void 0!==n&&n.env,t.exports=o}).call(this,void 0)},{117:117,142:142,22:22}],98:[function(e,t,n){"use strict";function r(e,t,n){Array.isArray(e)?e.forEach(t,n):e&&t.call(n,e)}t.exports=r},{}],99:[function(e,t,n){"use strict";function r(e){var t,n=e.keyCode;return"charCode"in e?0===(t=e.charCode)&&13===n&&(t=13):t=n,t>=32||13===t?t:0}t.exports=r},{}],100:[function(e,t,n){"use strict";function r(e){if(e.key){var t=i[e.key]||e.key;if("Unidentified"!==t)return t}if("keypress"===e.type){var n=o(e);return 13===n?"Enter":String.fromCharCode(n)}return"keydown"===e.type||"keyup"===e.type?a[e.keyCode]||"Unidentified":""}var o=e(99),i={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},a={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"};t.exports=r},{99:99}],101:[function(e,t,n){"use strict";function r(e){var t=this,n=t.nativeEvent;if(n.getModifierState)return n.getModifierState(e);var r=i[e];return!!r&&!!n[r]}function o(e){return r}var i={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"};t.exports=o},{}],102:[function(e,t,n){"use strict";function r(e){var t=e.target||e.srcElement||window;return t.correspondingUseElement&&(t=t.correspondingUseElement),3===t.nodeType?t.parentNode:t}t.exports=r},{}],103:[function(e,t,n){"use strict";function r(e){for(var t;(t=e._renderedNodeType)===o.COMPOSITE;)e=e._renderedComponent;return t===o.HOST?e._renderedComponent:t===o.EMPTY?null:void 0}var o=e(62);t.exports=r},{62:62}],104:[function(e,t,n){"use strict";function r(e){var t=e&&(o&&e[o]||e[i]);if("function"==typeof t)return t}var o="function"==typeof Symbol&&Symbol.iterator,i="@@iterator";t.exports=r},{}],105:[function(e,t,n){"use strict";function r(e){for(;e&&e.firstChild;)e=e.firstChild;return e}function o(e){for(;e;){if(e.nextSibling)return e.nextSibling;e=e.parentNode}}function i(e,t){for(var n=r(e),i=0,a=0;n;){if(3===n.nodeType){if(a=i+n.textContent.length,i<=t&&a>=t)return{node:n,offset:t-i};i=a}n=r(o(n))}}t.exports=i},{}],106:[function(e,t,n){"use strict";function r(){return!i&&o.canUseDOM&&(i="textContent"in document.documentElement?"textContent":"innerText"),i}var o=e(123),i=null;t.exports=r},{123:123}],107:[function(e,t,n){"use strict";function r(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit"+e]="webkit"+t,n["Moz"+e]="moz"+t,n["ms"+e]="MS"+t,n["O"+e]="o"+t.toLowerCase(),n}function o(e){if(s[e])return s[e];if(!a[e])return e;var t=a[e];for(var n in t)if(t.hasOwnProperty(n)&&n in u)return s[e]=t[n];return""}var i=e(123),a={animationend:r("Animation","AnimationEnd"),animationiteration:r("Animation","AnimationIteration"),animationstart:r("Animation","AnimationStart"),transitionend:r("Transition","TransitionEnd")},s={},u={};i.canUseDOM&&(u=document.createElement("div").style,"AnimationEvent"in window||(delete a.animationend.animation,delete a.animationiteration.animation,delete a.animationstart.animation),"TransitionEvent"in window||delete a.transitionend.transition),t.exports=o},{123:123}],108:[function(e,t,n){"use strict";function r(e){if(e){var t=e.getName();if(t)return" Check the render method of `"+t+"`."}return""}function o(e){return"function"==typeof e&&void 0!==e.prototype&&"function"==typeof e.prototype.mountComponent&&"function"==typeof e.prototype.receiveComponent}function i(e,t){var n;if(null===e||!1===e)n=l.create(i);else if("object"==typeof e){var s=e,u=s.type;if("function"!=typeof u&&"string"!=typeof u){var d="";d+=r(s._owner),a("130",null==u?u:typeof u,d)}"string"==typeof s.type?n=c.createInternalComponent(s):o(s.type)?(n=new s.type(s),n.getHostNode||(n.getHostNode=n.getNativeNode)):n=new p(s)}else"string"==typeof e||"number"==typeof e?n=c.createInstanceForText(e):a("131",typeof e);return n._mountIndex=0,n._mountImage=null,n}var a=e(112),s=e(143),u=e(29),l=e(49),c=e(54),p=(e(121),e(137),e(142),function(e){this.construct(e)});s(p.prototype,u,{_instantiateReactComponent:i}),t.exports=i},{112:112,121:121,137:137,142:142,143:143,29:29,49:49,54:54}],109:[function(e,t,n){"use strict";function r(e,t){if(!i.canUseDOM||t&&!("addEventListener"in document))return!1;var n="on"+e,r=n in document;if(!r){var a=document.createElement("div");a.setAttribute(n,"return;"),r="function"==typeof a[n]}return!r&&o&&"wheel"===e&&(r=document.implementation.hasFeature("Events.wheel","3.0")),r}var o,i=e(123);i.canUseDOM&&(o=document.implementation&&document.implementation.hasFeature&&!0!==document.implementation.hasFeature("","")),t.exports=r},{123:123}],110:[function(e,t,n){"use strict";function r(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return"input"===t?!!o[e.type]:"textarea"===t}var o={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};t.exports=r},{}],111:[function(e,t,n){"use strict";function r(e){return'"'+o(e)+'"'}var o=e(95);t.exports=r},{95:95}],112:[function(e,t,n){"use strict";function r(e){for(var t=arguments.length-1,n="Minified React error #"+e+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant="+e,r=0;r<t;r++)n+="&args[]="+encodeURIComponent(arguments[r+1]);n+=" for the full message or use the non-minified dev environment for full errors and additional helpful warnings.";var o=new Error(n);throw o.name="Invariant Violation",o.framesToPop=1,o}t.exports=r},{}],113:[function(e,t,n){"use strict";var r=e(60);t.exports=r.renderSubtreeIntoContainer},{60:60}],114:[function(e,t,n){"use strict";var r,o=e(123),i=e(10),a=/^[ \r\n\t\f]/,s=/<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/,u=e(93),l=u(function(e,t){if(e.namespaceURI!==i.svg||"innerHTML"in e)e.innerHTML=t;else{r=r||document.createElement("div"),r.innerHTML="<svg>"+t+"</svg>";for(var n=r.firstChild;n.firstChild;)e.appendChild(n.firstChild)}});if(o.canUseDOM){var c=document.createElement("div");c.innerHTML=" ",""===c.innerHTML&&(l=function(e,t){if(e.parentNode&&e.parentNode.replaceChild(e,e),a.test(t)||"<"===t[0]&&s.test(t)){e.innerHTML=String.fromCharCode(65279)+t;var n=e.firstChild;1===n.data.length?e.removeChild(n):n.deleteData(0,1)}else e.innerHTML=t}),c=null}t.exports=l},{10:10,123:123,93:93}],115:[function(e,t,n){"use strict";var r=e(123),o=e(95),i=e(114),a=function(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&3===n.nodeType)return void(n.nodeValue=t)}e.textContent=t};r.canUseDOM&&("textContent"in document.documentElement||(a=function(e,t){if(3===e.nodeType)return void(e.nodeValue=t);i(e,o(t))})),t.exports=a},{114:114,123:123,95:95}],116:[function(e,t,n){"use strict";function r(e,t){var n=null===e||!1===e,r=null===t||!1===t;if(n||r)return n===r;var o=typeof e,i=typeof t;return"string"===o||"number"===o?"string"===i||"number"===i:"object"===i&&e.type===t.type&&e.key===t.key}t.exports=r},{}],117:[function(e,t,n){"use strict";function r(e,t){return e&&"object"==typeof e&&null!=e.key?l.escape(e.key):t.toString(36)}function o(e,t,n,i){var d=typeof e;if("undefined"!==d&&"boolean"!==d||(e=null),null===e||"string"===d||"number"===d||"object"===d&&e.$$typeof===s)return n(i,e,""===t?c+r(e,0):t),1;var f,h,m=0,v=""===t?c:t+p;if(Array.isArray(e))for(var g=0;g<e.length;g++)f=e[g],h=v+r(f,g),m+=o(f,h,n,i);else{var y=u(e);if(y){var _,C=y.call(e);if(y!==e.entries)for(var b=0;!(_=C.next()).done;)f=_.value,h=v+r(f,b++),m+=o(f,h,n,i);else for(;!(_=C.next()).done;){var E=_.value;E&&(f=E[1],h=v+l.escape(E[0])+p+r(f,0),m+=o(f,h,n,i))}}else if("object"===d){var x=String(e);a("31","[object Object]"===x?"object with keys {"+Object.keys(e).join(", ")+"}":x,"")}}return m}function i(e,t,n){return null==e?0:o(e,"",t,n)}var a=e(112),s=(e(119),e(48)),u=e(104),l=(e(137),e(22)),c=(e(142),"."),p=":";t.exports=i},{104:104,112:112,119:119,137:137,142:142,22:22,48:48}],118:[function(e,t,n){"use strict";var r=(e(143),e(129)),o=(e(142),r);t.exports=o},{129:129,142:142,143:143}],119:[function(t,n,r){"use strict";var o=e.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;n.exports=o.ReactCurrentOwner},{}],120:[function(t,n,r){"use strict";n.exports=e},{}],121:[function(t,n,r){"use strict";var o=e.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;n.exports=o.getNextDebugID},{}],122:[function(e,t,n){"use strict";var r=e(129),o={listen:function(e,t,n){return e.addEventListener?(e.addEventListener(t,n,!1),{remove:function(){e.removeEventListener(t,n,!1)}}):e.attachEvent?(e.attachEvent("on"+t,n),{remove:function(){e.detachEvent("on"+t,n)}}):void 0},capture:function(e,t,n){return e.addEventListener?(e.addEventListener(t,n,!0),{remove:function(){e.removeEventListener(t,n,!0)}}):{remove:r}},registerDefault:function(){}};t.exports=o},{129:129}],123:[function(e,t,n){"use strict";var r=!("undefined"==typeof window||!window.document||!window.document.createElement),o={canUseDOM:r,canUseWorkers:"undefined"!=typeof Worker,canUseEventListeners:r&&!(!window.addEventListener&&!window.attachEvent),canUseViewport:r&&!!window.screen,isInWorker:!r};t.exports=o},{}],124:[function(e,t,n){"use strict";function r(e){return e.replace(o,function(e,t){return t.toUpperCase()})}var o=/-(.)/g;t.exports=r},{}],125:[function(e,t,n){"use strict";function r(e){return o(e.replace(i,"ms-"))}var o=e(124),i=/^-ms-/;t.exports=r},{124:124}],126:[function(e,t,n){"use strict";function r(e,t){return!(!e||!t)&&(e===t||!o(e)&&(o(t)?r(e,t.parentNode):"contains"in e?e.contains(t):!!e.compareDocumentPosition&&!!(16&e.compareDocumentPosition(t))))}var o=e(139);t.exports=r},{139:139}],127:[function(e,t,n){"use strict";function r(e){var t=e.length;if((Array.isArray(e)||"object"!=typeof e&&"function"!=typeof e)&&a(!1),"number"!=typeof t&&a(!1),0===t||t-1 in e||a(!1),"function"==typeof e.callee&&a(!1),e.hasOwnProperty)try{return Array.prototype.slice.call(e)}catch(e){}for(var n=Array(t),r=0;r<t;r++)n[r]=e[r];return n}function o(e){return!!e&&("object"==typeof e||"function"==typeof e)&&"length"in e&&!("setInterval"in e)&&"number"!=typeof e.nodeType&&(Array.isArray(e)||"callee"in e||"item"in e)}function i(e){return o(e)?Array.isArray(e)?e.slice():r(e):[e]}var a=e(137);t.exports=i},{137:137}],128:[function(e,t,n){"use strict";function r(e){var t=e.match(c);return t&&t[1].toLowerCase()}function o(e,t){var n=l;l||u(!1);var o=r(e),i=o&&s(o);if(i){n.innerHTML=i[1]+e+i[2];for(var c=i[0];c--;)n=n.lastChild}else n.innerHTML=e;var p=n.getElementsByTagName("script");p.length&&(t||u(!1),a(p).forEach(t));for(var d=Array.from(n.childNodes);n.lastChild;)n.removeChild(n.lastChild);return d}var i=e(123),a=e(127),s=e(133),u=e(137),l=i.canUseDOM?document.createElement("div"):null,c=/^\s*<(\w+)/;t.exports=o},{123:123,127:127,133:133,137:137}],129:[function(e,t,n){"use strict";function r(e){return function(){return e}}var o=function(){};o.thatReturns=r,o.thatReturnsFalse=r(!1),o.thatReturnsTrue=r(!0),o.thatReturnsNull=r(null),o.thatReturnsThis=function(){return this},o.thatReturnsArgument=function(e){return e},t.exports=o},{}],130:[function(e,t,n){"use strict";var r={};t.exports=r},{}],131:[function(e,t,n){"use strict";function r(e){try{e.focus()}catch(e){}}t.exports=r},{}],132:[function(e,t,n){"use strict";function r(e){if(void 0===(e=e||("undefined"!=typeof document?document:void 0)))return null;try{return e.activeElement||e.body}catch(t){return e.body}}t.exports=r},{}],133:[function(e,t,n){"use strict";function r(e){return a||i(!1),d.hasOwnProperty(e)||(e="*"),s.hasOwnProperty(e)||(a.innerHTML="*"===e?"<link />":"<"+e+"></"+e+">",s[e]=!a.firstChild),s[e]?d[e]:null}var o=e(123),i=e(137),a=o.canUseDOM?document.createElement("div"):null,s={},u=[1,'<select multiple="true">',"</select>"],l=[1,"<table>","</table>"],c=[3,"<table><tbody><tr>","</tr></tbody></table>"],p=[1,'<svg xmlns="http://www.w3.org/2000/svg">',"</svg>"],d={"*":[1,"?<div>","</div>"],area:[1,"<map>","</map>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],legend:[1,"<fieldset>","</fieldset>"],param:[1,"<object>","</object>"],tr:[2,"<table><tbody>","</tbody></table>"],optgroup:u,option:u,caption:l,colgroup:l,tbody:l,tfoot:l,thead:l,td:c,th:c};["circle","clipPath","defs","ellipse","g","image","line","linearGradient","mask","path","pattern","polygon","polyline","radialGradient","rect","stop","text","tspan"].forEach(function(e){d[e]=p,s[e]=!0}),t.exports=r},{123:123,137:137}],134:[function(e,t,n){"use strict";function r(e){return e.Window&&e instanceof e.Window?{x:e.pageXOffset||e.document.documentElement.scrollLeft,y:e.pageYOffset||e.document.documentElement.scrollTop}:{x:e.scrollLeft,y:e.scrollTop}}t.exports=r},{}],135:[function(e,t,n){"use strict";function r(e){return e.replace(o,"-$1").toLowerCase()}var o=/([A-Z])/g;t.exports=r},{}],136:[function(e,t,n){"use strict";function r(e){return o(e).replace(i,"-ms-")}var o=e(135),i=/^ms-/;t.exports=r},{135:135}],137:[function(e,t,n){"use strict";function r(e,t,n,r,i,a,s,u){if(o(t),!e){var l;if(void 0===t)l=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[n,r,i,a,s,u],p=0;l=new Error(t.replace(/%s/g,function(){return c[p++]})),l.name="Invariant Violation"}throw l.framesToPop=1,l}}var o=function(e){};t.exports=r},{}],138:[function(e,t,n){"use strict";function r(e){var t=e?e.ownerDocument||e:document,n=t.defaultView||window;return!(!e||!("function"==typeof n.Node?e instanceof n.Node:"object"==typeof e&&"number"==typeof e.nodeType&&"string"==typeof e.nodeName))}t.exports=r},{}],139:[function(e,t,n){"use strict";function r(e){return o(e)&&3==e.nodeType}var o=e(138);t.exports=r},{138:138}],140:[function(e,t,n){"use strict";function r(e){var t={};return function(n){return t.hasOwnProperty(n)||(t[n]=e.call(this,n)),t[n]}}t.exports=r},{}],141:[function(e,t,n){"use strict";function r(e,t){return e===t?0!==e||0!==t||1/e==1/t:e!==e&&t!==t}function o(e,t){if(r(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),o=Object.keys(t);if(n.length!==o.length)return!1;for(var a=0;a<n.length;a++)if(!i.call(t,n[a])||!r(e[n[a]],t[n[a]]))return!1;return!0}var i=Object.prototype.hasOwnProperty;t.exports=o},{}],142:[function(e,t,n){"use strict";var r=e(129),o=r;t.exports=o},{129:129}],143:[function(e,t,n){"use strict";function r(e){if(null===e||void 0===e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}var o=Object.getOwnPropertySymbols,i=Object.prototype.hasOwnProperty,a=Object.prototype.propertyIsEnumerable;t.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map(function(e){return t[e]}).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach(function(e){r[e]=e}),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(e){return!1}}()?Object.assign:function(e,t){for(var n,s,u=r(e),l=1;l<arguments.length;l++){n=Object(arguments[l]);for(var c in n)i.call(n,c)&&(u[c]=n[c]);if(o){s=o(n);for(var p=0;p<s.length;p++)a.call(n,s[p])&&(u[s[p]]=n[s[p]])}}return u}},{}],144:[function(e,t,n){"use strict";function r(e,t,n,r,o){}t.exports=r},{137:137,142:142,147:147}],145:[function(e,t,n){"use strict";var r=e(146);t.exports=function(e){return r(e,!1)}},{146:146}],146:[function(e,t,n){"use strict";var r=e(129),o=e(137),i=(e(142),e(147)),a=e(144);t.exports=function(e,t){function n(e){var t=e&&(E&&e[E]||e[x]);if("function"==typeof t)return t}function s(e,t){return e===t?0!==e||1/e==1/t:e!==e&&t!==t}function u(e){this.message=e,this.stack=""}function l(e){function n(n,r,a,s,l,c,p){if(s=s||w,c=c||a,p!==i)if(t)o(!1,"Calling PropTypes validators directly is not supported by the `prop-types` package. Use `PropTypes.checkPropTypes()` to call them. Read more at http://fb.me/use-check-prop-types");else;return null==r[a]?n?new u(null===r[a]?"The "+l+" `"+c+"` is marked as required in `"+s+"`, but its value is `null`.":"The "+l+" `"+c+"` is marked as required in `"+s+"`, but its value is `undefined`."):null:e(r,a,s,l,c)}var r=n.bind(null,!1);return r.isRequired=n.bind(null,!0),r}function c(e){function t(t,n,r,o,i,a){var s=t[n];if(_(s)!==e)return new u("Invalid "+o+" `"+i+"` of type `"+C(s)+"` supplied to `"+r+"`, expected `"+e+"`.");return null}return l(t)}function p(e){function t(t,n,r,o,a){if("function"!=typeof e)return new u("Property `"+a+"` of component `"+r+"` has invalid PropType notation inside arrayOf.");var s=t[n];if(!Array.isArray(s)){return new u("Invalid "+o+" `"+a+"` of type `"+_(s)+"` supplied to `"+r+"`, expected an array.")}for(var l=0;l<s.length;l++){var c=e(s,l,r,o,a+"["+l+"]",i);if(c instanceof Error)return c}return null}return l(t)}function d(e){function t(t,n,r,o,i){if(!(t[n]instanceof e)){var a=e.name||w;return new u("Invalid "+o+" `"+i+"` of type `"+b(t[n])+"` supplied to `"+r+"`, expected instance of `"+a+"`.")}return null}return l(t)}function f(e){function t(t,n,r,o,i){for(var a=t[n],l=0;l<e.length;l++)if(s(a,e[l]))return null;return new u("Invalid "+o+" `"+i+"` of value `"+a+"` supplied to `"+r+"`, expected one of "+JSON.stringify(e)+".")}return Array.isArray(e)?l(t):r.thatReturnsNull}function h(e){function t(t,n,r,o,a){if("function"!=typeof e)return new u("Property `"+a+"` of component `"+r+"` has invalid PropType notation inside objectOf.");var s=t[n],l=_(s);if("object"!==l)return new u("Invalid "+o+" `"+a+"` of type `"+l+"` supplied to `"+r+"`, expected an object.");for(var c in s)if(s.hasOwnProperty(c)){var p=e(s,c,r,o,a+"."+c,i);if(p instanceof Error)return p}return null}return l(t)}function m(e){function t(t,n,r,o,a){for(var s=0;s<e.length;s++){if(null==(0,e[s])(t,n,r,o,a,i))return null}return new u("Invalid "+o+" `"+a+"` supplied to `"+r+"`.")}return Array.isArray(e)?l(t):r.thatReturnsNull}function v(e){function t(t,n,r,o,a){var s=t[n],l=_(s);if("object"!==l)return new u("Invalid "+o+" `"+a+"` of type `"+l+"` supplied to `"+r+"`, expected `object`.");for(var c in e){var p=e[c];if(p){var d=p(s,c,r,o,a+"."+c,i);if(d)return d}}return null}return l(t)}function g(t){switch(typeof t){case"number":case"string":case"undefined":return!0;case"boolean":return!t;case"object":if(Array.isArray(t))return t.every(g);if(null===t||e(t))return!0;var r=n(t);if(!r)return!1;var o,i=r.call(t);if(r!==t.entries){for(;!(o=i.next()).done;)if(!g(o.value))return!1}else for(;!(o=i.next()).done;){var a=o.value;if(a&&!g(a[1]))return!1}return!0;default:return!1}}function y(e,t){return"symbol"===e||("Symbol"===t["@@toStringTag"]||"function"==typeof Symbol&&t instanceof Symbol)}function _(e){var t=typeof e;return Array.isArray(e)?"array":e instanceof RegExp?"object":y(t,e)?"symbol":t}function C(e){var t=_(e);if("object"===t){if(e instanceof Date)return"date";if(e instanceof RegExp)return"regexp"}return t}function b(e){return e.constructor&&e.constructor.name?e.constructor.name:w}var E="function"==typeof Symbol&&Symbol.iterator,x="@@iterator",w="<<anonymous>>",T={array:c("array"),bool:c("boolean"),func:c("function"),number:c("number"),object:c("object"),string:c("string"),symbol:c("symbol"),any:function(){return l(r.thatReturnsNull)}(),arrayOf:p,element:function(){function t(t,n,r,o,i){var a=t[n];if(!e(a)){return new u("Invalid "+o+" `"+i+"` of type `"+_(a)+"` supplied to `"+r+"`, expected a single ReactElement.")}return null}return l(t)}(),instanceOf:d,node:function(){function e(e,t,n,r,o){return g(e[t])?null:new u("Invalid "+r+" `"+o+"` supplied to `"+n+"`, expected a ReactNode.")}return l(e)}(),objectOf:h,oneOf:f,oneOfType:m,shape:v} +;return u.prototype=Error.prototype,T.checkPropTypes=a,T.PropTypes=T,T}},{129:129,137:137,142:142,144:144,147:147}],147:[function(e,t,n){"use strict";t.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},{}]},{},[45])(45)}()}()}); +/*! http://mths.be/fromcodepoint v0.1.0 by @mathias */ +if (!String.fromCodePoint) { + (function() { + var defineProperty = (function() { + // IE 8 only supports `Object.defineProperty` on DOM elements + try { + var object = {}; + var $defineProperty = Object.defineProperty; + var result = $defineProperty(object, object, object) && $defineProperty; + } catch(error) {} + return result; + }()); + var stringFromCharCode = String.fromCharCode; + var floor = Math.floor; + var fromCodePoint = function() { + var MAX_SIZE = 0x4000; + var codeUnits = []; + var highSurrogate; + var lowSurrogate; + var index = -1; + var length = arguments.length; + if (!length) { + return ''; + } + var result = ''; + while (++index < length) { + var codePoint = Number(arguments[index]); + if ( + !isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity` + codePoint < 0 || // not a valid Unicode code point + codePoint > 0x10FFFF || // not a valid Unicode code point + floor(codePoint) != codePoint // not an integer + ) { + throw RangeError('Invalid code point: ' + codePoint); + } + if (codePoint <= 0xFFFF) { // BMP code point + codeUnits.push(codePoint); + } else { // Astral code point; split in surrogate halves + // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + codePoint -= 0x10000; + highSurrogate = (codePoint >> 10) + 0xD800; + lowSurrogate = (codePoint % 0x400) + 0xDC00; + codeUnits.push(highSurrogate, lowSurrogate); + } + if (index + 1 == length || codeUnits.length > MAX_SIZE) { + result += stringFromCharCode.apply(null, codeUnits); + codeUnits.length = 0; + } + } + return result; + }; + if (defineProperty) { + defineProperty(String, 'fromCodePoint', { + 'value': fromCodePoint, + 'configurable': true, + 'writable': true + }); + } else { + String.fromCodePoint = fromCodePoint; + } + }()); +} + +/*! http://mths.be/codepointat v0.1.0 by @mathias */ +if (!String.prototype.codePointAt) { + (function() { + 'use strict'; // needed to support `apply`/`call` with `undefined`/`null` + var codePointAt = function(position) { + if (this == null) { + throw TypeError(); + } + var string = String(this); + var size = string.length; + // `ToInteger` + var index = position ? Number(position) : 0; + if (index != index) { // better `isNaN` + index = 0; + } + // Account for out-of-bounds indices: + if (index < 0 || index >= size) { + return undefined; + } + // Get the first code unit + var first = string.charCodeAt(index); + var second; + if ( // check if it’s the start of a surrogate pair + first >= 0xD800 && first <= 0xDBFF && // high surrogate + size > index + 1 // there is a next code unit + ) { + second = string.charCodeAt(index + 1); + if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate + // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; + } + } + return first; + }; + if (Object.defineProperty) { + Object.defineProperty(String.prototype, 'codePointAt', { + 'value': codePointAt, + 'configurable': true, + 'writable': true + }); + } else { + String.prototype.codePointAt = codePointAt; + } + }()); +} + +function registerAsciinemaPlayerElement() { + var AsciinemaPlayerProto = Object.create(HTMLElement.prototype); + + function merge() { + var merged = {}; + for (var i=0; i<arguments.length; i++) { + var obj = arguments[i]; + for (var attrname in obj) { + merged[attrname] = obj[attrname]; + } + } + return merged; + } + + function attribute(element, attrName, optName, defaultValue, coerceFn) { + var obj = {}; + var value = element.getAttribute(attrName); + if (value !== null) { + if (value === '' && defaultValue !== undefined) { + value = defaultValue; + } else if (coerceFn) { + value = coerceFn(value); + } + obj[optName] = value; + } + return obj; + }; + + function fixEscapeCodes(text) { + if (text) { + var f = function(match, p1, offset, string) { + return String.fromCodePoint(parseInt(p1, 16)); + }; + + return text. + replace(/\\u([a-z0-9]{4})/gi, f). + replace(/\\x([a-z0-9]{2})/gi, f). + replace(/\\e/g, "\x1b"); + } else { + return text; + } + } + + AsciinemaPlayerProto.createdCallback = function() { + var self = this; + + var opts = merge( + attribute(this, 'cols', 'width', 0, parseInt), + attribute(this, 'rows', 'height', 0, parseInt), + attribute(this, 'autoplay', 'autoPlay', true, Boolean), + attribute(this, 'preload', 'preload', true, Boolean), + attribute(this, 'loop', 'loop', true, Boolean), + attribute(this, 'start-at', 'startAt', 0, parseInt), + attribute(this, 'speed', 'speed', 1, parseFloat), + attribute(this, 'idle-time-limit', 'idleTimeLimit', null, parseFloat), + attribute(this, 'poster', 'poster', null, fixEscapeCodes), + attribute(this, 'font-size', 'fontSize'), + attribute(this, 'theme', 'theme'), + attribute(this, 'title', 'title'), + attribute(this, 'author', 'author'), + attribute(this, 'author-url', 'authorURL'), + attribute(this, 'author-img-url', 'authorImgURL'), + { + onCanPlay: function() { + self.dispatchEvent(new CustomEvent("loadedmetadata")); + self.dispatchEvent(new CustomEvent("loadeddata")); + self.dispatchEvent(new CustomEvent("canplay")); + self.dispatchEvent(new CustomEvent("canplaythrough")); + }, + + onPlay: function() { + self.dispatchEvent(new CustomEvent("play")); + }, + + onPause: function() { + self.dispatchEvent(new CustomEvent("pause")); + } + } + ); + + this.player = asciinema.player.js.CreatePlayer(this, this.getAttribute('src'), opts); + }; + + AsciinemaPlayerProto.attachedCallback = function() { + var self = this; + setTimeout(function() { + self.dispatchEvent(new CustomEvent("attached")); + }, 0); + }; + + AsciinemaPlayerProto.detachedCallback = function() { + asciinema.player.js.UnmountPlayer(this); + this.player = undefined; + }; + + AsciinemaPlayerProto.play = function() { + this.player.play(); + }; + + AsciinemaPlayerProto.pause = function() { + this.player.pause(); + }; + + Object.defineProperty(AsciinemaPlayerProto, "duration", { + get: function() { + return this.player.getDuration() || 0; + }, + + set: function(value) {} + }); + + Object.defineProperty(AsciinemaPlayerProto, "currentTime", { + get: function() { + return this.player.getCurrentTime(); + }, + + set: function(value) { + this.player.setCurrentTime(value); + } + }); + + document.registerElement('asciinema-player', { prototype: AsciinemaPlayerProto }); +}; + +;(function(){ +var g,aa=aa||{},ba=this;function ca(a){return"string"==typeof a}function da(a,b){var c=a.split("."),d=ba;c[0]in d||!d.execScript||d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||void 0===b?d=d[e]&&d[e]!==Object.prototype[e]?d[e]:d[e]={}:d[e]=b}function ea(){} +function n(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null"; +else if("function"==b&&"undefined"==typeof a.call)return"object";return b}function fa(a){var b=n(a);return"array"==b||"object"==b&&"number"==typeof a.length}function ha(a){return"function"==n(a)}function ia(a){var b=typeof a;return"object"==b&&null!=a||"function"==b}function ja(a){return a[la]||(a[la]=++ma)}var la="closure_uid_"+(1E9*Math.random()>>>0),ma=0;function na(a,b,c){return a.call.apply(a.bind,arguments)} +function oa(a,b,c){if(!a)throw Error();if(2<arguments.length){var d=Array.prototype.slice.call(arguments,2);return function(){var c=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(c,d);return a.apply(b,c)}}return function(){return a.apply(b,arguments)}}function pa(a,b,c){pa=Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf("native code")?na:oa;return pa.apply(null,arguments)} +function qa(a,b){function c(){}c.prototype=b.prototype;a.Zd=b.prototype;a.prototype=new c;a.prototype.constructor=a;a.base=function(a,c,f){for(var d=Array(arguments.length-2),e=2;e<arguments.length;e++)d[e-2]=arguments[e];return b.prototype[c].apply(a,d)}};var ra=String.prototype.trim?function(a){return a.trim()}:function(a){return a.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},sa=String.prototype.repeat?function(a,b){return a.repeat(b)}:function(a,b){return Array(b+1).join(a)};function ta(a,b){return a<b?-1:a>b?1:0};var ua=Array.prototype.indexOf?function(a,b,c){return Array.prototype.indexOf.call(a,b,c)}:function(a,b,c){c=null==c?0:0>c?Math.max(0,a.length+c):c;if(ca(a))return ca(b)&&1==b.length?a.indexOf(b,c):-1;for(;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},va=Array.prototype.forEach?function(a,b,c){Array.prototype.forEach.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=ca(a)?a.split(""):a,f=0;f<d;f++)f in e&&b.call(c,e[f],f,a)}; +function wa(a){a:{var b=xa;for(var c=a.length,d=ca(a)?a.split(""):a,e=0;e<c;e++)if(e in d&&b.call(void 0,d[e],e,a)){b=e;break a}b=-1}return 0>b?null:ca(a)?a.charAt(b):a[b]}function ya(a,b){var c=ua(a,b),d;(d=0<=c)&&Array.prototype.splice.call(a,c,1);return d}function za(a,b){a.sort(b||Aa)}function Ca(a,b){for(var c=Array(a.length),d=0;d<a.length;d++)c[d]={index:d,value:a[d]};var e=b||Aa;za(c,function(a,b){return e(a.value,b.value)||a.index-b.index});for(d=0;d<a.length;d++)a[d]=c[d].value} +function Aa(a,b){return a>b?1:a<b?-1:0};function Da(a){var b=[],c=0,d;for(d in a)b[c++]=a[d];return b}function Ea(a){var b=[],c=0,d;for(d in a)b[c++]=d;return b}var Fa="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" ");function Ia(a,b){for(var c,d,e=1;e<arguments.length;e++){d=arguments[e];for(c in d)a[c]=d[c];for(var f=0;f<Fa.length;f++)c=Fa[f],Object.prototype.hasOwnProperty.call(d,c)&&(a[c]=d[c])}};function Ka(a){if(a.Yc&&"function"==typeof a.Yc)return a.Yc();if(ca(a))return a.split("");if(fa(a)){for(var b=[],c=a.length,d=0;d<c;d++)b.push(a[d]);return b}return Da(a)} +function La(a,b){if(a.forEach&&"function"==typeof a.forEach)a.forEach(b,void 0);else if(fa(a)||ca(a))va(a,b,void 0);else{if(a.Xc&&"function"==typeof a.Xc)var c=a.Xc();else if(a.Yc&&"function"==typeof a.Yc)c=void 0;else if(fa(a)||ca(a)){c=[];for(var d=a.length,e=0;e<d;e++)c.push(e)}else c=Ea(a);d=Ka(a);e=d.length;for(var f=0;f<e;f++)b.call(void 0,d[f],c&&c[f],a)}};function Ma(a,b){this.ic={};this.ib=[];this.Fc=0;var c=arguments.length;if(1<c){if(c%2)throw Error("Uneven number of arguments");for(var d=0;d<c;d+=2)this.set(arguments[d],arguments[d+1])}else a&&this.addAll(a)}g=Ma.prototype;g.Yc=function(){Na(this);for(var a=[],b=0;b<this.ib.length;b++)a.push(this.ic[this.ib[b]]);return a};g.Xc=function(){Na(this);return this.ib.concat()};g.Td=function(){return 0==this.Fc};g.clear=function(){this.ic={};this.Fc=this.ib.length=0}; +g.remove=function(a){return Object.prototype.hasOwnProperty.call(this.ic,a)?(delete this.ic[a],this.Fc--,this.ib.length>2*this.Fc&&Na(this),!0):!1};function Na(a){if(a.Fc!=a.ib.length){for(var b=0,c=0;b<a.ib.length;){var d=a.ib[b];Object.prototype.hasOwnProperty.call(a.ic,d)&&(a.ib[c++]=d);b++}a.ib.length=c}if(a.Fc!=a.ib.length){var e={};for(c=b=0;b<a.ib.length;)d=a.ib[b],Object.prototype.hasOwnProperty.call(e,d)||(a.ib[c++]=d,e[d]=1),b++;a.ib.length=c}} +g.get=function(a,b){return Object.prototype.hasOwnProperty.call(this.ic,a)?this.ic[a]:b};g.set=function(a,b){Object.prototype.hasOwnProperty.call(this.ic,a)||(this.Fc++,this.ib.push(a));this.ic[a]=b};g.addAll=function(a){if(a instanceof Ma){var b=a.Xc();a=a.Yc()}else b=Ea(a),a=Da(a);for(var c=0;c<b.length;c++)this.set(b[c],a[c])};g.forEach=function(a,b){for(var c=this.Xc(),d=0;d<c.length;d++){var e=c[d],f=this.get(e);a.call(b,f,e,this)}};g.clone=function(){return new Ma(this)};var Pa=/^(?:([^:/?#.]+):)?(?:\/\/(?:([^/?#]*)@)?([^/#?]*?)(?::([0-9]+))?(?=[/#?]|$))?([^?#]+)?(?:\?([^#]*))?(?:#([\s\S]*))?$/;function Qa(a,b){this.Ma=[];this.Lc=b;for(var c=!0,d=a.length-1;0<=d;d--){var e=a[d]|0;c&&e==b||(this.Ma[d]=e,c=!1)}}var Ra={};function Sa(a){if(-128<=a&&128>a){var b=Ra[a];if(b)return b}b=new Qa([a|0],0>a?-1:0);-128<=a&&128>a&&(Ra[a]=b);return b}function Ta(a){if(isNaN(a)||!isFinite(a))return Ua;if(0>a)return Ta(-a).kb();for(var b=[],c=1,d=0;a>=c;d++)b[d]=a/c|0,c*=Va;return new Qa(b,0)}var Va=4294967296,Ua=Sa(0),Wa=Sa(1),Xa=Sa(16777216);g=Qa.prototype; +g.Of=function(){return 0<this.Ma.length?this.Ma[0]:this.Lc};g.vd=function(){if(this.Eb())return-this.kb().vd();for(var a=0,b=1,c=0;c<this.Ma.length;c++){var d=Ya(this,c);a+=(0<=d?d:Va+d)*b;b*=Va}return a}; +g.toString=function(a){a=a||10;if(2>a||36<a)throw Error("radix out of range: "+a);if(this.hc())return"0";if(this.Eb())return"-"+this.kb().toString(a);for(var b=Ta(Math.pow(a,6)),c=this,d="";;){var e=Za(c,b),f=(c.ze(e.multiply(b)).Of()>>>0).toString(a);c=e;if(c.hc())return f+d;for(;6>f.length;)f="0"+f;d=""+f+d}};function Ya(a,b){return 0>b?0:b<a.Ma.length?a.Ma[b]:a.Lc}g.hc=function(){if(0!=this.Lc)return!1;for(var a=0;a<this.Ma.length;a++)if(0!=this.Ma[a])return!1;return!0}; +g.Eb=function(){return-1==this.Lc};g.xf=function(a){return 0<this.compare(a)};g.yf=function(a){return 0<=this.compare(a)};g.Ue=function(){return 0>this.compare(Xa)};g.Ve=function(a){return 0>=this.compare(a)};g.compare=function(a){a=this.ze(a);return a.Eb()?-1:a.hc()?0:1};g.kb=function(){return this.Hf().add(Wa)}; +g.add=function(a){for(var b=Math.max(this.Ma.length,a.Ma.length),c=[],d=0,e=0;e<=b;e++){var f=d+(Ya(this,e)&65535)+(Ya(a,e)&65535),h=(f>>>16)+(Ya(this,e)>>>16)+(Ya(a,e)>>>16);d=h>>>16;f&=65535;h&=65535;c[e]=h<<16|f}return new Qa(c,c[c.length-1]&-2147483648?-1:0)};g.ze=function(a){return this.add(a.kb())}; +g.multiply=function(a){if(this.hc()||a.hc())return Ua;if(this.Eb())return a.Eb()?this.kb().multiply(a.kb()):this.kb().multiply(a).kb();if(a.Eb())return this.multiply(a.kb()).kb();if(this.Ue()&&a.Ue())return Ta(this.vd()*a.vd());for(var b=this.Ma.length+a.Ma.length,c=[],d=0;d<2*b;d++)c[d]=0;for(d=0;d<this.Ma.length;d++)for(var e=0;e<a.Ma.length;e++){var f=Ya(this,d)>>>16,h=Ya(this,d)&65535,k=Ya(a,e)>>>16,l=Ya(a,e)&65535;c[2*d+2*e]+=h*l;ab(c,2*d+2*e);c[2*d+2*e+1]+=f*l;ab(c,2*d+2*e+1);c[2*d+2*e+1]+= +h*k;ab(c,2*d+2*e+1);c[2*d+2*e+2]+=f*k;ab(c,2*d+2*e+2)}for(d=0;d<b;d++)c[d]=c[2*d+1]<<16|c[2*d];for(d=b;d<2*b;d++)c[d]=0;return new Qa(c,0)};function ab(a,b){for(;(a[b]&65535)!=a[b];)a[b+1]+=a[b]>>>16,a[b]&=65535,b++} +function Za(a,b){if(b.hc())throw Error("division by zero");if(a.hc())return Ua;if(a.Eb())return b.Eb()?Za(a.kb(),b.kb()):Za(a.kb(),b).kb();if(b.Eb())return Za(a,b.kb()).kb();if(30<a.Ma.length){if(a.Eb()||b.Eb())throw Error("slowDivide_ only works with positive integers.");for(var c=Wa,d=b;d.Ve(a);)c=c.shiftLeft(1),d=d.shiftLeft(1);var e=c.ad(1),f=d.ad(1);d=d.ad(2);for(c=c.ad(2);!d.hc();){var h=f.add(d);h.Ve(a)&&(e=e.add(c),f=h);d=d.ad(1);c=c.ad(1)}return e}c=Ua;for(d=a;d.yf(b);){e=Math.max(1,Math.floor(d.vd()/ +b.vd()));f=Math.ceil(Math.log(e)/Math.LN2);f=48>=f?1:Math.pow(2,f-48);h=Ta(e);for(var k=h.multiply(b);k.Eb()||k.xf(d);)e-=f,h=Ta(e),k=h.multiply(b);h.hc()&&(h=Wa);c=c.add(h);d=d.ze(k)}return c}g.Hf=function(){for(var a=this.Ma.length,b=[],c=0;c<a;c++)b[c]=~this.Ma[c];return new Qa(b,~this.Lc)};g.shiftLeft=function(a){var b=a>>5;a%=32;for(var c=this.Ma.length+b+(0<a?1:0),d=[],e=0;e<c;e++)d[e]=0<a?Ya(this,e-b)<<a|Ya(this,e-b-1)>>>32-a:Ya(this,e-b);return new Qa(d,this.Lc)}; +g.ad=function(a){var b=a>>5;a%=32;for(var c=this.Ma.length-b,d=[],e=0;e<c;e++)d[e]=0<a?Ya(this,e+b)>>>a|Ya(this,e+b+1)<<32-a:Ya(this,e+b);return new Qa(d,this.Lc)};function cb(a,b){null!=a&&this.append.apply(this,arguments)}g=cb.prototype;g.xc="";g.set=function(a){this.xc=""+a};g.append=function(a,b,c){this.xc+=String(a);if(null!=b)for(var d=1;d<arguments.length;d++)this.xc+=arguments[d];return this};g.clear=function(){this.xc=""};g.toString=function(){return this.xc};function eb(a){eb[" "](a);return a}eb[" "]=ea;function fb(a,b){var c=gb;return Object.prototype.hasOwnProperty.call(c,a)?c[a]:c[a]=b(a)};var hb;if("undefined"===typeof q)var q={};if("undefined"===typeof ib)var ib=null;if("undefined"===typeof kb)var kb=null;var lb=null;if("undefined"===typeof mb)var mb=null;function ob(){return new r(null,5,[pb,!0,qb,!0,rb,!1,sb,!1,tb,null],null)}function t(a){return null!=a&&!1!==a}function ub(a){return null==a}function vb(a){return a instanceof Array}function wb(a){return null==a?!0:!1===a?!0:!1}function yb(a){return ca(a)}function Ab(a,b){return a[n(null==b?null:b)]?!0:a._?!0:!1} +function Bb(a){return null==a?null:a.constructor}function Cb(a,b){var c=Bb(b);c=t(t(c)?c.qc:c)?c.Tb:n(b);return Error(["No protocol method ",a," defined for type ",c,": ",b].join(""))}function Db(a){var b=a.Tb;return t(b)?b:""+v.h(a)}var Fb="undefined"!==typeof Symbol&&"function"===n(Symbol)?Symbol.iterator:"@@iterator";function Gb(a){for(var b=a.length,c=Array(b),d=0;;)if(d<b)c[d]=a[d],d+=1;else break;return c} +var Hb=function Hb(a){switch(arguments.length){case 2:return Hb.c(arguments[0],arguments[1]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return Hb.A(arguments[0],arguments[1],new Jb(c.slice(2),0,null))}};Hb.c=function(a,b){return a[b]};Hb.A=function(a,b,c){return Kb(Hb,a[b],c)};Hb.N=function(a){var b=y(a),c=z(a);a=y(c);c=z(c);return Hb.A(b,a,c)};Hb.L=2;function Lb(a){return Mb(function(a,c){a.push(c);return a},[],a)}function Nb(){}function Ob(){} +function Pb(){}var Qb=function Qb(a){if(null!=a&&null!=a.W)return a.W(a);var c=Qb[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Qb._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("ICounted.-count",a);},Rb=function Rb(a){if(null!=a&&null!=a.oa)return a.oa(a);var c=Rb[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Rb._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("IEmptyableCollection.-empty",a);};function Sb(){} +var Tb=function Tb(a,b){if(null!=a&&null!=a.X)return a.X(a,b);var d=Tb[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=Tb._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("ICollection.-conj",a);};function Ub(){}var A=function A(a){switch(arguments.length){case 2:return A.c(arguments[0],arguments[1]);case 3:return A.l(arguments[0],arguments[1],arguments[2]);default:throw Error(["Invalid arity: ",v.h(arguments.length)].join(""));}}; +A.c=function(a,b){if(null!=a&&null!=a.$)return a.$(a,b);var c=A[n(null==a?null:a)];if(null!=c)return c.c?c.c(a,b):c.call(null,a,b);c=A._;if(null!=c)return c.c?c.c(a,b):c.call(null,a,b);throw Cb("IIndexed.-nth",a);};A.l=function(a,b,c){if(null!=a&&null!=a.ka)return a.ka(a,b,c);var d=A[n(null==a?null:a)];if(null!=d)return d.l?d.l(a,b,c):d.call(null,a,b,c);d=A._;if(null!=d)return d.l?d.l(a,b,c):d.call(null,a,b,c);throw Cb("IIndexed.-nth",a);};A.L=3;function Vb(){} +var Wb=function Wb(a){if(null!=a&&null!=a.Ia)return a.Ia(a);var c=Wb[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Wb._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("ISeq.-first",a);},Yb=function Yb(a){if(null!=a&&null!=a.bb)return a.bb(a);var c=Yb[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Yb._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("ISeq.-rest",a);};function Zb(){}function $b(){} +var cc=function cc(a){switch(arguments.length){case 2:return cc.c(arguments[0],arguments[1]);case 3:return cc.l(arguments[0],arguments[1],arguments[2]);default:throw Error(["Invalid arity: ",v.h(arguments.length)].join(""));}};cc.c=function(a,b){if(null!=a&&null!=a.V)return a.V(a,b);var c=cc[n(null==a?null:a)];if(null!=c)return c.c?c.c(a,b):c.call(null,a,b);c=cc._;if(null!=c)return c.c?c.c(a,b):c.call(null,a,b);throw Cb("ILookup.-lookup",a);}; +cc.l=function(a,b,c){if(null!=a&&null!=a.I)return a.I(a,b,c);var d=cc[n(null==a?null:a)];if(null!=d)return d.l?d.l(a,b,c):d.call(null,a,b,c);d=cc._;if(null!=d)return d.l?d.l(a,b,c):d.call(null,a,b,c);throw Cb("ILookup.-lookup",a);};cc.L=3; +var dc=function dc(a,b){if(null!=a&&null!=a.yc)return a.yc(a,b);var d=dc[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=dc._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("IAssociative.-contains-key?",a);},ec=function ec(a,b,c){if(null!=a&&null!=a.O)return a.O(a,b,c);var e=ec[n(null==a?null:a)];if(null!=e)return e.l?e.l(a,b,c):e.call(null,a,b,c);e=ec._;if(null!=e)return e.l?e.l(a,b,c):e.call(null,a,b,c);throw Cb("IAssociative.-assoc",a);};function fc(){} +var gc=function gc(a,b){if(null!=a&&null!=a.ga)return a.ga(a,b);var d=gc[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=gc._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("IMap.-dissoc",a);};function hc(){} +var jc=function jc(a){if(null!=a&&null!=a.fd)return a.fd(a);var c=jc[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=jc._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("IMapEntry.-key",a);},kc=function kc(a){if(null!=a&&null!=a.gd)return a.gd(a);var c=kc[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=kc._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("IMapEntry.-val",a);};function lc(){} +var mc=function mc(a,b){if(null!=a&&null!=a.ie)return a.ie(a,b);var d=mc[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=mc._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("ISet.-disjoin",a);},nc=function nc(a){if(null!=a&&null!=a.Ac)return a.Ac(a);var c=nc[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=nc._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("IStack.-peek",a);},oc=function oc(a){if(null!=a&&null!=a.Bc)return a.Bc(a);var c=oc[n(null== +a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=oc._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("IStack.-pop",a);};function pc(){} +var qc=function qc(a,b,c){if(null!=a&&null!=a.dc)return a.dc(a,b,c);var e=qc[n(null==a?null:a)];if(null!=e)return e.l?e.l(a,b,c):e.call(null,a,b,c);e=qc._;if(null!=e)return e.l?e.l(a,b,c):e.call(null,a,b,c);throw Cb("IVector.-assoc-n",a);},B=function B(a){if(null!=a&&null!=a.pc)return a.pc(a);var c=B[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=B._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("IDeref.-deref",a);};function rc(){} +var sc=function sc(a){if(null!=a&&null!=a.P)return a.P(a);var c=sc[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=sc._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("IMeta.-meta",a);},tc=function tc(a,b){if(null!=a&&null!=a.T)return a.T(a,b);var d=tc[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=tc._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("IWithMeta.-with-meta",a);};function uc(){} +var vc=function vc(a){switch(arguments.length){case 2:return vc.c(arguments[0],arguments[1]);case 3:return vc.l(arguments[0],arguments[1],arguments[2]);default:throw Error(["Invalid arity: ",v.h(arguments.length)].join(""));}};vc.c=function(a,b){if(null!=a&&null!=a.Fa)return a.Fa(a,b);var c=vc[n(null==a?null:a)];if(null!=c)return c.c?c.c(a,b):c.call(null,a,b);c=vc._;if(null!=c)return c.c?c.c(a,b):c.call(null,a,b);throw Cb("IReduce.-reduce",a);}; +vc.l=function(a,b,c){if(null!=a&&null!=a.Ga)return a.Ga(a,b,c);var d=vc[n(null==a?null:a)];if(null!=d)return d.l?d.l(a,b,c):d.call(null,a,b,c);d=vc._;if(null!=d)return d.l?d.l(a,b,c):d.call(null,a,b,c);throw Cb("IReduce.-reduce",a);};vc.L=3;function wc(){} +var yc=function yc(a,b,c){if(null!=a&&null!=a.Qc)return a.Qc(a,b,c);var e=yc[n(null==a?null:a)];if(null!=e)return e.l?e.l(a,b,c):e.call(null,a,b,c);e=yc._;if(null!=e)return e.l?e.l(a,b,c):e.call(null,a,b,c);throw Cb("IKVReduce.-kv-reduce",a);},zc=function zc(a,b){if(null!=a&&null!=a.K)return a.K(a,b);var d=zc[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=zc._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("IEquiv.-equiv",a);},Ac=function Ac(a){if(null!=a&&null!=a.U)return a.U(a); +var c=Ac[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Ac._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("IHash.-hash",a);};function Bc(){}var Cc=function Cc(a){if(null!=a&&null!=a.S)return a.S(a);var c=Cc[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Cc._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("ISeqable.-seq",a);};function Ec(){}function Fc(){}function Gc(){}function Hc(){} +var Ic=function Ic(a){if(null!=a&&null!=a.Rc)return a.Rc(a);var c=Ic[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Ic._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("IReversible.-rseq",a);},Jc=function Jc(a,b){if(null!=a&&null!=a.Re)return a.Re(0,b);var d=Jc[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=Jc._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("IWriter.-write",a);};function Kc(){} +var Lc=function Lc(a,b,c){if(null!=a&&null!=a.Kd)return a.Kd(a,b,c);var e=Lc[n(null==a?null:a)];if(null!=e)return e.l?e.l(a,b,c):e.call(null,a,b,c);e=Lc._;if(null!=e)return e.l?e.l(a,b,c):e.call(null,a,b,c);throw Cb("IWatchable.-notify-watches",a);},Mc=function Mc(a,b,c){if(null!=a&&null!=a.Jd)return a.Jd(a,b,c);var e=Mc[n(null==a?null:a)];if(null!=e)return e.l?e.l(a,b,c):e.call(null,a,b,c);e=Mc._;if(null!=e)return e.l?e.l(a,b,c):e.call(null,a,b,c);throw Cb("IWatchable.-add-watch",a);},Nc=function Nc(a, +b){if(null!=a&&null!=a.Ld)return a.Ld(a,b);var d=Nc[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=Nc._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("IWatchable.-remove-watch",a);},Oc=function Oc(a){if(null!=a&&null!=a.Pc)return a.Pc(a);var c=Oc[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Oc._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("IEditableCollection.-as-transient",a);},Pc=function Pc(a,b){if(null!=a&&null!=a.Dc)return a.Dc(a, +b);var d=Pc[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=Pc._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("ITransientCollection.-conj!",a);},Qc=function Qc(a){if(null!=a&&null!=a.kd)return a.kd(a);var c=Qc[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Qc._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("ITransientCollection.-persistent!",a);},Rc=function Rc(a,b,c){if(null!=a&&null!=a.Cc)return a.Cc(a,b,c);var e=Rc[n(null==a?null:a)];if(null!= +e)return e.l?e.l(a,b,c):e.call(null,a,b,c);e=Rc._;if(null!=e)return e.l?e.l(a,b,c):e.call(null,a,b,c);throw Cb("ITransientAssociative.-assoc!",a);};function Tc(){} +var Uc=function Uc(a,b){if(null!=a&&null!=a.cc)return a.cc(a,b);var d=Uc[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=Uc._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("IComparable.-compare",a);},Vc=function Vc(a){if(null!=a&&null!=a.Le)return a.Le();var c=Vc[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Vc._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("IChunk.-drop-first",a);},Wc=function Wc(a){if(null!=a&&null!=a.ge)return a.ge(a); +var c=Wc[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Wc._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("IChunkedSeq.-chunked-first",a);},Xc=function Xc(a){if(null!=a&&null!=a.Hd)return a.Hd(a);var c=Xc[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Xc._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("IChunkedSeq.-chunked-rest",a);},Yc=function Yc(a){if(null!=a&&null!=a.hd)return a.hd(a);var c=Yc[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null, +a);c=Yc._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("INamed.-name",a);},Zc=function Zc(a){if(null!=a&&null!=a.jd)return a.jd(a);var c=Zc[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Zc._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("INamed.-namespace",a);},$c=function $c(a,b){if(null!=a&&null!=a.Gb)return a.Gb(a,b);var d=$c[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=$c._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("IReset.-reset!", +a);},ad=function ad(a){switch(arguments.length){case 2:return ad.c(arguments[0],arguments[1]);case 3:return ad.l(arguments[0],arguments[1],arguments[2]);case 4:return ad.M(arguments[0],arguments[1],arguments[2],arguments[3]);case 5:return ad.Z(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4]);default:throw Error(["Invalid arity: ",v.h(arguments.length)].join(""));}}; +ad.c=function(a,b){if(null!=a&&null!=a.je)return a.je(a,b);var c=ad[n(null==a?null:a)];if(null!=c)return c.c?c.c(a,b):c.call(null,a,b);c=ad._;if(null!=c)return c.c?c.c(a,b):c.call(null,a,b);throw Cb("ISwap.-swap!",a);};ad.l=function(a,b,c){if(null!=a&&null!=a.ke)return a.ke(a,b,c);var d=ad[n(null==a?null:a)];if(null!=d)return d.l?d.l(a,b,c):d.call(null,a,b,c);d=ad._;if(null!=d)return d.l?d.l(a,b,c):d.call(null,a,b,c);throw Cb("ISwap.-swap!",a);}; +ad.M=function(a,b,c,d){if(null!=a&&null!=a.le)return a.le(a,b,c,d);var e=ad[n(null==a?null:a)];if(null!=e)return e.M?e.M(a,b,c,d):e.call(null,a,b,c,d);e=ad._;if(null!=e)return e.M?e.M(a,b,c,d):e.call(null,a,b,c,d);throw Cb("ISwap.-swap!",a);};ad.Z=function(a,b,c,d,e){if(null!=a&&null!=a.me)return a.me(a,b,c,d,e);var f=ad[n(null==a?null:a)];if(null!=f)return f.Z?f.Z(a,b,c,d,e):f.call(null,a,b,c,d,e);f=ad._;if(null!=f)return f.Z?f.Z(a,b,c,d,e):f.call(null,a,b,c,d,e);throw Cb("ISwap.-swap!",a);}; +ad.L=5;var bd=function bd(a,b){if(null!=a&&null!=a.Qe)return a.Qe(0,b);var d=bd[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=bd._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("IVolatile.-vreset!",a);};function cd(){}var dd=function dd(a){if(null!=a&&null!=a.ba)return a.ba(a);var c=dd[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=dd._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("IIterable.-iterator",a);}; +function ed(a){this.Nf=a;this.m=1073741824;this.J=0}ed.prototype.Re=function(a,b){return this.Nf.append(b)};function fd(a){var b=new cb;a.R(null,new ed(b),ob());return""+v.h(b)}var gd="undefined"!==typeof Math.imul&&0!==Math.imul(4294967295,5)?function(a,b){return Math.imul(a,b)}:function(a,b){var c=a&65535,d=b&65535;return c*d+((a>>>16&65535)*d+c*(b>>>16&65535)<<16>>>0)|0};function hd(a){a=gd(a|0,-862048943);return gd(a<<15|a>>>-15,461845907)} +function id(a,b){var c=(a|0)^(b|0);return gd(c<<13|c>>>-13,5)+-430675100|0}function jd(a,b){var c=(a|0)^b;c=gd(c^c>>>16,-2048144789);c=gd(c^c>>>13,-1028477387);return c^c>>>16}function kd(a){a:{var b=1;for(var c=0;;)if(b<a.length){var d=b+2;c=id(c,hd(a.charCodeAt(b-1)|a.charCodeAt(b)<<16));b=d}else{b=c;break a}}b=1===(a.length&1)?b^hd(a.charCodeAt(a.length-1)):b;return jd(b,gd(2,a.length))}var ld={},md=0; +function nd(a){255<md&&(ld={},md=0);if(null==a)return 0;var b=ld[a];if("number"!==typeof b){a:if(null!=a)if(b=a.length,0<b)for(var c=0,d=0;;)if(c<b){var e=c+1;d=gd(31,d)+a.charCodeAt(c);c=e}else{b=d;break a}else b=0;else b=0;ld[a]=b;md+=1}return a=b} +function od(a){if(null!=a&&(a.m&4194304||q===a.Sf))return a.U(null)^0;if("number"===typeof a){if(t(isFinite(a)))return Math.floor(a)%2147483647;switch(a){case Infinity:return 2146435072;case -Infinity:return-1048576;default:return 2146959360}}else return!0===a?a=1231:!1===a?a=1237:"string"===typeof a?(a=nd(a),0!==a&&(a=hd(a),a=id(0,a),a=jd(a,4))):a=a instanceof Date?a.valueOf()^0:null==a?0:Ac(a)^0,a}function pd(a,b){return a^b+2654435769+(a<<6)+(a>>2)}function qd(a){return a instanceof rd} +function sd(a,b){if(a.Zb===b.Zb)return 0;var c=wb(a.fb);if(t(c?b.fb:c))return-1;if(t(a.fb)){if(wb(b.fb))return 1;c=Aa(a.fb,b.fb);return 0===c?Aa(a.name,b.name):c}return Aa(a.name,b.name)}function rd(a,b,c,d,e){this.fb=a;this.name=b;this.Zb=c;this.Oc=d;this.hb=e;this.m=2154168321;this.J=4096}g=rd.prototype;g.toString=function(){return this.Zb};g.equiv=function(a){return this.K(null,a)};g.K=function(a,b){return b instanceof rd?this.Zb===b.Zb:!1}; +g.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return D.c(c,this);case 3:return D.l(c,this,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.c=function(a,c){return D.c(c,this)};a.l=function(a,c,d){return D.l(c,this,d)};return a}();g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))};g.h=function(a){return D.c(a,this)};g.c=function(a,b){return D.l(a,this,b)};g.P=function(){return this.hb}; +g.T=function(a,b){return new rd(this.fb,this.name,this.Zb,this.Oc,b)};g.U=function(){var a=this.Oc;return null!=a?a:this.Oc=a=pd(kd(this.name),nd(this.fb))};g.hd=function(){return this.name};g.jd=function(){return this.fb};g.R=function(a,b){return Jc(b,this.Zb)};var td=function td(a){switch(arguments.length){case 1:return td.h(arguments[0]);case 2:return td.c(arguments[0],arguments[1]);default:throw Error(["Invalid arity: ",v.h(arguments.length)].join(""));}}; +td.h=function(a){if(a instanceof rd)return a;var b=a.indexOf("/");return 1>b?td.c(null,a):td.c(a.substring(0,b),a.substring(b+1,a.length))};td.c=function(a,b){var c=null!=a?[v.h(a),"/",v.h(b)].join(""):b;return new rd(a,b,c,null,null)};td.L=2;function ud(a){return null!=a?a.J&131072||q===a.Tf?!0:a.J?!1:Ab(cd,a):Ab(cd,a)} +function E(a){if(null==a)return null;if(null!=a&&(a.m&8388608||q===a.Pe))return a.S(null);if(vb(a)||"string"===typeof a)return 0===a.length?null:new Jb(a,0,null);if(Ab(Bc,a))return Cc(a);throw Error([v.h(a)," is not ISeqable"].join(""));}function y(a){if(null==a)return null;if(null!=a&&(a.m&64||q===a.G))return a.Ia(null);a=E(a);return null==a?null:Wb(a)}function vd(a){return null!=a?null!=a&&(a.m&64||q===a.G)?a.bb(null):(a=E(a))?Yb(a):wd:wd} +function z(a){return null==a?null:null!=a&&(a.m&128||q===a.Id)?a.Ka(null):E(vd(a))}var G=function G(a){switch(arguments.length){case 1:return G.h(arguments[0]);case 2:return G.c(arguments[0],arguments[1]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return G.A(arguments[0],arguments[1],new Jb(c.slice(2),0,null))}};G.h=function(){return!0};G.c=function(a,b){return null==a?null==b:a===b||zc(a,b)}; +G.A=function(a,b,c){for(;;)if(G.c(a,b))if(z(c))a=b,b=y(c),c=z(c);else return G.c(b,y(c));else return!1};G.N=function(a){var b=y(a),c=z(a);a=y(c);c=z(c);return G.A(b,a,c)};G.L=2;function xd(a){this.s=a}xd.prototype.next=function(){if(null!=this.s){var a=y(this.s);this.s=z(this.s);return{value:a,done:!1}}return{value:null,done:!0}};function yd(a){return new xd(E(a))}function zd(a,b){var c=hd(a);c=id(0,c);return jd(c,b)} +function Ad(a){var b=0,c=1;for(a=E(a);;)if(null!=a)b+=1,c=gd(31,c)+od(y(a))|0,a=z(a);else return zd(c,b)}var Cd=zd(1,0);function Dd(a){var b=0,c=0;for(a=E(a);;)if(null!=a)b+=1,c=c+od(y(a))|0,a=z(a);else return zd(c,b)}var Ed=zd(0,0);Pb["null"]=!0;Qb["null"]=function(){return 0};Date.prototype.K=function(a,b){return b instanceof Date&&this.valueOf()===b.valueOf()};Date.prototype.zc=q; +Date.prototype.cc=function(a,b){if(b instanceof Date)return Aa(this.valueOf(),b.valueOf());throw Error(["Cannot compare ",v.h(this)," to ",v.h(b)].join(""));};zc.number=function(a,b){return a===b};Nb["function"]=!0;rc["function"]=!0;sc["function"]=function(){return null};Ac._=function(a){return ja(a)};function Fd(a){return a+1}function Gd(a){this.H=a;this.m=32768;this.J=0}Gd.prototype.pc=function(){return this.H};function Hd(a){return a instanceof Gd}function Id(a){return Hd(a)?a:new Gd(a)} +function Jd(a){return Hd(a)?B(a):a}function Kd(a,b){var c=Qb(a);if(0===c)return b.B?b.B():b.call(null);for(var d=A.c(a,0),e=1;;)if(e<c){var f=A.c(a,e);d=b.c?b.c(d,f):b.call(null,d,f);if(Hd(d))return B(d);e+=1}else return d}function Ld(a,b,c){var d=Qb(a),e=c;for(c=0;;)if(c<d){var f=A.c(a,c);e=b.c?b.c(e,f):b.call(null,e,f);if(Hd(e))return B(e);c+=1}else return e} +function Md(a,b){var c=a.length;if(0===a.length)return b.B?b.B():b.call(null);for(var d=a[0],e=1;;)if(e<c){var f=a[e];d=b.c?b.c(d,f):b.call(null,d,f);if(Hd(d))return B(d);e+=1}else return d}function Nd(a,b,c){var d=a.length,e=c;for(c=0;;)if(c<d){var f=a[c];e=b.c?b.c(e,f):b.call(null,e,f);if(Hd(e))return B(e);c+=1}else return e}function Od(a,b,c,d){for(var e=a.length;;)if(d<e){var f=a[d];c=b.c?b.c(c,f):b.call(null,c,f);if(Hd(c))return B(c);d+=1}else return c} +function Pd(a){return null!=a?a.m&2||q===a.jf?!0:a.m?!1:Ab(Pb,a):Ab(Pb,a)}function Qd(a){return null!=a?a.m&16||q===a.Ne?!0:a.m?!1:Ab(Ub,a):Ab(Ub,a)}function Ud(a,b,c){var d=H(a);if(c>=d)return-1;!(0<c)&&0>c&&(c+=d,c=0>c?0:c);for(;;)if(c<d){if(G.c(Vd(a,c),b))return c;c+=1}else return-1}function Xd(a,b,c){var d=H(a);if(0===d)return-1;0<c?(--d,c=d<c?d:c):c=0>c?d+c:c;for(;;)if(0<=c){if(G.c(Vd(a,c),b))return c;--c}else return-1}function Yd(a,b){this.o=a;this.i=b} +Yd.prototype.ja=function(){return this.i<this.o.length};Yd.prototype.next=function(){var a=this.o[this.i];this.i+=1;return a};function Jb(a,b,c){this.o=a;this.i=b;this.meta=c;this.m=166592766;this.J=139264}g=Jb.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)}; +g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.$=function(a,b){var c=b+this.i;if(0<=c&&c<this.o.length)return this.o[c];throw Error("Index out of bounds");};g.ka=function(a,b,c){a=b+this.i;return 0<=a&&a<this.o.length?this.o[a]:c}; +g.ba=function(){return new Yd(this.o,this.i)};g.P=function(){return this.meta};g.Ka=function(){return this.i+1<this.o.length?new Jb(this.o,this.i+1,null):null};g.W=function(){var a=this.o.length-this.i;return 0>a?0:a};g.Rc=function(){var a=this.W(null);return 0<a?new Zd(this,a-1,null):null};g.U=function(){return Ad(this)};g.K=function(a,b){return $d(this,b)};g.oa=function(){return wd};g.Fa=function(a,b){return Od(this.o,b,this.o[this.i],this.i+1)};g.Ga=function(a,b,c){return Od(this.o,b,c,this.i)}; +g.Ia=function(){return this.o[this.i]};g.bb=function(){return this.i+1<this.o.length?new Jb(this.o,this.i+1,null):wd};g.S=function(){return this.i<this.o.length?this:null};g.T=function(a,b){return new Jb(this.o,this.i,b)};g.X=function(a,b){return ae(b,this)};Jb.prototype[Fb]=function(){return yd(this)};function be(a){return 0<a.length?new Jb(a,0,null):null}function Zd(a,b,c){this.Gd=a;this.i=b;this.meta=c;this.m=32374990;this.J=8192}g=Zd.prototype;g.toString=function(){return fd(this)}; +g.equiv=function(a){return this.K(null,a)};g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.P=function(){return this.meta};g.Ka=function(){return 0<this.i?new Zd(this.Gd,this.i-1,null):null};g.W=function(){return this.i+1};g.U=function(){return Ad(this)};g.K=function(a,b){return $d(this,b)}; +g.oa=function(){return tc(wd,this.meta)};g.Fa=function(a,b){return ce(b,this)};g.Ga=function(a,b,c){return de(b,c,this)};g.Ia=function(){return A.c(this.Gd,this.i)};g.bb=function(){return 0<this.i?new Zd(this.Gd,this.i-1,null):wd};g.S=function(){return this};g.T=function(a,b){return new Zd(this.Gd,this.i,b)};g.X=function(a,b){return ae(b,this)};Zd.prototype[Fb]=function(){return yd(this)};function ee(a){return y(z(a))}function fe(a){for(;;){var b=z(a);if(null!=b)a=b;else return y(a)}} +zc._=function(a,b){return a===b};var ge=function ge(a){switch(arguments.length){case 0:return ge.B();case 1:return ge.h(arguments[0]);case 2:return ge.c(arguments[0],arguments[1]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return ge.A(arguments[0],arguments[1],new Jb(c.slice(2),0,null))}};ge.B=function(){return he};ge.h=function(a){return a};ge.c=function(a,b){return null!=a?Tb(a,b):Tb(wd,b)}; +ge.A=function(a,b,c){for(;;)if(t(c))a=ge.c(a,b),b=y(c),c=z(c);else return ge.c(a,b)};ge.N=function(a){var b=y(a),c=z(a);a=y(c);c=z(c);return ge.A(b,a,c)};ge.L=2;function ie(a){return null==a?null:Rb(a)}function H(a){if(null!=a)if(null!=a&&(a.m&2||q===a.jf))a=a.W(null);else if(vb(a))a=a.length;else if("string"===typeof a)a=a.length;else if(null!=a&&(a.m&8388608||q===a.Pe))a:{a=E(a);for(var b=0;;){if(Pd(a)){a=b+Qb(a);break a}a=z(a);b+=1}}else a=Qb(a);else a=0;return a} +function je(a,b,c){for(;;){if(null==a)return c;if(0===b)return E(a)?y(a):c;if(Qd(a))return A.l(a,b,c);if(E(a))a=z(a),--b;else return c}} +function Vd(a,b){if("number"!==typeof b)throw Error("Index argument to nth must be a number");if(null==a)return a;if(null!=a&&(a.m&16||q===a.Ne))return a.$(null,b);if(vb(a)){if(0<=b&&b<a.length)return a[b];throw Error("Index out of bounds");}if("string"===typeof a){if(0<=b&&b<a.length)return a.charAt(b);throw Error("Index out of bounds");}if(null!=a&&(a.m&64||q===a.G)){a:{var c=a;for(var d=b;;){if(null==c)throw Error("Index out of bounds");if(0===d){if(E(c)){c=y(c);break a}throw Error("Index out of bounds"); +}if(Qd(c)){c=A.c(c,d);break a}if(E(c))c=z(c),--d;else throw Error("Index out of bounds");}}return c}if(Ab(Ub,a))return A.c(a,b);throw Error(["nth not supported on this type ",v.h(Db(Bb(a)))].join(""));} +function J(a,b,c){if("number"!==typeof b)throw Error("Index argument to nth must be a number.");if(null==a)return c;if(null!=a&&(a.m&16||q===a.Ne))return a.ka(null,b,c);if(vb(a))return 0<=b&&b<a.length?a[b]:c;if("string"===typeof a)return 0<=b&&b<a.length?a.charAt(b):c;if(null!=a&&(a.m&64||q===a.G))return je(a,b,c);if(Ab(Ub,a))return A.l(a,b,c);throw Error(["nth not supported on this type ",v.h(Db(Bb(a)))].join(""));} +var D=function D(a){switch(arguments.length){case 2:return D.c(arguments[0],arguments[1]);case 3:return D.l(arguments[0],arguments[1],arguments[2]);default:throw Error(["Invalid arity: ",v.h(arguments.length)].join(""));}};D.c=function(a,b){return null==a?null:null!=a&&(a.m&256||q===a.rf)?a.V(null,b):vb(a)?null!=b&&b<a.length?a[b|0]:null:"string"===typeof a?null!=b&&b<a.length?a.charAt(b|0):null:Ab($b,a)?cc.c(a,b):null}; +D.l=function(a,b,c){return null!=a?null!=a&&(a.m&256||q===a.rf)?a.I(null,b,c):vb(a)?null!=b&&0<=b&&b<a.length?a[b|0]:c:"string"===typeof a?null!=b&&0<=b&&b<a.length?a.charAt(b|0):c:Ab($b,a)?cc.l(a,b,c):c:c};D.L=3;var K=function K(a){switch(arguments.length){case 3:return K.l(arguments[0],arguments[1],arguments[2]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return K.A(arguments[0],arguments[1],arguments[2],new Jb(c.slice(3),0,null))}}; +K.l=function(a,b,c){return null!=a?ec(a,b,c):ke([b,c])};K.A=function(a,b,c,d){for(;;)if(a=K.l(a,b,c),t(d))b=y(d),c=ee(d),d=z(z(d));else return a};K.N=function(a){var b=y(a),c=z(a);a=y(c);var d=z(c);c=y(d);d=z(d);return K.A(b,a,c,d)};K.L=3; +var le=function le(a){switch(arguments.length){case 1:return le.h(arguments[0]);case 2:return le.c(arguments[0],arguments[1]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return le.A(arguments[0],arguments[1],new Jb(c.slice(2),0,null))}};le.h=function(a){return a};le.c=function(a,b){return null==a?null:gc(a,b)};le.A=function(a,b,c){for(;;){if(null==a)return null;a=le.c(a,b);if(t(c))b=y(c),c=z(c);else return a}}; +le.N=function(a){var b=y(a),c=z(a);a=y(c);c=z(c);return le.A(b,a,c)};le.L=2;function me(a){var b=ha(a);return b?b:null!=a?q===a.hf?!0:a.Tc?!1:Ab(Nb,a):Ab(Nb,a)}function ne(a,b){this.C=a;this.meta=b;this.m=393217;this.J=0}g=ne.prototype;g.P=function(){return this.meta};g.T=function(a,b){return new ne(this.C,b)};g.hf=q; +g.call=function(){function a(a,b,c,d,e,f,h,k,m,l,p,u,w,x,C,F,I,M,S,X,Q,Ga){return oe(this.C,b,c,d,e,be([f,h,k,m,l,p,u,w,x,C,F,I,M,S,X,Q,Ga]))}function b(a,b,c,d,e,f,h,k,m,l,p,u,w,x,C,F,I,M,S,X,Q){a=this;return a.C.Xa?a.C.Xa(b,c,d,e,f,h,k,m,l,p,u,w,x,C,F,I,M,S,X,Q):a.C.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,C,F,I,M,S,X,Q)}function c(a,b,c,d,e,f,h,k,m,l,p,u,w,x,C,F,I,M,S,X){a=this;return a.C.Wa?a.C.Wa(b,c,d,e,f,h,k,m,l,p,u,w,x,C,F,I,M,S,X):a.C.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,C,F,I,M,S,X)}function d(a, +b,c,d,e,f,h,k,m,l,p,u,w,x,C,F,I,M,S){a=this;return a.C.Va?a.C.Va(b,c,d,e,f,h,k,m,l,p,u,w,x,C,F,I,M,S):a.C.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,C,F,I,M,S)}function e(a,b,c,d,e,f,h,k,m,l,p,u,w,x,C,F,I,M){a=this;return a.C.Ua?a.C.Ua(b,c,d,e,f,h,k,m,l,p,u,w,x,C,F,I,M):a.C.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,C,F,I,M)}function f(a,b,c,d,e,f,h,k,m,l,p,u,w,x,C,F,I){a=this;return a.C.Ta?a.C.Ta(b,c,d,e,f,h,k,m,l,p,u,w,x,C,F,I):a.C.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,C,F,I)}function h(a,b,c,d,e,f,h,k,m,l,p,u, +w,x,C,F){a=this;return a.C.Sa?a.C.Sa(b,c,d,e,f,h,k,m,l,p,u,w,x,C,F):a.C.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,C,F)}function k(a,b,c,d,e,f,h,k,m,l,p,u,w,x,C){a=this;return a.C.Ra?a.C.Ra(b,c,d,e,f,h,k,m,l,p,u,w,x,C):a.C.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,C)}function l(a,b,c,d,e,f,h,k,m,l,p,u,w,x){a=this;return a.C.Qa?a.C.Qa(b,c,d,e,f,h,k,m,l,p,u,w,x):a.C.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x)}function p(a,b,c,d,e,f,h,k,m,l,p,u,w){a=this;return a.C.Pa?a.C.Pa(b,c,d,e,f,h,k,m,l,p,u,w):a.C.call(null,b,c,d, +e,f,h,k,m,l,p,u,w)}function m(a,b,c,d,e,f,h,k,m,l,p,u){a=this;return a.C.Oa?a.C.Oa(b,c,d,e,f,h,k,m,l,p,u):a.C.call(null,b,c,d,e,f,h,k,m,l,p,u)}function u(a,b,c,d,e,f,h,k,m,l,p){a=this;return a.C.Na?a.C.Na(b,c,d,e,f,h,k,m,l,p):a.C.call(null,b,c,d,e,f,h,k,m,l,p)}function w(a,b,c,d,e,f,h,k,m,l){a=this;return a.C.Za?a.C.Za(b,c,d,e,f,h,k,m,l):a.C.call(null,b,c,d,e,f,h,k,m,l)}function x(a,b,c,d,e,f,h,k,m){a=this;return a.C.Ha?a.C.Ha(b,c,d,e,f,h,k,m):a.C.call(null,b,c,d,e,f,h,k,m)}function C(a,b,c,d,e,f, +h,k){a=this;return a.C.Ya?a.C.Ya(b,c,d,e,f,h,k):a.C.call(null,b,c,d,e,f,h,k)}function F(a,b,c,d,e,f,h){a=this;return a.C.Ca?a.C.Ca(b,c,d,e,f,h):a.C.call(null,b,c,d,e,f,h)}function I(a,b,c,d,e,f){a=this;return a.C.Z?a.C.Z(b,c,d,e,f):a.C.call(null,b,c,d,e,f)}function M(a,b,c,d,e){a=this;return a.C.M?a.C.M(b,c,d,e):a.C.call(null,b,c,d,e)}function S(a,b,c,d){a=this;return a.C.l?a.C.l(b,c,d):a.C.call(null,b,c,d)}function X(a,b,c){a=this;return a.C.c?a.C.c(b,c):a.C.call(null,b,c)}function Ga(a,b){a=this; +return a.C.h?a.C.h(b):a.C.call(null,b)}function db(a){a=this;return a.C.B?a.C.B():a.C.call(null)}var Q=null;Q=function(xb,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Q,Xb,ic,xc,Sc,Bd,se,Lf,Ih,kl){switch(arguments.length){case 1:return db.call(this,xb);case 2:return Ga.call(this,xb,Ha);case 3:return X.call(this,xb,Ha,Ja);case 4:return S.call(this,xb,Ha,Ja,Oa);case 5:return M.call(this,xb,Ha,Ja,Oa,Ba);case 6:return I.call(this,xb,Ha,Ja,Oa,Ba,W);case 7:return F.call(this,xb,Ha,Ja,Oa,Ba,W,$a);case 8:return C.call(this, +xb,Ha,Ja,Oa,Ba,W,$a,ka);case 9:return x.call(this,xb,Ha,Ja,Oa,Ba,W,$a,ka,jb);case 10:return w.call(this,xb,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb);case 11:return u.call(this,xb,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb);case 12:return m.call(this,xb,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib);case 13:return p.call(this,xb,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Q);case 14:return l.call(this,xb,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Q,Xb);case 15:return k.call(this,xb,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Q,Xb,ic);case 16:return h.call(this,xb,Ha,Ja,Oa,Ba, +W,$a,ka,jb,nb,zb,Ib,Q,Xb,ic,xc);case 17:return f.call(this,xb,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Q,Xb,ic,xc,Sc);case 18:return e.call(this,xb,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Q,Xb,ic,xc,Sc,Bd);case 19:return d.call(this,xb,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Q,Xb,ic,xc,Sc,Bd,se);case 20:return c.call(this,xb,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Q,Xb,ic,xc,Sc,Bd,se,Lf);case 21:return b.call(this,xb,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Q,Xb,ic,xc,Sc,Bd,se,Lf,Ih);case 22:return a.call(this,0,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb, +zb,Ib,Q,Xb,ic,xc,Sc,Bd,se,Lf,Ih,kl)}throw Error("Invalid arity: "+(arguments.length-1));};Q.h=db;Q.c=Ga;Q.l=X;Q.M=S;Q.Z=M;Q.Ca=I;Q.Ya=F;Q.Ha=C;Q.Za=x;Q.Na=w;Q.Oa=u;Q.Pa=m;Q.Qa=p;Q.Ra=l;Q.Sa=k;Q.Ta=h;Q.Ua=f;Q.Va=e;Q.Wa=d;Q.Xa=c;Q.he=b;Q.qf=a;return Q}();g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))};g.B=function(){return this.C.B?this.C.B():this.C.call(null)};g.h=function(a){return this.C.h?this.C.h(a):this.C.call(null,a)}; +g.c=function(a,b){return this.C.c?this.C.c(a,b):this.C.call(null,a,b)};g.l=function(a,b,c){return this.C.l?this.C.l(a,b,c):this.C.call(null,a,b,c)};g.M=function(a,b,c,d){return this.C.M?this.C.M(a,b,c,d):this.C.call(null,a,b,c,d)};g.Z=function(a,b,c,d,e){return this.C.Z?this.C.Z(a,b,c,d,e):this.C.call(null,a,b,c,d,e)};g.Ca=function(a,b,c,d,e,f){return this.C.Ca?this.C.Ca(a,b,c,d,e,f):this.C.call(null,a,b,c,d,e,f)}; +g.Ya=function(a,b,c,d,e,f,h){return this.C.Ya?this.C.Ya(a,b,c,d,e,f,h):this.C.call(null,a,b,c,d,e,f,h)};g.Ha=function(a,b,c,d,e,f,h,k){return this.C.Ha?this.C.Ha(a,b,c,d,e,f,h,k):this.C.call(null,a,b,c,d,e,f,h,k)};g.Za=function(a,b,c,d,e,f,h,k,l){return this.C.Za?this.C.Za(a,b,c,d,e,f,h,k,l):this.C.call(null,a,b,c,d,e,f,h,k,l)};g.Na=function(a,b,c,d,e,f,h,k,l,p){return this.C.Na?this.C.Na(a,b,c,d,e,f,h,k,l,p):this.C.call(null,a,b,c,d,e,f,h,k,l,p)}; +g.Oa=function(a,b,c,d,e,f,h,k,l,p,m){return this.C.Oa?this.C.Oa(a,b,c,d,e,f,h,k,l,p,m):this.C.call(null,a,b,c,d,e,f,h,k,l,p,m)};g.Pa=function(a,b,c,d,e,f,h,k,l,p,m,u){return this.C.Pa?this.C.Pa(a,b,c,d,e,f,h,k,l,p,m,u):this.C.call(null,a,b,c,d,e,f,h,k,l,p,m,u)};g.Qa=function(a,b,c,d,e,f,h,k,l,p,m,u,w){return this.C.Qa?this.C.Qa(a,b,c,d,e,f,h,k,l,p,m,u,w):this.C.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w)}; +g.Ra=function(a,b,c,d,e,f,h,k,l,p,m,u,w,x){return this.C.Ra?this.C.Ra(a,b,c,d,e,f,h,k,l,p,m,u,w,x):this.C.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x)};g.Sa=function(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C){return this.C.Sa?this.C.Sa(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C):this.C.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x,C)};g.Ta=function(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F){return this.C.Ta?this.C.Ta(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F):this.C.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F)}; +g.Ua=function(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I){return this.C.Ua?this.C.Ua(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I):this.C.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I)};g.Va=function(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M){return this.C.Va?this.C.Va(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M):this.C.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M)}; +g.Wa=function(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S){return this.C.Wa?this.C.Wa(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S):this.C.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S)};g.Xa=function(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X){return this.C.Xa?this.C.Xa(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X):this.C.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X)};g.he=function(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X,Ga){return oe(this.C,a,b,c,d,be([e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X,Ga]))}; +function pe(a,b){return ha(a)?new ne(a,b):null==a?null:tc(a,b)}function qe(a){var b=null!=a;return(b?null!=a?a.m&131072||q===a.tf||(a.m?0:Ab(rc,a)):Ab(rc,a):b)?sc(a):null}var re=function re(a){switch(arguments.length){case 1:return re.h(arguments[0]);case 2:return re.c(arguments[0],arguments[1]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return re.A(arguments[0],arguments[1],new Jb(c.slice(2),0,null))}};re.h=function(a){return a}; +re.c=function(a,b){return null==a?null:mc(a,b)};re.A=function(a,b,c){for(;;){if(null==a)return null;a=re.c(a,b);if(t(c))b=y(c),c=z(c);else return a}};re.N=function(a){var b=y(a),c=z(a);a=y(c);c=z(c);return re.A(b,a,c)};re.L=2;function te(a){return null==a||wb(E(a))}function ue(a){return null==a?!1:null!=a?a.m&8||q===a.Qf?!0:a.m?!1:Ab(Sb,a):Ab(Sb,a)}function ve(a){return null==a?!1:null!=a?a.m&4096||q===a.$f?!0:a.m?!1:Ab(lc,a):Ab(lc,a)} +function we(a){return null!=a?a.m&16777216||q===a.Zf?!0:a.m?!1:Ab(Ec,a):Ab(Ec,a)}function xe(a){return null==a?!1:null!=a?a.m&1024||q===a.Wf?!0:a.m?!1:Ab(fc,a):Ab(fc,a)}function ye(a){return null!=a?a.m&67108864||q===a.Xf?!0:a.m?!1:Ab(Gc,a):Ab(Gc,a)}function ze(a){return null!=a?a.m&16384||q===a.ag?!0:a.m?!1:Ab(pc,a):Ab(pc,a)}function Ae(a){return null!=a?a.J&512||q===a.Pf?!0:!1:!1}function Be(a,b,c,d,e){for(;0!==e;)c[d]=a[b],d+=1,--e,b+=1}var Ce={}; +function De(a){return null==a?!1:null!=a?a.m&64||q===a.G?!0:a.m?!1:Ab(Vb,a):Ab(Vb,a)}function Ee(a){return null==a?!1:!1===a?!1:!0}function Fe(a){var b=me(a);return b?b:null!=a?a.m&1||q===a.Rf?!0:a.m?!1:Ab(Ob,a):Ab(Ob,a)}function Ge(a){return"number"===typeof a&&!isNaN(a)&&Infinity!==a&&parseFloat(a)===parseInt(a,10)}function He(a,b){return D.l(a,b,Ce)===Ce?!1:!0} +var Ie=function Ie(a){switch(arguments.length){case 1:return Ie.h(arguments[0]);case 2:return Ie.c(arguments[0],arguments[1]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return Ie.A(arguments[0],arguments[1],new Jb(c.slice(2),0,null))}};Ie.h=function(){return!0};Ie.c=function(a,b){return!G.c(a,b)};Ie.A=function(a,b,c){if(G.c(a,b))return!1;a=Je([a,b]);for(b=c;;){var d=y(b);c=z(b);if(t(b)){if(He(a,d))return!1;a=ge.c(a,d);b=c}else return!0}}; +Ie.N=function(a){var b=y(a),c=z(a);a=y(c);c=z(c);return Ie.A(b,a,c)};Ie.L=2;function Ke(a,b){if(a===b)return 0;if(null==a)return-1;if(null==b)return 1;if("number"===typeof a){if("number"===typeof b)return Aa(a,b);throw Error(["Cannot compare ",v.h(a)," to ",v.h(b)].join(""));}if(null!=a?a.J&2048||q===a.zc||(a.J?0:Ab(Tc,a)):Ab(Tc,a))return Uc(a,b);if("string"!==typeof a&&!vb(a)&&!0!==a&&!1!==a||Bb(a)!==Bb(b))throw Error(["Cannot compare ",v.h(a)," to ",v.h(b)].join(""));return Aa(a,b)} +function Le(a,b){var c=H(a),d=H(b);if(c<d)c=-1;else if(c>d)c=1;else if(0===c)c=0;else a:for(d=0;;){var e=Ke(Vd(a,d),Vd(b,d));if(0===e&&d+1<c)d+=1;else{c=e;break a}}return c}function Me(a){return G.c(a,Ke)?Ke:function(b,c){var d=a.c?a.c(b,c):a.call(null,b,c);return"number"===typeof d?d:t(d)?-1:t(a.c?a.c(c,b):a.call(null,c,b))?1:0}}function Ne(a,b){if(E(b)){a:{var c=[];for(var d=E(b);;)if(null!=d)c.push(y(d)),d=z(d);else break a}d=Me(a);Ca(c,d);return E(c)}return wd} +function Oe(a){var b=Pe("@!\"#%\x26'*+-/:[{\x3c\\|\x3d]}\x3e^~?".split(""),"_CIRCA_ _BANG_ _DOUBLEQUOTE_ _SHARP_ _PERCENT_ _AMPERSAND_ _SINGLEQUOTE_ _STAR_ _PLUS_ _ _SLASH_ _COLON_ _LBRACK_ _LBRACE_ _LT_ _BSLASH_ _BAR_ _EQ_ _RBRACK_ _RBRACE_ _GT_ _CARET_ _TILDE_ _QMARK_".split(" "));return Qe(a,b)}function Qe(a,b){return Ne(function(b,d){var c=a.h?a.h(b):a.call(null,b),f=a.h?a.h(d):a.call(null,d),h=Me(Ke);return h.c?h.c(c,f):h.call(null,c,f)},b)} +function ce(a,b){var c=E(b);return c?Mb(a,y(c),z(c)):a.B?a.B():a.call(null)}function de(a,b,c){for(c=E(c);;)if(c){var d=y(c);b=a.c?a.c(b,d):a.call(null,b,d);if(Hd(b))return B(b);c=z(c)}else return b}function Re(a,b){var c=dd(a);if(t(c.ja()))for(var d=c.next();;)if(c.ja()){var e=c.next();d=b.c?b.c(d,e):b.call(null,d,e);if(Hd(d))return B(d)}else return d;else return b.B?b.B():b.call(null)} +function Se(a,b,c){for(a=dd(a);;)if(a.ja()){var d=a.next();c=b.c?b.c(c,d):b.call(null,c,d);if(Hd(c))return B(c)}else return c}function Te(a,b){return null!=b&&(b.m&524288||q===b.uf)?b.Fa(null,a):vb(b)?Md(b,a):"string"===typeof b?Md(b,a):Ab(uc,b)?vc.c(b,a):ud(b)?Re(b,a):ce(a,b)}function Mb(a,b,c){return null!=c&&(c.m&524288||q===c.uf)?c.Ga(null,a,b):vb(c)?Nd(c,a,b):"string"===typeof c?Nd(c,a,b):Ab(uc,c)?vc.l(c,a,b):ud(c)?Se(c,a,b):de(a,b,c)}function Ue(a,b,c){return null!=c?yc(c,a,b):b} +function Ve(a){return a}function We(a,b,c,d){a=a.h?a.h(b):a.call(null,b);c=Mb(a,c,d);return a.h?a.h(c):a.call(null,c)}var Xe=function Xe(a){switch(arguments.length){case 0:return Xe.B();case 1:return Xe.h(arguments[0]);case 2:return Xe.c(arguments[0],arguments[1]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return Xe.A(arguments[0],arguments[1],new Jb(c.slice(2),0,null))}};Xe.B=function(){return 0};Xe.h=function(a){return a}; +Xe.c=function(a,b){return a+b};Xe.A=function(a,b,c){return Mb(Xe,a+b,c)};Xe.N=function(a){var b=y(a),c=z(a);a=y(c);c=z(c);return Xe.A(b,a,c)};Xe.L=2;var Ye=function Ye(a){switch(arguments.length){case 0:return Ye.B();case 1:return Ye.h(arguments[0]);case 2:return Ye.c(arguments[0],arguments[1]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return Ye.A(arguments[0],arguments[1],new Jb(c.slice(2),0,null))}};Ye.B=function(){return 1};Ye.h=function(a){return a}; +Ye.c=function(a,b){return a*b};Ye.A=function(a,b,c){return Mb(Ye,a*b,c)};Ye.N=function(a){var b=y(a),c=z(a);a=y(c);c=z(c);return Ye.A(b,a,c)};Ye.L=2;function Ze(a){a=(a-a%2)/2;return 0<=a?Math.floor(a):Math.ceil(a)}function $e(a){a-=a>>1&1431655765;a=(a&858993459)+(a>>2&858993459);return 16843009*(a+(a>>4)&252645135)>>24} +var v=function v(a){switch(arguments.length){case 0:return v.B();case 1:return v.h(arguments[0]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return v.A(arguments[0],new Jb(c.slice(1),0,null))}};v.B=function(){return""};v.h=function(a){return null==a?"":""+a};v.A=function(a,b){for(var c=new cb(""+v.h(a)),d=b;;)if(t(d))c=c.append(""+v.h(y(d))),d=z(d);else return c.toString()};v.N=function(a){var b=y(a);a=z(a);return v.A(b,a)};v.L=1; +function $d(a,b){if(we(b))if(Pd(a)&&Pd(b)&&H(a)!==H(b))var c=!1;else a:{c=E(a);for(var d=E(b);;){if(null==c){c=null==d;break a}if(null!=d&&G.c(y(c),y(d)))c=z(c),d=z(d);else{c=!1;break a}}}else c=null;return Ee(c)}function af(a,b,c,d,e){this.meta=a;this.first=b;this.kc=c;this.count=d;this.w=e;this.m=65937646;this.J=8192}g=af.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)}; +g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,this.count)}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.P=function(){return this.meta};g.Ka=function(){return 1===this.count?null:this.kc};g.W=function(){return this.count};g.Ac=function(){return this.first};g.Bc=function(){return this.bb(null)}; +g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)};g.K=function(a,b){return $d(this,b)};g.oa=function(){return tc(wd,this.meta)};g.Fa=function(a,b){return ce(b,this)};g.Ga=function(a,b,c){return de(b,c,this)};g.Ia=function(){return this.first};g.bb=function(){return 1===this.count?wd:this.kc};g.S=function(){return this};g.T=function(a,b){return new af(b,this.first,this.kc,this.count,this.w)};g.X=function(a,b){return new af(this.meta,b,this,this.count+1,null)};af.prototype[Fb]=function(){return yd(this)}; +function bf(a){this.meta=a;this.m=65937614;this.J=8192}g=bf.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)};g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.P=function(){return this.meta};g.Ka=function(){return null};g.W=function(){return 0};g.Ac=function(){return null};g.Bc=function(){throw Error("Can't pop empty list");};g.U=function(){return Cd}; +g.K=function(a,b){return(null!=b?b.m&33554432||q===b.Vf||(b.m?0:Ab(Fc,b)):Ab(Fc,b))||we(b)?null==E(b):!1};g.oa=function(){return this};g.Fa=function(a,b){return ce(b,this)};g.Ga=function(a,b,c){return de(b,c,this)};g.Ia=function(){return null};g.bb=function(){return wd};g.S=function(){return null};g.T=function(a,b){return new bf(b)};g.X=function(a,b){return new af(this.meta,b,null,1,null)};var wd=new bf(null);bf.prototype[Fb]=function(){return yd(this)}; +function cf(a){return(null!=a?a.m&134217728||q===a.Yf||(a.m?0:Ab(Hc,a)):Ab(Hc,a))?Ic(a):Mb(ge,wd,a)}var df=function df(a){for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return df.A(0<c.length?new Jb(c.slice(0),0,null):null)};df.A=function(a){if(a instanceof Jb&&0===a.i)var b=a.o;else a:for(b=[];;)if(null!=a)b.push(a.Ia(null)),a=a.Ka(null);else break a;a=b.length;for(var c=wd;;)if(0<a){var d=a-1;c=c.X(null,b[a-1]);a=d}else return c};df.L=0;df.N=function(a){return df.A(E(a))}; +function ef(a,b,c,d){this.meta=a;this.first=b;this.kc=c;this.w=d;this.m=65929452;this.J=8192}g=ef.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)};g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.P=function(){return this.meta};g.Ka=function(){return null==this.kc?null:E(this.kc)};g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)};g.K=function(a,b){return $d(this,b)}; +g.oa=function(){return tc(wd,this.meta)};g.Fa=function(a,b){return ce(b,this)};g.Ga=function(a,b,c){return de(b,c,this)};g.Ia=function(){return this.first};g.bb=function(){return null==this.kc?wd:this.kc};g.S=function(){return this};g.T=function(a,b){return new ef(b,this.first,this.kc,this.w)};g.X=function(a,b){return new ef(null,b,this,null)};ef.prototype[Fb]=function(){return yd(this)};function ae(a,b){return null==b||null!=b&&(b.m&64||q===b.G)?new ef(null,a,b,null):new ef(null,a,E(b),null)} +function ff(a,b){if(a.ea===b.ea)return 0;var c=wb(a.fb);if(t(c?b.fb:c))return-1;if(t(a.fb)){if(wb(b.fb))return 1;c=Aa(a.fb,b.fb);return 0===c?Aa(a.name,b.name):c}return Aa(a.name,b.name)}function L(a,b,c,d){this.fb=a;this.name=b;this.ea=c;this.Oc=d;this.m=2153775105;this.J=4096}g=L.prototype;g.toString=function(){return[":",v.h(this.ea)].join("")};g.equiv=function(a){return this.K(null,a)};g.K=function(a,b){return b instanceof L?this.ea===b.ea:!1}; +g.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return D.c(c,this);case 3:return D.l(c,this,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.c=function(a,c){return D.c(c,this)};a.l=function(a,c,d){return D.l(c,this,d)};return a}();g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))};g.h=function(a){return D.c(a,this)};g.c=function(a,b){return D.l(a,this,b)}; +g.U=function(){var a=this.Oc;return null!=a?a:this.Oc=a=pd(kd(this.name),nd(this.fb))+2654435769|0};g.hd=function(){return this.name};g.jd=function(){return this.fb};g.R=function(a,b){return Jc(b,[":",v.h(this.ea)].join(""))};function gf(a){return a instanceof L}function N(a,b){return a===b?!0:a instanceof L&&b instanceof L?a.ea===b.ea:!1} +var hf=function hf(a){switch(arguments.length){case 1:return hf.h(arguments[0]);case 2:return hf.c(arguments[0],arguments[1]);default:throw Error(["Invalid arity: ",v.h(arguments.length)].join(""));}}; +hf.h=function(a){if(a instanceof L)return a;if(a instanceof rd){if(null!=a&&(a.J&4096||q===a.Oe))var b=a.jd(null);else throw Error(["Doesn't support namespace: ",v.h(a)].join(""));return new L(b,jf(a),a.Zb,null)}return"string"===typeof a?(b=a.split("/"),2===b.length?new L(b[0],b[1],a,null):new L(null,b[0],a,null)):null}; +hf.c=function(a,b){var c=a instanceof L?jf(a):a instanceof rd?jf(a):a,d=b instanceof L?jf(b):b instanceof rd?jf(b):b;return new L(c,d,[v.h(t(c)?[v.h(c),"/"].join(""):null),v.h(d)].join(""),null)};hf.L=2;function kf(a,b,c,d){this.meta=a;this.Vc=b;this.s=c;this.w=d;this.m=32374988;this.J=1}g=kf.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)};function lf(a){null!=a.Vc&&(a.s=a.Vc.B?a.Vc.B():a.Vc.call(null),a.Vc=null);return a.s} +g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.P=function(){return this.meta};g.Ka=function(){this.S(null);return null==this.s?null:z(this.s)};g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)};g.K=function(a,b){return $d(this,b)}; +g.oa=function(){return tc(wd,this.meta)};g.Fa=function(a,b){return ce(b,this)};g.Ga=function(a,b,c){return de(b,c,this)};g.Ia=function(){this.S(null);return null==this.s?null:y(this.s)};g.bb=function(){this.S(null);return null!=this.s?vd(this.s):wd};g.S=function(){lf(this);if(null==this.s)return null;for(var a=this.s;;)if(a instanceof kf)a=lf(a);else return this.s=a,E(this.s)};g.T=function(a,b){return new kf(b,this.Vc,this.s,this.w)};g.X=function(a,b){return ae(b,this)};kf.prototype[Fb]=function(){return yd(this)}; +function mf(a,b){this.aa=a;this.end=b;this.m=2;this.J=0}mf.prototype.add=function(a){this.aa[this.end]=a;return this.end+=1};mf.prototype.Da=function(){var a=new nf(this.aa,0,this.end);this.aa=null;return a};mf.prototype.W=function(){return this.end};function of(a){return new mf(Array(a),0)}function nf(a,b,c){this.o=a;this.ab=b;this.end=c;this.m=524306;this.J=0}g=nf.prototype;g.W=function(){return this.end-this.ab};g.$=function(a,b){return this.o[this.ab+b]}; +g.ka=function(a,b,c){return 0<=b&&b<this.end-this.ab?this.o[this.ab+b]:c};g.Le=function(){if(this.ab===this.end)throw Error("-drop-first of empty chunk");return new nf(this.o,this.ab+1,this.end)};g.Fa=function(a,b){return Od(this.o,b,this.o[this.ab],this.ab+1)};g.Ga=function(a,b,c){return Od(this.o,b,c,this.ab)};function pf(a,b,c,d){this.Da=a;this.Wb=b;this.meta=c;this.w=d;this.m=31850732;this.J=1536}g=pf.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)}; +g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.P=function(){return this.meta};g.Ka=function(){if(1<Qb(this.Da))return new pf(Vc(this.Da),this.Wb,this.meta,null);var a=Cc(this.Wb);return null==a?null:a};g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)}; +g.K=function(a,b){return $d(this,b)};g.oa=function(){return tc(wd,this.meta)};g.Ia=function(){return A.c(this.Da,0)};g.bb=function(){return 1<Qb(this.Da)?new pf(Vc(this.Da),this.Wb,this.meta,null):null==this.Wb?wd:this.Wb};g.S=function(){return this};g.ge=function(){return this.Da};g.Hd=function(){return null==this.Wb?wd:this.Wb};g.T=function(a,b){return new pf(this.Da,this.Wb,b,this.w)};g.X=function(a,b){return ae(b,this)};g.Me=function(){return null==this.Wb?null:this.Wb};pf.prototype[Fb]=function(){return yd(this)}; +function qf(a,b){return 0===Qb(a)?b:new pf(a,b,null,null)}function rf(a,b){a.add(b)}function sf(a,b){if(Pd(b))return H(b);for(var c=0,d=E(b);;)if(null!=d&&c<a)c+=1,d=z(d);else return c} +var tf=function tf(a){if(null==a)return null;var c=z(a);return null==c?E(y(a)):ae(y(a),tf.h?tf.h(c):tf.call(null,c))},O=function O(a){switch(arguments.length){case 0:return O.B();case 1:return O.h(arguments[0]);case 2:return O.c(arguments[0],arguments[1]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return O.A(arguments[0],arguments[1],new Jb(c.slice(2),0,null))}};O.B=function(){return new kf(null,function(){return null},null,null)}; +O.h=function(a){return new kf(null,function(){return a},null,null)};O.c=function(a,b){return new kf(null,function(){var c=E(a);return c?Ae(c)?qf(Wc(c),O.c(Xc(c),b)):ae(y(c),O.c(vd(c),b)):b},null,null)};O.A=function(a,b,c){return function h(a,b){return new kf(null,function(){var c=E(a);return c?Ae(c)?qf(Wc(c),h(Xc(c),b)):ae(y(c),h(vd(c),b)):t(b)?h(y(b),z(b)):null},null,null)}(O.c(a,b),c)};O.N=function(a){var b=y(a),c=z(a);a=y(c);c=z(c);return O.A(b,a,c)};O.L=2; +var uf=function uf(a){switch(arguments.length){case 0:return uf.B();case 1:return uf.h(arguments[0]);case 2:return uf.c(arguments[0],arguments[1]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return uf.A(arguments[0],arguments[1],new Jb(c.slice(2),0,null))}};uf.B=function(){return Oc(he)};uf.h=function(a){return a};uf.c=function(a,b){return Pc(a,b)};uf.A=function(a,b,c){for(;;)if(a=Pc(a,b),t(c))b=y(c),c=z(c);else return a}; +uf.N=function(a){var b=y(a),c=z(a);a=y(c);c=z(c);return uf.A(b,a,c)};uf.L=2; +function vf(a,b,c){var d=E(c);if(0===b)return a.B?a.B():a.call(null);c=Wb(d);var e=Yb(d);if(1===b)return a.h?a.h(c):a.call(null,c);d=Wb(e);var f=Yb(e);if(2===b)return a.c?a.c(c,d):a.call(null,c,d);e=Wb(f);var h=Yb(f);if(3===b)return a.l?a.l(c,d,e):a.call(null,c,d,e);f=Wb(h);var k=Yb(h);if(4===b)return a.M?a.M(c,d,e,f):a.call(null,c,d,e,f);h=Wb(k);var l=Yb(k);if(5===b)return a.Z?a.Z(c,d,e,f,h):a.call(null,c,d,e,f,h);k=Wb(l);var p=Yb(l);if(6===b)return a.Ca?a.Ca(c,d,e,f,h,k):a.call(null,c,d,e,f,h,k); +l=Wb(p);var m=Yb(p);if(7===b)return a.Ya?a.Ya(c,d,e,f,h,k,l):a.call(null,c,d,e,f,h,k,l);p=Wb(m);var u=Yb(m);if(8===b)return a.Ha?a.Ha(c,d,e,f,h,k,l,p):a.call(null,c,d,e,f,h,k,l,p);m=Wb(u);var w=Yb(u);if(9===b)return a.Za?a.Za(c,d,e,f,h,k,l,p,m):a.call(null,c,d,e,f,h,k,l,p,m);u=Wb(w);var x=Yb(w);if(10===b)return a.Na?a.Na(c,d,e,f,h,k,l,p,m,u):a.call(null,c,d,e,f,h,k,l,p,m,u);w=Wb(x);var C=Yb(x);if(11===b)return a.Oa?a.Oa(c,d,e,f,h,k,l,p,m,u,w):a.call(null,c,d,e,f,h,k,l,p,m,u,w);x=Wb(C);var F=Yb(C); +if(12===b)return a.Pa?a.Pa(c,d,e,f,h,k,l,p,m,u,w,x):a.call(null,c,d,e,f,h,k,l,p,m,u,w,x);C=Wb(F);var I=Yb(F);if(13===b)return a.Qa?a.Qa(c,d,e,f,h,k,l,p,m,u,w,x,C):a.call(null,c,d,e,f,h,k,l,p,m,u,w,x,C);F=Wb(I);var M=Yb(I);if(14===b)return a.Ra?a.Ra(c,d,e,f,h,k,l,p,m,u,w,x,C,F):a.call(null,c,d,e,f,h,k,l,p,m,u,w,x,C,F);I=Wb(M);var S=Yb(M);if(15===b)return a.Sa?a.Sa(c,d,e,f,h,k,l,p,m,u,w,x,C,F,I):a.call(null,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I);M=Wb(S);var X=Yb(S);if(16===b)return a.Ta?a.Ta(c,d,e,f,h,k,l, +p,m,u,w,x,C,F,I,M):a.call(null,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M);S=Wb(X);var Ga=Yb(X);if(17===b)return a.Ua?a.Ua(c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S):a.call(null,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S);X=Wb(Ga);var db=Yb(Ga);if(18===b)return a.Va?a.Va(c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X):a.call(null,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X);Ga=Wb(db);db=Yb(db);if(19===b)return a.Wa?a.Wa(c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X,Ga):a.call(null,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X,Ga);var Q=Wb(db);Yb(db);if(20===b)return a.Xa? +a.Xa(c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X,Ga,Q):a.call(null,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X,Ga,Q);throw Error("Only up to 20 arguments supported on functions");}function wf(a,b,c){return null==c?a.h?a.h(b):a.call(a,b):xf(a,b,Wb(c),z(c))}function xf(a,b,c,d){return null==d?a.c?a.c(b,c):a.call(a,b,c):yf(a,b,c,Wb(d),z(d))}function yf(a,b,c,d,e){return null==e?a.l?a.l(b,c,d):a.call(a,b,c,d):zf(a,b,c,d,Wb(e),z(e))} +function zf(a,b,c,d,e,f){if(null==f)return a.M?a.M(b,c,d,e):a.call(a,b,c,d,e);var h=Wb(f),k=z(f);if(null==k)return a.Z?a.Z(b,c,d,e,h):a.call(a,b,c,d,e,h);f=Wb(k);var l=z(k);if(null==l)return a.Ca?a.Ca(b,c,d,e,h,f):a.call(a,b,c,d,e,h,f);k=Wb(l);var p=z(l);if(null==p)return a.Ya?a.Ya(b,c,d,e,h,f,k):a.call(a,b,c,d,e,h,f,k);l=Wb(p);var m=z(p);if(null==m)return a.Ha?a.Ha(b,c,d,e,h,f,k,l):a.call(a,b,c,d,e,h,f,k,l);p=Wb(m);var u=z(m);if(null==u)return a.Za?a.Za(b,c,d,e,h,f,k,l,p):a.call(a,b,c,d,e,h,f,k, +l,p);m=Wb(u);var w=z(u);if(null==w)return a.Na?a.Na(b,c,d,e,h,f,k,l,p,m):a.call(a,b,c,d,e,h,f,k,l,p,m);u=Wb(w);var x=z(w);if(null==x)return a.Oa?a.Oa(b,c,d,e,h,f,k,l,p,m,u):a.call(a,b,c,d,e,h,f,k,l,p,m,u);w=Wb(x);var C=z(x);if(null==C)return a.Pa?a.Pa(b,c,d,e,h,f,k,l,p,m,u,w):a.call(a,b,c,d,e,h,f,k,l,p,m,u,w);x=Wb(C);var F=z(C);if(null==F)return a.Qa?a.Qa(b,c,d,e,h,f,k,l,p,m,u,w,x):a.call(a,b,c,d,e,h,f,k,l,p,m,u,w,x);C=Wb(F);var I=z(F);if(null==I)return a.Ra?a.Ra(b,c,d,e,h,f,k,l,p,m,u,w,x,C):a.call(a, +b,c,d,e,h,f,k,l,p,m,u,w,x,C);F=Wb(I);var M=z(I);if(null==M)return a.Sa?a.Sa(b,c,d,e,h,f,k,l,p,m,u,w,x,C,F):a.call(a,b,c,d,e,h,f,k,l,p,m,u,w,x,C,F);I=Wb(M);var S=z(M);if(null==S)return a.Ta?a.Ta(b,c,d,e,h,f,k,l,p,m,u,w,x,C,F,I):a.call(a,b,c,d,e,h,f,k,l,p,m,u,w,x,C,F,I);M=Wb(S);var X=z(S);if(null==X)return a.Ua?a.Ua(b,c,d,e,h,f,k,l,p,m,u,w,x,C,F,I,M):a.call(a,b,c,d,e,h,f,k,l,p,m,u,w,x,C,F,I,M);S=Wb(X);var Ga=z(X);if(null==Ga)return a.Va?a.Va(b,c,d,e,h,f,k,l,p,m,u,w,x,C,F,I,M,S):a.call(a,b,c,d,e,h,f, +k,l,p,m,u,w,x,C,F,I,M,S);X=Wb(Ga);var db=z(Ga);if(null==db)return a.Wa?a.Wa(b,c,d,e,h,f,k,l,p,m,u,w,x,C,F,I,M,S,X):a.call(a,b,c,d,e,h,f,k,l,p,m,u,w,x,C,F,I,M,S,X);Ga=Wb(db);db=z(db);if(null==db)return a.Xa?a.Xa(b,c,d,e,h,f,k,l,p,m,u,w,x,C,F,I,M,S,X,Ga):a.call(a,b,c,d,e,h,f,k,l,p,m,u,w,x,C,F,I,M,S,X,Ga);b=[b,c,d,e,h,f,k,l,p,m,u,w,x,C,F,I,M,S,X,Ga];for(c=db;;)if(c)b.push(Wb(c)),c=z(c);else break;return a.apply(a,b)} +function P(a,b){if(a.N){var c=a.L,d=sf(c+1,b);return d<=c?vf(a,d,b):a.N(b)}c=E(b);return null==c?a.B?a.B():a.call(a):wf(a,Wb(c),z(c))}function Kb(a,b,c){if(a.N){b=ae(b,c);var d=a.L;c=sf(d,c)+1;return c<=d?vf(a,c,b):a.N(b)}return wf(a,b,E(c))}function Af(a,b,c,d,e){return a.N?(b=ae(b,ae(c,ae(d,e))),c=a.L,e=3+sf(c-2,e),e<=c?vf(a,e,b):a.N(b)):yf(a,b,c,d,E(e))}function oe(a,b,c,d,e,f){return a.N?(f=tf(f),b=ae(b,ae(c,ae(d,ae(e,f)))),c=a.L,f=4+sf(c-3,f),f<=c?vf(a,f,b):a.N(b)):zf(a,b,c,d,e,tf(f))} +function Bf(a){return E(a)?a:null} +function Cf(){"undefined"===typeof hb&&(hb=function(a){this.zf=a;this.m=393216;this.J=0},hb.prototype.T=function(a,b){return new hb(b)},hb.prototype.P=function(){return this.zf},hb.prototype.ja=function(){return!1},hb.prototype.next=function(){return Error("No such element")},hb.prototype.remove=function(){return Error("Unsupported operation")},hb.Wc=function(){return new R(null,1,5,T,[Df],null)},hb.qc=!0,hb.Tb="cljs.core/t_cljs$core34616",hb.Ec=function(a,b){return Jc(b,"cljs.core/t_cljs$core34616")}); +return new hb(Ef)}function Ff(a,b){this.s=a;this.i=b}Ff.prototype.ja=function(){return this.i<this.s.length};Ff.prototype.next=function(){var a=this.s.charAt(this.i);this.i+=1;return a};Ff.prototype.remove=function(){return Error("Unsupported operation")};function Gf(a,b){this.o=a;this.i=b}Gf.prototype.ja=function(){return this.i<this.o.length};Gf.prototype.next=function(){var a=this.o[this.i];this.i+=1;return a};Gf.prototype.remove=function(){return Error("Unsupported operation")};var Hf={},If={}; +function Jf(a,b){this.cd=a;this.ub=b}Jf.prototype.ja=function(){this.cd===Hf?(this.cd=If,this.ub=E(this.ub)):this.cd===this.ub&&(this.ub=z(this.cd));return null!=this.ub};Jf.prototype.next=function(){if(this.ja())return this.cd=this.ub,y(this.ub);throw Error("No such element");};Jf.prototype.remove=function(){return Error("Unsupported operation")}; +function Kf(a){if(ud(a))return dd(a);if(null==a)return Cf();if("string"===typeof a)return new Ff(a,0);if(vb(a))return new Gf(a,0);if((null!=a?a.m&8388608||q===a.Pe||(a.m?0:Ab(Bc,a)):Ab(Bc,a))||vb(a)||"string"===typeof a)return new Jf(Hf,a);throw Error(["Cannot create iterator from ",v.h(a)].join(""));}function Mf(a){this.ae=a}Mf.prototype.add=function(a){this.ae.push(a);return this};Mf.prototype.remove=function(){return this.ae.shift()};Mf.prototype.Td=function(){return 0===this.ae.length}; +Mf.prototype.toString=function(){return["Many: ",v.h(this.ae)].join("")};var Nf={};function Of(a){this.H=a}Of.prototype.add=function(a){return this.H===Nf?(this.H=a,this):new Mf([this.H,a])};Of.prototype.remove=function(){if(this.H===Nf)throw Error("Removing object from empty buffer");var a=this.H;this.H=Nf;return a};Of.prototype.Td=function(){return this.H===Nf};Of.prototype.toString=function(){return["Single: ",v.h(this.H)].join("")};function Pf(){}Pf.prototype.add=function(a){return new Of(a)}; +Pf.prototype.remove=function(){throw Error("Removing object from empty buffer");};Pf.prototype.Td=function(){return!0};Pf.prototype.toString=function(){return"Empty"};var Qf=new Pf,Rf=function Rf(a){return new kf(null,function(){if(a.ja())for(var c=[],d=0;;){var e=a.ja();if(t(t(e)?32>d:e))c[d]=a.next(),d+=1;else return qf(new nf(c,0,d),Rf.h?Rf.h(a):Rf.call(null,a))}else return null},null,null)};function Sf(a,b,c,d,e,f){this.buffer=a;this.ub=b;this.pe=c;this.Rb=d;this.ye=e;this.Gf=f} +Sf.prototype.step=function(){if(this.ub!==Nf)return!0;for(;;)if(this.ub===Nf)if(this.buffer.Td()){if(this.pe)return!1;if(this.ye.ja()){if(this.Gf)var a=P(this.Rb,ae(null,this.ye.next()));else a=this.ye.next(),a=this.Rb.c?this.Rb.c(null,a):this.Rb.call(null,null,a);Hd(a)&&(this.Rb.h?this.Rb.h(null):this.Rb.call(null,null),this.pe=!0)}else this.Rb.h?this.Rb.h(null):this.Rb.call(null,null),this.pe=!0}else this.ub=this.buffer.remove();else return!0};Sf.prototype.ja=function(){return this.step()}; +Sf.prototype.next=function(){if(this.ja()){var a=this.ub;this.ub=Nf;return a}throw Error("No such element");};Sf.prototype.remove=function(){return Error("Unsupported operation")};Sf.prototype[Fb]=function(){return yd(this)}; +function Tf(a,b){var c=new Sf(Qf,Nf,!1,null,b,!1);c.Rb=function(){var b=function(a){return function(){function b(b,c){a.buffer=a.buffer.add(c);return b}var c=null;c=function(a,c){switch(arguments.length){case 0:return null;case 1:return a;case 2:return b.call(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};c.B=function(){return null};c.h=function(a){return a};c.c=b;return c}()}(c);return a.h?a.h(b):a.call(null,b)}();return c} +function Uf(a,b){var c=Kf(b);c=Tf(a,c);c=Rf(c);return t(c)?c:wd}function Vf(a,b){for(;;){if(null==E(b))return!0;var c=y(b);c=a.h?a.h(c):a.call(null,c);if(t(c)){c=a;var d=z(b);a=c;b=d}else return!1}}function Wf(a,b){for(;;)if(E(b)){var c=y(b);c=a.h?a.h(c):a.call(null,c);if(t(c))return c;c=a;var d=z(b);a=c;b=d}else return null}function Xf(a){if(Ge(a))return 0===(a&1);throw Error(["Argument must be an integer: ",v.h(a)].join(""));} +function Yf(a){return function(){function b(b,c){return wb(a.c?a.c(b,c):a.call(null,b,c))}function c(b){return wb(a.h?a.h(b):a.call(null,b))}function d(){return wb(a.B?a.B():a.call(null))}var e=null,f=function(){function b(a,b,d){var e=null;if(2<arguments.length){e=0;for(var f=Array(arguments.length-2);e<f.length;)f[e]=arguments[e+2],++e;e=new Jb(f,0,null)}return c.call(this,a,b,e)}function c(b,c,d){a.N?(b=ae(b,ae(c,d)),c=a.L,d=2+sf(c-1,d),d=d<=c?vf(a,d,b):a.N(b)):d=xf(a,b,c,E(d));return wb(d)}b.L= +2;b.N=function(a){var b=y(a);a=z(a);var d=y(a);a=vd(a);return c(b,d,a)};b.A=c;return b}();e=function(a,e,l){switch(arguments.length){case 0:return d.call(this);case 1:return c.call(this,a);case 2:return b.call(this,a,e);default:var h=null;if(2<arguments.length){h=0;for(var k=Array(arguments.length-2);h<k.length;)k[h]=arguments[h+2],++h;h=new Jb(k,0,null)}return f.A(a,e,h)}throw Error("Invalid arity: "+(arguments.length-1));};e.L=2;e.N=f.N;e.B=d;e.h=c;e.c=b;e.A=f.A;return e}()} +function Zf(a){return function(){function b(b){if(0<arguments.length)for(var c=0,e=Array(arguments.length-0);c<e.length;)e[c]=arguments[c+0],++c;return a}b.L=0;b.N=function(b){E(b);return a};b.A=function(){return a};return b}()} +var $f=function $f(a){switch(arguments.length){case 0:return $f.B();case 1:return $f.h(arguments[0]);case 2:return $f.c(arguments[0],arguments[1]);case 3:return $f.l(arguments[0],arguments[1],arguments[2]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return $f.A(arguments[0],arguments[1],arguments[2],new Jb(c.slice(3),0,null))}};$f.B=function(){return Ve};$f.h=function(a){return a}; +$f.c=function(a,b){return function(){function c(c,d,e){c=b.l?b.l(c,d,e):b.call(null,c,d,e);return a.h?a.h(c):a.call(null,c)}function d(c,d){var e=b.c?b.c(c,d):b.call(null,c,d);return a.h?a.h(e):a.call(null,e)}function e(c){c=b.h?b.h(c):b.call(null,c);return a.h?a.h(c):a.call(null,c)}function f(){var c=b.B?b.B():b.call(null);return a.h?a.h(c):a.call(null,c)}var h=null,k=function(){function c(a,b,c,e){var f=null;if(3<arguments.length){f=0;for(var h=Array(arguments.length-3);f<h.length;)h[f]=arguments[f+ +3],++f;f=new Jb(h,0,null)}return d.call(this,a,b,c,f)}function d(c,d,e,f){c=Af(b,c,d,e,f);return a.h?a.h(c):a.call(null,c)}c.L=3;c.N=function(a){var b=y(a);a=z(a);var c=y(a);a=z(a);var e=y(a);a=vd(a);return d(b,c,e,a)};c.A=d;return c}();h=function(a,b,h,u){switch(arguments.length){case 0:return f.call(this);case 1:return e.call(this,a);case 2:return d.call(this,a,b);case 3:return c.call(this,a,b,h);default:var m=null;if(3<arguments.length){m=0;for(var p=Array(arguments.length-3);m<p.length;)p[m]= +arguments[m+3],++m;m=new Jb(p,0,null)}return k.A(a,b,h,m)}throw Error("Invalid arity: "+(arguments.length-1));};h.L=3;h.N=k.N;h.B=f;h.h=e;h.c=d;h.l=c;h.A=k.A;return h}()}; +$f.l=function(a,b,c){return function(){function d(d,e,f){d=c.l?c.l(d,e,f):c.call(null,d,e,f);d=b.h?b.h(d):b.call(null,d);return a.h?a.h(d):a.call(null,d)}function e(d,e){var f=c.c?c.c(d,e):c.call(null,d,e);f=b.h?b.h(f):b.call(null,f);return a.h?a.h(f):a.call(null,f)}function f(d){d=c.h?c.h(d):c.call(null,d);d=b.h?b.h(d):b.call(null,d);return a.h?a.h(d):a.call(null,d)}function h(){var d=c.B?c.B():c.call(null);d=b.h?b.h(d):b.call(null,d);return a.h?a.h(d):a.call(null,d)}var k=null,l=function(){function d(a, +b,c,d){var f=null;if(3<arguments.length){f=0;for(var h=Array(arguments.length-3);f<h.length;)h[f]=arguments[f+3],++f;f=new Jb(h,0,null)}return e.call(this,a,b,c,f)}function e(d,e,f,h){d=Af(c,d,e,f,h);d=b.h?b.h(d):b.call(null,d);return a.h?a.h(d):a.call(null,d)}d.L=3;d.N=function(a){var b=y(a);a=z(a);var c=y(a);a=z(a);var d=y(a);a=vd(a);return e(b,c,d,a)};d.A=e;return d}();k=function(a,b,c,k){switch(arguments.length){case 0:return h.call(this);case 1:return f.call(this,a);case 2:return e.call(this, +a,b);case 3:return d.call(this,a,b,c);default:var m=null;if(3<arguments.length){m=0;for(var p=Array(arguments.length-3);m<p.length;)p[m]=arguments[m+3],++m;m=new Jb(p,0,null)}return l.A(a,b,c,m)}throw Error("Invalid arity: "+(arguments.length-1));};k.L=3;k.N=l.N;k.B=h;k.h=f;k.c=e;k.l=d;k.A=l.A;return k}()}; +$f.A=function(a,b,c,d){return function(a){return function(){function b(a){var b=null;if(0<arguments.length){b=0;for(var d=Array(arguments.length-0);b<d.length;)d[b]=arguments[b+0],++b;b=new Jb(d,0,null)}return c.call(this,b)}function c(b){b=P(y(a),b);for(var c=z(a);;)if(c){var d=y(c);b=d.h?d.h(b):d.call(null,b);c=z(c)}else return b}b.L=0;b.N=function(a){a=E(a);return c(a)};b.A=c;return b}()}(cf(ae(a,ae(b,ae(c,d)))))}; +$f.N=function(a){var b=y(a),c=z(a);a=y(c);var d=z(c);c=y(d);d=z(d);return $f.A(b,a,c,d)};$f.L=3; +var ag=function ag(a){switch(arguments.length){case 1:return ag.h(arguments[0]);case 2:return ag.c(arguments[0],arguments[1]);case 3:return ag.l(arguments[0],arguments[1],arguments[2]);case 4:return ag.M(arguments[0],arguments[1],arguments[2],arguments[3]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return ag.A(arguments[0],arguments[1],arguments[2],arguments[3],new Jb(c.slice(4),0,null))}};ag.h=function(a){return a}; +ag.c=function(a,b){return function(){function c(c,d,e){return a.M?a.M(b,c,d,e):a.call(null,b,c,d,e)}function d(c,d){return a.l?a.l(b,c,d):a.call(null,b,c,d)}function e(c){return a.c?a.c(b,c):a.call(null,b,c)}function f(){return a.h?a.h(b):a.call(null,b)}var h=null,k=function(){function c(a,b,c,e){var f=null;if(3<arguments.length){f=0;for(var h=Array(arguments.length-3);f<h.length;)h[f]=arguments[f+3],++f;f=new Jb(h,0,null)}return d.call(this,a,b,c,f)}function d(c,d,e,f){return oe(a,b,c,d,e,be([f]))} +c.L=3;c.N=function(a){var b=y(a);a=z(a);var c=y(a);a=z(a);var e=y(a);a=vd(a);return d(b,c,e,a)};c.A=d;return c}();h=function(a,b,h,u){switch(arguments.length){case 0:return f.call(this);case 1:return e.call(this,a);case 2:return d.call(this,a,b);case 3:return c.call(this,a,b,h);default:var m=null;if(3<arguments.length){m=0;for(var l=Array(arguments.length-3);m<l.length;)l[m]=arguments[m+3],++m;m=new Jb(l,0,null)}return k.A(a,b,h,m)}throw Error("Invalid arity: "+(arguments.length-1));};h.L=3;h.N=k.N; +h.B=f;h.h=e;h.c=d;h.l=c;h.A=k.A;return h}()}; +ag.l=function(a,b,c){return function(){function d(d,e,f){return a.Z?a.Z(b,c,d,e,f):a.call(null,b,c,d,e,f)}function e(d,e){return a.M?a.M(b,c,d,e):a.call(null,b,c,d,e)}function f(d){return a.l?a.l(b,c,d):a.call(null,b,c,d)}function h(){return a.c?a.c(b,c):a.call(null,b,c)}var k=null,l=function(){function d(a,b,c,d){var f=null;if(3<arguments.length){f=0;for(var h=Array(arguments.length-3);f<h.length;)h[f]=arguments[f+3],++f;f=new Jb(h,0,null)}return e.call(this,a,b,c,f)}function e(d,e,f,h){return oe(a, +b,c,d,e,be([f,h]))}d.L=3;d.N=function(a){var b=y(a);a=z(a);var c=y(a);a=z(a);var d=y(a);a=vd(a);return e(b,c,d,a)};d.A=e;return d}();k=function(a,b,c,k){switch(arguments.length){case 0:return h.call(this);case 1:return f.call(this,a);case 2:return e.call(this,a,b);case 3:return d.call(this,a,b,c);default:var m=null;if(3<arguments.length){m=0;for(var p=Array(arguments.length-3);m<p.length;)p[m]=arguments[m+3],++m;m=new Jb(p,0,null)}return l.A(a,b,c,m)}throw Error("Invalid arity: "+(arguments.length- +1));};k.L=3;k.N=l.N;k.B=h;k.h=f;k.c=e;k.l=d;k.A=l.A;return k}()}; +ag.M=function(a,b,c,d){return function(){function e(e,f,h){return a.Ca?a.Ca(b,c,d,e,f,h):a.call(null,b,c,d,e,f,h)}function f(e,f){return a.Z?a.Z(b,c,d,e,f):a.call(null,b,c,d,e,f)}function h(e){return a.M?a.M(b,c,d,e):a.call(null,b,c,d,e)}function k(){return a.l?a.l(b,c,d):a.call(null,b,c,d)}var l=null,p=function(){function e(a,b,c,d){var e=null;if(3<arguments.length){e=0;for(var h=Array(arguments.length-3);e<h.length;)h[e]=arguments[e+3],++e;e=new Jb(h,0,null)}return f.call(this,a,b,c,e)}function f(e, +f,h,k){return oe(a,b,c,d,e,be([f,h,k]))}e.L=3;e.N=function(a){var b=y(a);a=z(a);var c=y(a);a=z(a);var d=y(a);a=vd(a);return f(b,c,d,a)};e.A=f;return e}();l=function(a,b,c,d){switch(arguments.length){case 0:return k.call(this);case 1:return h.call(this,a);case 2:return f.call(this,a,b);case 3:return e.call(this,a,b,c);default:var m=null;if(3<arguments.length){m=0;for(var l=Array(arguments.length-3);m<l.length;)l[m]=arguments[m+3],++m;m=new Jb(l,0,null)}return p.A(a,b,c,m)}throw Error("Invalid arity: "+ +(arguments.length-1));};l.L=3;l.N=p.N;l.B=k;l.h=h;l.c=f;l.l=e;l.A=p.A;return l}()};ag.A=function(a,b,c,d,e){return function(){function f(a){var b=null;if(0<arguments.length){b=0;for(var c=Array(arguments.length-0);b<c.length;)c[b]=arguments[b+0],++b;b=new Jb(c,0,null)}return h.call(this,b)}function h(f){return Af(a,b,c,d,O.c(e,f))}f.L=0;f.N=function(a){a=E(a);return h(a)};f.A=h;return f}()};ag.N=function(a){var b=y(a),c=z(a);a=y(c);var d=z(c);c=y(d);var e=z(d);d=y(e);e=z(e);return ag.A(b,a,c,d,e)}; +ag.L=4;function bg(a,b){return function f(b,e){return new kf(null,function(){var d=E(e);if(d){if(Ae(d)){for(var k=Wc(d),l=H(k),p=of(l),m=0;;)if(m<l)rf(p,function(){var d=b+m,e=A.c(k,m);return a.c?a.c(d,e):a.call(null,d,e)}()),m+=1;else break;return qf(p.Da(),f(b+l,Xc(d)))}return ae(function(){var e=y(d);return a.c?a.c(b,e):a.call(null,b,e)}(),f(b+1,vd(d)))}return null},null,null)}(0,b)}function cg(a,b,c,d){this.state=a;this.meta=b;this.df=c;this.gb=d;this.J=16386;this.m=6455296}g=cg.prototype; +g.equiv=function(a){return this.K(null,a)};g.K=function(a,b){return this===b};g.pc=function(){return this.state};g.P=function(){return this.meta};g.Kd=function(a,b,c){a=E(this.gb);for(var d=null,e=0,f=0;;)if(f<e){var h=d.$(null,f),k=J(h,0,null);h=J(h,1,null);h.M?h.M(k,this,b,c):h.call(null,k,this,b,c);f+=1}else if(a=E(a))Ae(a)?(d=Wc(a),a=Xc(a),k=d,e=H(d),d=k):(d=y(a),k=J(d,0,null),h=J(d,1,null),h.M?h.M(k,this,b,c):h.call(null,k,this,b,c),a=z(a),d=null,e=0),f=0;else return null}; +g.Jd=function(a,b,c){this.gb=K.l(this.gb,b,c);return this};g.Ld=function(a,b){return this.gb=le.c(this.gb,b)};g.U=function(){return ja(this)};var dg=function dg(a){switch(arguments.length){case 1:return dg.h(arguments[0]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return dg.A(arguments[0],new Jb(c.slice(1),0,null))}};dg.h=function(a){return new cg(a,null,null,null)}; +dg.A=function(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b,d=D.c(c,rb);c=D.c(c,eg);return new cg(a,d,c,null)};dg.N=function(a){var b=y(a);a=z(a);return dg.A(b,a)};dg.L=1;function fg(a,b){if(a instanceof cg){var c=a.df;if(null!=c&&!t(c.h?c.h(b):c.call(null,b)))throw Error("Validator rejected reference state");c=a.state;a.state=b;null!=a.gb&&Lc(a,c,b);return b}return $c(a,b)} +var gg=function gg(a){switch(arguments.length){case 2:return gg.c(arguments[0],arguments[1]);case 3:return gg.l(arguments[0],arguments[1],arguments[2]);case 4:return gg.M(arguments[0],arguments[1],arguments[2],arguments[3]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return gg.A(arguments[0],arguments[1],arguments[2],arguments[3],new Jb(c.slice(4),0,null))}}; +gg.c=function(a,b){if(a instanceof cg){var c=a.state;c=b.h?b.h(c):b.call(null,c);c=fg(a,c)}else c=ad.c(a,b);return c};gg.l=function(a,b,c){if(a instanceof cg){var d=a.state;b=b.c?b.c(d,c):b.call(null,d,c);a=fg(a,b)}else a=ad.l(a,b,c);return a};gg.M=function(a,b,c,d){if(a instanceof cg){var e=a.state;b=b.l?b.l(e,c,d):b.call(null,e,c,d);a=fg(a,b)}else a=ad.M(a,b,c,d);return a};gg.A=function(a,b,c,d,e){return a instanceof cg?fg(a,Af(b,a.state,c,d,e)):ad.Z(a,b,c,d,e)}; +gg.N=function(a){var b=y(a),c=z(a);a=y(c);var d=z(c);c=y(d);var e=z(d);d=y(e);e=z(e);return gg.A(b,a,c,d,e)};gg.L=4;function hg(a){this.state=a;this.m=32768;this.J=0}hg.prototype.Qe=function(a,b){return this.state=b};hg.prototype.pc=function(){return this.state}; +var ig=function ig(a){switch(arguments.length){case 1:return ig.h(arguments[0]);case 2:return ig.c(arguments[0],arguments[1]);case 3:return ig.l(arguments[0],arguments[1],arguments[2]);case 4:return ig.M(arguments[0],arguments[1],arguments[2],arguments[3]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return ig.A(arguments[0],arguments[1],arguments[2],arguments[3],new Jb(c.slice(4),0,null))}}; +ig.h=function(a){return function(b){return function(){function c(c,d){var e=a.h?a.h(d):a.call(null,d);return b.c?b.c(c,e):b.call(null,c,e)}function d(a){return b.h?b.h(a):b.call(null,a)}function e(){return b.B?b.B():b.call(null)}var f=null,h=function(){function c(a,b,c){var e=null;if(2<arguments.length){e=0;for(var f=Array(arguments.length-2);e<f.length;)f[e]=arguments[e+2],++e;e=new Jb(f,0,null)}return d.call(this,a,b,e)}function d(c,d,e){d=Kb(a,d,e);return b.c?b.c(c,d):b.call(null,c,d)}c.L=2;c.N= +function(a){var b=y(a);a=z(a);var c=y(a);a=vd(a);return d(b,c,a)};c.A=d;return c}();f=function(a,b,f){switch(arguments.length){case 0:return e.call(this);case 1:return d.call(this,a);case 2:return c.call(this,a,b);default:var k=null;if(2<arguments.length){k=0;for(var l=Array(arguments.length-2);k<l.length;)l[k]=arguments[k+2],++k;k=new Jb(l,0,null)}return h.A(a,b,k)}throw Error("Invalid arity: "+(arguments.length-1));};f.L=2;f.N=h.N;f.B=e;f.h=d;f.c=c;f.A=h.A;return f}()}}; +ig.c=function(a,b){return new kf(null,function(){var c=E(b);if(c){if(Ae(c)){for(var d=Wc(c),e=H(d),f=of(e),h=0;;)if(h<e)rf(f,function(){var b=A.c(d,h);return a.h?a.h(b):a.call(null,b)}()),h+=1;else break;return qf(f.Da(),ig.c(a,Xc(c)))}return ae(function(){var b=y(c);return a.h?a.h(b):a.call(null,b)}(),ig.c(a,vd(c)))}return null},null,null)}; +ig.l=function(a,b,c){return new kf(null,function(){var d=E(b),e=E(c);if(d&&e){var f=ae;var h=y(d);var k=y(e);h=a.c?a.c(h,k):a.call(null,h,k);d=f(h,ig.l(a,vd(d),vd(e)))}else d=null;return d},null,null)};ig.M=function(a,b,c,d){return new kf(null,function(){var e=E(b),f=E(c),h=E(d);if(e&&f&&h){var k=ae;var l=y(e);var p=y(f),m=y(h);l=a.l?a.l(l,p,m):a.call(null,l,p,m);e=k(l,ig.M(a,vd(e),vd(f),vd(h)))}else e=null;return e},null,null)}; +ig.A=function(a,b,c,d,e){var f=function l(a){return new kf(null,function(){var b=ig.c(E,a);return Vf(Ve,b)?ae(ig.c(y,b),l(ig.c(vd,b))):null},null,null)};return ig.c(function(){return function(b){return P(a,b)}}(f),f(ge.A(e,d,be([c,b]))))};ig.N=function(a){var b=y(a),c=z(a);a=y(c);var d=z(c);c=y(d);var e=z(d);d=y(e);e=z(e);return ig.A(b,a,c,d,e)};ig.L=4;function jg(a,b){return new kf(null,function(){if(0<a){var c=E(b);return c?ae(y(c),jg(a-1,vd(c))):null}return null},null,null)} +function kg(a,b){return new kf(null,function(c){return function(){return c(a,b)}}(function(a,b){for(;;){var c=E(b);if(0<a&&c){var d=a-1;c=vd(c);a=d;b=c}else return c}}),null,null)}function lg(a){return ig.l(function(a){return a},a,kg(2,a))} +function mg(a){return function(b){return function(c){return function(){function d(d,e){var f=B(c);if(t(t(f)?a.h?a.h(e):a.call(null,e):f))return d;bd(c,null);return b.c?b.c(d,e):b.call(null,d,e)}function e(a){return b.h?b.h(a):b.call(null,a)}function f(){return b.B?b.B():b.call(null)}var h=null;h=function(a,b){switch(arguments.length){case 0:return f.call(this);case 1:return e.call(this,a);case 2:return d.call(this,a,b)}throw Error("Invalid arity: "+(arguments.length-1));};h.B=f;h.h=e;h.c=d;return h}()}(new hg(!0))}} +function ng(a,b){return new kf(null,function(c){return function(){return c(a,b)}}(function(a,b){for(;;){var c=E(b),d;if(d=c)d=y(c),d=a.h?a.h(d):a.call(null,d);if(t(d))d=a,c=vd(c),a=d,b=c;else return c}}),null,null)}var og=function og(a){return new kf(null,function(){var c=E(a);return c?O.c(c,og.h?og.h(c):og.call(null,c)):null},null,null)};function pg(a){return new kf(null,function(){return ae(a,pg(a))},null,null)}function qg(a,b){return jg(a,pg(b))} +var rg=function rg(a,b){return ae(b,new kf(null,function(){var d=a.h?a.h(b):a.call(null,b);return rg.c?rg.c(a,d):rg.call(null,a,d)},null,null))};function sg(a,b){return P(O,Kb(ig,a,b))} +function tg(a){return function(b){return function(){function c(c,d){return t(a.h?a.h(d):a.call(null,d))?b.c?b.c(c,d):b.call(null,c,d):c}function d(a){return b.h?b.h(a):b.call(null,a)}function e(){return b.B?b.B():b.call(null)}var f=null;f=function(a,b){switch(arguments.length){case 0:return e.call(this);case 1:return d.call(this,a);case 2:return c.call(this,a,b)}throw Error("Invalid arity: "+(arguments.length-1));};f.B=e;f.h=d;f.c=c;return f}()}} +function ug(a,b){return new kf(null,function(){var c=E(b);if(c){if(Ae(c)){for(var d=Wc(c),e=H(d),f=of(e),h=0;;)if(h<e){var k=A.c(d,h);k=a.h?a.h(k):a.call(null,k);t(k)&&(k=A.c(d,h),f.add(k));h+=1}else break;return qf(f.Da(),ug(a,Xc(c)))}d=y(c);c=vd(c);return t(a.h?a.h(d):a.call(null,d))?ae(d,ug(a,c)):ug(a,c)}return null},null,null)}function vg(a,b){return ug(Yf(a),b)} +var wg=function wg(a){switch(arguments.length){case 0:return wg.B();case 1:return wg.h(arguments[0]);case 2:return wg.c(arguments[0],arguments[1]);case 3:return wg.l(arguments[0],arguments[1],arguments[2]);default:throw Error(["Invalid arity: ",v.h(arguments.length)].join(""));}};wg.B=function(){return he};wg.h=function(a){return a};wg.c=function(a,b){return null!=a?null!=a&&(a.J&4||q===a.kf)?tc(Qc(Mb(Pc,Oc(a),b)),qe(a)):Mb(Tb,a,b):Mb(ge,wd,b)}; +wg.l=function(a,b,c){return null!=a&&(a.J&4||q===a.kf)?tc(Qc(We(b,uf,Oc(a),c)),qe(a)):We(b,ge,a,c)};wg.L=3;function xg(a,b){return Qc(Mb(function(b,d){return uf.c(b,a.h?a.h(d):a.call(null,d))},Oc(he),b))}function yg(a,b,c){return new kf(null,function(){var d=E(c);if(d){var e=jg(a,d);return a===H(e)?ae(e,yg(a,b,kg(b,d))):null}return null},null,null)} +var zg=function zg(a,b,c){b=E(b);var e=y(b),f=z(b);return f?K.l(a,e,function(){var b=D.c(a,e);return zg.l?zg.l(b,f,c):zg.call(null,b,f,c)}()):K.l(a,e,c)},Ag=function Ag(a){switch(arguments.length){case 3:return Ag.l(arguments[0],arguments[1],arguments[2]);case 4:return Ag.M(arguments[0],arguments[1],arguments[2],arguments[3]);case 5:return Ag.Z(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4]);case 6:return Ag.Ca(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4],arguments[5]); +default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return Ag.A(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4],arguments[5],new Jb(c.slice(6),0,null))}};Ag.l=function(a,b,c){b=E(b);var d=y(b);return(b=z(b))?K.l(a,d,Ag.l(D.c(a,d),b,c)):K.l(a,d,function(){var b=D.c(a,d);return c.h?c.h(b):c.call(null,b)}())}; +Ag.M=function(a,b,c,d){b=E(b);var e=y(b);return(b=z(b))?K.l(a,e,Ag.M(D.c(a,e),b,c,d)):K.l(a,e,function(){var b=D.c(a,e);return c.c?c.c(b,d):c.call(null,b,d)}())};Ag.Z=function(a,b,c,d,e){b=E(b);var f=y(b);return(b=z(b))?K.l(a,f,Ag.Z(D.c(a,f),b,c,d,e)):K.l(a,f,function(){var b=D.c(a,f);return c.l?c.l(b,d,e):c.call(null,b,d,e)}())}; +Ag.Ca=function(a,b,c,d,e,f){b=E(b);var h=y(b);return(b=z(b))?K.l(a,h,Ag.Ca(D.c(a,h),b,c,d,e,f)):K.l(a,h,function(){var b=D.c(a,h);return c.M?c.M(b,d,e,f):c.call(null,b,d,e,f)}())};Ag.A=function(a,b,c,d,e,f,h){var k=E(b);b=y(k);return(k=z(k))?K.l(a,b,oe(Ag,D.c(a,b),k,c,d,be([e,f,h]))):K.l(a,b,oe(c,D.c(a,b),d,e,f,be([h])))};Ag.N=function(a){var b=y(a),c=z(a);a=y(c);var d=z(c);c=y(d);var e=z(d);d=y(e);var f=z(e);e=y(f);var h=z(f);f=y(h);h=z(h);return Ag.A(b,a,c,d,e,f,h)};Ag.L=6; +function Bg(a,b,c){return K.l(a,b,function(){var d=D.c(a,b);return c.h?c.h(d):c.call(null,d)}())}function Cg(a,b,c,d){return K.l(a,b,function(){var e=D.c(a,b);return c.c?c.c(e,d):c.call(null,e,d)}())}function Dg(a,b,c){var d=V,e=Eg;return K.l(a,d,function(){var f=D.c(a,d);return e.l?e.l(f,b,c):e.call(null,f,b,c)}())}function Fg(a,b){this.la=a;this.o=b} +function Gg(a){return new Fg(a,[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null])}function Hg(a){return new Fg(a.la,Gb(a.o))}function Ig(a){a=a.F;return 32>a?0:a-1>>>5<<5}function Jg(a,b,c){for(;;){if(0===b)return c;var d=Gg(a);d.o[0]=c;c=d;b-=5}} +var Kg=function Kg(a,b,c,d){var f=Hg(c),h=a.F-1>>>b&31;5===b?f.o[h]=d:(c=c.o[h],null!=c?(b-=5,a=Kg.M?Kg.M(a,b,c,d):Kg.call(null,a,b,c,d)):a=Jg(null,b-5,d),f.o[h]=a);return f};function Lg(a,b){throw Error(["No item ",v.h(a)," in vector of length ",v.h(b)].join(""));}function Mg(a,b){if(b>=Ig(a))return a.fa;for(var c=a.root,d=a.shift;;)if(0<d){var e=d-5;c=c.o[b>>>d&31];d=e}else return c.o} +var Ng=function Ng(a,b,c,d,e){var h=Hg(c);if(0===b)h.o[d&31]=e;else{var k=d>>>b&31;b-=5;c=c.o[k];a=Ng.Z?Ng.Z(a,b,c,d,e):Ng.call(null,a,b,c,d,e);h.o[k]=a}return h},Og=function Og(a,b,c){var e=a.F-2>>>b&31;if(5<b){b-=5;var f=c.o[e];a=Og.l?Og.l(a,b,f):Og.call(null,a,b,f);if(null==a&&0===e)return null;c=Hg(c);c.o[e]=a;return c}if(0===e)return null;c=Hg(c);c.o[e]=null;return c};function Pg(a,b,c,d,e,f){this.i=a;this.base=b;this.o=c;this.Ja=d;this.start=e;this.end=f} +Pg.prototype.ja=function(){return this.i<this.end};Pg.prototype.next=function(){32===this.i-this.base&&(this.o=Mg(this.Ja,this.i),this.base+=32);var a=this.o[this.i&31];this.i+=1;return a};function Qg(a,b,c){return new Pg(b,b-b%32,b<H(a)?Mg(a,b):null,a,b,c)}function Rg(a,b,c,d){return c<d?Sg(a,b,Vd(a,c),c+1,d):b.B?b.B():b.call(null)} +function Sg(a,b,c,d,e){var f=c;c=d;for(d=Mg(a,d);;)if(c<e){var h=c&31;d=0===h?Mg(a,c):d;h=d[h];f=b.c?b.c(f,h):b.call(null,f,h);if(Hd(f))return B(f);c+=1}else return f}function R(a,b,c,d,e,f){this.meta=a;this.F=b;this.shift=c;this.root=d;this.fa=e;this.w=f;this.m=167668511;this.J=139268}g=R.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)}; +g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){return"number"===typeof b?this.ka(null,b,c):c}; +g.Qc=function(a,b,c){a=0;for(var d=c;;)if(a<this.F){var e=Mg(this,a);c=e.length;a:for(var f=0;;)if(f<c){var h=f+a,k=e[f];d=b.l?b.l(d,h,k):b.call(null,d,h,k);if(Hd(d)){e=d;break a}f+=1}else{e=d;break a}if(Hd(e))return B(e);a+=c;d=e}else return d};g.fe=q;g.$=function(a,b){return(0<=b&&b<this.F?Mg(this,b):Lg(b,this.F))[b&31]};g.ka=function(a,b,c){return 0<=b&&b<this.F?Mg(this,b)[b&31]:c}; +g.dc=function(a,b,c){if(0<=b&&b<this.F)return Ig(this)<=b?(a=Gb(this.fa),a[b&31]=c,new R(this.meta,this.F,this.shift,this.root,a,null)):new R(this.meta,this.F,this.shift,Ng(this,this.shift,this.root,b,c),this.fa,null);if(b===this.F)return this.X(null,c);throw Error(["Index ",v.h(b)," out of bounds [0,",v.h(this.F),"]"].join(""));};g.ba=function(){return Qg(this,0,this.F)};g.P=function(){return this.meta};g.W=function(){return this.F};g.fd=function(){return this.$(null,0)}; +g.gd=function(){return this.$(null,1)};g.Ac=function(){return 0<this.F?this.$(null,this.F-1):null}; +g.Bc=function(){if(0===this.F)throw Error("Can't pop empty vector");if(1===this.F)return tc(he,this.meta);if(1<this.F-Ig(this))return new R(this.meta,this.F-1,this.shift,this.root,this.fa.slice(0,-1),null);var a=Mg(this,this.F-2),b=Og(this,this.shift,this.root);b=null==b?T:b;var c=this.F-1;return 5<this.shift&&null==b.o[1]?new R(this.meta,c,this.shift-5,b.o[0],a,null):new R(this.meta,c,this.shift,b,a,null)};g.Rc=function(){return 0<this.F?new Zd(this,this.F-1,null):null}; +g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)};g.K=function(a,b){if(b instanceof R)if(this.F===H(b))for(var c=this.ba(null),d=dd(b);;)if(c.ja()){var e=c.next(),f=d.next();if(!G.c(e,f))return!1}else return!0;else return!1;else return $d(this,b)}; +g.Pc=function(){var a=this.F,b=this.shift,c=new Fg({},Gb(this.root.o)),d=this.fa,e=[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null];Be(d,0,e,0,d.length);return new Tg(a,b,c,e)};g.oa=function(){return tc(he,this.meta)};g.Fa=function(a,b){return Rg(this,b,0,this.F)}; +g.Ga=function(a,b,c){a=0;for(var d=c;;)if(a<this.F){var e=Mg(this,a);c=e.length;a:for(var f=0;;)if(f<c){var h=e[f];d=b.c?b.c(d,h):b.call(null,d,h);if(Hd(d)){e=d;break a}f+=1}else{e=d;break a}if(Hd(e))return B(e);a+=c;d=e}else return d};g.O=function(a,b,c){if("number"===typeof b)return this.dc(null,b,c);throw Error("Vector's key for assoc must be a number.");};g.yc=function(a,b){return Ge(b)?0<=b&&b<this.F:!1}; +g.S=function(){if(0===this.F)var a=null;else if(32>=this.F)a=new Jb(this.fa,0,null);else{a:{a=this.root;for(var b=this.shift;;)if(0<b)b-=5,a=a.o[0];else{a=a.o;break a}}a=new Ug(this,a,0,0,null,null)}return a};g.T=function(a,b){return new R(b,this.F,this.shift,this.root,this.fa,this.w)}; +g.X=function(a,b){if(32>this.F-Ig(this)){for(var c=this.fa.length,d=Array(c+1),e=0;;)if(e<c)d[e]=this.fa[e],e+=1;else break;d[c]=b;return new R(this.meta,this.F+1,this.shift,this.root,d,null)}c=(d=this.F>>>5>1<<this.shift)?this.shift+5:this.shift;d?(d=Gg(null),d.o[0]=this.root,e=Jg(null,this.shift,new Fg(null,this.fa)),d.o[1]=e):d=Kg(this,this.shift,this.root,new Fg(null,this.fa));return new R(this.meta,this.F+1,c,d,[b],null)}; +g.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return this.$(null,c);case 3:return this.ka(null,c,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.c=function(a,c){return this.$(null,c)};a.l=function(a,c,d){return this.ka(null,c,d)};return a}();g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))};g.h=function(a){return this.$(null,a)};g.c=function(a,b){return this.ka(null,a,b)}; +var T=new Fg(null,[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]),he=new R(null,0,5,T,[],Cd);function Vg(a){var b=a.length;if(32>b)return new R(null,b,5,T,a,null);for(var c=32,d=(new R(null,32,5,T,a.slice(0,32),null)).Pc(null);;)if(c<b){var e=c+1;d=uf.c(d,a[c]);c=e}else return Qc(d)}R.prototype[Fb]=function(){return yd(this)};function Wg(a){return vb(a)?Vg(a):Qc(Mb(Pc,Oc(he),a))} +var Xg=function Xg(a){for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return Xg.A(0<c.length?new Jb(c.slice(0),0,null):null)};Xg.A=function(a){return a instanceof Jb&&0===a.i?Vg(a.o):Wg(a)};Xg.L=0;Xg.N=function(a){return Xg.A(E(a))};function Ug(a,b,c,d,e,f){this.zb=a;this.node=b;this.i=c;this.ab=d;this.meta=e;this.w=f;this.m=32375020;this.J=1536}g=Ug.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)}; +g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.P=function(){return this.meta};g.Ka=function(){if(this.ab+1<this.node.length){var a=new Ug(this.zb,this.node,this.i,this.ab+1,null,null);return null==a?null:a}return this.Me(null)}; +g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)};g.K=function(a,b){return $d(this,b)};g.oa=function(){return tc(he,this.meta)};g.Fa=function(a,b){return Rg(this.zb,b,this.i+this.ab,H(this.zb))};g.Ga=function(a,b,c){return Sg(this.zb,b,c,this.i+this.ab,H(this.zb))};g.Ia=function(){return this.node[this.ab]};g.bb=function(){if(this.ab+1<this.node.length){var a=new Ug(this.zb,this.node,this.i,this.ab+1,null,null);return null==a?wd:a}return this.Hd(null)};g.S=function(){return this}; +g.ge=function(){var a=this.node;return new nf(a,this.ab,a.length)};g.Hd=function(){var a=this.i+this.node.length;return a<Qb(this.zb)?new Ug(this.zb,Mg(this.zb,a),a,0,null,null):wd};g.T=function(a,b){return new Ug(this.zb,this.node,this.i,this.ab,b,null)};g.X=function(a,b){return ae(b,this)};g.Me=function(){var a=this.i+this.node.length;return a<Qb(this.zb)?new Ug(this.zb,Mg(this.zb,a),a,0,null,null):null};Ug.prototype[Fb]=function(){return yd(this)}; +function Yg(a,b,c,d,e){this.meta=a;this.Ja=b;this.start=c;this.end=d;this.w=e;this.m=167666463;this.J=139264}g=Yg.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)};g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){return"number"===typeof b?this.ka(null,b,c):c}; +g.Qc=function(a,b,c){a=this.start;for(var d=0;;)if(a<this.end){var e=d,f=A.c(this.Ja,a);c=b.l?b.l(c,e,f):b.call(null,c,e,f);if(Hd(c))return B(c);d+=1;a+=1}else return c};g.$=function(a,b){return 0>b||this.end<=this.start+b?Lg(b,this.end-this.start):A.c(this.Ja,this.start+b)};g.ka=function(a,b,c){return 0>b||this.end<=this.start+b?c:A.l(this.Ja,this.start+b,c)}; +g.dc=function(a,b,c){a=this.start+b;if(0>b||this.end+1<=a)throw Error(["Index ",v.h(b)," out of bounds [0,",v.h(this.W(null)),"]"].join(""));b=this.meta;c=K.l(this.Ja,a,c);var d=this.end;a+=1;return Zg(b,c,this.start,d>a?d:a,null)};g.ba=function(){return null!=this.Ja&&q===this.Ja.fe?Qg(this.Ja,this.start,this.end):new Jf(Hf,this)};g.P=function(){return this.meta};g.W=function(){return this.end-this.start};g.Ac=function(){return A.c(this.Ja,this.end-1)}; +g.Bc=function(){if(this.start===this.end)throw Error("Can't pop empty vector");return Zg(this.meta,this.Ja,this.start,this.end-1,null)};g.Rc=function(){return this.start!==this.end?new Zd(this,this.end-this.start-1,null):null};g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)};g.K=function(a,b){return $d(this,b)};g.oa=function(){return tc(he,this.meta)};g.Fa=function(a,b){return null!=this.Ja&&q===this.Ja.fe?Rg(this.Ja,b,this.start,this.end):Kd(this,b)}; +g.Ga=function(a,b,c){return null!=this.Ja&&q===this.Ja.fe?Sg(this.Ja,b,c,this.start,this.end):Ld(this,b,c)};g.O=function(a,b,c){if("number"===typeof b)return this.dc(null,b,c);throw Error("Subvec's key for assoc must be a number.");};g.S=function(){var a=this;return function(b){return function e(d){return d===a.end?null:ae(A.c(a.Ja,d),new kf(null,function(){return function(){return e(d+1)}}(b),null,null))}}(this)(a.start)};g.T=function(a,b){return Zg(b,this.Ja,this.start,this.end,this.w)}; +g.X=function(a,b){return Zg(this.meta,qc(this.Ja,this.end,b),this.start,this.end+1,null)};g.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return this.$(null,c);case 3:return this.ka(null,c,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.c=function(a,c){return this.$(null,c)};a.l=function(a,c,d){return this.ka(null,c,d)};return a}();g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))};g.h=function(a){return this.$(null,a)}; +g.c=function(a,b){return this.ka(null,a,b)};Yg.prototype[Fb]=function(){return yd(this)};function Zg(a,b,c,d,e){for(;;)if(b instanceof Yg)c=b.start+c,d=b.start+d,b=b.Ja;else{if(!ze(b))throw Error("v must satisfy IVector");var f=H(b);if(0>c||0>d||c>f||d>f)throw Error("Index out of bounds");return new Yg(a,b,c,d,e)}}function $g(a,b){return a===b.la?b:new Fg(a,Gb(b.o))} +var ah=function ah(a,b,c,d){c=$g(a.root.la,c);var f=a.F-1>>>b&31;if(5===b)a=d;else{var h=c.o[f];null!=h?(b-=5,a=ah.M?ah.M(a,b,h,d):ah.call(null,a,b,h,d)):a=Jg(a.root.la,b-5,d)}c.o[f]=a;return c};function Tg(a,b,c,d){this.F=a;this.shift=b;this.root=c;this.fa=d;this.J=88;this.m=275}g=Tg.prototype; +g.Dc=function(a,b){if(this.root.la){if(32>this.F-Ig(this))this.fa[this.F&31]=b;else{var c=new Fg(this.root.la,this.fa),d=[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null];d[0]=b;this.fa=d;if(this.F>>>5>1<<this.shift){d=[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null];var e=this.shift+ +5;d[0]=this.root;d[1]=Jg(this.root.la,this.shift,c);this.root=new Fg(this.root.la,d);this.shift=e}else this.root=ah(this,this.shift,this.root,c)}this.F+=1;return this}throw Error("conj! after persistent!");};g.kd=function(){if(this.root.la){this.root.la=null;var a=this.F-Ig(this),b=Array(a);Be(this.fa,0,b,0,a);return new R(null,this.F,this.shift,this.root,b,null)}throw Error("persistent! called twice");}; +g.Cc=function(a,b,c){if("number"===typeof b)return bh(this,b,c);throw Error("TransientVector's key for assoc! must be a number.");}; +function bh(a,b,c){if(a.root.la){if(0<=b&&b<a.F){if(Ig(a)<=b)a.fa[b&31]=c;else{var d=function(){return function(){return function k(d,h){var f=$g(a.root.la,h);if(0===d)f.o[b&31]=c;else{var p=b>>>d&31,m=k(d-5,f.o[p]);f.o[p]=m}return f}}(a)(a.shift,a.root)}();a.root=d}return a}if(b===a.F)return a.Dc(null,c);throw Error(["Index ",v.h(b)," out of bounds for TransientVector of length",v.h(a.F)].join(""));}throw Error("assoc! after persistent!");} +g.W=function(){if(this.root.la)return this.F;throw Error("count after persistent!");};g.$=function(a,b){if(this.root.la)return(0<=b&&b<this.F?Mg(this,b):Lg(b,this.F))[b&31];throw Error("nth after persistent!");};g.ka=function(a,b,c){return 0<=b&&b<this.F?this.$(null,b):c};g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){return"number"===typeof b?this.ka(null,b,c):c}; +g.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return this.V(null,c);case 3:return this.I(null,c,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.c=function(a,c){return this.V(null,c)};a.l=function(a,c,d){return this.I(null,c,d)};return a}();g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))};g.h=function(a){return this.V(null,a)};g.c=function(a,b){return this.I(null,a,b)};function ch(){this.m=2097152;this.J=0} +ch.prototype.equiv=function(a){return this.K(null,a)};ch.prototype.K=function(){return!1};var dh=new ch;function eh(a,b){return Ee(xe(b)&&!ye(b)?H(a)===H(b)?(null!=a?a.m&1048576||q===a.Uf||(a.m?0:Ab(wc,a)):Ab(wc,a))?Ue(function(a,d,e){return G.c(D.l(b,d,dh),e)?!0:new Gd(!1)},!0,a):Vf(function(a){return G.c(D.l(b,y(a),dh),ee(a))},a):null:null)}function fh(a,b,c,d,e){this.i=a;this.Mf=b;this.Ie=c;this.wf=d;this.Se=e}fh.prototype.ja=function(){var a=this.i<this.Ie;return a?a:this.Se.ja()}; +fh.prototype.next=function(){if(this.i<this.Ie){var a=Vd(this.wf,this.i);this.i+=1;return new R(null,2,5,T,[a,cc.c(this.Mf,a)],null)}return this.Se.next()};fh.prototype.remove=function(){return Error("Unsupported operation")};function gh(a){this.s=a}gh.prototype.next=function(){if(null!=this.s){var a=y(this.s),b=J(a,0,null);a=J(a,1,null);this.s=z(this.s);return{value:[b,a],done:!1}}return{value:null,done:!0}};function hh(a){this.s=a} +hh.prototype.next=function(){if(null!=this.s){var a=y(this.s);this.s=z(this.s);return{value:[a,a],done:!1}}return{value:null,done:!0}}; +function ih(a,b){if(b instanceof L)a:{var c=a.length;for(var d=b.ea,e=0;;){if(c<=e){c=-1;break a}if(a[e]instanceof L&&d===a[e].ea){c=e;break a}e+=2}}else if(ca(b)||"number"===typeof b)a:for(c=a.length,d=0;;){if(c<=d){c=-1;break a}if(b===a[d]){c=d;break a}d+=2}else if(b instanceof rd)a:for(c=a.length,d=b.Zb,e=0;;){if(c<=e){c=-1;break a}if(a[e]instanceof rd&&d===a[e].Zb){c=e;break a}e+=2}else if(null==b)a:for(c=a.length,d=0;;){if(c<=d){c=-1;break a}if(null==a[d]){c=d;break a}d+=2}else a:for(c=a.length, +d=0;;){if(c<=d){c=-1;break a}if(G.c(b,a[d])){c=d;break a}d+=2}return c}function jh(a,b,c){this.o=a;this.i=b;this.hb=c;this.m=32374990;this.J=0}g=jh.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)};g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.P=function(){return this.hb};g.Ka=function(){return this.i<this.o.length-2?new jh(this.o,this.i+2,this.hb):null};g.W=function(){return(this.o.length-this.i)/2};g.U=function(){return Ad(this)}; +g.K=function(a,b){return $d(this,b)};g.oa=function(){return tc(wd,this.hb)};g.Fa=function(a,b){return ce(b,this)};g.Ga=function(a,b,c){return de(b,c,this)};g.Ia=function(){return new R(null,2,5,T,[this.o[this.i],this.o[this.i+1]],null)};g.bb=function(){return this.i<this.o.length-2?new jh(this.o,this.i+2,this.hb):wd};g.S=function(){return this};g.T=function(a,b){return new jh(this.o,this.i,b)};g.X=function(a,b){return ae(b,this)};jh.prototype[Fb]=function(){return yd(this)}; +function kh(a,b,c){this.o=a;this.i=b;this.F=c}kh.prototype.ja=function(){return this.i<this.F};kh.prototype.next=function(){var a=new R(null,2,5,T,[this.o[this.i],this.o[this.i+1]],null);this.i+=2;return a};function r(a,b,c,d){this.meta=a;this.F=b;this.o=c;this.w=d;this.m=16647951;this.J=139268}g=r.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)};g.keys=function(){return yd(lh(this))};g.entries=function(){return new gh(E(E(this)))};g.values=function(){return yd(mh(this))}; +g.has=function(a){return He(this,a)};g.get=function(a,b){return this.I(null,a,b)};g.forEach=function(a){for(var b=E(this),c=null,d=0,e=0;;)if(e<d){var f=c.$(null,e),h=J(f,0,null);f=J(f,1,null);a.c?a.c(f,h):a.call(null,f,h);e+=1}else if(b=E(b))Ae(b)?(c=Wc(b),b=Xc(b),h=c,d=H(c),c=h):(c=y(b),h=J(c,0,null),f=J(c,1,null),a.c?a.c(f,h):a.call(null,f,h),b=z(b),c=null,d=0),e=0;else return null};g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){a=ih(this.o,b);return-1===a?c:this.o[a+1]}; +g.Qc=function(a,b,c){a=this.o.length;for(var d=0;;)if(d<a){var e=this.o[d],f=this.o[d+1];c=b.l?b.l(c,e,f):b.call(null,c,e,f);if(Hd(c))return B(c);d+=2}else return c};g.ba=function(){return new kh(this.o,0,2*this.F)};g.P=function(){return this.meta};g.W=function(){return this.F};g.U=function(){var a=this.w;return null!=a?a:this.w=a=Dd(this)}; +g.K=function(a,b){if(xe(b)&&!ye(b)){var c=this.o.length;if(this.F===b.W(null))for(var d=0;;)if(d<c){var e=b.I(null,this.o[d],Ce);if(e!==Ce)if(G.c(this.o[d+1],e))d+=2;else return!1;else return!1}else return!0;else return!1}else return!1};g.Pc=function(){return new nh({},this.o.length,Gb(this.o))};g.oa=function(){return tc(Ef,this.meta)};g.Fa=function(a,b){return Re(this,b)};g.Ga=function(a,b,c){return Se(this,b,c)}; +g.ga=function(a,b){if(0<=ih(this.o,b)){var c=this.o.length,d=c-2;if(0===d)return this.oa(null);d=Array(d);for(var e=0,f=0;;){if(e>=c)return new r(this.meta,this.F-1,d,null);G.c(b,this.o[e])||(d[f]=this.o[e],d[f+1]=this.o[e+1],f+=2);e+=2}}else return this}; +g.O=function(a,b,c){a=ih(this.o,b);if(-1===a){if(this.F<oh){a=this.o;for(var d=a.length,e=Array(d+2),f=0;;)if(f<d)e[f]=a[f],f+=1;else break;e[d]=b;e[d+1]=c;return new r(this.meta,this.F+1,e,null)}return tc(ec(wg.c(ph,this),b,c),this.meta)}if(c===this.o[a+1])return this;b=Gb(this.o);b[a+1]=c;return new r(this.meta,this.F,b,null)};g.yc=function(a,b){return-1!==ih(this.o,b)};g.S=function(){var a=this.o;return 0<=a.length-2?new jh(a,0,null):null};g.T=function(a,b){return new r(b,this.F,this.o,this.w)}; +g.X=function(a,b){if(ze(b))return this.O(null,A.c(b,0),A.c(b,1));for(var c=this,d=E(b);;){if(null==d)return c;var e=y(d);if(ze(e))c=c.O(null,A.c(e,0),A.c(e,1)),d=z(d);else throw Error("conj on a map takes map entries or seqables of map entries");}}; +g.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return this.V(null,c);case 3:return this.I(null,c,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.c=function(a,c){return this.V(null,c)};a.l=function(a,c,d){return this.I(null,c,d)};return a}();g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))};g.h=function(a){return this.V(null,a)};g.c=function(a,b){return this.I(null,a,b)};var Ef=new r(null,0,[],Ed),oh=8; +function ke(a){for(var b=[],c=0;;)if(c<a.length){var d=a[c],e=a[c+1],f=ih(b,d);-1===f?(f=b,f.push(d),f.push(e)):b[f+1]=e;c+=2}else break;return new r(null,b.length/2,b,null)}r.prototype[Fb]=function(){return yd(this)};function nh(a,b,c){this.Uc=a;this.Zc=b;this.o=c;this.m=258;this.J=56}g=nh.prototype;g.W=function(){if(t(this.Uc))return Ze(this.Zc);throw Error("count after persistent!");};g.V=function(a,b){return this.I(null,b,null)}; +g.I=function(a,b,c){if(t(this.Uc))return a=ih(this.o,b),-1===a?c:this.o[a+1];throw Error("lookup after persistent!");};g.Dc=function(a,b){if(t(this.Uc)){if(null!=b?b.m&2048||q===b.sf||(b.m?0:Ab(hc,b)):Ab(hc,b))return this.Cc(null,jc(b),kc(b));for(var c=E(b),d=this;;){var e=y(c);if(t(e))c=z(c),d=d.Cc(null,jc(e),kc(e));else return d}}else throw Error("conj! after persistent!");}; +g.kd=function(){if(t(this.Uc))return this.Uc=!1,new r(null,Ze(this.Zc),this.o,null);throw Error("persistent! called twice");};g.Cc=function(a,b,c){if(t(this.Uc)){a=ih(this.o,b);if(-1===a){if(this.Zc+2<=2*oh)return this.Zc+=2,this.o.push(b),this.o.push(c),this;a:{a=this.Zc;var d=this.o;var e=Oc(ph);for(var f=0;;)if(f<a)e=Rc(e,d[f],d[f+1]),f+=2;else break a}return Rc(e,b,c)}c!==this.o[a+1]&&(this.o[a+1]=c);return this}throw Error("assoc! after persistent!");};function qh(){this.H=!1} +function rh(a,b){return a===b?!0:N(a,b)?!0:G.c(a,b)}function sh(a,b,c){a=Gb(a);a[b]=c;return a}function th(a,b){var c=Array(a.length-2);Be(a,0,c,0,2*b);Be(a,2*(b+1),c,2*b,c.length-2*b);return c}function uh(a,b,c,d){a=a.Gc(b);a.o[c]=d;return a}function vh(a,b,c){for(var d=a.length,e=0,f=c;;)if(e<d){c=a[e];if(null!=c){var h=a[e+1];c=b.l?b.l(f,c,h):b.call(null,f,c,h)}else c=a[e+1],c=null!=c?c.Jc(b,f):f;if(Hd(c))return c;e+=2;f=c}else return f} +function wh(a,b,c,d){this.o=a;this.i=b;this.sd=c;this.Lb=d}wh.prototype.advance=function(){for(var a=this.o.length;;)if(this.i<a){var b=this.o[this.i],c=this.o[this.i+1];null!=b?b=this.sd=new R(null,2,5,T,[b,c],null):null!=c?(b=dd(c),b=b.ja()?this.Lb=b:!1):b=!1;this.i+=2;if(b)return!0}else return!1};wh.prototype.ja=function(){var a=null!=this.sd;return a?a:(a=null!=this.Lb)?a:this.advance()}; +wh.prototype.next=function(){if(null!=this.sd){var a=this.sd;this.sd=null;return a}if(null!=this.Lb)return a=this.Lb.next(),this.Lb.ja()||(this.Lb=null),a;if(this.advance())return this.next();throw Error("No such element");};wh.prototype.remove=function(){return Error("Unsupported operation")};function xh(a,b,c){this.la=a;this.na=b;this.o=c;this.J=131072;this.m=0}g=xh.prototype; +g.Gc=function(a){if(a===this.la)return this;var b=$e(this.na),c=Array(0>b?4:2*(b+1));Be(this.o,0,c,0,2*b);return new xh(a,this.na,c)};g.qd=function(){return yh(this.o,0,null)};g.Jc=function(a,b){return vh(this.o,a,b)};g.sc=function(a,b,c,d){var e=1<<(b>>>a&31);if(0===(this.na&e))return d;var f=$e(this.na&e-1);e=this.o[2*f];f=this.o[2*f+1];return null==e?f.sc(a+5,b,c,d):rh(c,e)?f:d}; +g.Kb=function(a,b,c,d,e,f){var h=1<<(c>>>b&31),k=$e(this.na&h-1);if(0===(this.na&h)){var l=$e(this.na);if(2*l<this.o.length){a=this.Gc(a);b=a.o;f.H=!0;a:for(c=2*(l-k),f=2*k+(c-1),l=2*(k+1)+(c-1);;){if(0===c)break a;b[l]=b[f];--l;--c;--f}b[2*k]=d;b[2*k+1]=e;a.na|=h;return a}if(16<=l){k=[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null];k[c>>>b&31]=zh.Kb(a,b+5,c,d,e,f);for(e=d=0;;)if(32>d)0!== +(this.na>>>d&1)&&(k[d]=null!=this.o[e]?zh.Kb(a,b+5,od(this.o[e]),this.o[e],this.o[e+1],f):this.o[e+1],e+=2),d+=1;else break;return new Ah(a,l+1,k)}b=Array(2*(l+4));Be(this.o,0,b,0,2*k);b[2*k]=d;b[2*k+1]=e;Be(this.o,2*k,b,2*(k+1),2*(l-k));f.H=!0;a=this.Gc(a);a.o=b;a.na|=h;return a}l=this.o[2*k];h=this.o[2*k+1];if(null==l)return l=h.Kb(a,b+5,c,d,e,f),l===h?this:uh(this,a,2*k+1,l);if(rh(d,l))return e===h?this:uh(this,a,2*k+1,e);f.H=!0;f=b+5;b=od(l);if(b===c)e=new Bh(null,b,2,[l,h,d,e]);else{var p=new qh; +e=zh.Kb(a,f,b,l,h,p).Kb(a,f,c,d,e,p)}d=2*k;k=2*k+1;a=this.Gc(a);a.o[d]=null;a.o[k]=e;return a}; +g.Jb=function(a,b,c,d,e){var f=1<<(b>>>a&31),h=$e(this.na&f-1);if(0===(this.na&f)){var k=$e(this.na);if(16<=k){h=[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null];h[b>>>a&31]=zh.Jb(a+5,b,c,d,e);for(d=c=0;;)if(32>c)0!==(this.na>>>c&1)&&(h[c]=null!=this.o[d]?zh.Jb(a+5,od(this.o[d]),this.o[d],this.o[d+1],e):this.o[d+1],d+=2),c+=1;else break;return new Ah(null,k+1,h)}a=Array(2*(k+1));Be(this.o, +0,a,0,2*h);a[2*h]=c;a[2*h+1]=d;Be(this.o,2*h,a,2*(h+1),2*(k-h));e.H=!0;return new xh(null,this.na|f,a)}var l=this.o[2*h];f=this.o[2*h+1];if(null==l)return k=f.Jb(a+5,b,c,d,e),k===f?this:new xh(null,this.na,sh(this.o,2*h+1,k));if(rh(c,l))return d===f?this:new xh(null,this.na,sh(this.o,2*h+1,d));e.H=!0;e=this.na;k=this.o;a+=5;var p=od(l);if(p===b)c=new Bh(null,p,2,[l,f,c,d]);else{var m=new qh;c=zh.Jb(a,p,l,f,m).Jb(a,b,c,d,m)}a=2*h;h=2*h+1;d=Gb(k);d[a]=null;d[h]=c;return new xh(null,e,d)}; +g.rd=function(a,b,c){var d=1<<(b>>>a&31);if(0===(this.na&d))return this;var e=$e(this.na&d-1),f=this.o[2*e],h=this.o[2*e+1];return null==f?(a=h.rd(a+5,b,c),a===h?this:null!=a?new xh(null,this.na,sh(this.o,2*e+1,a)):this.na===d?null:new xh(null,this.na^d,th(this.o,e))):rh(c,f)?new xh(null,this.na^d,th(this.o,e)):this};g.ba=function(){return new wh(this.o,0,null,null)};var zh=new xh(null,0,[]);function Ch(a,b,c){this.o=a;this.i=b;this.Lb=c} +Ch.prototype.ja=function(){for(var a=this.o.length;;){if(null!=this.Lb&&this.Lb.ja())return!0;if(this.i<a){var b=this.o[this.i];this.i+=1;null!=b&&(this.Lb=dd(b))}else return!1}};Ch.prototype.next=function(){if(this.ja())return this.Lb.next();throw Error("No such element");};Ch.prototype.remove=function(){return Error("Unsupported operation")};function Ah(a,b,c){this.la=a;this.F=b;this.o=c;this.J=131072;this.m=0}g=Ah.prototype;g.Gc=function(a){return a===this.la?this:new Ah(a,this.F,Gb(this.o))}; +g.qd=function(){return Dh(this.o,0,null)};g.Jc=function(a,b){for(var c=this.o.length,d=0,e=b;;)if(d<c){var f=this.o[d];if(null!=f&&(e=f.Jc(a,e),Hd(e)))return e;d+=1}else return e};g.sc=function(a,b,c,d){var e=this.o[b>>>a&31];return null!=e?e.sc(a+5,b,c,d):d};g.Kb=function(a,b,c,d,e,f){var h=c>>>b&31,k=this.o[h];if(null==k)return a=uh(this,a,h,zh.Kb(a,b+5,c,d,e,f)),a.F+=1,a;b=k.Kb(a,b+5,c,d,e,f);return b===k?this:uh(this,a,h,b)}; +g.Jb=function(a,b,c,d,e){var f=b>>>a&31,h=this.o[f];if(null==h)return new Ah(null,this.F+1,sh(this.o,f,zh.Jb(a+5,b,c,d,e)));a=h.Jb(a+5,b,c,d,e);return a===h?this:new Ah(null,this.F,sh(this.o,f,a))}; +g.rd=function(a,b,c){var d=b>>>a&31,e=this.o[d];if(null!=e){a=e.rd(a+5,b,c);if(a===e)d=this;else if(null==a)if(8>=this.F)a:{e=this.o;a=e.length;b=Array(2*(this.F-1));c=0;for(var f=1,h=0;;)if(c<a)c!==d&&null!=e[c]&&(b[f]=e[c],f+=2,h|=1<<c),c+=1;else{d=new xh(null,h,b);break a}}else d=new Ah(null,this.F-1,sh(this.o,d,a));else d=new Ah(null,this.F,sh(this.o,d,a));return d}return this};g.ba=function(){return new Ch(this.o,0,null)}; +function Eh(a,b,c){b*=2;for(var d=0;;)if(d<b){if(rh(c,a[d]))return d;d+=2}else return-1}function Bh(a,b,c,d){this.la=a;this.ec=b;this.F=c;this.o=d;this.J=131072;this.m=0}g=Bh.prototype;g.Gc=function(a){if(a===this.la)return this;var b=Array(2*(this.F+1));Be(this.o,0,b,0,2*this.F);return new Bh(a,this.ec,this.F,b)};g.qd=function(){return yh(this.o,0,null)};g.Jc=function(a,b){return vh(this.o,a,b)};g.sc=function(a,b,c,d){a=Eh(this.o,this.F,c);return 0>a?d:rh(c,this.o[a])?this.o[a+1]:d}; +g.Kb=function(a,b,c,d,e,f){if(c===this.ec){b=Eh(this.o,this.F,d);if(-1===b){if(this.o.length>2*this.F)return b=2*this.F,c=2*this.F+1,a=this.Gc(a),a.o[b]=d,a.o[c]=e,f.H=!0,a.F+=1,a;c=this.o.length;b=Array(c+2);Be(this.o,0,b,0,c);b[c]=d;b[c+1]=e;f.H=!0;d=this.F+1;a===this.la?(this.o=b,this.F=d,a=this):a=new Bh(this.la,this.ec,d,b);return a}return this.o[b+1]===e?this:uh(this,a,b+1,e)}return(new xh(a,1<<(this.ec>>>b&31),[null,this,null,null])).Kb(a,b,c,d,e,f)}; +g.Jb=function(a,b,c,d,e){return b===this.ec?(a=Eh(this.o,this.F,c),-1===a?(a=2*this.F,b=Array(a+2),Be(this.o,0,b,0,a),b[a]=c,b[a+1]=d,e.H=!0,new Bh(null,this.ec,this.F+1,b)):G.c(this.o[a+1],d)?this:new Bh(null,this.ec,this.F,sh(this.o,a+1,d))):(new xh(null,1<<(this.ec>>>a&31),[null,this])).Jb(a,b,c,d,e)};g.rd=function(a,b,c){a=Eh(this.o,this.F,c);return-1===a?this:1===this.F?null:new Bh(null,this.ec,this.F-1,th(this.o,Ze(a)))};g.ba=function(){return new wh(this.o,0,null,null)}; +function Fh(a,b,c,d,e){this.meta=a;this.Mb=b;this.i=c;this.s=d;this.w=e;this.m=32374988;this.J=0}g=Fh.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)};g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.P=function(){return this.meta};g.Ka=function(){return null==this.s?yh(this.Mb,this.i+2,null):yh(this.Mb,this.i,z(this.s))};g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)}; +g.K=function(a,b){return $d(this,b)};g.oa=function(){return tc(wd,this.meta)};g.Fa=function(a,b){return ce(b,this)};g.Ga=function(a,b,c){return de(b,c,this)};g.Ia=function(){return null==this.s?new R(null,2,5,T,[this.Mb[this.i],this.Mb[this.i+1]],null):y(this.s)};g.bb=function(){var a=null==this.s?yh(this.Mb,this.i+2,null):yh(this.Mb,this.i,z(this.s));return null!=a?a:wd};g.S=function(){return this};g.T=function(a,b){return new Fh(b,this.Mb,this.i,this.s,this.w)};g.X=function(a,b){return ae(b,this)}; +Fh.prototype[Fb]=function(){return yd(this)};function yh(a,b,c){if(null==c)for(c=a.length;;)if(b<c){if(null!=a[b])return new Fh(null,a,b,null,null);var d=a[b+1];if(t(d)&&(d=d.qd(),t(d)))return new Fh(null,a,b+2,d,null);b+=2}else return null;else return new Fh(null,a,b,c,null)}function Gh(a,b,c,d,e){this.meta=a;this.Mb=b;this.i=c;this.s=d;this.w=e;this.m=32374988;this.J=0}g=Gh.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)}; +g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.P=function(){return this.meta};g.Ka=function(){return Dh(this.Mb,this.i,z(this.s))};g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)};g.K=function(a,b){return $d(this,b)};g.oa=function(){return tc(wd,this.meta)}; +g.Fa=function(a,b){return ce(b,this)};g.Ga=function(a,b,c){return de(b,c,this)};g.Ia=function(){return y(this.s)};g.bb=function(){var a=Dh(this.Mb,this.i,z(this.s));return null!=a?a:wd};g.S=function(){return this};g.T=function(a,b){return new Gh(b,this.Mb,this.i,this.s,this.w)};g.X=function(a,b){return ae(b,this)};Gh.prototype[Fb]=function(){return yd(this)}; +function Dh(a,b,c){if(null==c)for(c=a.length;;)if(b<c){var d=a[b];if(t(d)&&(d=d.qd(),t(d)))return new Gh(null,a,b+1,d,null);b+=1}else return null;else return new Gh(null,a,b,c,null)}function Hh(a,b,c){this.eb=a;this.bf=b;this.xe=c}Hh.prototype.ja=function(){return!this.xe||this.bf.ja()};Hh.prototype.next=function(){if(this.xe)return this.bf.next();this.xe=!0;return new R(null,2,5,T,[null,this.eb],null)};Hh.prototype.remove=function(){return Error("Unsupported operation")}; +function Jh(a,b,c,d,e,f){this.meta=a;this.F=b;this.root=c;this.cb=d;this.eb=e;this.w=f;this.m=16123663;this.J=139268}g=Jh.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)};g.keys=function(){return yd(lh(this))};g.entries=function(){return new gh(E(E(this)))};g.values=function(){return yd(mh(this))};g.has=function(a){return He(this,a)};g.get=function(a,b){return this.I(null,a,b)}; +g.forEach=function(a){for(var b=E(this),c=null,d=0,e=0;;)if(e<d){var f=c.$(null,e),h=J(f,0,null);f=J(f,1,null);a.c?a.c(f,h):a.call(null,f,h);e+=1}else if(b=E(b))Ae(b)?(c=Wc(b),b=Xc(b),h=c,d=H(c),c=h):(c=y(b),h=J(c,0,null),f=J(c,1,null),a.c?a.c(f,h):a.call(null,f,h),b=z(b),c=null,d=0),e=0;else return null};g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){return null==b?this.cb?this.eb:c:null==this.root?c:this.root.sc(0,od(b),b,c)}; +g.Qc=function(a,b,c){a=this.cb?b.l?b.l(c,null,this.eb):b.call(null,c,null,this.eb):c;return Hd(a)?B(a):null!=this.root?Jd(this.root.Jc(b,a)):a};g.ba=function(){var a=this.root?dd(this.root):Cf();return this.cb?new Hh(this.eb,a,!1):a};g.P=function(){return this.meta};g.W=function(){return this.F};g.U=function(){var a=this.w;return null!=a?a:this.w=a=Dd(this)};g.K=function(a,b){return eh(this,b)};g.Pc=function(){return new Kh({},this.root,this.F,this.cb,this.eb)};g.oa=function(){return tc(ph,this.meta)}; +g.ga=function(a,b){if(null==b)return this.cb?new Jh(this.meta,this.F-1,this.root,!1,null,null):this;if(null==this.root)return this;var c=this.root.rd(0,od(b),b);return c===this.root?this:new Jh(this.meta,this.F-1,c,this.cb,this.eb,null)}; +g.O=function(a,b,c){if(null==b)return this.cb&&c===this.eb?this:new Jh(this.meta,this.cb?this.F:this.F+1,this.root,!0,c,null);a=new qh;b=(null==this.root?zh:this.root).Jb(0,od(b),b,c,a);return b===this.root?this:new Jh(this.meta,a.H?this.F+1:this.F,b,this.cb,this.eb,null)};g.yc=function(a,b){return null==b?this.cb:null==this.root?!1:this.root.sc(0,od(b),b,Ce)!==Ce};g.S=function(){if(0<this.F){var a=null!=this.root?this.root.qd():null;return this.cb?ae(new R(null,2,5,T,[null,this.eb],null),a):a}return null}; +g.T=function(a,b){return new Jh(b,this.F,this.root,this.cb,this.eb,this.w)};g.X=function(a,b){if(ze(b))return this.O(null,A.c(b,0),A.c(b,1));for(var c=this,d=E(b);;){if(null==d)return c;var e=y(d);if(ze(e))c=c.O(null,A.c(e,0),A.c(e,1)),d=z(d);else throw Error("conj on a map takes map entries or seqables of map entries");}}; +g.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return this.V(null,c);case 3:return this.I(null,c,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.c=function(a,c){return this.V(null,c)};a.l=function(a,c,d){return this.I(null,c,d)};return a}();g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))};g.h=function(a){return this.V(null,a)};g.c=function(a,b){return this.I(null,a,b)};var ph=new Jh(null,0,null,!1,null,Ed); +function Pe(a,b){for(var c=a.length,d=0,e=Oc(ph);;)if(d<c){var f=d+1;e=e.Cc(null,a[d],b[d]);d=f}else return Qc(e)}Jh.prototype[Fb]=function(){return yd(this)};function Kh(a,b,c,d,e){this.la=a;this.root=b;this.count=c;this.cb=d;this.eb=e;this.m=258;this.J=56} +function Lh(a,b,c){if(a.la){if(null==b)a.eb!==c&&(a.eb=c),a.cb||(a.count+=1,a.cb=!0);else{var d=new qh;b=(null==a.root?zh:a.root).Kb(a.la,0,od(b),b,c,d);b!==a.root&&(a.root=b);d.H&&(a.count+=1)}return a}throw Error("assoc! after persistent!");}g=Kh.prototype;g.W=function(){if(this.la)return this.count;throw Error("count after persistent!");};g.V=function(a,b){return null==b?this.cb?this.eb:null:null==this.root?null:this.root.sc(0,od(b),b)}; +g.I=function(a,b,c){return null==b?this.cb?this.eb:c:null==this.root?c:this.root.sc(0,od(b),b,c)};g.Dc=function(a,b){a:if(this.la)if(null!=b?b.m&2048||q===b.sf||(b.m?0:Ab(hc,b)):Ab(hc,b))var c=Lh(this,jc(b),kc(b));else{c=E(b);for(var d=this;;){var e=y(c);if(t(e))c=z(c),d=Lh(d,jc(e),kc(e));else{c=d;break a}}}else throw Error("conj! after persistent");return c}; +g.kd=function(){if(this.la){this.la=null;var a=new Jh(null,this.count,this.root,this.cb,this.eb,null)}else throw Error("persistent! called twice");return a};g.Cc=function(a,b,c){return Lh(this,b,c)};function Mh(a,b,c){for(var d=b;;)if(null!=a)b=c?a.left:a.right,d=ge.c(d,a),a=b;else return d}function Nh(a,b,c,d,e){this.meta=a;this.stack=b;this.vc=c;this.F=d;this.w=e;this.m=32374990;this.J=0}g=Nh.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)}; +g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.P=function(){return this.meta};g.Ka=function(){var a=y(this.stack);a=Mh(this.vc?a.right:a.left,z(this.stack),this.vc);return null==a?null:new Nh(null,a,this.vc,this.F-1,null)}; +g.W=function(){return 0>this.F?H(z(this))+1:this.F};g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)};g.K=function(a,b){return $d(this,b)};g.oa=function(){return tc(wd,this.meta)};g.Fa=function(a,b){return ce(b,this)};g.Ga=function(a,b,c){return de(b,c,this)};g.Ia=function(){var a=this.stack;return null==a?null:nc(a)};g.bb=function(){var a=y(this.stack);a=Mh(this.vc?a.right:a.left,z(this.stack),this.vc);return null!=a?new Nh(null,a,this.vc,this.F-1,null):wd};g.S=function(){return this}; +g.T=function(a,b){return new Nh(b,this.stack,this.vc,this.F,this.w)};g.X=function(a,b){return ae(b,this)};Nh.prototype[Fb]=function(){return yd(this)};function Oh(a,b,c){return new Nh(null,Mh(a,null,b),b,c,null)} +function Ph(a,b,c,d){return c instanceof Qh?c.left instanceof Qh?new Qh(c.key,c.H,c.left.bc(),new Rh(a,b,c.right,d,null),null):c.right instanceof Qh?new Qh(c.right.key,c.right.H,new Rh(c.key,c.H,c.left,c.right.left,null),new Rh(a,b,c.right.right,d,null),null):new Rh(a,b,c,d,null):new Rh(a,b,c,d,null)} +function Sh(a,b,c,d){return d instanceof Qh?d.right instanceof Qh?new Qh(d.key,d.H,new Rh(a,b,c,d.left,null),d.right.bc(),null):d.left instanceof Qh?new Qh(d.left.key,d.left.H,new Rh(a,b,c,d.left.left,null),new Rh(d.key,d.H,d.left.right,d.right,null),null):new Rh(a,b,c,d,null):new Rh(a,b,c,d,null)} +function Th(a,b,c,d){if(c instanceof Qh)return new Qh(a,b,c.bc(),d,null);if(d instanceof Rh)return Sh(a,b,c,d.ud());if(d instanceof Qh&&d.left instanceof Rh)return new Qh(d.left.key,d.left.H,new Rh(a,b,c,d.left.left,null),Sh(d.key,d.H,d.left.right,d.right.ud()),null);throw Error("red-black tree invariant violation");} +function Uh(a,b,c,d){if(d instanceof Qh)return new Qh(a,b,c,d.bc(),null);if(c instanceof Rh)return Ph(a,b,c.ud(),d);if(c instanceof Qh&&c.right instanceof Rh)return new Qh(c.right.key,c.right.H,Ph(c.key,c.H,c.left.ud(),c.right.left),new Rh(a,b,c.right.right,d,null),null);throw Error("red-black tree invariant violation");} +var Vh=function Vh(a,b,c){var e=null!=a.left?function(){var e=a.left;return Vh.l?Vh.l(e,b,c):Vh.call(null,e,b,c)}():c;if(Hd(e))return e;var f=function(){var c=a.key,f=a.H;return b.l?b.l(e,c,f):b.call(null,e,c,f)}();if(Hd(f))return f;if(null!=a.right){var h=a.right;return Vh.l?Vh.l(h,b,f):Vh.call(null,h,b,f)}return f};function Rh(a,b,c,d,e){this.key=a;this.H=b;this.left=c;this.right=d;this.w=e;this.m=32402207;this.J=0}g=Rh.prototype; +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}(); +g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}();g.Ee=function(a){return a.He(this)};g.ud=function(){return new Qh(this.key,this.H,this.left,this.right,null)};g.bc=function(){return this};g.De=function(a){return a.Ge(this)};g.replace=function(a,b,c,d){return new Rh(a,b,c,d,null)}; +g.Ge=function(a){return new Rh(a.key,a.H,this,a.right,null)};g.He=function(a){return new Rh(a.key,a.H,a.left,this,null)};g.Jc=function(a,b){return Vh(this,a,b)};g.V=function(a,b){return this.ka(null,b,null)};g.I=function(a,b,c){return this.ka(null,b,c)};g.$=function(a,b){if(0===b)return this.key;if(1===b)return this.H;throw Error("Index out of bounds");};g.ka=function(a,b,c){return 0===b?this.key:1===b?this.H:c};g.dc=function(a,b,c){return(new R(null,2,5,T,[this.key,this.H],null)).dc(null,b,c)}; +g.P=function(){return null};g.W=function(){return 2};g.fd=function(){return this.key};g.gd=function(){return this.H};g.Ac=function(){return this.H};g.Bc=function(){return new R(null,1,5,T,[this.key],null)};g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)};g.K=function(a,b){return $d(this,b)};g.oa=function(){return he};g.Fa=function(a,b){return Kd(this,b)};g.Ga=function(a,b,c){return Ld(this,b,c)};g.O=function(a,b,c){return K.l(new R(null,2,5,T,[this.key,this.H],null),b,c)}; +g.yc=function(a,b){return 0===b||1===b};g.S=function(){var a=this.key;return Tb(Tb(wd,this.H),a)};g.T=function(a,b){return tc(new R(null,2,5,T,[this.key,this.H],null),b)};g.X=function(a,b){return new R(null,3,5,T,[this.key,this.H,b],null)}; +g.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return this.$(null,c);case 3:return this.ka(null,c,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.c=function(a,c){return this.$(null,c)};a.l=function(a,c,d){return this.ka(null,c,d)};return a}();g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))};g.h=function(a){return this.$(null,a)};g.c=function(a,b){return this.ka(null,a,b)};Rh.prototype[Fb]=function(){return yd(this)}; +function Qh(a,b,c,d,e){this.key=a;this.H=b;this.left=c;this.right=d;this.w=e;this.m=32402207;this.J=0}g=Qh.prototype;g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}(); +g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}();g.Ee=function(a){return new Qh(this.key,this.H,this.left,a,null)};g.ud=function(){throw Error("red-black tree invariant violation");};g.bc=function(){return new Rh(this.key,this.H,this.left,this.right,null)}; +g.De=function(a){return new Qh(this.key,this.H,a,this.right,null)};g.replace=function(a,b,c,d){return new Qh(a,b,c,d,null)};g.Ge=function(a){return this.left instanceof Qh?new Qh(this.key,this.H,this.left.bc(),new Rh(a.key,a.H,this.right,a.right,null),null):this.right instanceof Qh?new Qh(this.right.key,this.right.H,new Rh(this.key,this.H,this.left,this.right.left,null),new Rh(a.key,a.H,this.right.right,a.right,null),null):new Rh(a.key,a.H,this,a.right,null)}; +g.He=function(a){return this.right instanceof Qh?new Qh(this.key,this.H,new Rh(a.key,a.H,a.left,this.left,null),this.right.bc(),null):this.left instanceof Qh?new Qh(this.left.key,this.left.H,new Rh(a.key,a.H,a.left,this.left.left,null),new Rh(this.key,this.H,this.left.right,this.right,null),null):new Rh(a.key,a.H,a.left,this,null)};g.Jc=function(a,b){return Vh(this,a,b)};g.V=function(a,b){return this.ka(null,b,null)};g.I=function(a,b,c){return this.ka(null,b,c)}; +g.$=function(a,b){if(0===b)return this.key;if(1===b)return this.H;throw Error("Index out of bounds");};g.ka=function(a,b,c){return 0===b?this.key:1===b?this.H:c};g.dc=function(a,b,c){return(new R(null,2,5,T,[this.key,this.H],null)).dc(null,b,c)};g.P=function(){return null};g.W=function(){return 2};g.fd=function(){return this.key};g.gd=function(){return this.H};g.Ac=function(){return this.H};g.Bc=function(){return new R(null,1,5,T,[this.key],null)}; +g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)};g.K=function(a,b){return $d(this,b)};g.oa=function(){return he};g.Fa=function(a,b){return Kd(this,b)};g.Ga=function(a,b,c){return Ld(this,b,c)};g.O=function(a,b,c){return K.l(new R(null,2,5,T,[this.key,this.H],null),b,c)};g.yc=function(a,b){return 0===b||1===b};g.S=function(){var a=this.key;return Tb(Tb(wd,this.H),a)};g.T=function(a,b){return tc(new R(null,2,5,T,[this.key,this.H],null),b)}; +g.X=function(a,b){return new R(null,3,5,T,[this.key,this.H,b],null)};g.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return this.$(null,c);case 3:return this.ka(null,c,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.c=function(a,c){return this.$(null,c)};a.l=function(a,c,d){return this.ka(null,c,d)};return a}();g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))};g.h=function(a){return this.$(null,a)}; +g.c=function(a,b){return this.ka(null,a,b)};Qh.prototype[Fb]=function(){return yd(this)}; +var Wh=function Wh(a,b,c,d,e){if(null==b)return new Qh(c,d,null,null,null);var h=function(){var d=b.key;return a.c?a.c(c,d):a.call(null,c,d)}();if(0===h)return e[0]=b,null;if(0>h)return h=function(){var h=b.left;return Wh.Z?Wh.Z(a,h,c,d,e):Wh.call(null,a,h,c,d,e)}(),null!=h?b.De(h):null;h=function(){var h=b.right;return Wh.Z?Wh.Z(a,h,c,d,e):Wh.call(null,a,h,c,d,e)}();return null!=h?b.Ee(h):null},Xh=function Xh(a,b){if(null==a)return b;if(null==b)return a;if(a instanceof Qh){if(b instanceof Qh){var d= +function(){var d=a.right,f=b.left;return Xh.c?Xh.c(d,f):Xh.call(null,d,f)}();return d instanceof Qh?new Qh(d.key,d.H,new Qh(a.key,a.H,a.left,d.left,null),new Qh(b.key,b.H,d.right,b.right,null),null):new Qh(a.key,a.H,a.left,new Qh(b.key,b.H,d,b.right,null),null)}return new Qh(a.key,a.H,a.left,function(){var d=a.right;return Xh.c?Xh.c(d,b):Xh.call(null,d,b)}(),null)}if(b instanceof Qh)return new Qh(b.key,b.H,function(){var d=b.left;return Xh.c?Xh.c(a,d):Xh.call(null,a,d)}(),b.right,null);d=function(){var d= +a.right,f=b.left;return Xh.c?Xh.c(d,f):Xh.call(null,d,f)}();return d instanceof Qh?new Qh(d.key,d.H,new Rh(a.key,a.H,a.left,d.left,null),new Rh(b.key,b.H,d.right,b.right,null),null):Th(a.key,a.H,a.left,new Rh(b.key,b.H,d,b.right,null))},Yh=function Yh(a,b,c,d){if(null!=b){var f=function(){var d=b.key;return a.c?a.c(c,d):a.call(null,c,d)}();if(0===f)return d[0]=b,Xh(b.left,b.right);if(0>f)return f=function(){var f=b.left;return Yh.M?Yh.M(a,f,c,d):Yh.call(null,a,f,c,d)}(),null!=f||null!=d[0]?b.left instanceof +Rh?Th(b.key,b.H,f,b.right):new Qh(b.key,b.H,f,b.right,null):null;f=function(){var f=b.right;return Yh.M?Yh.M(a,f,c,d):Yh.call(null,a,f,c,d)}();return null!=f||null!=d[0]?b.right instanceof Rh?Uh(b.key,b.H,b.left,f):new Qh(b.key,b.H,b.left,f,null):null}return null},Zh=function Zh(a,b,c,d){var f=b.key,h=a.c?a.c(c,f):a.call(null,c,f);return 0===h?b.replace(f,d,b.left,b.right):0>h?b.replace(f,b.H,function(){var f=b.left;return Zh.M?Zh.M(a,f,c,d):Zh.call(null,a,f,c,d)}(),b.right):b.replace(f,b.H,b.left, +function(){var f=b.right;return Zh.M?Zh.M(a,f,c,d):Zh.call(null,a,f,c,d)}())};function $h(a,b,c,d,e){this.Bb=a;this.mc=b;this.F=c;this.meta=d;this.w=e;this.m=418776847;this.J=8192}g=$h.prototype;g.forEach=function(a){for(var b=E(this),c=null,d=0,e=0;;)if(e<d){var f=c.$(null,e),h=J(f,0,null);f=J(f,1,null);a.c?a.c(f,h):a.call(null,f,h);e+=1}else if(b=E(b))Ae(b)?(c=Wc(b),b=Xc(b),h=c,d=H(c),c=h):(c=y(b),h=J(c,0,null),f=J(c,1,null),a.c?a.c(f,h):a.call(null,f,h),b=z(b),c=null,d=0),e=0;else return null}; +g.get=function(a,b){return this.I(null,a,b)};g.entries=function(){return new gh(E(E(this)))};g.toString=function(){return fd(this)};g.keys=function(){return yd(lh(this))};g.values=function(){return yd(mh(this))};g.equiv=function(a){return this.K(null,a)};function ai(a,b){for(var c=a.mc;;)if(null!=c){var d=c.key;d=a.Bb.c?a.Bb.c(b,d):a.Bb.call(null,b,d);if(0===d)return c;c=0>d?c.left:c.right}else return null}g.has=function(a){return He(this,a)};g.V=function(a,b){return this.I(null,b,null)}; +g.I=function(a,b,c){a=ai(this,b);return null!=a?a.H:c};g.Qc=function(a,b,c){return null!=this.mc?Jd(Vh(this.mc,b,c)):c};g.P=function(){return this.meta};g.W=function(){return this.F};g.Rc=function(){return 0<this.F?Oh(this.mc,!1,this.F):null};g.U=function(){var a=this.w;return null!=a?a:this.w=a=Dd(this)};g.K=function(a,b){return eh(this,b)};g.oa=function(){return new $h(this.Bb,null,0,this.meta,0)}; +g.ga=function(a,b){var c=[null],d=Yh(this.Bb,this.mc,b,c);return null==d?null==Vd(c,0)?this:new $h(this.Bb,null,0,this.meta,null):new $h(this.Bb,d.bc(),this.F-1,this.meta,null)};g.O=function(a,b,c){a=[null];var d=Wh(this.Bb,this.mc,b,c,a);return null==d?(a=Vd(a,0),G.c(c,a.H)?this:new $h(this.Bb,Zh(this.Bb,this.mc,b,c),this.F,this.meta,null)):new $h(this.Bb,d.bc(),this.F+1,this.meta,null)};g.yc=function(a,b){return null!=ai(this,b)};g.S=function(){return 0<this.F?Oh(this.mc,!0,this.F):null}; +g.T=function(a,b){return new $h(this.Bb,this.mc,this.F,b,this.w)};g.X=function(a,b){if(ze(b))return this.O(null,A.c(b,0),A.c(b,1));for(var c=this,d=E(b);;){if(null==d)return c;var e=y(d);if(ze(e))c=c.O(null,A.c(e,0),A.c(e,1)),d=z(d);else throw Error("conj on a map takes map entries or seqables of map entries");}}; +g.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return this.V(null,c);case 3:return this.I(null,c,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.c=function(a,c){return this.V(null,c)};a.l=function(a,c,d){return this.I(null,c,d)};return a}();g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))};g.h=function(a){return this.V(null,a)};g.c=function(a,b){return this.I(null,a,b)};var bi=new $h(Ke,null,0,null,Ed);$h.prototype[Fb]=function(){return yd(this)}; +var U=function U(a){for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return U.A(0<c.length?new Jb(c.slice(0),0,null):null)};U.A=function(a){for(var b=E(a),c=Oc(ph);;)if(b){a=z(z(b));var d=y(b);b=ee(b);c=Rc(c,d,b);b=a}else return Qc(c)};U.L=0;U.N=function(a){return U.A(E(a))};var ci=function ci(a){for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return ci.A(0<c.length?new Jb(c.slice(0),0,null):null)}; +ci.A=function(a){a=a instanceof Jb&&0===a.i?a.o:Lb(a);return ke(a)};ci.L=0;ci.N=function(a){return ci.A(E(a))};function di(a){for(var b=[],c=arguments.length,d=0;;)if(d<c)b.push(arguments[d]),d+=1;else break;a:for(b=E(0<b.length?new Jb(b.slice(0),0,null):null),d=bi;;)if(b)c=z(z(b)),d=K.l(d,y(b),ee(b)),b=c;else break a;return d}function ei(a,b){this.da=a;this.hb=b;this.m=32374988;this.J=0}g=ei.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)}; +g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.P=function(){return this.hb};g.Ka=function(){var a=(null!=this.da?this.da.m&128||q===this.da.Id||(this.da.m?0:Ab(Zb,this.da)):Ab(Zb,this.da))?this.da.Ka(null):z(this.da);return null==a?null:new ei(a,this.hb)};g.U=function(){return Ad(this)}; +g.K=function(a,b){return $d(this,b)};g.oa=function(){return tc(wd,this.hb)};g.Fa=function(a,b){return ce(b,this)};g.Ga=function(a,b,c){return de(b,c,this)};g.Ia=function(){return this.da.Ia(null).fd(null)};g.bb=function(){var a=(null!=this.da?this.da.m&128||q===this.da.Id||(this.da.m?0:Ab(Zb,this.da)):Ab(Zb,this.da))?this.da.Ka(null):z(this.da);return null!=a?new ei(a,this.hb):wd};g.S=function(){return this};g.T=function(a,b){return new ei(this.da,b)};g.X=function(a,b){return ae(b,this)}; +ei.prototype[Fb]=function(){return yd(this)};function lh(a){return(a=E(a))?new ei(a,null):null}function fi(a){return jc(a)}function gi(a,b){this.da=a;this.hb=b;this.m=32374988;this.J=0}g=gi.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)}; +g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.P=function(){return this.hb};g.Ka=function(){var a=(null!=this.da?this.da.m&128||q===this.da.Id||(this.da.m?0:Ab(Zb,this.da)):Ab(Zb,this.da))?this.da.Ka(null):z(this.da);return null==a?null:new gi(a,this.hb)};g.U=function(){return Ad(this)}; +g.K=function(a,b){return $d(this,b)};g.oa=function(){return tc(wd,this.hb)};g.Fa=function(a,b){return ce(b,this)};g.Ga=function(a,b,c){return de(b,c,this)};g.Ia=function(){return this.da.Ia(null).gd(null)};g.bb=function(){var a=(null!=this.da?this.da.m&128||q===this.da.Id||(this.da.m?0:Ab(Zb,this.da)):Ab(Zb,this.da))?this.da.Ka(null):z(this.da);return null!=a?new gi(a,this.hb):wd};g.S=function(){return this};g.T=function(a,b){return new gi(this.da,b)};g.X=function(a,b){return ae(b,this)}; +gi.prototype[Fb]=function(){return yd(this)};function mh(a){return(a=E(a))?new gi(a,null):null}var hi=function hi(a){for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return hi.A(0<c.length?new Jb(c.slice(0),0,null):null)};hi.A=function(a){return t(Wf(Ve,a))?Te(function(a,c){return ge.c(t(a)?a:Ef,c)},a):null};hi.L=0;hi.N=function(a){return hi.A(E(a))}; +var ii=function ii(a){for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return ii.A(arguments[0],1<c.length?new Jb(c.slice(1),0,null):null)};ii.A=function(a,b){return t(Wf(Ve,b))?Te(function(a){return function(b,c){return Mb(a,t(b)?b:Ef,E(c))}}(function(b,d){var c=y(d),f=ee(d);return He(b,c)?K.l(b,c,function(){var d=D.c(b,c);return a.c?a.c(d,f):a.call(null,d,f)}()):K.l(b,c,f)}),b):null};ii.L=1;ii.N=function(a){var b=y(a);a=z(a);return ii.A(b,a)}; +function ji(a){for(var b=Ef,c=E(new R(null,7,5,T,[ki,li,mi,ni,oi,pi,qi],null));;)if(c){var d=y(c),e=D.l(a,d,ri);b=G.c(e,ri)?b:K.l(b,d,e);c=z(c)}else return tc(b,qe(a))}function si(a){this.te=a}si.prototype.ja=function(){return this.te.ja()};si.prototype.next=function(){if(this.te.ja())return this.te.next().fa[0];throw Error("No such element");};si.prototype.remove=function(){return Error("Unsupported operation")};function ti(a,b,c){this.meta=a;this.gc=b;this.w=c;this.m=15077647;this.J=139268}g=ti.prototype; +g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)};g.keys=function(){return yd(E(this))};g.entries=function(){return new hh(E(E(this)))};g.values=function(){return yd(E(this))};g.has=function(a){return He(this,a)}; +g.forEach=function(a){for(var b=E(this),c=null,d=0,e=0;;)if(e<d){var f=c.$(null,e),h=J(f,0,null);f=J(f,1,null);a.c?a.c(f,h):a.call(null,f,h);e+=1}else if(b=E(b))Ae(b)?(c=Wc(b),b=Xc(b),h=c,d=H(c),c=h):(c=y(b),h=J(c,0,null),f=J(c,1,null),a.c?a.c(f,h):a.call(null,f,h),b=z(b),c=null,d=0),e=0;else return null};g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){return dc(this.gc,b)?b:c};g.ba=function(){return new si(dd(this.gc))};g.P=function(){return this.meta};g.W=function(){return Qb(this.gc)}; +g.U=function(){var a=this.w;return null!=a?a:this.w=a=Dd(this)};g.K=function(a,b){return ve(b)&&H(this)===H(b)&&Ue(function(){return function(a,d){var c=He(b,d);return c?c:new Gd(!1)}}(this),!0,this.gc)};g.Pc=function(){return new ui(Oc(this.gc))};g.oa=function(){return tc(vi,this.meta)};g.ie=function(a,b){return new ti(this.meta,gc(this.gc,b),null)};g.S=function(){return lh(this.gc)};g.T=function(a,b){return new ti(b,this.gc,this.w)}; +g.X=function(a,b){return new ti(this.meta,K.l(this.gc,b,null),null)};g.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return this.V(null,c);case 3:return this.I(null,c,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.c=function(a,c){return this.V(null,c)};a.l=function(a,c,d){return this.I(null,c,d)};return a}();g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))};g.h=function(a){return this.V(null,a)}; +g.c=function(a,b){return this.I(null,a,b)};var vi=new ti(null,Ef,Ed);function Je(a){for(var b=a.length,c=Oc(vi),d=0;;)if(d<b)Pc(c,a[d]),d+=1;else break;return Qc(c)}ti.prototype[Fb]=function(){return yd(this)};function ui(a){this.lc=a;this.J=136;this.m=259}g=ui.prototype;g.Dc=function(a,b){this.lc=Rc(this.lc,b,null);return this};g.kd=function(){return new ti(null,Qc(this.lc),null)};g.W=function(){return H(this.lc)};g.V=function(a,b){return this.I(null,b,null)}; +g.I=function(a,b,c){return cc.l(this.lc,b,Ce)===Ce?c:b};g.call=function(){function a(a,b,c){return cc.l(this.lc,b,Ce)===Ce?c:b}function b(a,b){return cc.l(this.lc,b,Ce)===Ce?null:b}var c=null;c=function(c,e,f){switch(arguments.length){case 2:return b.call(this,0,e);case 3:return a.call(this,0,e,f)}throw Error("Invalid arity: "+(arguments.length-1));};c.c=b;c.l=a;return c}();g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))}; +g.h=function(a){return cc.l(this.lc,a,Ce)===Ce?null:a};g.c=function(a,b){return cc.l(this.lc,a,Ce)===Ce?b:a};function wi(a,b,c){this.meta=a;this.$b=b;this.w=c;this.m=417730831;this.J=8192}g=wi.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)};g.keys=function(){return yd(E(this))};g.entries=function(){return new hh(E(E(this)))};g.values=function(){return yd(E(this))};g.has=function(a){return He(this,a)}; +g.forEach=function(a){for(var b=E(this),c=null,d=0,e=0;;)if(e<d){var f=c.$(null,e),h=J(f,0,null);f=J(f,1,null);a.c?a.c(f,h):a.call(null,f,h);e+=1}else if(b=E(b))Ae(b)?(c=Wc(b),b=Xc(b),h=c,d=H(c),c=h):(c=y(b),h=J(c,0,null),f=J(c,1,null),a.c?a.c(f,h):a.call(null,f,h),b=z(b),c=null,d=0),e=0;else return null};g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){a=ai(this.$b,b);return null!=a?a.key:c};g.P=function(){return this.meta};g.W=function(){return H(this.$b)}; +g.Rc=function(){return 0<H(this.$b)?ig.c(fi,Ic(this.$b)):null};g.U=function(){var a=this.w;return null!=a?a:this.w=a=Dd(this)};g.K=function(a,b){return ve(b)&&H(this)===H(b)&&Ue(function(){return function(a,d){var c=He(b,d);return c?c:new Gd(!1)}}(this),!0,this.$b)};g.oa=function(){return new wi(this.meta,Rb(this.$b),0)};g.ie=function(a,b){return new wi(this.meta,le.c(this.$b,b),null)};g.S=function(){return lh(this.$b)};g.T=function(a,b){return new wi(b,this.$b,this.w)}; +g.X=function(a,b){return new wi(this.meta,K.l(this.$b,b,null),null)};g.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return this.V(null,c);case 3:return this.I(null,c,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.c=function(a,c){return this.V(null,c)};a.l=function(a,c,d){return this.I(null,c,d)};return a}();g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))};g.h=function(a){return this.V(null,a)}; +g.c=function(a,b){return this.I(null,a,b)};var xi=new wi(null,bi,Ed);wi.prototype[Fb]=function(){return yd(this)};function yi(a){a=E(a);if(null==a)return vi;if(a instanceof Jb&&0===a.i)return Je(a.o);for(var b=Oc(vi);;)if(null!=a){var c=z(a);b=b.Dc(null,a.Ia(null));a=c}else return Qc(b)}var zi=function zi(a){for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return zi.A(0<c.length?new Jb(c.slice(0),0,null):null)};zi.A=function(a){return Mb(Tb,xi,a)};zi.L=0;zi.N=function(a){return zi.A(E(a))}; +function jf(a){if(null!=a&&(a.J&4096||q===a.Oe))return a.hd(null);if("string"===typeof a)return a;throw Error(["Doesn't support name: ",v.h(a)].join(""));}var Ai=function Ai(a){switch(arguments.length){case 2:return Ai.c(arguments[0],arguments[1]);case 3:return Ai.l(arguments[0],arguments[1],arguments[2]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return Ai.A(arguments[0],arguments[1],arguments[2],new Jb(c.slice(3),0,null))}};Ai.c=function(a,b){return b}; +Ai.l=function(a,b,c){return(a.h?a.h(b):a.call(null,b))>(a.h?a.h(c):a.call(null,c))?b:c};Ai.A=function(a,b,c,d){return Mb(function(b,c){return Ai.l(a,b,c)},Ai.l(a,b,c),d)};Ai.N=function(a){var b=y(a),c=z(a);a=y(c);var d=z(c);c=y(d);d=z(d);return Ai.A(b,a,c,d)};Ai.L=3;function Bi(a,b){return new kf(null,function(){var c=E(b);if(c){var d=y(c);d=a.h?a.h(d):a.call(null,d);c=t(d)?ae(y(c),Bi(a,vd(c))):null}else c=null;return c},null,null)}function Di(a,b,c){this.i=a;this.end=b;this.step=c} +Di.prototype.ja=function(){return 0<this.step?this.i<this.end:this.i>this.end};Di.prototype.next=function(){var a=this.i;this.i+=this.step;return a};function Ei(a,b,c,d,e){this.meta=a;this.start=b;this.end=c;this.step=d;this.w=e;this.m=32375006;this.J=139264}g=Ei.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)}; +g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.$=function(a,b){if(0<=b&&b<this.W(null))return this.start+b*this.step;if(0<=b&&this.start>this.end&&0===this.step)return this.start;throw Error("Index out of bounds");}; +g.ka=function(a,b,c){return 0<=b&&b<this.W(null)?this.start+b*this.step:0<=b&&this.start>this.end&&0===this.step?this.start:c};g.ba=function(){return new Di(this.start,this.end,this.step)};g.P=function(){return this.meta};g.Ka=function(){return 0<this.step?this.start+this.step<this.end?new Ei(this.meta,this.start+this.step,this.end,this.step,null):null:this.start+this.step>this.end?new Ei(this.meta,this.start+this.step,this.end,this.step,null):null}; +g.W=function(){return wb(this.S(null))?0:Math.ceil((this.end-this.start)/this.step)};g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)};g.K=function(a,b){return $d(this,b)};g.oa=function(){return tc(wd,this.meta)};g.Fa=function(a,b){return Kd(this,b)};g.Ga=function(a,b,c){for(a=this.start;;)if(0<this.step?a<this.end:a>this.end){c=b.c?b.c(c,a):b.call(null,c,a);if(Hd(c))return B(c);a+=this.step}else return c};g.Ia=function(){return null==this.S(null)?null:this.start}; +g.bb=function(){return null!=this.S(null)?new Ei(this.meta,this.start+this.step,this.end,this.step,null):wd};g.S=function(){return 0<this.step?this.start<this.end?this:null:0>this.step?this.start>this.end?this:null:this.start===this.end?null:this};g.T=function(a,b){return new Ei(b,this.start,this.end,this.step,this.w)};g.X=function(a,b){return ae(b,this)};Ei.prototype[Fb]=function(){return yd(this)};function Fi(a,b,c){return new Ei(null,a,b,c,null)} +function Gi(a,b){return new R(null,2,5,T,[Bi(a,b),ng(a,b)],null)} +function Hi(a){var b=y;return function(){function c(c,d,e){return new R(null,2,5,T,[b.l?b.l(c,d,e):b.call(null,c,d,e),a.l?a.l(c,d,e):a.call(null,c,d,e)],null)}function d(c,d){return new R(null,2,5,T,[b.c?b.c(c,d):b.call(null,c,d),a.c?a.c(c,d):a.call(null,c,d)],null)}function e(c){return new R(null,2,5,T,[b.h?b.h(c):b.call(null,c),a.h?a.h(c):a.call(null,c)],null)}function f(){return new R(null,2,5,T,[b.B?b.B():b.call(null),a.B?a.B():a.call(null)],null)}var h=null,k=function(){function c(a,b,c,e){var f= +null;if(3<arguments.length){f=0;for(var h=Array(arguments.length-3);f<h.length;)h[f]=arguments[f+3],++f;f=new Jb(h,0,null)}return d.call(this,a,b,c,f)}function d(c,d,e,f){return new R(null,2,5,T,[Af(b,c,d,e,f),Af(a,c,d,e,f)],null)}c.L=3;c.N=function(a){var b=y(a);a=z(a);var c=y(a);a=z(a);var e=y(a);a=vd(a);return d(b,c,e,a)};c.A=d;return c}();h=function(a,b,h,u){switch(arguments.length){case 0:return f.call(this);case 1:return e.call(this,a);case 2:return d.call(this,a,b);case 3:return c.call(this, +a,b,h);default:var m=null;if(3<arguments.length){m=0;for(var l=Array(arguments.length-3);m<l.length;)l[m]=arguments[m+3],++m;m=new Jb(l,0,null)}return k.A(a,b,h,m)}throw Error("Invalid arity: "+(arguments.length-1));};h.L=3;h.N=k.N;h.B=f;h.h=e;h.c=d;h.l=c;h.A=k.A;return h}()}function Ii(a){a:for(var b=a;;)if(E(b))b=z(b);else break a;return a} +function Ji(a,b){if("string"===typeof b){var c=a.exec(b);return G.c(y(c),b)?1===H(c)?y(c):Wg(c):null}throw new TypeError("re-matches must match against a string.");} +function Y(a,b,c,d,e,f,h){var k=lb;lb=null==lb?null:lb-1;try{if(null!=lb&&0>lb)return Jc(a,"#");Jc(a,c);if(0===tb.h(f))E(h)&&Jc(a,function(){var a=Ki.h(f);return t(a)?a:"..."}());else{if(E(h)){var l=y(h);b.l?b.l(l,a,f):b.call(null,l,a,f)}for(var p=z(h),m=tb.h(f)-1;;)if(!p||null!=m&&0===m){E(p)&&0===m&&(Jc(a,d),Jc(a,function(){var a=Ki.h(f);return t(a)?a:"..."}()));break}else{Jc(a,d);var u=y(p);c=a;h=f;b.l?b.l(u,c,h):b.call(null,u,c,h);var w=z(p);c=m-1;p=w;m=c}}return Jc(a,e)}finally{lb=k}} +function Li(a,b){for(var c=E(b),d=null,e=0,f=0;;)if(f<e){var h=d.$(null,f);Jc(a,h);f+=1}else if(c=E(c))d=c,Ae(d)?(c=Wc(d),e=Xc(d),d=c,h=H(c),c=e,e=h):(h=y(d),Jc(a,h),c=z(d),d=null,e=0),f=0;else return null}var Mi={'"':'\\"',"\\":"\\\\","\b":"\\b","\f":"\\f","\n":"\\n","\r":"\\r","\t":"\\t"};function Ni(a){return[v.h('"'),v.h(a.replace(RegExp('[\\\\"\b\f\n\r\t]',"g"),function(a){return Mi[a]})),v.h('"')].join("")} +function Oi(a,b){var c=Ee(D.c(a,rb));return c?(c=null!=b?b.m&131072||q===b.tf?!0:!1:!1)?null!=qe(b):c:c} +function Pi(a,b,c){if(null==a)return Jc(b,"nil");Oi(c,a)&&(Jc(b,"^"),Qi(qe(a),b,c),Jc(b," "));if(a.qc)return a.Ec(a,b,c);if(null!=a&&(a.m&2147483648||q===a.ma))return a.R(null,b,c);if(!0===a||!1===a)return Jc(b,""+v.h(a));if("number"===typeof a)return Jc(b,isNaN(a)?"##NaN":a===Number.POSITIVE_INFINITY?"##Inf":a===Number.NEGATIVE_INFINITY?"##-Inf":""+v.h(a));if(null!=a&&a.constructor===Object)return Jc(b,"#js "),Ri(ig.c(function(b){return new R(null,2,5,T,[null!=Ji(/[A-Za-z_\*\+\?!\-'][\w\*\+\?!\-']*/, +b)?hf.h(b):b,a[b]],null)},Ea(a)),b,c);if(vb(a))return Y(b,Qi,"#js ["," ","]",c,a);if(ca(a))return t(qb.h(c))?Jc(b,Ni(a)):Jc(b,a);if(ha(a)){var d=a.name;c=t(function(){var a=null==d;return a?a:/^[\s\xa0]*$/.test(d)}())?"Function":d;return Li(b,be(["#object[",c,"","]"]))}if(a instanceof Date)return c=function(a,b){for(var c=""+v.h(a);;)if(H(c)<b)c=["0",v.h(c)].join("");else return c},Li(b,be(['#inst "',""+v.h(a.getUTCFullYear()),"-",c(a.getUTCMonth()+1,2),"-",c(a.getUTCDate(),2),"T",c(a.getUTCHours(), +2),":",c(a.getUTCMinutes(),2),":",c(a.getUTCSeconds(),2),".",c(a.getUTCMilliseconds(),3),"-",'00:00"']));if(a instanceof RegExp)return Li(b,be(['#"',a.source,'"']));if(t(function(){var b=null==a?null:a.constructor;return null==b?null:b.Tb}()))return Li(b,be(["#object[",a.constructor.Tb.replace(RegExp("/","g"),"."),"]"]));d=function(){var b=null==a?null:a.constructor;return null==b?null:b.name}();c=t(function(){var a=null==d;return a?a:/^[\s\xa0]*$/.test(d)}())?"Object":d;return null==a.constructor? +Li(b,be(["#object[",c,"]"])):Li(b,be(["#object[",c," ",""+v.h(a),"]"]))}function Qi(a,b,c){var d=Si.h(c);return t(d)?(c=K.l(c,Ti,Pi),d.l?d.l(a,b,c):d.call(null,a,b,c)):Pi(a,b,c)}function Ui(a,b){var c=new cb;a:{var d=new ed(c);Qi(y(a),d,b);for(var e=E(z(a)),f=null,h=0,k=0;;)if(k<h){var l=f.$(null,k);Jc(d," ");Qi(l,d,b);k+=1}else if(e=E(e))f=e,Ae(f)?(e=Wc(f),h=Xc(f),f=e,l=H(e),e=h,h=l):(l=y(f),Jc(d," "),Qi(l,d,b),e=z(f),f=null,h=0),k=0;else break a}return c} +function Vi(a){var b=ob();return te(a)?"":""+v.h(Ui(a,b))}function Wi(a,b,c,d,e){return Y(d,function(a,b,d){var e=jc(a);c.l?c.l(e,b,d):c.call(null,e,b,d);Jc(b," ");a=kc(a);return c.l?c.l(a,b,d):c.call(null,a,b,d)},[v.h(a),"{"].join(""),", ","}",e,E(b))}function Ri(a,b,c){var d=Qi,e=(xe(a),null),f=J(e,0,null);e=J(e,1,null);return t(f)?Wi(["#:",v.h(f)].join(""),e,d,b,c):Wi(null,a,d,b,c)}hg.prototype.ma=q; +hg.prototype.R=function(a,b,c){Jc(b,"#object [cljs.core.Volatile ");Qi(new r(null,1,[Xi,this.state],null),b,c);return Jc(b,"]")};Jb.prototype.ma=q;Jb.prototype.R=function(a,b,c){return Y(b,Qi,"("," ",")",c,this)};kf.prototype.ma=q;kf.prototype.R=function(a,b,c){return Y(b,Qi,"("," ",")",c,this)};Nh.prototype.ma=q;Nh.prototype.R=function(a,b,c){return Y(b,Qi,"("," ",")",c,this)};Fh.prototype.ma=q;Fh.prototype.R=function(a,b,c){return Y(b,Qi,"("," ",")",c,this)};Rh.prototype.ma=q; +Rh.prototype.R=function(a,b,c){return Y(b,Qi,"["," ","]",c,this)};jh.prototype.ma=q;jh.prototype.R=function(a,b,c){return Y(b,Qi,"("," ",")",c,this)};wi.prototype.ma=q;wi.prototype.R=function(a,b,c){return Y(b,Qi,"#{"," ","}",c,this)};Ug.prototype.ma=q;Ug.prototype.R=function(a,b,c){return Y(b,Qi,"("," ",")",c,this)};ef.prototype.ma=q;ef.prototype.R=function(a,b,c){return Y(b,Qi,"("," ",")",c,this)};Zd.prototype.ma=q;Zd.prototype.R=function(a,b,c){return Y(b,Qi,"("," ",")",c,this)}; +Jh.prototype.ma=q;Jh.prototype.R=function(a,b,c){return Ri(this,b,c)};Gh.prototype.ma=q;Gh.prototype.R=function(a,b,c){return Y(b,Qi,"("," ",")",c,this)};Yg.prototype.ma=q;Yg.prototype.R=function(a,b,c){return Y(b,Qi,"["," ","]",c,this)};$h.prototype.ma=q;$h.prototype.R=function(a,b,c){return Ri(this,b,c)};ti.prototype.ma=q;ti.prototype.R=function(a,b,c){return Y(b,Qi,"#{"," ","}",c,this)};pf.prototype.ma=q;pf.prototype.R=function(a,b,c){return Y(b,Qi,"("," ",")",c,this)};cg.prototype.ma=q; +cg.prototype.R=function(a,b,c){Jc(b,"#object [cljs.core.Atom ");Qi(new r(null,1,[Xi,this.state],null),b,c);return Jc(b,"]")};gi.prototype.ma=q;gi.prototype.R=function(a,b,c){return Y(b,Qi,"("," ",")",c,this)};Qh.prototype.ma=q;Qh.prototype.R=function(a,b,c){return Y(b,Qi,"["," ","]",c,this)};R.prototype.ma=q;R.prototype.R=function(a,b,c){return Y(b,Qi,"["," ","]",c,this)};bf.prototype.ma=q;bf.prototype.R=function(a,b){return Jc(b,"()")};r.prototype.ma=q; +r.prototype.R=function(a,b,c){return Ri(this,b,c)};Ei.prototype.ma=q;Ei.prototype.R=function(a,b,c){return Y(b,Qi,"("," ",")",c,this)};Sf.prototype.ma=q;Sf.prototype.R=function(a,b,c){return Y(b,Qi,"("," ",")",c,this)};ei.prototype.ma=q;ei.prototype.R=function(a,b,c){return Y(b,Qi,"("," ",")",c,this)};af.prototype.ma=q;af.prototype.R=function(a,b,c){return Y(b,Qi,"("," ",")",c,this)};rd.prototype.zc=q; +rd.prototype.cc=function(a,b){if(b instanceof rd)return sd(this,b);throw Error(["Cannot compare ",v.h(this)," to ",v.h(b)].join(""));};L.prototype.zc=q;L.prototype.cc=function(a,b){if(b instanceof L)return ff(this,b);throw Error(["Cannot compare ",v.h(this)," to ",v.h(b)].join(""));};Yg.prototype.zc=q;Yg.prototype.cc=function(a,b){if(ze(b))return Le(this,b);throw Error(["Cannot compare ",v.h(this)," to ",v.h(b)].join(""));};R.prototype.zc=q; +R.prototype.cc=function(a,b){if(ze(b))return Le(this,b);throw Error(["Cannot compare ",v.h(this)," to ",v.h(b)].join(""));};Rh.prototype.zc=q;Rh.prototype.cc=function(a,b){if(ze(b))return Le(this,b);throw Error(["Cannot compare ",v.h(this)," to ",v.h(b)].join(""));};Qh.prototype.zc=q;Qh.prototype.cc=function(a,b){if(ze(b))return Le(this,b);throw Error(["Cannot compare ",v.h(this)," to ",v.h(b)].join(""));};var Yi=null; +function Zi(){null==Yi&&(Yi=dg.h(0));return td.h([v.h("reagent"),v.h(gg.c(Yi,Fd))].join(""))}function $i(){}var aj=function aj(a){if(null!=a&&null!=a.pf)return a.pf(a);var c=aj[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=aj._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("IEncodeJS.-clj-\x3ejs",a);};function bj(a){return(null!=a?q===a.nf||(a.Tc?0:Ab($i,a)):Ab($i,a))?aj(a):"string"===typeof a||"number"===typeof a||a instanceof L||a instanceof rd?cj(a):Vi(be([a]))} +var cj=function cj(a){if(null==a)return null;if(null!=a?q===a.nf||(a.Tc?0:Ab($i,a)):Ab($i,a))return aj(a);if(a instanceof L)return jf(a);if(a instanceof rd)return""+v.h(a);if(xe(a)){var c={};a=E(a);for(var d=null,e=0,f=0;;)if(f<e){var h=d.$(null,f),k=J(h,0,null),l=J(h,1,null);h=c;k=bj(k);l=cj.h?cj.h(l):cj.call(null,l);h[k]=l;f+=1}else if(a=E(a))Ae(a)?(e=Wc(a),a=Xc(a),d=e,e=H(e)):(d=y(a),e=J(d,0,null),f=J(d,1,null),d=c,e=bj(e),f=cj.h?cj.h(f):cj.call(null,f),d[e]=f,a=z(a),d=null,e=0),f=0;else break; +return c}if(ue(a)){c=[];a=E(ig.c(cj,a));d=null;for(f=e=0;;)if(f<e)h=d.$(null,f),c.push(h),f+=1;else if(a=E(a))d=a,Ae(d)?(a=Wc(d),f=Xc(d),d=a,e=H(a),a=f):(a=y(d),c.push(a),a=z(d),d=null,e=0),f=0;else break;return c}return a};function dj(){}var ej=function ej(a,b){if(null!=a&&null!=a.mf)return a.mf(a,b);var d=ej[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=ej._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("IEncodeClojure.-js-\x3eclj",a);}; +function fj(a){var b=be([gj,!0]),c=null!=b&&(b.m&64||q===b.G)?P(U,b):b,d=D.c(c,gj);return function(a,c,d,k){return function m(e){return(null!=e?q===e.lf||(e.Tc?0:Ab(dj,e)):Ab(dj,e))?ej(e,P(ci,b)):De(e)?Ii(ig.c(m,e)):ue(e)?wg.c(ie(e),ig.c(m,e)):vb(e)?Wg(ig.c(m,e)):Bb(e)===Object?wg.c(Ef,function(){return function(a,b,c,d){return function M(f){return new kf(null,function(a,b,c,d){return function(){for(;;){var a=E(f);if(a){if(Ae(a)){var b=Wc(a),c=H(b),h=of(c);a:for(var k=0;;)if(k<c){var p=A.c(b,k);p= +new R(null,2,5,T,[d.h?d.h(p):d.call(null,p),m(e[p])],null);h.add(p);k+=1}else{b=!0;break a}return b?qf(h.Da(),M(Xc(a))):qf(h.Da(),null)}h=y(a);return ae(new R(null,2,5,T,[d.h?d.h(h):d.call(null,h),m(e[h])],null),M(vd(a)))}return null}}}(a,b,c,d),null,null)}}(a,c,d,k)(Ea(e))}()):e}}(b,c,d,t(d)?hf:v)(a)} +function hj(a){return function(b){return function(){function c(a){var b=null;if(0<arguments.length){b=0;for(var c=Array(arguments.length-0);b<c.length;)c[b]=arguments[b+0],++b;b=new Jb(c,0,null)}return d.call(this,b)}function d(c){var d=D.l(B(b),c,Ce);d===Ce&&(d=P(a,c),gg.M(b,K,c,d));return d}c.L=0;c.N=function(a){a=E(a);return d(a)};c.A=d;return c}()}(dg.h(Ef))}var ij=null;function jj(){null==ij&&(ij=dg.h(new r(null,3,[kj,Ef,lj,Ef,mj,Ef],null)));return ij} +function nj(a,b,c){var d=G.c(b,c);if(d)return d;d=mj.h(a);d=d.h?d.h(b):d.call(null,b);if(!(d=He(d,c))&&(d=ze(c)))if(d=ze(b))if(d=H(c)===H(b)){d=!0;for(var e=0;;)if(d&&e!==H(c))d=nj(a,b.h?b.h(e):b.call(null,e),c.h?c.h(e):c.call(null,e)),e+=1;else return d}else return d;else return d;else return d}function oj(a){var b=B(jj());return Bf(D.c(kj.h(b),a))}function pj(a,b,c,d){gg.c(a,function(){return B(b)});gg.c(c,function(){return B(d)})} +var qj=function qj(a,b,c){var e=function(){var b=B(c);return b.h?b.h(a):b.call(null,a)}();e=t(t(e)?e.h?e.h(b):e.call(null,b):e)?!0:null;if(t(e))return e;e=function(){for(var e=oj(b);;)if(0<H(e)){var h=y(e);qj.l?qj.l(a,h,c):qj.call(null,a,h,c);e=vd(e)}else return null}();if(t(e))return e;e=function(){for(var e=oj(a);;)if(0<H(e)){var h=y(e);qj.l?qj.l(h,b,c):qj.call(null,h,b,c);e=vd(e)}else return null}();return t(e)?e:!1};function rj(a,b,c,d){c=qj(a,b,c);return t(c)?c:nj(d,a,b)} +var sj=function sj(a,b,c,d,e,f,h,k){var p=Mb(function(d,f){var h=J(f,0,null);J(f,1,null);if(nj(B(c),b,h)){var k=(k=null==d)?k:rj(h,y(d),e,B(c));k=t(k)?f:d;if(!t(rj(y(k),h,e,B(c))))throw Error(["Multiple methods in multimethod '",v.h(a),"' match dispatch value: ",v.h(b)," -\x3e ",v.h(h)," and ",v.h(y(k)),", and neither is preferred"].join(""));return k}return d},null,B(d)),m=function(){var a;if(a=null==p)a=B(d),a=a.h?a.h(k):a.call(null,k);return t(a)?new R(null,2,5,T,[k,a],null):p}();if(t(m)){if(G.c(B(h), +B(c)))return gg.M(f,K,b,ee(m)),ee(m);pj(f,d,h,c);return sj.Ha?sj.Ha(a,b,c,d,e,f,h,k):sj.call(null,a,b,c,d,e,f,h,k)}return null};function tj(a,b){throw Error(["No method in multimethod '",v.h(a),"' for dispatch value: ",v.h(b)].join(""));}function uj(a,b,c,d,e,f,h,k){this.name=a;this.D=b;this.vf=c;this.Rd=d;this.Vd=e;this.Kf=f;this.Ud=h;this.Ed=k;this.m=4194305;this.J=4352}g=uj.prototype; +g.call=function(){function a(a,b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M,S,X,Q,Ga){a=this;var W=oe(a.D,b,c,d,e,be([f,h,k,m,l,p,u,w,x,F,C,I,M,S,X,Q,Ga])),ka=vj(this,W);t(ka)||tj(a.name,W);return oe(ka,b,c,d,e,be([f,h,k,m,l,p,u,w,x,F,C,I,M,S,X,Q,Ga]))}function b(a,b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M,S,X,Q){a=this;var W=a.D.Xa?a.D.Xa(b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M,S,X,Q):a.D.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M,S,X,Q),ka=vj(this,W);t(ka)||tj(a.name,W);return ka.Xa?ka.Xa(b,c,d,e,f,h,k,m,l,p,u,w,x,F,C, +I,M,S,X,Q):ka.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M,S,X,Q)}function c(a,b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M,S,X){a=this;var W=a.D.Wa?a.D.Wa(b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M,S,X):a.D.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M,S,X),ka=vj(this,W);t(ka)||tj(a.name,W);return ka.Wa?ka.Wa(b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M,S,X):ka.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M,S,X)}function d(a,b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M,S){a=this;var W=a.D.Va?a.D.Va(b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M,S):a.D.call(null, +b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M,S),ka=vj(this,W);t(ka)||tj(a.name,W);return ka.Va?ka.Va(b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M,S):ka.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M,S)}function e(a,b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M){a=this;var W=a.D.Ua?a.D.Ua(b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M):a.D.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M),ka=vj(this,W);t(ka)||tj(a.name,W);return ka.Ua?ka.Ua(b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M):ka.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I,M)}function f(a,b,c,d,e,f,h,k,m, +l,p,u,w,x,F,C,I){a=this;var W=a.D.Ta?a.D.Ta(b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I):a.D.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I),ka=vj(this,W);t(ka)||tj(a.name,W);return ka.Ta?ka.Ta(b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I):ka.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,F,C,I)}function h(a,b,c,d,e,f,h,k,m,l,p,u,w,x,F,C){a=this;var W=a.D.Sa?a.D.Sa(b,c,d,e,f,h,k,m,l,p,u,w,x,F,C):a.D.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,F,C),ka=vj(this,W);t(ka)||tj(a.name,W);return ka.Sa?ka.Sa(b,c,d,e,f,h,k,m,l,p,u,w,x,F,C):ka.call(null,b, +c,d,e,f,h,k,m,l,p,u,w,x,F,C)}function k(a,b,c,d,e,f,h,k,m,l,p,u,w,x,F){a=this;var W=a.D.Ra?a.D.Ra(b,c,d,e,f,h,k,m,l,p,u,w,x,F):a.D.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,F),C=vj(this,W);t(C)||tj(a.name,W);return C.Ra?C.Ra(b,c,d,e,f,h,k,m,l,p,u,w,x,F):C.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x,F)}function l(a,b,c,d,e,f,h,k,m,l,p,u,w,x){a=this;var W=a.D.Qa?a.D.Qa(b,c,d,e,f,h,k,m,l,p,u,w,x):a.D.call(null,b,c,d,e,f,h,k,m,l,p,u,w,x),F=vj(this,W);t(F)||tj(a.name,W);return F.Qa?F.Qa(b,c,d,e,f,h,k,m,l,p,u,w,x):F.call(null, +b,c,d,e,f,h,k,m,l,p,u,w,x)}function p(a,b,c,d,e,f,h,k,m,l,p,u,w){a=this;var x=a.D.Pa?a.D.Pa(b,c,d,e,f,h,k,m,l,p,u,w):a.D.call(null,b,c,d,e,f,h,k,m,l,p,u,w),W=vj(this,x);t(W)||tj(a.name,x);return W.Pa?W.Pa(b,c,d,e,f,h,k,m,l,p,u,w):W.call(null,b,c,d,e,f,h,k,m,l,p,u,w)}function m(a,b,c,d,e,f,h,k,m,l,p,u){a=this;var w=a.D.Oa?a.D.Oa(b,c,d,e,f,h,k,m,l,p,u):a.D.call(null,b,c,d,e,f,h,k,m,l,p,u),x=vj(this,w);t(x)||tj(a.name,w);return x.Oa?x.Oa(b,c,d,e,f,h,k,m,l,p,u):x.call(null,b,c,d,e,f,h,k,m,l,p,u)}function u(a, +b,c,d,e,f,h,k,m,l,p){a=this;var u=a.D.Na?a.D.Na(b,c,d,e,f,h,k,m,l,p):a.D.call(null,b,c,d,e,f,h,k,m,l,p),w=vj(this,u);t(w)||tj(a.name,u);return w.Na?w.Na(b,c,d,e,f,h,k,m,l,p):w.call(null,b,c,d,e,f,h,k,m,l,p)}function w(a,b,c,d,e,f,h,k,m,l){a=this;var p=a.D.Za?a.D.Za(b,c,d,e,f,h,k,m,l):a.D.call(null,b,c,d,e,f,h,k,m,l),u=vj(this,p);t(u)||tj(a.name,p);return u.Za?u.Za(b,c,d,e,f,h,k,m,l):u.call(null,b,c,d,e,f,h,k,m,l)}function x(a,b,c,d,e,f,h,k,m){a=this;var l=a.D.Ha?a.D.Ha(b,c,d,e,f,h,k,m):a.D.call(null, +b,c,d,e,f,h,k,m),p=vj(this,l);t(p)||tj(a.name,l);return p.Ha?p.Ha(b,c,d,e,f,h,k,m):p.call(null,b,c,d,e,f,h,k,m)}function C(a,b,c,d,e,f,h,k){a=this;var m=a.D.Ya?a.D.Ya(b,c,d,e,f,h,k):a.D.call(null,b,c,d,e,f,h,k),l=vj(this,m);t(l)||tj(a.name,m);return l.Ya?l.Ya(b,c,d,e,f,h,k):l.call(null,b,c,d,e,f,h,k)}function F(a,b,c,d,e,f,h){a=this;var k=a.D.Ca?a.D.Ca(b,c,d,e,f,h):a.D.call(null,b,c,d,e,f,h),m=vj(this,k);t(m)||tj(a.name,k);return m.Ca?m.Ca(b,c,d,e,f,h):m.call(null,b,c,d,e,f,h)}function I(a,b,c,d, +e,f){a=this;var h=a.D.Z?a.D.Z(b,c,d,e,f):a.D.call(null,b,c,d,e,f),k=vj(this,h);t(k)||tj(a.name,h);return k.Z?k.Z(b,c,d,e,f):k.call(null,b,c,d,e,f)}function M(a,b,c,d,e){a=this;var f=a.D.M?a.D.M(b,c,d,e):a.D.call(null,b,c,d,e),h=vj(this,f);t(h)||tj(a.name,f);return h.M?h.M(b,c,d,e):h.call(null,b,c,d,e)}function S(a,b,c,d){a=this;var e=a.D.l?a.D.l(b,c,d):a.D.call(null,b,c,d),f=vj(this,e);t(f)||tj(a.name,e);return f.l?f.l(b,c,d):f.call(null,b,c,d)}function X(a,b,c){a=this;var d=a.D.c?a.D.c(b,c):a.D.call(null, +b,c),e=vj(this,d);t(e)||tj(a.name,d);return e.c?e.c(b,c):e.call(null,b,c)}function Ga(a,b){a=this;var c=a.D.h?a.D.h(b):a.D.call(null,b),d=vj(this,c);t(d)||tj(a.name,c);return d.h?d.h(b):d.call(null,b)}function db(a){a=this;var b=a.D.B?a.D.B():a.D.call(null),c=vj(this,b);t(c)||tj(a.name,b);return c.B?c.B():c.call(null)}var Q=null;Q=function(Q,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Wd,Xb,ic,xc,Sc,Bd,se,Lf,Ih,kl){switch(arguments.length){case 1:return db.call(this,Q);case 2:return Ga.call(this,Q,Ha);case 3:return X.call(this, +Q,Ha,Ja);case 4:return S.call(this,Q,Ha,Ja,Oa);case 5:return M.call(this,Q,Ha,Ja,Oa,Ba);case 6:return I.call(this,Q,Ha,Ja,Oa,Ba,W);case 7:return F.call(this,Q,Ha,Ja,Oa,Ba,W,$a);case 8:return C.call(this,Q,Ha,Ja,Oa,Ba,W,$a,ka);case 9:return x.call(this,Q,Ha,Ja,Oa,Ba,W,$a,ka,jb);case 10:return w.call(this,Q,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb);case 11:return u.call(this,Q,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb);case 12:return m.call(this,Q,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib);case 13:return p.call(this,Q,Ha,Ja,Oa,Ba,W,$a, +ka,jb,nb,zb,Ib,Wd);case 14:return l.call(this,Q,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Wd,Xb);case 15:return k.call(this,Q,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Wd,Xb,ic);case 16:return h.call(this,Q,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Wd,Xb,ic,xc);case 17:return f.call(this,Q,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Wd,Xb,ic,xc,Sc);case 18:return e.call(this,Q,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Wd,Xb,ic,xc,Sc,Bd);case 19:return d.call(this,Q,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Wd,Xb,ic,xc,Sc,Bd,se);case 20:return c.call(this,Q, +Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Wd,Xb,ic,xc,Sc,Bd,se,Lf);case 21:return b.call(this,Q,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Wd,Xb,ic,xc,Sc,Bd,se,Lf,Ih);case 22:return a.call(this,Q,Ha,Ja,Oa,Ba,W,$a,ka,jb,nb,zb,Ib,Wd,Xb,ic,xc,Sc,Bd,se,Lf,Ih,kl)}throw Error("Invalid arity: "+(arguments.length-1));};Q.h=db;Q.c=Ga;Q.l=X;Q.M=S;Q.Z=M;Q.Ca=I;Q.Ya=F;Q.Ha=C;Q.Za=x;Q.Na=w;Q.Oa=u;Q.Pa=m;Q.Qa=p;Q.Ra=l;Q.Sa=k;Q.Ta=h;Q.Ua=f;Q.Va=e;Q.Wa=d;Q.Xa=c;Q.he=b;Q.qf=a;return Q}(); +g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))};g.B=function(){var a=this.D.B?this.D.B():this.D.call(null),b=vj(this,a);t(b)||tj(this.name,a);return b.B?b.B():b.call(null)};g.h=function(a){var b=this.D.h?this.D.h(a):this.D.call(null,a),c=vj(this,b);t(c)||tj(this.name,b);return c.h?c.h(a):c.call(null,a)};g.c=function(a,b){var c=this.D.c?this.D.c(a,b):this.D.call(null,a,b),d=vj(this,c);t(d)||tj(this.name,c);return d.c?d.c(a,b):d.call(null,a,b)}; +g.l=function(a,b,c){var d=this.D.l?this.D.l(a,b,c):this.D.call(null,a,b,c),e=vj(this,d);t(e)||tj(this.name,d);return e.l?e.l(a,b,c):e.call(null,a,b,c)};g.M=function(a,b,c,d){var e=this.D.M?this.D.M(a,b,c,d):this.D.call(null,a,b,c,d),f=vj(this,e);t(f)||tj(this.name,e);return f.M?f.M(a,b,c,d):f.call(null,a,b,c,d)};g.Z=function(a,b,c,d,e){var f=this.D.Z?this.D.Z(a,b,c,d,e):this.D.call(null,a,b,c,d,e),h=vj(this,f);t(h)||tj(this.name,f);return h.Z?h.Z(a,b,c,d,e):h.call(null,a,b,c,d,e)}; +g.Ca=function(a,b,c,d,e,f){var h=this.D.Ca?this.D.Ca(a,b,c,d,e,f):this.D.call(null,a,b,c,d,e,f),k=vj(this,h);t(k)||tj(this.name,h);return k.Ca?k.Ca(a,b,c,d,e,f):k.call(null,a,b,c,d,e,f)};g.Ya=function(a,b,c,d,e,f,h){var k=this.D.Ya?this.D.Ya(a,b,c,d,e,f,h):this.D.call(null,a,b,c,d,e,f,h),l=vj(this,k);t(l)||tj(this.name,k);return l.Ya?l.Ya(a,b,c,d,e,f,h):l.call(null,a,b,c,d,e,f,h)}; +g.Ha=function(a,b,c,d,e,f,h,k){var l=this.D.Ha?this.D.Ha(a,b,c,d,e,f,h,k):this.D.call(null,a,b,c,d,e,f,h,k),p=vj(this,l);t(p)||tj(this.name,l);return p.Ha?p.Ha(a,b,c,d,e,f,h,k):p.call(null,a,b,c,d,e,f,h,k)};g.Za=function(a,b,c,d,e,f,h,k,l){var p=this.D.Za?this.D.Za(a,b,c,d,e,f,h,k,l):this.D.call(null,a,b,c,d,e,f,h,k,l),m=vj(this,p);t(m)||tj(this.name,p);return m.Za?m.Za(a,b,c,d,e,f,h,k,l):m.call(null,a,b,c,d,e,f,h,k,l)}; +g.Na=function(a,b,c,d,e,f,h,k,l,p){var m=this.D.Na?this.D.Na(a,b,c,d,e,f,h,k,l,p):this.D.call(null,a,b,c,d,e,f,h,k,l,p),u=vj(this,m);t(u)||tj(this.name,m);return u.Na?u.Na(a,b,c,d,e,f,h,k,l,p):u.call(null,a,b,c,d,e,f,h,k,l,p)};g.Oa=function(a,b,c,d,e,f,h,k,l,p,m){var u=this.D.Oa?this.D.Oa(a,b,c,d,e,f,h,k,l,p,m):this.D.call(null,a,b,c,d,e,f,h,k,l,p,m),w=vj(this,u);t(w)||tj(this.name,u);return w.Oa?w.Oa(a,b,c,d,e,f,h,k,l,p,m):w.call(null,a,b,c,d,e,f,h,k,l,p,m)}; +g.Pa=function(a,b,c,d,e,f,h,k,l,p,m,u){var w=this.D.Pa?this.D.Pa(a,b,c,d,e,f,h,k,l,p,m,u):this.D.call(null,a,b,c,d,e,f,h,k,l,p,m,u),x=vj(this,w);t(x)||tj(this.name,w);return x.Pa?x.Pa(a,b,c,d,e,f,h,k,l,p,m,u):x.call(null,a,b,c,d,e,f,h,k,l,p,m,u)};g.Qa=function(a,b,c,d,e,f,h,k,l,p,m,u,w){var x=this.D.Qa?this.D.Qa(a,b,c,d,e,f,h,k,l,p,m,u,w):this.D.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w),C=vj(this,x);t(C)||tj(this.name,x);return C.Qa?C.Qa(a,b,c,d,e,f,h,k,l,p,m,u,w):C.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w)}; +g.Ra=function(a,b,c,d,e,f,h,k,l,p,m,u,w,x){var C=this.D.Ra?this.D.Ra(a,b,c,d,e,f,h,k,l,p,m,u,w,x):this.D.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x),F=vj(this,C);t(F)||tj(this.name,C);return F.Ra?F.Ra(a,b,c,d,e,f,h,k,l,p,m,u,w,x):F.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x)}; +g.Sa=function(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C){var F=this.D.Sa?this.D.Sa(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C):this.D.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x,C),I=vj(this,F);t(I)||tj(this.name,F);return I.Sa?I.Sa(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C):I.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x,C)}; +g.Ta=function(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F){var I=this.D.Ta?this.D.Ta(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F):this.D.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F),M=vj(this,I);t(M)||tj(this.name,I);return M.Ta?M.Ta(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F):M.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F)}; +g.Ua=function(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I){var M=this.D.Ua?this.D.Ua(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I):this.D.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I),S=vj(this,M);t(S)||tj(this.name,M);return S.Ua?S.Ua(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I):S.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I)}; +g.Va=function(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M){var S=this.D.Va?this.D.Va(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M):this.D.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M),X=vj(this,S);t(X)||tj(this.name,S);return X.Va?X.Va(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M):X.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M)}; +g.Wa=function(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S){var X=this.D.Wa?this.D.Wa(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S):this.D.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S),Ga=vj(this,X);t(Ga)||tj(this.name,X);return Ga.Wa?Ga.Wa(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S):Ga.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S)}; +g.Xa=function(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X){var Ga=this.D.Xa?this.D.Xa(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X):this.D.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X),db=vj(this,Ga);t(db)||tj(this.name,Ga);return db.Xa?db.Xa(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X):db.call(null,a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X)}; +g.he=function(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X,Ga){var db=oe(this.D,a,b,c,d,be([e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X,Ga])),Q=vj(this,db);t(Q)||tj(this.name,db);return oe(Q,a,b,c,d,be([e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X,Ga]))};function wj(a,b){var c=xj;gg.M(c.Vd,K,a,b);pj(c.Ud,c.Vd,c.Ed,c.Rd)}function vj(a,b){G.c(B(a.Ed),B(a.Rd))||pj(a.Ud,a.Vd,a.Ed,a.Rd);var c=B(a.Ud);c=c.h?c.h(b):c.call(null,b);return t(c)?c:sj(a.name,b,a.Rd,a.Vd,a.Kf,a.Ud,a.Ed,a.vf)}g.hd=function(){return Yc(this.name)};g.jd=function(){return Zc(this.name)}; +g.U=function(){return ja(this)};function yj(a,b){this.Mc=a;this.w=b;this.m=2153775104;this.J=2048}g=yj.prototype;g.toString=function(){return this.Mc};g.equiv=function(a){return this.K(null,a)};g.K=function(a,b){return b instanceof yj&&this.Mc===b.Mc};g.R=function(a,b){return Jc(b,['#uuid "',v.h(this.Mc),'"'].join(""))};g.U=function(){null==this.w&&(this.w=od(this.Mc));return this.w};g.cc=function(a,b){return Aa(this.Mc,b.Mc)};var zj=new L(null,"hook","hook",750265408),Aj=new L(null,"y","y",-1757859776),Bj=new L(null,"setCurrentTime","setCurrentTime",-623552),Cj=new L(null,"span.gutter","span.gutter",-700214016),Dj=new rd(null,"\x26","\x26",-2144855648,null),Ej=new L(null,"dcs-param","dcs-param",-971011648),Fj=new L(null,"path","path",-188191168),Gj=new L(null,"escape","escape",-991601952),Df=new rd(null,"meta34617","meta34617",-1789836320,null),Hj=new L(null,"force-load-ch","force-load-ch",-1689229247),Ij=new rd("schema.core", +"Any","schema.core/Any",-1891898271,null),Jj=new L(null,"tab-index","tab-index",895755393),Kj=new L(null,"bold","bold",-116809535),Lj=new L(null,"authorImgURL","authorImgURL",-1171541759),Mj=new L(null,"schema","schema",-1582001791),Nj=new rd(null,"optional-key","optional-key",988406145,null),Oj=new L(null,"char-attrs","char-attrs",-1444091455),Pj=new L(null,"esc-dispatch","esc-dispatch",17832481),Qj=new L(null,"idle_time_limit","idle_time_limit",-1837919647),Rj=new L(null,"auto-wrap-mode","auto-wrap-mode", +-2049555583),Sj=new L(null,"preload?","preload?",445442977),Tj=new L(null,"on-set","on-set",-140953470),Uj=new L(null,"current-time","current-time",-1609407134),Vj=new L(null,"span.progressbar","span.progressbar",766750210),Wj=new L(null,"osc-end","osc-end",1762953954),Xj=new L("internal","rewind","internal/rewind",-31749342),Yj=new L(null,"bottom-margin","bottom-margin",-701300733),Zj=new L(null,"on-key-press","on-key-press",-399563677),ak=new L(null,"osc-put","osc-put",-1827844733),bk=new L(null, +"cljsLegacyRender","cljsLegacyRender",-1527295613),ck=new L(null,"klass","klass",-1386752349),dk=new L(null,"blink","blink",-271985917),ek=new rd(null,"meta43127","meta43127",166183907,null),fk=new L(null,"primary","primary",817773892),gk=new rd(null,"meta43105","meta43105",-531987068,null),rb=new L(null,"meta","meta",1499536964),V=new L(null,"screen","screen",1990059748),hk=new rd(null,"Symbol","Symbol",716452869,null),ik=new L(null,"color","color",1011675173),jk=new rd(null,"blockable","blockable", +-28395259,null),sb=new L(null,"dup","dup",556298533),kk=new L(null,"parser-params","parser-params",36457893),lk=new rd(null,"height","height",-1629257147,null),mk=new L(null,"key","key",-1516042587),nk=new rd(null,"CellLine","CellLine",-317574363,null),ok=new L(null,"asciicast","asciicast",509526949),pk=new rd(null,"conditional","conditional",-1212542970,null),qk=new L(null,"exit","exit",351849638),rk=new L(null,"parser-intermediates","parser-intermediates",-169100058),sk=new L(null,"else","else", +-1508377146),tk=new L(null,"tabs","tabs",-779855354),uk=new L(null,"ground","ground",1193572934),vk=new L(null,"next-print-wraps","next-print-wraps",-1664999738),wk=new L(null,"font-size","font-size",-1847940346),xk=new rd(null,"Bool","Bool",195910502,null),yk=new L(null,"transition","transition",765692007),zk=new rd(null,"one","one",-1719427865,null),Ak=new L(null,"speed","speed",1257663751),Bk=new L(null,"displayName","displayName",-809144601),Ck=new L(null,"_","_",1453416199),eg=new L(null,"validator", +"validator",-1966190681),Dk=new rd(null,"char-attrs","char-attrs",196440072,null),Ek=new L(null,"div.loading","div.loading",-155515768),Fk=new L(null,"dcs-passthrough","dcs-passthrough",-671044440),Gk=new L(null,"show-hud","show-hud",1983299752),Hk=new L(null,"start-at","start-at",-103334680),Ik=new L(null,"default","default",-1987822328),Jk=new L(null,"csi-param","csi-param",-1120111192),Kk=new L(null,"div.control-bar","div.control-bar",-1316808248),Lk=new L(null,"finally-block","finally-block", +832982472),Mk=new rd(null,"cb","cb",-2064487928,null),Nk=new L(null,"inverse","inverse",-1623859672),Ok=new L(null,"fg","fg",-101797208),Pk=new L(null,"warn","warn",-436710552),Qk=new L(null,"dcs-intermediate","dcs-intermediate",480808872),Rk=new L(null,"osc-string","osc-string",-486531128),Sk=new L(null,"on-enter","on-enter",-928988216),Tk=new L(null,"name","name",1843675177),Uk=new L(null,"frames","frames",1765687497),Vk=new L(null,"extra-validator-fn","extra-validator-fn",1562905865),Wk=new L(null, +"output-schema","output-schema",272504137),Xk=new L(null,"div.play-button","div.play-button",1020321513),Yk=new L(null,"span.time-elapsed","span.time-elapsed",-1782475638),Zk=new L(null,"time","time",1385887882),$k=new L(null,"component-did-mount","component-did-mount",-1126910518),al=new L(null,"background-color","background-color",570434026),bl=new L(null,"recording-ch-fn","recording-ch-fn",-902533462),cl=new L(null,"span.playback-button","span.playback-button",-1136389398),dl=new L(null,"span.title-bar", +"span.title-bar",-1165872085),el=new L(null,"loaded","loaded",-1246482293),fl=new L(null,"width","width",-384071477),gl=new L(null,"start","start",-355208981),hl=new rd(null,"meta43130","meta43130",1056327947,null),il=new L(null,"lines","lines",-700165781),jl=new L(null,"input-schemas","input-schemas",-982154805),ll=new L(null,"sos-pm-apc-string","sos-pm-apc-string",398998091),ml=new L(null,"cursor-on","cursor-on",302555051),nl=new L(null,"component-did-update","component-did-update",-1468549173), +ol=new L(null,"div.start-prompt","div.start-prompt",-41424788),Xi=new L(null,"val","val",128701612),pl=new L(null,"cursor","cursor",1011937484),ql=new L(null,"dcs-entry","dcs-entry",216833388),Z=new L(null,"recur","recur",-437573268),rl=new L(null,"type","type",1174270348),sl=new rd(null,"Num","Num",-2044934708,null),tl=new L(null,"alternate","alternate",-931038644),ul=new L(null,"catch-block","catch-block",1175212748),vl=new L(null,"onPlay","onPlay",150417132),wl=new L(null,"duration","duration", +1444101068),xl=new L(null,"execute","execute",-129499188),yl=new rd(null,"pred","pred",-727012372,null),zl=new L(null,"src","src",-1651076051),Al=new rd(null,"Any","Any",1277492269,null),Bl=new L(null,"span.bar","span.bar",-1986926323),Cl=new rd(null,"Regex","Regex",205914413,null),Dl=new L(null,"msg-ch","msg-ch",-1840176755),El=new L(null,"on-exit","on-exit",1821961613),Ti=new L(null,"fallback-impl","fallback-impl",-1501286995),Fl=new L(null,"view-box","view-box",-1792199155),Gl=new L(null,"source", +"source",-433931539),Hl=new L(null,"csi-entry","csi-entry",-1787942099),pb=new L(null,"flush-on-newline","flush-on-newline",-151457939),Il=new L(null,"preds-and-schemas","preds-and-schemas",-1306766355),Jl=new L(null,"command-ch","command-ch",508874766),Kl=new L(null,"componentWillUnmount","componentWillUnmount",1573788814),Ll=new rd(null,"Inst","Inst",292408622,null),Ml=new L(null,"span.timer","span.timer",2111534382),Nl=new L(null,"toggle","toggle",1291842030),Ol=new L(null,"cursor-blink-ch","cursor-blink-ch", +1063651214),Pl=new L(null,"print","print",1299562414),Ql=new L(null,"on-mouse-down","on-mouse-down",1147755470),Rl=new L(null,"csi-dispatch","csi-dispatch",-126857169),Sl=new L(null,"on-click","on-click",1632826543),Tl=new L(null,"parser-state","parser-state",594493647),Ul=new L(null,"ignore","ignore",-1631542033),lj=new L(null,"descendants","descendants",1824886031),Vl=new L(null,"underline","underline",2018066703),Wl=new rd(null,"Str","Str",907970895,null),Xl=new L(null,"param","param",2013631823), +Yl=new L(null,"k","k",-2146297393),ki=new L(null,"title","title",636505583),Zl=new L(null,"stop-ch","stop-ch",-219113969),$l=new L(null,"insert-mode","insert-mode",894811791),am=new rd(null,"maybe","maybe",1326133967,null),bm=new L(null,"toggle-fullscreen","toggle-fullscreen",-1647254833),cm=new L(null,"loop","loop",-395552849),ni=new L(null,"author-img-url","author-img-url",2016975920),dm=new L(null,"shouldComponentUpdate","shouldComponentUpdate",1795750960),mj=new L(null,"ancestors","ancestors", +-776045424),em=new rd(null,"flag","flag",-1565787888,null),fm=new L(null,"style","style",-496642736),gm=new L(null,"theme","theme",-1247880880),hm=new L(null,"stream","stream",1534941648),im=new L(null,"charset-fn","charset-fn",1374523920),li=new L(null,"author","author",2111686192),jm=new L(null,"escape-intermediate","escape-intermediate",1036490448),km=new L(null,"div","div",1057191632),qb=new L(null,"readably","readably",1129599760),lm=new L(null,"change-speed","change-speed",2125740976),Ki=new L(null, +"more-marker","more-marker",-14717935),mm=new L(null,"new-line-mode","new-line-mode",1467504785),nm=new L(null,"optional?","optional?",1184638129),om=new L(null,"csi-intermediate","csi-intermediate",-410048175),pm=new L(null,"reagentRender","reagentRender",-358306383),qm=new L(null,"idle-time-limit","idle-time-limit",-928369231),rm=new L(null,"started?","started?",-1301062863),sm=new L(null,"other-buffer-saved","other-buffer-saved",-2048065486),tm=new L(null,"snapshot","snapshot",-1274785710),um= +new L(null,"osc-start","osc-start",-1717437326),vm=new L(null,"preload","preload",1646824722),wm=new L(null,"stop","stop",-2140911342),xm=new L(null,"no-cache","no-cache",1588056370),ym=new rd(null,"Uuid","Uuid",-1866694318,null),zm=new L(null,"render","render",-1408033454),Am=new rd(null,"width","width",1256460050,null),Bm=new L(null,"poster","poster",-1616913550),Cm=new L(null,"csi-ignore","csi-ignore",-764437550),Dm=new L(null,"reagent-render","reagent-render",-985383853),Em=new L(null,"auto-play", +"auto-play",-645319501),Fm=new L(null,"collect","collect",-284321549),Gm=new L(null,"pre.asciinema-terminal","pre.asciinema-terminal",832737619),Hm=new L(null,"loading","loading",-737050189),Im=new L(null,"priority","priority",1431093715),Jm=new L(null,"auto-play?","auto-play?",385278451),Km=new rd(null,"val","val",1769233139,null),Lm=new L(null,"span.line","span.line",-1541583788),tb=new L(null,"print-length","print-length",1931866356),Mm=new L(null,"poster-time","poster-time",1478579796),Nm=new L(null, +"saved","saved",288760660),Om=new L(null,"error-symbol","error-symbol",-823480428),oi=new L(null,"on-can-play","on-can-play",1481578549),Pm=new L(null,"catch-exception","catch-exception",-1997306795),Qm=new L(null,"constructor","constructor",-1953928811),Rm=new L(null,"auto-run","auto-run",1958400437),Sm=new L(null,"div.asciinema-player","div.asciinema-player",-1293079051),kj=new L(null,"parents","parents",-2027538891),mi=new L(null,"author-url","author-url",1091920533),Tm=new L(null,"pred-name", +"pred-name",-3677451),Um=new rd(null,"meta42957","meta42957",-1080714315,null),Vm=new L(null,"on-mouse-move","on-mouse-move",-1386320874),Wm=new L(null,"component-will-unmount","component-will-unmount",-2058314698),Xm=new L(null,"prev","prev",-1597069226),Ym=new L(null,"svg","svg",856789142),Zm=new L(null,"getDuration","getDuration",-995932010),$m=new L(null,"url","url",276297046),an=new L(null,"authorURL","authorURL",549221782),bn=new rd(null,"meta38850","meta38850",1963771318,null),cn=new L(null, +"continue-block","continue-block",-1852047850),dn=new L(null,"loop?","loop?",457687798),en=new rd(null,"ch","ch",1085813622,null),fn=new rd(null,"CodePoint","CodePoint",-132710345,null),gn=new L(null,"autoPlay","autoPlay",-561263241),hn=new rd(null,"\x3d\x3e","\x3d\x3e",-813269641,null),jn=new L(null,"playing","playing",70013335),kn=new rd(null,"Keyword","Keyword",-850065993,null),ln=new L(null,"display-name","display-name",694513143),mn=new L(null,"random","random",-557811113),nn=new L(null,"position", +"position",-2011731912),on=new L(null,"on-dispose","on-dispose",2105306360),pn=new L(null,"d","d",1972142424),qn=new L(null,"action","action",-811238024),rn=new L(null,"stdout-ch","stdout-ch",825692568),sn=new L(null,"pause","pause",-2095325672),tn=new L(null,"error","error",-978969032),un=new L(null,"span.fullscreen-button","span.fullscreen-button",-1476136392),vn=new L(null,"class-name","class-name",945142584),wn=new L(null,"componentFunction","componentFunction",825866104),xn=new L(null,"div.loader", +"div.loader",-1644603528),yn=new L(null,"origin-mode","origin-mode",-1430095912),zn=new L(null,"x","x",2099068185),An=new L(null,"__html","__html",674048345),Bn=new L(null,"fontSize","fontSize",919623033),Cn=new L(null,"div.asciinema-player-wrapper","div.asciinema-player-wrapper",2009764409),Dn=new L(null,"startAt","startAt",849336089),En=new L(null,"getCurrentTime","getCurrentTime",697283642),Fn=new L(null,"put","put",1299772570),Gn=new rd(null,"CharAttrs","CharAttrs",1533586778,null),Hn=new L(null, +"top-margin","top-margin",655579514),In=new L(null,"unhook","unhook",1440586234),Jn=new L(null,"play","play",-580418022),Kn=new L(null,"seek","seek",758996602),Ln=new rd(null,"chars","chars",545901210,null),Mn=new L(null,"version","version",425292698),Nn=new rd(null,"line","line",1852876762,null),qi=new L(null,"on-pause","on-pause",1839279163),On=new L(null,"visible","visible",-1024216805),Pn=new L(null,"autobind","autobind",-570650245),Qn=new L(null,"hierarchy","hierarchy",-1053470341),Rn=new L(null, +"on-key-down","on-key-down",-1374733765),pi=new L(null,"on-play","on-play",-188934501),Sn=new rd(null,"\x3d\x3e*","\x3d\x3e*",1909690043,null),Si=new L(null,"alt-impl","alt-impl",670969595),Tn=new L(null,"bg","bg",-206688421),Un=new L(null,"p?","p?",-1172161701),Vn=new L(null,"onCanPlay","onCanPlay",197552027),Wn=new L(null,"other-buffer-lines","other-buffer-lines",-1562366021),Xn=new rd(null,"record","record",861424668,null),Yn=new L(null,"italic","italic",32599196),Zn=new rd(null,"required-key", +"required-key",1624616412,null),$n=new L(null,"dcs-ignore","dcs-ignore",198619612),ao=new rd(null,"optional","optional",-600484260,null),gj=new L(null,"keywordize-keys","keywordize-keys",1310784252),bo=new rd(null,"Int","Int",-2116888740,null),co=new L(null,"span.time-remaining","span.time-remaining",706865437),eo=new L(null,"componentWillMount","componentWillMount",-285327619),fo=new L(null,"idleTimeLimit","idleTimeLimit",-867712227),go=new L("internal","seek","internal/seek",-1958914115),ho=new L(null, +"href","href",-793805698),io=new L(null,"buffer","buffer",617295198),jo=new L(null,"img","img",1442687358),ko=new L(null,"stdout","stdout",-531490018),lo=new L(null,"a","a",-2123407586),mo=new L(null,"dangerouslySetInnerHTML","dangerouslySetInnerHTML",-554971138),no=new L(null,"height","height",1025178622),oo=new rd("s","Num","s/Num",-2044935073,null),po=new L(null,"clear","clear",1877104959),ri=new L("cljs.core","not-found","cljs.core/not-found",-1572889185),qo=new rd(null,"meta36583","meta36583", +-346463841,null),ro=new L(null,"span","span",1394872991),so=new L(null,"show","show",-576705889),to=new rd(null,"f","f",43394975,null),uo=new L(null,"onPause","onPause",-470027297);function vo(a,b){var c=Kb(Ai,a,b);return ae(c,vg(function(a){return function(b){return a===b}}(c),b))}var wo=function wo(a){switch(arguments.length){case 0:return wo.B();case 1:return wo.h(arguments[0]);case 2:return wo.c(arguments[0],arguments[1]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return wo.A(arguments[0],arguments[1],new Jb(c.slice(2),0,null))}};wo.B=function(){return vi};wo.h=function(a){return a}; +wo.c=function(a,b){return H(a)<H(b)?Mb(ge,b,a):Mb(ge,a,b)};wo.A=function(a,b,c){a=vo(H,ge.A(c,b,be([a])));return Mb(wg,y(a),vd(a))};wo.N=function(a){var b=y(a),c=z(a);a=y(c);c=z(c);return wo.A(b,a,c)};wo.L=2;var xo=function xo(a){switch(arguments.length){case 1:return xo.h(arguments[0]);case 2:return xo.c(arguments[0],arguments[1]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return xo.A(arguments[0],arguments[1],new Jb(c.slice(2),0,null))}};xo.h=function(a){return a}; +xo.c=function(a,b){return H(a)<H(b)?Mb(function(a,d){return He(b,d)?re.c(a,d):a},a,a):Mb(re,a,b)};xo.A=function(a,b,c){return Mb(xo,a,ge.c(c,b))};xo.N=function(a){var b=y(a),c=z(a);a=y(c);c=z(c);return xo.A(b,a,c)};xo.L=2;function yo(a){var b=Pe([Lj,vl,tm,an,gn,Bn,Dn,Vn,fo,uo],[ni,pi,Bm,mi,Em,wk,Hk,oi,qm,qi]);return Mb(function(b,d){var c=J(d,0,null),f=J(d,1,null);return He(a,c)?K.l(b,f,D.c(a,c)):b},Kb(le,a,lh(b)),b)};if("undefined"===typeof zo)var zo=dg.h(null); +if("undefined"===typeof Ao)var Ao=function(){var a={};a.warn=function(){return function(){function a(a){var b=null;if(0<arguments.length){b=0;for(var d=Array(arguments.length-0);b<d.length;)d[b]=arguments[b+0],++b;b=new Jb(d,0,null)}return c.call(this,b)}function c(a){return gg.A(zo,Ag,new R(null,1,5,T,[Pk],null),ge,be([P(v,a)]))}a.L=0;a.N=function(a){a=E(a);return c(a)};a.A=c;return a}()}(a);a.error=function(){return function(){function a(a){var b=null;if(0<arguments.length){b=0;for(var d=Array(arguments.length- +0);b<d.length;)d[b]=arguments[b+0],++b;b=new Jb(d,0,null)}return c.call(this,b)}function c(a){return gg.A(zo,Ag,new R(null,1,5,T,[tn],null),ge,be([P(v,a)]))}a.L=0;a.N=function(a){a=E(a);return c(a)};a.A=c;return a}()}(a);return a}();function Bo(a,b,c){var d=RegExp,e=b.source,f=t(b.ignoreCase)?[v.h("g"),"i"].join(""):"g";f=t(b.multiline)?[v.h(f),"m"].join(""):f;b=t(b.cg)?[v.h(f),"u"].join(""):f;d=new d(e,b);return a.replace(d,c)} +function Co(a){return function(){function b(a){var b=null;if(0<arguments.length){b=0;for(var d=Array(arguments.length-0);b<d.length;)d[b]=arguments[b+0],++b;b=new Jb(d,0,null)}return c.call(this,b)}function c(b){b=lg(b);if(G.c(H(b),1))return b=y(b),a.h?a.h(b):a.call(null,b);b=Wg(b);return a.h?a.h(b):a.call(null,b)}b.L=0;b.N=function(a){a=E(a);return c(a)};b.A=c;return b}()} +function Do(a,b,c){if("string"===typeof b)return a.replace(new RegExp(String(b).replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g,"\\$1").replace(/\x08/g,"\\x08"),"g"),c);if(b instanceof RegExp)return"string"===typeof c?Bo(a,b,c):Bo(a,b,Co(c));throw["Invalid match arg: ",v.h(b)].join("");}function Eo(a){var b=new cb;for(a=E(a);;)if(null!=a)b=b.append(""+v.h(y(a))),a=z(a);else return b.toString()} +function Fo(a,b){var c="/(?:)/"===""+v.h(b)?ge.c(Wg(ae("",ig.c(v,E(a)))),""):Wg((""+v.h(a)).split(b));if(1<H(c))a:for(;;)if(""===(null==c?null:nc(c)))c=null==c?null:oc(c);else break a;return c};if("undefined"===typeof Go){var Ho;if("undefined"!==typeof React)Ho=React;else{var Io;if("undefined"!==typeof require){var Jo=require("react");if(t(Jo))Io=Jo;else throw Error("require('react') failed");}else throw Error("js/React is missing");Ho=Io}var Go=Ho} +if("undefined"===typeof Ko){var Lo;if("undefined"!==typeof createReactClass)Lo=createReactClass;else{var Mo;if("undefined"!==typeof require){var No=require("create-react-class");if(t(No))Mo=No;else throw Error("require('create-react-class') failed");}else throw Error("js/createReactClass is missing");Lo=Mo}var Ko=Lo}var Oo=new ti(null,new r(null,2,["aria",null,"data",null],null),null);function Po(a){return 2>H(a)?a.toUpperCase():[v.h(a.substring(0,1).toUpperCase()),v.h(a.substring(1))].join("")} +function Qo(a){if("string"===typeof a)return a;a=jf(a);var b=Fo(a,/-/),c=E(b);b=y(c);c=z(c);return t(Oo.h?Oo.h(b):Oo.call(null,b))?a:Kb(v,b,ig.c(Po,c))}function Ro(a){var b=function(){var b=function(){var b=me(a);return b?(b=a.displayName,t(b)?b:a.name):b}();if(t(b))return b;b=function(){var b=null!=a?a.J&4096||q===a.Oe?!0:!1:!1;return b?jf(a):b}();if(t(b))return b;b=qe(a);return xe(b)?Tk.h(b):null}();return Do(""+v.h(b),"$",".")}var So=!1;if("undefined"===typeof To)var To=0;function Uo(a){return setTimeout(a,16)}var Vo="undefined"===typeof window||null==window.document?Uo:function(){var a=window,b=a.requestAnimationFrame;if(t(b))return b;b=a.webkitRequestAnimationFrame;if(t(b))return b;b=a.mozRequestAnimationFrame;if(t(b))return b;a=a.msRequestAnimationFrame;return t(a)?a:Uo}();function Wo(a,b){return a.cljsMountOrder-b.cljsMountOrder}if("undefined"===typeof Xo)var Xo=function(){return null};function Yo(a){this.Yd=a} +function Zo(a,b){var c=a[b];if(null==c)return null;a[b]=null;for(var d=c.length,e=0;;)if(e<d){var f=c[e];f.B?f.B():f.call(null);e+=1}else return null}function $o(a){if(a.Yd)return null;a.Yd=!0;a=function(a){return function(){a.Yd=!1;return ap(a)}}(a);return Vo.h?Vo.h(a):Vo.call(null,a)} +function ap(a){Zo(a,"beforeFlush");Xo();var b=a.componentQueue;if(null!=b)a:{a.componentQueue=null,b.sort(Wo);for(var c=b.length,d=0;;)if(d<c){var e=b[d];!0===e.cljsIsDirty&&e.forceUpdate();d+=1}else break a}return Zo(a,"afterRender")}Yo.prototype.enqueue=function(a,b){null==this[a]&&(this[a]=[]);this[a].push(b);return $o(this)};if("undefined"===typeof bp)var bp=new Yo(!1);function cp(a){if(t(a.cljsIsDirty))return null;a.cljsIsDirty=!0;return bp.enqueue("componentQueue",a)};var dp;if("undefined"===typeof ep)var ep=!1;if("undefined"===typeof fp)var fp=0;if("undefined"===typeof gp)var gp=dg.h(0); +function hp(a,b){b.captured=null;a:{var c=dp;dp=b;try{var d=a.B?a.B():a.call(null);break a}finally{dp=c}d=void 0}var e=b.captured;b.rc=!1;a:{c=b.Nc;var f=null==e?0:e.length,h=f===(null==c?0:c.length);if(h)for(h=0;;){var k=h===f;if(k){c=k;break a}if(e[h]===c[h])h+=1;else{c=!1;break a}}else c=h}if(!c)a:{c=yi(e);f=yi(b.Nc);b.Nc=e;e=E(xo.c(c,f));h=null;for(var l=k=0;;)if(l<k){var p=h.$(null,l);Mc(p,b,ip);l+=1}else if(e=E(e))h=e,Ae(h)?(e=Wc(h),l=Xc(h),h=e,k=H(e),e=l):(e=y(h),Mc(e,b,ip),e=z(h),h=null,k= +0),l=0;else break;c=E(xo.c(f,c));f=null;for(k=h=0;;)if(k<h)e=f.$(null,k),Nc(e,b),k+=1;else if(c=E(c))f=c,Ae(f)?(c=Wc(f),h=Xc(f),f=c,e=H(c),c=h,h=e):(e=y(f),Nc(e,b),c=z(f),f=null,h=0),k=0;else break a}return d}function jp(a){var b=dp;if(null!=b){var c=b.captured;null==c?b.captured=[a]:c.push(a)}}function kp(a,b){ep&&gg.l(gp,Xe,H(b)-H(a));return b}function lp(a,b,c){var d=a.gb;a.gb=kp(d,K.l(d,b,c));return a.Ce=null}function mp(a,b){var c=a.gb;a.gb=kp(c,le.c(c,b));return a.Ce=null} +function np(a,b,c){var d=a.Ce;d=null==d?a.Ce=Ue(function(){return function(a,b,c){a.push(b);a.push(c);return a}}(d),[],a.gb):d;for(var e=d.length,f=0;;)if(f<e){var h=d[f],k=d[f+1];k.M?k.M(h,a,b,c):k.call(null,h,a,b,c);f=2+f}else return null}function op(a,b,c,d){Jc(b,["#\x3c",v.h(d)," "].join(""));a:{d=dp;dp=null;try{var e=B(a);break a}finally{dp=d}e=void 0}Qi(e,b,c);return Jc(b,"\x3e")}if("undefined"===typeof pp)var pp=null; +function qp(){for(;;){var a=pp;if(null==a)return null;pp=null;for(var b=a.length,c=0;;)if(c<b){var d=a[c];d.rc&&null!=d.Nc&&rp(d,!0);c+=1}else break}}Xo=qp;function sp(a,b,c,d){this.state=a;this.meta=b;this.df=c;this.gb=d;this.m=2153938944;this.J=114690}g=sp.prototype;g.R=function(a,b,c){return op(this,b,c,"Atom:")};g.P=function(){return this.meta};g.U=function(){return ja(this)};g.K=function(a,b){return this===b};g.Gb=function(a,b){var c=this.state;this.state=b;null!=this.gb&&np(this,c,b);return b}; +g.je=function(a,b){return this.Gb(null,b.h?b.h(this.state):b.call(null,this.state))};g.ke=function(a,b,c){return this.Gb(null,b.c?b.c(this.state,c):b.call(null,this.state,c))};g.le=function(a,b,c,d){return this.Gb(null,b.l?b.l(this.state,c,d):b.call(null,this.state,c,d))};g.me=function(a,b,c,d,e){return this.Gb(null,Af(b,this.state,c,d,e))};g.Kd=function(a,b,c){return np(this,b,c)};g.Jd=function(a,b,c){return lp(this,b,c)};g.Ld=function(a,b){return mp(this,b)};g.pc=function(){jp(this);return this.state}; +var tp=function tp(a){switch(arguments.length){case 1:return tp.h(arguments[0]);default:for(var c=[],d=arguments.length,e=0;;)if(e<d)c.push(arguments[e]),e+=1;else break;return tp.A(arguments[0],new Jb(c.slice(1),0,null))}};tp.h=function(a){return new sp(a,null,null,null)};tp.A=function(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b,d=D.c(c,rb);c=D.c(c,eg);return new sp(a,d,c,null)};tp.N=function(a){var b=y(a);a=z(a);return tp.A(b,a)};tp.L=1; +var up=function up(a){if(null!=a&&null!=a.we)return a.we();var c=up[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=up._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("IDisposable.dispose!",a);};function ip(a,b,c,d){c===d||a.rc?a=null:null==a.Sb?(a.rc=!0,null==pp&&(pp=[],!1===bp.Yd&&$o(bp)),a=pp.push(a)):a=!0===a.Sb?rp(a,!1):a.Sb.h?a.Sb.h(a):a.Sb.call(null,a);return a} +function vp(a,b,c,d,e,f,h,k){this.Cb=a;this.state=b;this.rc=c;this.We=d;this.Nc=e;this.gb=f;this.Sb=h;this.ee=k;this.m=2153807872;this.J=114690}function wp(a){var b=dp;dp=null;try{return a.pc(null)}finally{dp=b}}function rp(a,b){var c=a.state;if(t(b)){var d=a.Cb;try{a.ee=null;var e=hp(d,a)}catch(f){e=f,a.state=e,a.ee=e,e=a.rc=!1}}else e=hp(a.Cb,a);a.We||(a.state=e,null==a.gb||G.c(c,e)||np(a,c,e));return e} +function xp(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b,d=D.c(c,Rm),e=D.c(c,Tj),f=D.c(c,on);c=D.c(c,xm);null!=d&&(a.Sb=d);null!=e&&(a.Jf=e);null!=f&&(a.Ze=f);null!=c&&(a.We=c)}g=vp.prototype;g.R=function(a,b,c){return op(this,b,c,["Reaction ",v.h(od(this)),":"].join(""))};g.U=function(){return ja(this)};g.K=function(a,b){return this===b}; +g.we=function(){var a=this.state,b=this.Nc;this.Sb=this.state=this.Nc=null;this.rc=!0;b=E(yi(b));for(var c=null,d=0,e=0;;)if(e<d){var f=c.$(null,e);Nc(f,this);e+=1}else if(b=E(b))c=b,Ae(c)?(b=Wc(c),e=Xc(c),c=b,d=H(b),b=e):(b=y(c),Nc(b,this),b=z(c),c=null,d=0),e=0;else break;null!=this.Ze&&this.Ze(a);a=this.bg;if(null==a)return null;b=a.length;for(c=0;;)if(c<b)d=a[c],d.h?d.h(this):d.call(null,this),c+=1;else return null};g.Gb=function(a,b){var c=this.state;this.state=b;this.Jf(c,b);np(this,c,b);return b}; +g.je=function(a,b){var c=this;return c.Gb(null,function(){var a=wp(c);return b.h?b.h(a):b.call(null,a)}())};g.ke=function(a,b,c){var d=this;return d.Gb(null,function(){var a=wp(d);return b.c?b.c(a,c):b.call(null,a,c)}())};g.le=function(a,b,c,d){var e=this;return e.Gb(null,function(){var a=wp(e);return b.l?b.l(a,c,d):b.call(null,a,c,d)}())};g.me=function(a,b,c,d,e){return this.Gb(null,Af(b,wp(this),c,d,e))};g.Kd=function(a,b,c){return np(this,b,c)};g.Jd=function(a,b,c){return lp(this,b,c)}; +g.Ld=function(a,b){var c=te(this.gb);mp(this,b);return!c&&te(this.gb)&&null==this.Sb?this.we():null};g.pc=function(){var a=this.ee;if(null!=a)throw a;(a=null==dp)&&qp();a&&null==this.Sb?this.rc&&(a=this.state,this.state=this.Cb.B?this.Cb.B():this.Cb.call(null),null==this.gb||G.c(a,this.state)||np(this,a,this.state)):(jp(this),this.rc&&rp(this,!1));return this.state}; +function yp(a){for(var b=[],c=arguments.length,d=0;;)if(d<c)b.push(arguments[d]),d+=1;else break;c=arguments[0];b=1<b.length?new Jb(b.slice(1),0,null):null;var e=null!=b&&(b.m&64||q===b.G)?P(U,b):b;b=D.c(e,Rm);d=D.c(e,Tj);e=D.c(e,on);c=new vp(c,null,!0,!1,null,null,null,null);xp(c,new r(null,3,[Rm,b,Tj,d,on,e],null));return c}var zp=yp(null); +function Ap(a,b){var c=Bp,d=zp,e=hp(a,d);null!=d.Nc&&(zp=yp(null),xp(d,c),d.Cb=a,d.Sb=function(){return function(){return cp.h?cp.h(b):cp.call(null,b)}}(d,e),b.cljsRatom=d);return e};var Cp;function Dp(a,b){var c=b.argv;if(null==c){c=T;var d=a.constructor;a:for(var e=Ea(b),f=e.length,h=Ef,k=0;;)if(k<f){var l=e[k];h=K.l(h,hf.h(l),b[l]);k+=1}else break a;c=new R(null,2,5,c,[d,h],null)}return c}function Ep(a){var b;if(b=me(a))a=null==a?null:a.prototype,b=null!=(null==a?null:a.reagentRender);return b}if("undefined"===typeof Fp)var Fp=null; +function Gp(a){for(;;){var b=a.reagentRender,c=!0===a.cljsLegacyRender?b.call(a,a):function(){var c=Dp(a,a.props);switch(H(c)){case 1:return b.call(a);case 2:return b.call(a,Vd(c,1));case 3:return b.call(a,Vd(c,1),Vd(c,2));case 4:return b.call(a,Vd(c,1),Vd(c,2),Vd(c,3));case 5:return b.call(a,Vd(c,1),Vd(c,2),Vd(c,3),Vd(c,4));default:return b.apply(a,Lb(c).slice(1))}}();if(ze(c))return Fp.h?Fp.h(c):Fp.call(null,c);if(Fe(c))c=Ep(c)?function(a,b,c,h){return function(){function a(a){var c=null;if(0<arguments.length){c= +0;for(var d=Array(arguments.length-0);c<d.length;)d[c]=arguments[c+0],++c;c=new Jb(d,0,null)}return b.call(this,c)}function b(a){a=Kb(Xg,h,a);return Fp.h?Fp.h(a):Fp.call(null,a)}a.L=0;a.N=function(a){a=E(a);return b(a)};a.A=b;return a}()}(a,b,null,c):c,a.reagentRender=c;else return c}} +var Bp=new r(null,1,[xm,!0],null),Hp=new r(null,1,[zm,function(){var a=this.cljsRatom;this.cljsIsDirty=!1;return null==a?Ap(function(a,c){return function(){a:{var a=Cp;Cp=c;try{var b=Gp(c);break a}finally{Cp=a}b=void 0}return b}}(a,this),this):rp(a,!1)}],null); +function Ip(a,b){var c=a instanceof L?a.ea:null;switch(c){case "getDefaultProps":throw Error("getDefaultProps not supported");case "getInitialState":return function(){return function(){var a=this.cljsState;a=null!=a?a:this.cljsState=tp.h(null);return fg(a,b.call(this,this))}}(a,c);case "componentWillReceiveProps":return function(){return function(a){return b.call(this,this,Dp(this,a))}}(a,c);case "shouldComponentUpdate":return function(){return function(a){var c=So;if(c)return c;c=this.props.argv; +var d=a.argv,h=null==c||null==d;return null==b?h||!G.c(c,d):h?b.call(this,this,Dp(this,this.props),Dp(this,a)):b.call(this,this,c,d)}}(a,c);case "componentWillUpdate":return function(){return function(a){return b.call(this,this,Dp(this,a))}}(a,c);case "componentDidUpdate":return function(){return function(a){return b.call(this,this,Dp(this,a))}}(a,c);case "componentWillMount":return function(){return function(){this.cljsMountOrder=To+=1;return null==b?null:b.call(this,this)}}(a,c);case "componentDidMount":return function(){return function(){return b.call(this, +this)}}(a,c);case "componentWillUnmount":return function(){return function(){var a=this.cljsRatom;null!=a&&up(a);this.cljsIsDirty=!1;return null==b?null:b.call(this,this)}}(a,c);default:return null}}function Jp(a,b){var c=Ip(a,b);return t(c)?c:b}var Kp=new r(null,3,[dm,null,eo,null,Kl,null],null),Lp=function(a){return function(b){return function(c){var d=D.c(B(b),c);if(null!=d)return d;d=a.h?a.h(c):a.call(null,c);gg.M(b,K,c,d);return d}}(dg.h(Ef))}(Qo); +function Mp(a){return Ue(function(a,c,d){return K.l(a,hf.h(Lp.h?Lp.h(c):Lp.call(null,c)),d)},Ef,a)}function Np(a){var b=function(){var b=pm.h(a);return t(b)?b:wn.h(a)}(),c=null==b,d=t(b)?b:zm.h(a),e=""+v.h(function(){var b=Bk.h(a);return t(b)?b:Ro(d)}());a:switch(e){case "":var f=""+v.h(Zi());break a;default:f=e}b=Ue(function(){return function(a,b,c){return K.l(a,b,Jp(b,c))}}(b,c,d,e,f),Ef,a);return K.A(b,Bk,f,be([Pn,!1,bk,c,pm,d,zm,zm.h(Hp)]))} +function Op(a){return Ue(function(a,c,d){a[jf(c)]=d;return a},{},a)}function Pp(a){a=Op(Np(hi.A(be([Kp,Mp(a)]))));return Ko.h?Ko.h(a):Ko.call(null,a)};var Qp=/([^\s\.#]+)(?:#([^\s\.#]+))?(?:\.([^\s#]+))?/;function Rp(a){return a instanceof L||a instanceof rd}var Sp={"class":"className","for":"htmlFor",charset:"charSet"};function Tp(a,b,c){if(Rp(b)){var d=jf(b);d=Sp.hasOwnProperty(d)?Sp[d]:null;b=null==d?Sp[jf(b)]=Qo(b):d}a[b]=Up.h?Up.h(c):Up.call(null,c);return a} +function Up(a){return"object"!==n(a)?a:Rp(a)?jf(a):xe(a)?Ue(Tp,{},a):ue(a)?cj(a):Fe(a)?function(){function b(a){var b=null;if(0<arguments.length){b=0;for(var d=Array(arguments.length-0);b<d.length;)d[b]=arguments[b+0],++b;b=new Jb(d,0,null)}return c.call(this,b)}function c(b){return P(a,b)}b.L=0;b.N=function(a){a=E(a);return c(a)};b.A=c;return b}():cj(a)}function Vp(a,b,c){a=null==a?{}:a;a[b]=c;return a}if("undefined"===typeof Wp)var Wp=null; +var Xp=new ti(null,new r(null,6,["url",null,"tel",null,"text",null,"textarea",null,"password",null,"search",null],null),null),Yp=function Yp(a){if(t(a.cljsInputLive)){a.cljsInputDirty=!1;var c=a.cljsRenderedValue,d=a.cljsDOMValue,e=Wp.h?Wp.h(a):Wp.call(null,a);if(!G.c(c,d)){if(e===document.activeElement&&He(Xp,e.type)&&"string"===typeof c&&"string"===typeof d){var f=e.value;if(!G.c(f,d))return bp.enqueue("afterRender",function(){return function(){return Yp.h?Yp.h(a):Yp.call(null,a)}}(f,c,d,e));d= +H(f)-e.selectionStart;d=H(c)-d;a.cljsDOMValue=c;e.value=c;e.selectionStart=d;return e.selectionEnd=d}a.cljsDOMValue=c;return e.value=c}}return null};function Zp(a,b,c){a.cljsDOMValue=c.target.value;t(a.cljsInputDirty)||(a.cljsInputDirty=!0,bp.enqueue("afterRender",function(){return Yp(a)}));return b.h?b.h(c):b.call(null,c)} +function $p(a){var b=Cp;if(t(function(){var b=null!=a;return b?(b=a.hasOwnProperty("onChange"),t(b)?a.hasOwnProperty("value"):b):b}())){var c=a.value,d=null==c?"":c,e=a.onChange;t(b.cljsInputLive)||(b.cljsInputLive=!0,b.cljsDOMValue=d);b.cljsRenderedValue=d;delete a.value;a.defaultValue=d;a.onChange=function(a,c,d,e){return function(a){return Zp(b,e,a)}}(a,c,d,e)}} +var aq=null,cq=new r(null,4,[ln,"ReagentInput",nl,Yp,Wm,function(a){return a.cljsInputLive=null},Dm,function(a,b,c,d){$p(c);return bq.M?bq.M(a,b,c,d):bq.call(null,a,b,c,d)}],null);function dq(a){if(xe(a))try{var b=D.c(a,mk)}catch(c){b=null}else b=null;return b}var eq={}; +function fq(a,b,c){var d=a.name,e=J(b,c,null),f=null==e||xe(e);e=Up(f?e:null);var h=a.id;e=null!=h&&null==(null==e?null:e.id)?Vp(e,"id",h):e;a=a.className;null==a?a=e:(h=null==e?null:e.className,a=Vp(e,"className",null==h?a:[v.h(a)," ",v.h(h)].join("")));c+=f?1:0;a:switch(d){case "input":case "textarea":f=!0;break a;default:f=!1}if(f)return f=T,null==aq&&(aq=Pp(cq)),b=pe(new R(null,5,5,f,[aq,b,d,a,c],null),qe(b)),gq.h?gq.h(b):gq.call(null,b);f=dq(qe(b));f=null==f?a:Vp(a,"key",f);return bq.M?bq.M(b, +d,f,c):bq.call(null,b,d,f,c)} +function hq(a){for(;;){var b=J(a,0,null);if(Rp(b)||"string"===typeof b){b=jf(b);var c=b.indexOf("\x3e");switch(c){case -1:c=b;b=eq;var d=c;b=b.hasOwnProperty(d)?b[d]:null;if(null==b){b=c;var e=z(Ji(Qp,jf(c)));c=J(e,0,null);d=J(e,1,null);e=J(e,2,null);e=null==e?null:Do(e,/\./," ");b=eq[b]={name:c,id:d,className:e}}return fq(b,a,1);case 0:return b=J(a,1,null),fq({name:b},a,2);default:a=new R(null,2,5,T,[b.substring(0,c),K.l(a,0,b.substring(c+1))],null)}}else return c=b.cljsReactClass,null==c?Ep(b)? +b=b.cljsReactClass=b:(c=qe(b),c=K.l(c,Dm,b),c=Pp(c),b=b.cljsReactClass=c):b=c,c={argv:a},d=dq(qe(a)),a=null==d?dq(J(a,1,null)):d,null!=a&&(c.key=a),Go.createElement(b,c)}}function gq(a){return"object"!==n(a)?a:ze(a)?hq(a):De(a)?iq.h?iq.h(a):iq.call(null,a):Rp(a)?jf(a):(null!=a?a.m&2147483648||q===a.ma||(a.m?0:Ab(Kc,a)):Ab(Kc,a))?Vi(be([a])):a}Fp=gq;function iq(a){a=Lb(a);for(var b=a.length,c=0;;)if(c<b)a[c]=gq(a[c]),c+=1;else break;return a} +function bq(a,b,c,d){var e=H(a)-d;switch(e){case 0:return Go.createElement(b,c);case 1:return Go.createElement(b,c,gq(J(a,d,null)));default:return Go.createElement.apply(null,Ue(function(){return function(a,b,c){b>=d&&a.push(gq(c));return a}}(e),[b,c],a))}};if("undefined"===typeof jq)var jq=null;function kq(){if(null!=jq)return jq;if("undefined"!==typeof ReactDOM)return jq=ReactDOM;if("undefined"!==typeof require){var a=jq=require("react-dom");if(t(a))return a;throw Error("require('react-dom') failed");}throw Error("js/ReactDOM is missing");}if("undefined"===typeof lq)var lq=dg.h(Ef); +function mq(a,b,c){var d=So;So=!0;try{return kq().render(a.B?a.B():a.call(null),b,function(){return function(){var d=So;So=!1;try{return gg.M(lq,K,b,new R(null,2,5,T,[a,b],null)),Zo(bp,"afterRender"),null!=c?c.B?c.B():c.call(null):null}finally{So=d}}}(d))}finally{So=d}}function nq(a,b){return mq(a,b,null)}function oq(a,b,c){qp();return mq(function(){return gq(me(a)?a.B?a.B():a.call(null):a)},b,c)}Wp=function(a){return kq().findDOMNode(a)};function pq(a){switch(arguments.length){case 2:return oq(arguments[0],arguments[1],null);case 3:return oq(arguments[0],arguments[1],arguments[2]);default:throw Error(["Invalid arity: ",v.h(arguments.length)].join(""));}}function qq(a,b){return oq(a,b,null)} +da("reagent.core.force_update_all",function(){qp();qp();for(var a=E(mh(B(lq))),b=null,c=0,d=0;;)if(d<c){var e=b.$(null,d);P(nq,e);d+=1}else if(a=E(a))b=a,Ae(b)?(a=Wc(b),d=Xc(b),b=a,c=H(a),a=d):(a=y(b),P(nq,a),a=z(b),b=null,c=0),d=0;else break;return Zo(bp,"afterRender")});var rq=yi(df(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,25,28,29,30,31)),sq=ke([yi(df(24,26,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,145,146,147,148,149,150,151,153,154)),new r(null,2,[qn,xl,yk,uk],null),yi(df(156)),new r(null,1,[yk,uk],null),yi(df(27)),new r(null,1,[yk,Gj],null),yi(df(152,158,159)),new r(null,1,[yk,ll],null),yi(df(144)),new r(null,1,[yk,ql],null),yi(df(157)),new r(null,1,[yk,Rk],null),yi(df(155)),new r(null,1,[yk,Hl],null)]),tq=Pe([Ej,Gj, +uk,Fk,Jk,Qk,Rk,ll,ql,Hl,jm,om,Cm,$n],[ke([rq,new r(null,1,[qn,Ul],null),yi(df(32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47)),new r(null,2,[qn,Fm,yk,Qk],null),yi(df(48,49,50,51,52,53,54,55,56,57,59)),new r(null,1,[qn,Xl],null),yi(df(58,60,61,62,63)),new r(null,1,[yk,$n],null),yi(df(64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126)), +new r(null,1,[yk,Fk],null),yi(df(127)),new r(null,1,[qn,Ul],null)]),Pe([Sk,yi(df(88,94,95)),rq,yi(df(91)),yi(df(80)),yi(df(32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47)),yi(df(127)),yi(df(48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,81,82,83,84,85,86,87,89,90,92,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126)),yi(df(93))],[po,new r(null,1,[yk,ll],null),new r(null,1,[qn,xl], +null),new r(null,1,[yk,Hl],null),new r(null,1,[yk,ql],null),new r(null,2,[qn,Fm,yk,jm],null),new r(null,1,[qn,Ul],null),new r(null,2,[qn,Pj,yk,uk],null),new r(null,1,[yk,Rk],null)]),ke([rq,new r(null,1,[qn,xl],null),yi(df(32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118, +119,120,121,122,123,124,125,126,127,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255)),new r(null,1,[qn,Pl],null)]),ke([Sk,zj,rq,new r(null,1,[qn,Fn],null),yi(df(32,33, +34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126)),new r(null,1,[qn,Fn],null),yi(df(127)),new r(null,1,[qn,Ul],null),El,In]),ke([rq,new r(null,1,[qn,xl],null),yi(df(48,49,50,51,52,53,54,55,56,57,59)),new r(null,1,[qn,Xl],null),yi(df(58,60,61,62, +63)),new r(null,1,[yk,Cm],null),yi(df(32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47)),new r(null,2,[qn,Fm,yk,om],null),yi(df(64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126)),new r(null,2,[qn,Rl,yk,uk],null),yi(df(127)),new r(null,1,[qn,Ul],null)]),ke([rq,new r(null,1,[qn,Ul],null),yi(df(32,33,34,35,36,37,38,39,40,41,42,43,44,45, +46,47)),new r(null,1,[qn,Fm],null),yi(df(48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63)),new r(null,1,[yk,$n],null),yi(df(64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126)),new r(null,1,[yk,Fk],null),yi(df(127)),new r(null,1,[qn,Ul],null)]),ke([Sk,um,re.c(rq,7),new r(null,1,[qn,Ul],null),yi(df(32,33,34,35,36,37,38,39,40,41,42,43,44, +45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127)),new r(null,1,[qn,ak],null),yi(df(7)),new r(null,1,[yk,uk],null),El,Wj]),ke([rq,new r(null,1,[qn,Ul],null),yi(df(32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68, +69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127)),new r(null,1,[qn,Ul],null)]),ke([Sk,po,rq,new r(null,1,[qn,Ul],null),yi(df(32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47)),new r(null,2,[qn,Fm,yk,Qk],null),yi(df(58)),new r(null,1,[yk,$n],null),yi(df(48,49,50,51,52,53,54,55,56,57,59)),new r(null,2,[qn,Xl,yk,Ej],null),yi(df(60,61,62,63)),new r(null, +2,[qn,Fm,yk,Ej],null),yi(df(64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126)),new r(null,1,[yk,Fk],null),yi(df(127)),new r(null,1,[qn,Ul],null)]),ke([Sk,po,rq,new r(null,1,[qn,xl],null),yi(df(64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108, +109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126)),new r(null,2,[qn,Rl,yk,uk],null),yi(df(48,49,50,51,52,53,54,55,56,57,59)),new r(null,2,[qn,Xl,yk,Jk],null),yi(df(60,61,62,63)),new r(null,2,[qn,Fm,yk,Jk],null),yi(df(58)),new r(null,1,[yk,Cm],null),yi(df(32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47)),new r(null,2,[qn,Fm,yk,om],null),yi(df(127)),new r(null,1,[qn,Ul],null)]),ke([rq,new r(null,1,[qn,xl],null),yi(df(32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47)),new r(null, +1,[qn,Fm],null),yi(df(48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126)),new r(null,2,[qn,Pj,yk,uk],null),yi(df(127)),new r(null,1,[qn,Ul],null)]),ke([rq,new r(null,1,[qn,xl],null),yi(df(32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47)),new r(null,1,[qn,Fm],null),yi(df(64,65,66,67,68,69, +70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126)),new r(null,2,[qn,Rl,yk,uk],null),yi(df(48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63)),new r(null,1,[yk,Cm],null),yi(df(127)),new r(null,1,[qn,Ul],null)]),ke([rq,new r(null,1,[qn,xl],null),yi(df(32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63)),new r(null, +1,[qn,Ul],null),yi(df(64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126)),new r(null,1,[yk,uk],null),yi(df(127)),new r(null,1,[qn,Ul],null)]),ke([rq,new r(null,1,[qn,Ul],null),yi(df(32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82, +83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127)),new r(null,1,[qn,Ul],null)])]);function uq(a,b){return Wf(function(a){var c=J(a,0,null);a=J(a,1,null);return t(c.h?c.h(b):c.call(null,b))?a:null},a)} +function vq(a,b){var c=D.c(tq,a),d=uq(sq,b);var e=t(d)?d:uq(c,160<=b?65:b);d=qn.h(e);e=yk.h(e);if(t(e)){var f=D.c(tq,e);c=El.h(c);f=Sk.h(f);d=Wg(vg(ub,new R(null,3,5,T,[c,d,f],null)));return new R(null,2,5,T,[e,d],null)}return new R(null,2,5,T,[a,t(d)?new R(null,1,5,T,[d],null):he],null)} +var xq=P(hi,function wq(a){return new kf(null,function(){for(;;){var c=E(a);if(c){if(Ae(c)){var d=Wc(c),e=H(d),f=of(e);a:for(var h=0;;)if(h<e){var k=A.c(d,h);k=ke([k,xg(ag.c(vq,k),Fi(0,160,1))]);f.add(k);h+=1}else{d=!0;break a}return d?qf(f.Da(),wq(Xc(c))):qf(f.Da(),null)}f=y(c);return ae(ke([f,xg(ag.c(vq,f),Fi(0,160,1))]),wq(vd(c)))}return null}},null,null)}(lh(tq)));function yq(a,b){var c=Array.prototype.slice.call(arguments),d=c.shift();if("undefined"==typeof d)throw Error("[goog.string.format] Template required");return d.replace(/%([0\-\ \+]*)(\d+)?(\.(\d+))?([%sfdiu])/g,function(a,b,d,k,l,p,m,u){if("%"==p)return"%";var e=c.shift();if("undefined"==typeof e)throw Error("[goog.string.format] Not enough arguments");arguments[0]=e;return yq.fc[p].apply(null,arguments)})}yq.fc={}; +yq.fc.s=function(a,b,c){return isNaN(c)||""==c||a.length>=Number(c)?a:a=-1<b.indexOf("-",0)?a+sa(" ",Number(c)-a.length):sa(" ",Number(c)-a.length)+a}; +yq.fc.f=function(a,b,c,d,e){d=a.toString();isNaN(e)||""==e||(d=parseFloat(a).toFixed(e));var f=0>Number(a)?"-":0<=b.indexOf("+")?"+":0<=b.indexOf(" ")?" ":"";0<=Number(a)&&(d=f+d);if(isNaN(c)||d.length>=Number(c))return d;d=isNaN(e)?Math.abs(Number(a)).toString():Math.abs(Number(a)).toFixed(e);a=Number(c)-d.length-f.length;0<=b.indexOf("-",0)?d=f+d+sa(" ",a):(b=0<=b.indexOf("0",0)?"0":" ",d=f+sa(b,a)+d);return d};yq.fc.d=function(a,b,c,d,e,f,h,k){return yq.fc.f(parseInt(a,10),b,c,d,0,f,h,k)}; +yq.fc.i=yq.fc.d;yq.fc.u=yq.fc.d;function zq(a){var b=be([Vk,null]);return wg.c(t(a)?a:Ef,function(){return function e(a){return new kf(null,function(){for(var b=a;;)if(b=E(b)){if(Ae(b)){var d=Wc(b),k=H(d),l=of(k);a:for(var p=0;;)if(p<k){var m=A.c(d,p),u=J(m,0,null);m=J(m,1,null);t(m)&&l.add(new R(null,2,5,T,[u,m],null));p+=1}else{d=!0;break a}return d?qf(l.Da(),e(Xc(b))):qf(l.Da(),null)}d=y(b);l=J(d,0,null);d=J(d,1,null);if(t(d))return ae(new R(null,2,5,T,[l,d],null),e(vd(b)));b=vd(b)}else return null},null,null)}(yg(2,2,b))}())} +function Aq(a){for(var b=[],c=arguments.length,d=0;;)if(d<c)b.push(arguments[d]),d+=1;else break;return Bq(arguments[0],1<b.length?new Jb(b.slice(1),0,null):null)}function Bq(a,b){return Kb(yq,a,b)}dg.h(19);function Cq(a){return Mb(function(a,c){var b=J(c,0,null),e=J(c,1,null);return Do(a,e,""+v.h(b))},a,Oe(function(a){return-H(ee(a))}))} +function Dq(a){a=""+v.h(a);var b=/function ([^\(]*)\(/;if("string"===typeof a)a=b.exec(a),a=null==a?null:1===H(a)?y(a):Wg(a);else throw new TypeError("re-find must match against a string.");a=Bf(ee(a));return Cq(t(a)?a:"function")}function Eq(a,b){a.schema$utils$schema=b}dg.h(!1);var Fq,Gq=function Gq(a){if(null!=a&&null!=a.xb)return a.xb(a);var c=Gq[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Gq._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("Schema.explain",a);}; +Gq["function"]=function(a){var b=a.schema$utils$schema;return t(b)?Gq(b):t(G.c?G.c(null,a):G.call(null,null,a))?Wl:t(G.c?G.c(Boolean,a):G.call(null,Boolean,a))?xk:t(G.c?G.c(Number,a):G.call(null,Number,a))?sl:t(G.c?G.c(null,a):G.call(null,null,a))?Cl:t(G.c?G.c(Date,a):G.call(null,Date,a))?Ll:t(G.c?G.c(yj,a):G.call(null,yj,a))?ym:a};function Hq(a,b,c,d){this.nc=a;this.v=b;this.j=c;this.w=d;this.m=2229667594;this.J=139264}g=Hq.prototype;g.V=function(a,b){return this.I(null,b,null)}; +g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "_":return this.nc;default:return D.l(this.j,b,c)}};g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#schema.core.AnythingSchema{",", ","}",c,O.c(new R(null,1,5,T,[new R(null,2,5,T,[Ck,this.nc],null)],null),this.j))};g.ba=function(){return new fh(0,this,1,new R(null,1,5,T,[Ck],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 1+H(this.j)}; +g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return-1432036169^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.nc,b.nc)&&G.c(this.j,b.j)};g.ga=function(a,b){return He(new ti(null,new r(null,1,[Ck,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new Hq(this.nc,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(Ck,b):N.call(null,Ck,b))?new Hq(c,this.v,this.j,null):new Hq(this.nc,this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(new R(null,1,5,T,[new R(null,2,5,T,[Ck,this.nc],null)],null),this.j))};g.T=function(a,b){return new Hq(this.nc,b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};g.xb=function(){return Al};var Iq=new Hq(null,null,null,null); +function Jq(a,b,c,d,e){this.wb=a;this.Xb=b;this.v=c;this.j=d;this.w=e;this.m=2229667594;this.J=139264}g=Jq.prototype;g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "p?":return this.wb;case "pred-name":return this.Xb;default:return D.l(this.j,b,c)}}; +g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#schema.core.Predicate{",", ","}",c,O.c(new R(null,2,5,T,[new R(null,2,5,T,[Un,this.wb],null),new R(null,2,5,T,[Tm,this.Xb],null)],null),this.j))};g.ba=function(){return new fh(0,this,2,new R(null,2,5,T,[Un,Tm],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 2+H(this.j)}; +g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return 2041221968^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.wb,b.wb)&&G.c(this.Xb,b.Xb)&&G.c(this.j,b.j)};g.ga=function(a,b){return He(new ti(null,new r(null,2,[Tm,null,Un,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new Jq(this.wb,this.Xb,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(Un,b):N.call(null,Un,b))?new Jq(c,this.Xb,this.v,this.j,null):t(N.c?N.c(Tm,b):N.call(null,Tm,b))?new Jq(this.wb,c,this.v,this.j,null):new Jq(this.wb,this.Xb,this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(new R(null,2,5,T,[new R(null,2,5,T,[Un,this.wb],null),new R(null,2,5,T,[Tm,this.Xb],null)],null),this.j))};g.T=function(a,b){return new Jq(this.wb,this.Xb,b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)}; +g.xb=function(){return G.c(this.wb,Ge)?bo:G.c(this.wb,gf)?kn:G.c(this.wb,qd)?hk:G.c(this.wb,yb)?Wl:Tb(Tb(wd,this.Xb),yl)};function Kq(a){var b=td.h(Dq(a));if(!Fe(a))throw Error(Bq("Not a function: %s",be([a])));return new Jq(a,b,null,null,null)}RegExp.prototype.xb=function(){return td.h(['#"',v.h((""+v.h(this)).slice(1,-1)),'"'].join(""))};var Lq=Kq(yb),Mq=Boolean,Nq=Number,Oq=Kq(Ge),Pq=Kq(gf);Kq(qd); +"undefined"===typeof Fq&&(Fq=function(a){this.Bf=a;this.m=393216;this.J=0},Fq.prototype.T=function(a,b){return new Fq(b)},Fq.prototype.P=function(){return this.Bf},Fq.prototype.xb=function(){return Cl},Fq.Wc=function(){return new R(null,1,5,T,[bn],null)},Fq.qc=!0,Fq.Tb="schema.core/t_schema$core38849",Fq.Ec=function(a,b){return Jc(b,"schema.core/t_schema$core38849")});function Qq(a,b,c,d){this.ia=a;this.v=b;this.j=c;this.w=d;this.m=2229667594;this.J=139264}g=Qq.prototype; +g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "schema":return this.ia;default:return D.l(this.j,b,c)}};g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#schema.core.Maybe{",", ","}",c,O.c(new R(null,1,5,T,[new R(null,2,5,T,[Mj,this.ia],null)],null),this.j))};g.ba=function(){return new fh(0,this,1,new R(null,1,5,T,[Mj],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v}; +g.W=function(){return 1+H(this.j)};g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return-805411239^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.ia,b.ia)&&G.c(this.j,b.j)};g.ga=function(a,b){return He(new ti(null,new r(null,1,[Mj,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new Qq(this.ia,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(Mj,b):N.call(null,Mj,b))?new Qq(c,this.v,this.j,null):new Qq(this.ia,this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(new R(null,1,5,T,[new R(null,2,5,T,[Mj,this.ia],null)],null),this.j))};g.T=function(a,b){return new Qq(this.ia,b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};g.xb=function(){var a=Gq(this.ia);a=Tb(wd,a);return Tb(a,am)}; +function Rq(a,b,c,d,e){this.Yb=a;this.Hb=b;this.v=c;this.j=d;this.w=e;this.m=2229667594;this.J=139264}g=Rq.prototype;g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "preds-and-schemas":return this.Yb;case "error-symbol":return this.Hb;default:return D.l(this.j,b,c)}}; +g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#schema.core.ConditionalSchema{",", ","}",c,O.c(new R(null,2,5,T,[new R(null,2,5,T,[Il,this.Yb],null),new R(null,2,5,T,[Om,this.Hb],null)],null),this.j))};g.ba=function(){return new fh(0,this,2,new R(null,2,5,T,[Il,Om],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 2+H(this.j)}; +g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return 1418435858^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.Yb,b.Yb)&&G.c(this.Hb,b.Hb)&&G.c(this.j,b.j)};g.ga=function(a,b){return He(new ti(null,new r(null,2,[Il,null,Om,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new Rq(this.Yb,this.Hb,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(Il,b):N.call(null,Il,b))?new Rq(c,this.Hb,this.v,this.j,null):t(N.c?N.c(Om,b):N.call(null,Om,b))?new Rq(this.Yb,c,this.v,this.j,null):new Rq(this.Yb,this.Hb,this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(new R(null,2,5,T,[new R(null,2,5,T,[Il,this.Yb],null),new R(null,2,5,T,[Om,this.Hb],null)],null),this.j))};g.T=function(a,b){return new Rq(this.Yb,this.Hb,b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)}; +g.xb=function(){return ae(pk,O.c(sg(function(){return function(a){var b=J(a,0,null);a=J(a,1,null);return new R(null,2,5,T,[td.h(Dq(b)),Gq(a)],null)}}(this),be([this.Yb])),t(this.Hb)?new R(null,1,5,T,[this.Hb],null):null))};function Sq(a){return a instanceof L||!1}function Tq(a,b,c,d){this.k=a;this.v=b;this.j=c;this.w=d;this.m=2229667594;this.J=139264}g=Tq.prototype;g.V=function(a,b){return this.I(null,b,null)}; +g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "k":return this.k;default:return D.l(this.j,b,c)}};g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#schema.core.OptionalKey{",", ","}",c,O.c(new R(null,1,5,T,[new R(null,2,5,T,[Yl,this.k],null)],null),this.j))};g.ba=function(){return new fh(0,this,1,new R(null,1,5,T,[Yl],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 1+H(this.j)}; +g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return-1508333161^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.k,b.k)&&G.c(this.j,b.j)};g.ga=function(a,b){return He(new ti(null,new r(null,1,[Yl,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new Tq(this.k,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(Yl,b):N.call(null,Yl,b))?new Tq(c,this.v,this.j,null):new Tq(this.k,this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(new R(null,1,5,T,[new R(null,2,5,T,[Yl,this.k],null)],null),this.j))};g.T=function(a,b){return new Tq(this.k,b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};function Uq(a){return new Tq(a,null,null,null)} +function Vq(a){var b=Sq(a);if(t(t(b)?b:a instanceof Tq)){if(a instanceof L)return a;b=t(Sq(a))?Zn:t(a instanceof Tq)?Nj:null;if(!(a instanceof L))if(t(a instanceof Tq))a=a.k;else throw Error(Bq("Bad explicit key: %s",be([a])));a=Tb(wd,a);return Tb(a,b)}return Gq(a)} +function Wq(a){return wg.c(Ef,function(){return function d(a){return new kf(null,function(){for(;;){var c=E(a);if(c){if(Ae(c)){var f=Wc(c),h=H(f),k=of(h);a:for(var l=0;;)if(l<h){var p=A.c(f,l),m=J(p,0,null);p=J(p,1,null);m=new R(null,2,5,T,[Vq(m),Gq(p)],null);k.add(m);l+=1}else{f=!0;break a}return f?qf(k.Da(),d(Xc(c))):qf(k.Da(),null)}f=y(c);k=J(f,0,null);f=J(f,1,null);return ae(new R(null,2,5,T,[Vq(k),Gq(f)],null),d(vd(c)))}return null}},null,null)}(a)}())}r.prototype.xb=function(){return Wq(this)}; +Jh.prototype.xb=function(){return Wq(this)};ti.prototype.xb=function(){return yi(new R(null,1,5,T,[Gq(y(this))],null))};function Xq(a,b,c,d,e,f){this.ia=a;this.Fb=b;this.name=c;this.v=d;this.j=e;this.w=f;this.m=2229667594;this.J=139264}g=Xq.prototype;g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "schema":return this.ia;case "optional?":return this.Fb;case "name":return this.name;default:return D.l(this.j,b,c)}}; +g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#schema.core.One{",", ","}",c,O.c(new R(null,3,5,T,[new R(null,2,5,T,[Mj,this.ia],null),new R(null,2,5,T,[nm,this.Fb],null),new R(null,2,5,T,[Tk,this.name],null)],null),this.j))};g.ba=function(){return new fh(0,this,3,new R(null,3,5,T,[Mj,nm,Tk],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 3+H(this.j)}; +g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return-197981045^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.ia,b.ia)&&G.c(this.Fb,b.Fb)&&G.c(this.name,b.name)&&G.c(this.j,b.j)};g.ga=function(a,b){return He(new ti(null,new r(null,3,[Mj,null,Tk,null,nm,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new Xq(this.ia,this.Fb,this.name,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(Mj,b):N.call(null,Mj,b))?new Xq(c,this.Fb,this.name,this.v,this.j,null):t(N.c?N.c(nm,b):N.call(null,nm,b))?new Xq(this.ia,c,this.name,this.v,this.j,null):t(N.c?N.c(Tk,b):N.call(null,Tk,b))?new Xq(this.ia,this.Fb,c,this.v,this.j,null):new Xq(this.ia,this.Fb,this.name,this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(new R(null,3,5,T,[new R(null,2,5,T,[Mj,this.ia],null),new R(null,2,5,T,[nm,this.Fb],null),new R(null,2,5,T,[Tk,this.name],null)],null),this.j))}; +g.T=function(a,b){return new Xq(this.ia,this.Fb,this.name,b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};function Yq(a,b){return new Xq(a,!1,b,null,null,null)} +function Zq(a){var b=Gi(function(a){return a instanceof Xq&&wb(nm.h(a))},a),c=J(b,0,null),d=J(b,1,null),e=Gi(function(){return function(a){var b=a instanceof Xq;return b?nm.h(a):b}}(b,c,d),d),f=J(e,0,null),h=J(e,1,null);if(!(1>=H(h)&&Vf(function(){return function(a){return!(a instanceof Xq)}}(b,c,d,e,f,h),h)))throw Error(Bq("%s is not a valid sequence schema; %s%s%s",be([a,"a valid sequence schema consists of zero or more `one` elements, ","followed by zero or more `optional` elements, followed by an optional ", +"schema that will match the remaining elements."])));return new R(null,2,5,T,[O.c(c,f),y(h)],null)} +R.prototype.xb=function(){var a=this,b=Zq(a),c=J(b,0,null),d=J(b,1,null);return Wg(O.c(function(){return function(a,b,c,d){return function m(e){return new kf(null,function(){return function(){for(;;){var a=E(e);if(a){if(Ae(a)){var b=Wc(a),c=H(b),d=of(c);return function(){for(var a=0;;)if(a<c){var e=A.c(b,a),f=d;var h=t(e.Fb)?ao:zk;var k=Gq(Mj.h(e));e=Tk.h(e);e=Tb(wd,e);k=Tb(e,k);h=Tb(k,h);f.add(h);a+=1}else return!0}()?qf(d.Da(),m(Xc(a))):qf(d.Da(),null)}var f=y(a);return ae(function(){var a=t(f.Fb)? +ao:zk;var b=Gq(Mj.h(f));var c=Tk.h(f);c=Tb(wd,c);b=Tb(c,b);return Tb(b,a)}(),m(vd(a)))}return null}}}(a,b,c,d),null,null)}}(b,c,d,a)(c)}(),t(d)?new R(null,1,5,T,[Gq(d)],null):null))};function $q(a,b,c,d,e){this.Vb=a;this.ia=b;this.v=c;this.j=d;this.w=e;this.m=2229667594;this.J=139264}g=$q.prototype;g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "klass":return this.Vb;case "schema":return this.ia;default:return D.l(this.j,b,c)}}; +g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#schema.core.Record{",", ","}",c,O.c(new R(null,2,5,T,[new R(null,2,5,T,[ck,this.Vb],null),new R(null,2,5,T,[Mj,this.ia],null)],null),this.j))};g.ba=function(){return new fh(0,this,2,new R(null,2,5,T,[ck,Mj],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 2+H(this.j)}; +g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return-1486476872^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.Vb,b.Vb)&&G.c(this.ia,b.ia)&&G.c(this.j,b.j)};g.ga=function(a,b){return He(new ti(null,new r(null,2,[Mj,null,ck,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new $q(this.Vb,this.ia,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(ck,b):N.call(null,ck,b))?new $q(c,this.ia,this.v,this.j,null):t(N.c?N.c(Mj,b):N.call(null,Mj,b))?new $q(this.Vb,c,this.v,this.j,null):new $q(this.Vb,this.ia,this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(new R(null,2,5,T,[new R(null,2,5,T,[ck,this.Vb],null),new R(null,2,5,T,[Mj,this.ia],null)],null),this.j))};g.T=function(a,b){return new $q(this.Vb,this.ia,b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)}; +g.xb=function(){var a=td.h(Vi(be([this.Vb])));var b=Gq(this.ia);b=Tb(wd,b);a=Tb(b,a);return Tb(a,Xn)};function ar(a,b,c){if(!xe(b))throw Error(Bq("Expected map, got %s",be([typeof b])));return pe(new $q(a,b,null,null,null),new r(null,1,[Qm,c],null))}function br(a){a=Gi(function(a){return a instanceof Xq},a);var b=J(a,0,null),c=J(a,1,null);return O.c(ig.c(function(){return function(a){return Gq(a.ia)}}(a,b,c),b),E(c)?new R(null,2,5,T,[Dj,xg(Gq,c)],null):null)} +function cr(a,b,c,d,e){this.Nb=a;this.Db=b;this.v=c;this.j=d;this.w=e;this.m=2229667594;this.J=139264}g=cr.prototype;g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "output-schema":return this.Nb;case "input-schemas":return this.Db;default:return D.l(this.j,b,c)}}; +g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#schema.core.FnSchema{",", ","}",c,O.c(new R(null,2,5,T,[new R(null,2,5,T,[Wk,this.Nb],null),new R(null,2,5,T,[jl,this.Db],null)],null),this.j))};g.ba=function(){return new fh(0,this,2,new R(null,2,5,T,[Wk,jl],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 2+H(this.j)}; +g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return-2054647546^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.Nb,b.Nb)&&G.c(this.Db,b.Db)&&G.c(this.j,b.j)};g.ga=function(a,b){return He(new ti(null,new r(null,2,[Wk,null,jl,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new cr(this.Nb,this.Db,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(Wk,b):N.call(null,Wk,b))?new cr(c,this.Db,this.v,this.j,null):t(N.c?N.c(jl,b):N.call(null,jl,b))?new cr(this.Nb,c,this.v,this.j,null):new cr(this.Nb,this.Db,this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(new R(null,2,5,T,[new R(null,2,5,T,[Wk,this.Nb],null),new R(null,2,5,T,[jl,this.Db],null)],null),this.j))};g.T=function(a,b){return new cr(this.Nb,this.Db,b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)}; +g.xb=function(){if(1<H(this.Db)){var a=Gq(this.Nb);var b=ig.c(br,this.Db);a=ae(Sn,ae(a,b))}else a=Gq(this.Nb),b=br(y(this.Db)),a=ae(hn,ae(a,b));return a};function dr(a,b){return new cr(a,b,null,null,null)}function er(a){return E(a)?fe(a)instanceof Xq?H(a):Number.MAX_VALUE:0} +function fr(a,b){if(!E(b))throw Error(Aq("Function must have at least one input schema"));if(!Vf(ze,b))throw Error(Aq("Each arity must be a vector."));if(!t(P(Ie,ig.c(er,b))))throw Error(Aq("Arities must be distinct"));return new cr(a,Qe(er,b),null,null,null)};var gr,hr,ir=Kq(Fe),jr=new r(null,3,[zn,Nq,Aj,Nq,On,Mq],null),kr; +kr=function(a){if(!E(a)||!(Xf(H(a))||fe(a)instanceof rd))throw Error(Bq("Expected even, nonzero number of args (with optional trailing symbol); got %s",be([H(a)])));return new Rq(Wg(function(){return function d(a){return new kf(null,function(){for(;;){var c=E(a);if(c){if(Ae(c)){var f=Wc(c),h=H(f),k=of(h);a:for(var l=0;;)if(l<h){var p=A.c(f,l),m=J(p,0,null),u=J(p,1,null);p=k;if(!Fe(m))throw Error(Aq(["Conditional predicate ",v.h(m)," must be a function"].join("")));m=new R(null,2,5,T,[G.c(m,sk)?Zf(!0): +m,u],null);p.add(m);l+=1}else{f=!0;break a}return f?qf(k.Da(),d(Xc(c))):qf(k.Da(),null)}f=y(c);k=J(f,0,null);h=J(f,1,null);f=ae;if(!Fe(k))throw Error(Aq(["Conditional predicate ",v.h(k)," must be a function"].join("")));k=new R(null,2,5,T,[G.c(k,sk)?Zf(!0):k,h],null);return f(k,d(vd(c)))}return null}},null,null)}(yg(2,2,a))}()),Xf(H(a))?null:fe(a),null,null,null)}(be([ze,new R(null,3,5,T,[Yq(Nq,"r"),Yq(Nq,"g"),Yq(Nq,"b")],null),Zf(!0),Nq])); +var lr=ke([Uq(Ok),kr,Uq(Tn),kr,Uq(Kj),Mq,Uq(Yn),Mq,Uq(Vl),Mq,Uq(dk),Mq,Uq(Nk),Mq]),mr=new r(null,4,[pl,new r(null,2,[zn,Nq,Aj,Nq],null),Oj,lr,yn,Mq,Rj,Mq],null),nr=new R(null,2,5,T,[Yq(Nq,"unicode codepoint"),Yq(lr,"text attributes")],null),or=new R(null,1,5,T,[nr],null),pr=E(ug(function(a){return Sq(a)},lh(null)));if(!wb(pr))throw Error(Bq("extra-key-schema? can not contain required keys: %s",be([Wg(pr)]))); +function qr(a,b,c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X,Ga){this.width=a;this.height=b;this.Ba=c;this.qa=d;this.Aa=e;this.cursor=f;this.ra=h;this.sa=k;this.ta=l;this.pa=p;this.ua=m;this.va=u;this.wa=w;this.buffer=x;this.lines=C;this.za=F;this.xa=I;this.ya=M;this.v=S;this.j=X;this.w=Ga;this.m=2229667594;this.J=139264}g=qr.prototype;g.V=function(a,b){return this.I(null,b,null)}; +g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "width":return this.width;case "height":return this.height;case "top-margin":return this.Ba;case "bottom-margin":return this.qa;case "tabs":return this.Aa;case "cursor":return this.cursor;case "char-attrs":return this.ra;case "charset-fn":return this.sa;case "insert-mode":return this.ta;case "auto-wrap-mode":return this.pa;case "new-line-mode":return this.ua;case "next-print-wraps":return this.va;case "origin-mode":return this.wa;case "buffer":return this.buffer; +case "lines":return this.lines;case "saved":return this.za;case "other-buffer-lines":return this.xa;case "other-buffer-saved":return this.ya;default:return D.l(this.j,b,c)}}; +g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.vt.screen.Screen{",", ","}",c,O.c(new R(null,18,5,T,[new R(null,2,5,T,[fl,this.width],null),new R(null,2,5,T,[no,this.height],null),new R(null,2,5,T,[Hn,this.Ba],null),new R(null,2,5,T,[Yj,this.qa],null),new R(null,2,5,T,[tk,this.Aa],null),new R(null,2,5,T,[pl,this.cursor],null),new R(null,2,5,T,[Oj,this.ra],null),new R(null,2,5,T,[im,this.sa],null),new R(null,2,5,T,[$l,this.ta],null),new R(null, +2,5,T,[Rj,this.pa],null),new R(null,2,5,T,[mm,this.ua],null),new R(null,2,5,T,[vk,this.va],null),new R(null,2,5,T,[yn,this.wa],null),new R(null,2,5,T,[io,this.buffer],null),new R(null,2,5,T,[il,this.lines],null),new R(null,2,5,T,[Nm,this.za],null),new R(null,2,5,T,[Wn,this.xa],null),new R(null,2,5,T,[sm,this.ya],null)],null),this.j))};g.ba=function(){return new fh(0,this,18,new R(null,18,5,T,[fl,no,Hn,Yj,tk,pl,Oj,im,$l,Rj,mm,vk,yn,io,il,Nm,Wn,sm],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v}; +g.W=function(){return 18+H(this.j)};g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return-1452363486^Dd(a)}}(b,a)(a)}();return this.w=c}; +g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.width,b.width)&&G.c(this.height,b.height)&&G.c(this.Ba,b.Ba)&&G.c(this.qa,b.qa)&&G.c(this.Aa,b.Aa)&&G.c(this.cursor,b.cursor)&&G.c(this.ra,b.ra)&&G.c(this.sa,b.sa)&&G.c(this.ta,b.ta)&&G.c(this.pa,b.pa)&&G.c(this.ua,b.ua)&&G.c(this.va,b.va)&&G.c(this.wa,b.wa)&&G.c(this.buffer,b.buffer)&&G.c(this.lines,b.lines)&&G.c(this.za,b.za)&&G.c(this.xa,b.xa)&&G.c(this.ya,b.ya)&&G.c(this.j,b.j)}; +g.ga=function(a,b){return He(new ti(null,new r(null,18,[Oj,null,Rj,null,Yj,null,tk,null,vk,null,fl,null,il,null,pl,null,$l,null,im,null,mm,null,sm,null,Nm,null,yn,null,Hn,null,Wn,null,io,null,no,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new qr(this.width,this.height,this.Ba,this.qa,this.Aa,this.cursor,this.ra,this.sa,this.ta,this.pa,this.ua,this.va,this.wa,this.buffer,this.lines,this.za,this.xa,this.ya,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(fl,b):N.call(null,fl,b))?new qr(c,this.height,this.Ba,this.qa,this.Aa,this.cursor,this.ra,this.sa,this.ta,this.pa,this.ua,this.va,this.wa,this.buffer,this.lines,this.za,this.xa,this.ya,this.v,this.j,null):t(N.c?N.c(no,b):N.call(null,no,b))?new qr(this.width,c,this.Ba,this.qa,this.Aa,this.cursor,this.ra,this.sa,this.ta,this.pa,this.ua,this.va,this.wa,this.buffer,this.lines,this.za,this.xa,this.ya,this.v,this.j,null):t(N.c?N.c(Hn,b):N.call(null,Hn,b))?new qr(this.width, +this.height,c,this.qa,this.Aa,this.cursor,this.ra,this.sa,this.ta,this.pa,this.ua,this.va,this.wa,this.buffer,this.lines,this.za,this.xa,this.ya,this.v,this.j,null):t(N.c?N.c(Yj,b):N.call(null,Yj,b))?new qr(this.width,this.height,this.Ba,c,this.Aa,this.cursor,this.ra,this.sa,this.ta,this.pa,this.ua,this.va,this.wa,this.buffer,this.lines,this.za,this.xa,this.ya,this.v,this.j,null):t(N.c?N.c(tk,b):N.call(null,tk,b))?new qr(this.width,this.height,this.Ba,this.qa,c,this.cursor,this.ra,this.sa,this.ta, +this.pa,this.ua,this.va,this.wa,this.buffer,this.lines,this.za,this.xa,this.ya,this.v,this.j,null):t(N.c?N.c(pl,b):N.call(null,pl,b))?new qr(this.width,this.height,this.Ba,this.qa,this.Aa,c,this.ra,this.sa,this.ta,this.pa,this.ua,this.va,this.wa,this.buffer,this.lines,this.za,this.xa,this.ya,this.v,this.j,null):t(N.c?N.c(Oj,b):N.call(null,Oj,b))?new qr(this.width,this.height,this.Ba,this.qa,this.Aa,this.cursor,c,this.sa,this.ta,this.pa,this.ua,this.va,this.wa,this.buffer,this.lines,this.za,this.xa, +this.ya,this.v,this.j,null):t(N.c?N.c(im,b):N.call(null,im,b))?new qr(this.width,this.height,this.Ba,this.qa,this.Aa,this.cursor,this.ra,c,this.ta,this.pa,this.ua,this.va,this.wa,this.buffer,this.lines,this.za,this.xa,this.ya,this.v,this.j,null):t(N.c?N.c($l,b):N.call(null,$l,b))?new qr(this.width,this.height,this.Ba,this.qa,this.Aa,this.cursor,this.ra,this.sa,c,this.pa,this.ua,this.va,this.wa,this.buffer,this.lines,this.za,this.xa,this.ya,this.v,this.j,null):t(N.c?N.c(Rj,b):N.call(null,Rj,b))?new qr(this.width, +this.height,this.Ba,this.qa,this.Aa,this.cursor,this.ra,this.sa,this.ta,c,this.ua,this.va,this.wa,this.buffer,this.lines,this.za,this.xa,this.ya,this.v,this.j,null):t(N.c?N.c(mm,b):N.call(null,mm,b))?new qr(this.width,this.height,this.Ba,this.qa,this.Aa,this.cursor,this.ra,this.sa,this.ta,this.pa,c,this.va,this.wa,this.buffer,this.lines,this.za,this.xa,this.ya,this.v,this.j,null):t(N.c?N.c(vk,b):N.call(null,vk,b))?new qr(this.width,this.height,this.Ba,this.qa,this.Aa,this.cursor,this.ra,this.sa,this.ta, +this.pa,this.ua,c,this.wa,this.buffer,this.lines,this.za,this.xa,this.ya,this.v,this.j,null):t(N.c?N.c(yn,b):N.call(null,yn,b))?new qr(this.width,this.height,this.Ba,this.qa,this.Aa,this.cursor,this.ra,this.sa,this.ta,this.pa,this.ua,this.va,c,this.buffer,this.lines,this.za,this.xa,this.ya,this.v,this.j,null):t(N.c?N.c(io,b):N.call(null,io,b))?new qr(this.width,this.height,this.Ba,this.qa,this.Aa,this.cursor,this.ra,this.sa,this.ta,this.pa,this.ua,this.va,this.wa,c,this.lines,this.za,this.xa,this.ya, +this.v,this.j,null):t(N.c?N.c(il,b):N.call(null,il,b))?new qr(this.width,this.height,this.Ba,this.qa,this.Aa,this.cursor,this.ra,this.sa,this.ta,this.pa,this.ua,this.va,this.wa,this.buffer,c,this.za,this.xa,this.ya,this.v,this.j,null):t(N.c?N.c(Nm,b):N.call(null,Nm,b))?new qr(this.width,this.height,this.Ba,this.qa,this.Aa,this.cursor,this.ra,this.sa,this.ta,this.pa,this.ua,this.va,this.wa,this.buffer,this.lines,c,this.xa,this.ya,this.v,this.j,null):t(N.c?N.c(Wn,b):N.call(null,Wn,b))?new qr(this.width, +this.height,this.Ba,this.qa,this.Aa,this.cursor,this.ra,this.sa,this.ta,this.pa,this.ua,this.va,this.wa,this.buffer,this.lines,this.za,c,this.ya,this.v,this.j,null):t(N.c?N.c(sm,b):N.call(null,sm,b))?new qr(this.width,this.height,this.Ba,this.qa,this.Aa,this.cursor,this.ra,this.sa,this.ta,this.pa,this.ua,this.va,this.wa,this.buffer,this.lines,this.za,this.xa,c,this.v,this.j,null):new qr(this.width,this.height,this.Ba,this.qa,this.Aa,this.cursor,this.ra,this.sa,this.ta,this.pa,this.ua,this.va,this.wa, +this.buffer,this.lines,this.za,this.xa,this.ya,this.v,K.l(this.j,b,c),null)}; +g.S=function(){return E(O.c(new R(null,18,5,T,[new R(null,2,5,T,[fl,this.width],null),new R(null,2,5,T,[no,this.height],null),new R(null,2,5,T,[Hn,this.Ba],null),new R(null,2,5,T,[Yj,this.qa],null),new R(null,2,5,T,[tk,this.Aa],null),new R(null,2,5,T,[pl,this.cursor],null),new R(null,2,5,T,[Oj,this.ra],null),new R(null,2,5,T,[im,this.sa],null),new R(null,2,5,T,[$l,this.ta],null),new R(null,2,5,T,[Rj,this.pa],null),new R(null,2,5,T,[mm,this.ua],null),new R(null,2,5,T,[vk,this.va],null),new R(null, +2,5,T,[yn,this.wa],null),new R(null,2,5,T,[io,this.buffer],null),new R(null,2,5,T,[il,this.lines],null),new R(null,2,5,T,[Nm,this.za],null),new R(null,2,5,T,[Wn,this.xa],null),new R(null,2,5,T,[sm,this.ya],null)],null),this.j))};g.T=function(a,b){return new qr(this.width,this.height,this.Ba,this.qa,this.Aa,this.cursor,this.ra,this.sa,this.ta,this.pa,this.ua,this.va,this.wa,this.buffer,this.lines,this.za,this.xa,this.ya,b,this.j,this.w)}; +g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};function rr(a){return new qr(fl.h(a),no.h(a),Hn.h(a),Yj.h(a),tk.h(a),pl.h(a),Oj.h(a),im.h(a),$l.h(a),Rj.h(a),mm.h(a),vk.h(a),yn.h(a),io.h(a),il.h(a),Nm.h(a),Wn.h(a),sm.h(a),null,Bf(le.A(a,fl,be([no,Hn,Yj,tk,pl,Oj,im,$l,Rj,mm,vk,yn,io,il,Nm,Wn,sm]))),null)} +Eq(qr,zq(ar(qr,hi.A(be([Pe([Oj,Rj,Yj,tk,vk,fl,il,pl,$l,im,mm,sm,Nm,yn,Hn,Wn,io,no],[lr,Mq,Nq,wi,Mq,Nq,new R(null,1,5,T,[or],null),jr,Mq,ir,Mq,mr,mr,Mq,Nq,new Qq(new R(null,1,5,T,[or],null),null,null,null),Pq,Nq]),null])),function(a){return rr(wg.c(Ef,a))})));var sr=new R(null,2,5,T,[Yq(Nq,pe(en,new r(null,1,[Mj,fn],null))),Yq(lr,pe(Dk,new r(null,1,[Mj,Gn],null)))],null),tr;tr=function(a,b){return new R(null,2,5,T,[a,b],null)};Eq(tr,dr(nr,new R(null,1,5,T,[sr],null))); +var ur=new R(null,1,5,T,[Yq(Iq,pe(Dk,new r(null,1,[Mj,Ij],null)))],null),vr;vr=function(a){return tr(32,a)};Eq(vr,dr(nr,new R(null,1,5,T,[ur],null)));var wr=new R(null,1,5,T,[Yq(Iq,pe(Am,new r(null,1,[Mj,Ij],null)))],null),xr=new R(null,2,5,T,[Yq(Iq,pe(Am,new r(null,1,[Mj,Ij],null))),Yq(Iq,pe(Dk,new r(null,1,[Mj,Ij],null)))],null); +gr=function yr(a){switch(arguments.length){case 1:return yr.h(arguments[0]);case 2:return yr.c(arguments[0],arguments[1]);default:throw Error(["Invalid arity: ",v.h(arguments.length)].join(""));}};gr.h=function(a){return gr.c(a,Ef)};gr.c=function(a,b){return Wg(qg(a,vr(b)))};gr.L=2;Eq(gr,fr(or,new R(null,2,5,T,[wr,xr],null))); +var zr=new R(null,1,5,T,[or],null),Ar=new R(null,2,5,T,[Yq(Iq,pe(Am,new r(null,1,[Mj,Ij],null))),Yq(Iq,pe(lk,new r(null,1,[Mj,Ij],null)))],null),Br=new R(null,3,5,T,[Yq(Iq,pe(Am,new r(null,1,[Mj,Ij],null))),Yq(Iq,pe(lk,new r(null,1,[Mj,Ij],null))),Yq(Iq,pe(Dk,new r(null,1,[Mj,Ij],null)))],null); +hr=function Cr(a){switch(arguments.length){case 2:return Cr.c(arguments[0],arguments[1]);case 3:return Cr.l(arguments[0],arguments[1],arguments[2]);default:throw Error(["Invalid arity: ",v.h(arguments.length)].join(""));}};hr.c=function(a,b){return hr.l(a,b,Ef)};hr.l=function(a,b,c){a=gr.c(a,c);return Wg(qg(b,a))};hr.L=3;Eq(hr,fr(zr,new R(null,2,5,T,[Ar,Br],null)));var Dr=new R(null,1,5,T,[Yq(Iq,pe(Am,new r(null,1,[Mj,Ij],null)))],null),Er;Er=function(a){return P(zi,Fi(8,a,8))}; +Eq(Er,dr(wi,new R(null,1,5,T,[Dr],null))); +var Fr=new r(null,3,[zn,0,Aj,0,On,!0],null),Gr=new r(null,4,[pl,new r(null,2,[zn,0,Aj,0],null),Oj,Ef,yn,!1,Rj,!0],null),Hr=Pe([121,110,101,102,106,119,104,116,99,113,117,108,109,118,100,122,111,103,125,107,97,115,112,123,120,126,98,124,96,105,114],[8804,9532,9226,176,9496,9516,9252,9500,9228,9472,9508,9484,9492,9524,9229,8805,9146,177,163,9488,9618,9149,9147,960,9474,8901,9225,8800,9830,9227,9148]),Ir=new R(null,2,5,T,[Yq(Nq,pe(Am,new r(null,1,[Mj,oo],null))),Yq(Nq,pe(lk,new r(null,1,[Mj,oo],null)))], +null),Jr;Jr=function(a,b){return rr(Pe([Oj,Rj,Yj,tk,vk,fl,il,pl,$l,im,mm,sm,Nm,yn,Hn,Wn,io,no],[Ef,!0,b-1,Er(a),!1,a,hr.c(a,b),Fr,!1,Ve,!1,Gr,Gr,!1,0,null,fk,b]))};Eq(Jr,dr(qr,new R(null,1,5,T,[Ir],null)));function Kr(a){return K.l(a,$l,!0)}function Lr(a){return K.l(a,$l,!1)}function Mr(a){return K.l(a,mm,!0)}function Nr(a){return K.l(a,mm,!1)}function Or(a){return K.l(a,Rj,!0)}function Pr(a){return K.l(a,Rj,!1)}function Qr(a,b,c){return zg(a,new R(null,2,5,T,[Oj,b],null),c)} +function Rr(a,b){return Cg(a,Oj,le,b)}function Sr(a,b,c){var d=H(a);b=b<d?b:d;return O.c(kg(b,a),qg(b,c))}var Tr=function Tr(a){switch(arguments.length){case 1:return Tr.h(arguments[0]);case 2:return Tr.c(arguments[0],arguments[1]);default:throw Error(["Invalid arity: ",v.h(arguments.length)].join(""));}};Tr.h=function(a){return Tr.c(a,1)}; +Tr.c=function(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,fl),e=D.c(c,Hn),f=D.c(c,Yj),h=D.c(c,Oj),k=gr.c(d,h);return Bg(c,il,function(a,c,d,e,f,h,k){return function(c){return Wg(O.A(jg(h,c),Sr(Zg(null,c,h,k+1,null),b,a),be([kg(k+1,c)])))}}(k,a,c,c,d,e,f,h))};Tr.L=2;function Ur(a,b,c){var d=H(a);b=b<d?b:d;return O.c(qg(b,c),jg(d-b,a))} +var Vr=function Vr(a){switch(arguments.length){case 1:return Vr.h(arguments[0]);case 2:return Vr.c(arguments[0],arguments[1]);default:throw Error(["Invalid arity: ",v.h(arguments.length)].join(""));}};Vr.h=function(a){return Vr.c(a,1)}; +Vr.c=function(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,fl),e=D.c(c,Hn),f=D.c(c,Yj),h=D.c(c,Oj),k=gr.c(d,h);return Bg(c,il,function(a,c,d,e,f,h,k){return function(c){return Wg(O.A(jg(h,c),Ur(Zg(null,c,h,k+1,null),b,a),be([kg(k+1,c)])))}}(k,a,c,c,d,e,f,h))};Vr.L=2;function Wr(a){return zg(a,new R(null,2,5,T,[pl,On],null),!0)}function Xr(a){return zg(a,new R(null,2,5,T,[pl,On],null),!1)}function Yr(a,b){return K.l(zg(a,new R(null,2,5,T,[pl,zn],null),b),vk,!1)} +function Zr(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,fl),e=0<b?b:0;--d;return Yr(c,e<d?e:d)}function $r(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,pl);d=null!=d&&(d.m&64||q===d.G)?P(U,d):d;d=D.c(d,zn);var e=D.c(c,fl)-1;return K.l(zg(zg(c,new R(null,2,5,T,[pl,zn],null),d<e?d:e),new R(null,2,5,T,[pl,Aj],null),b),vk,!1)}function as(a){var b=null!=a&&(a.m&64||q===a.G)?P(U,a):a;a=D.c(b,yn);b=D.c(b,Hn);return t(a)?b:0} +function bs(a,b){var c=as(a),d=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var e=D.c(d,yn);var f=D.c(d,Yj);d=D.c(d,no);e=t(e)?f:d-1;f=c+b;c=f>c?f:c;return $r(a,e<c?e:c)}function cs(a){return $r(Yr(a,0),as(a))}function Eg(a,b,c){return bs(Zr(a,b),c)}function ds(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,pl);b=null!=b&&(b.m&64||q===b.G)?P(U,b):b;b=D.c(b,Aj);var c=D.c(a,Yj),d=D.c(a,no)-1;return G.c(b,c)?Tr.h(a):b<d?$r(a,b+1):a} +function es(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,pl);b=null!=b&&(b.m&64||q===b.G)?P(U,b):b;b=D.c(b,zn);return Zr(a,b-1)}function fs(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,pl);d=null!=d&&(d.m&64||q===d.G)?P(U,d):d;var e=D.c(d,Aj),f=D.c(c,Hn);return $r(c,e<f?function(){var a=e-b;return 0>a?0:a}():function(){var a=e-b;return f>a?f:a}())} +function gs(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,pl);d=null!=d&&(d.m&64||q===d.G)?P(U,d):d;var e=D.c(d,Aj),f=D.c(c,Yj),h=D.c(c,no);return $r(c,e>f?function(){var a=h-1,c=e+b;return a<c?a:c}():function(){var a=e+b;return f<a?f:a}())}function hs(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,pl);d=null!=d&&(d.m&64||q===d.G)?P(U,d):d;d=D.c(d,zn);return Zr(c,d+b)} +function is(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,pl);d=null!=d&&(d.m&64||q===d.G)?P(U,d):d;d=D.c(d,zn);return Zr(c,d-b)}function js(a){var b=null!=a&&(a.m&64||q===a.G)?P(U,a):a;a=D.c(b,mm);b=ds(b);return t(a)?Yr(b,0):b}function ks(a){return Yr(ds(a),0)}function ls(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,pl);b=null!=b&&(b.m&64||q===b.G)?P(U,b):b;b=D.c(b,Aj);var c=D.c(a,Hn);return G.c(b,c)?Vr.h(a):0<b?$r(a,b-1):a} +function ms(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,pl),c=null!=b&&(b.m&64||q===b.G)?P(U,b):b;b=D.c(c,zn);c=D.c(c,Aj);var d=D.c(a,Oj),e=D.c(a,yn),f=D.c(a,Rj);return K.l(a,Nm,new r(null,4,[pl,new r(null,2,[zn,b,Aj,c],null),Oj,d,yn,e,Rj,f],null))}function ns(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,Nm),c=null!=b&&(b.m&64||q===b.G)?P(U,b):b;b=D.c(c,pl);var d=D.c(c,Oj),e=D.c(c,yn);c=D.c(c,Rj);return Cg(K.A(a,Oj,d,be([vk,!1,yn,e,Rj,c])),pl,hi,b)} +function os(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,io),c=D.c(a,fl),d=D.c(a,no),e=D.c(a,Oj);return G.c(b,fk)?K.A(a,io,tl,be([Wn,il.h(a),sm,Nm.h(a),il,hr.l(c,d,e),Nm,sm.h(a)])):a}function dt(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,io);return G.c(b,tl)?K.A(a,io,fk,be([Wn,null,sm,Nm.h(a),il,Wn.h(a),Nm,sm.h(a)])):a} +function et(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,pl);b=null!=b&&(b.m&64||q===b.G)?P(U,b):b;b=D.c(b,zn);var c=D.c(a,fl);return 0<b&&b<c?Cg(a,tk,ge,b):a}function ft(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,pl);b=null!=b&&(b.m&64||q===b.G)?P(U,b):b;b=D.c(b,zn);return Cg(a,tk,re,b)}function gt(a){return Bg(a,tk,ie)} +function ht(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,pl),e=null!=d&&(d.m&64||q===d.G)?P(U,d):d,f=D.c(e,zn),h=D.c(c,tk),k=D.c(c,fl),l=b-1,p=k-1;d=J(ng(function(a,b,c,d,e,f,h,k){return function(a){return k>=a}}(l,p,a,c,c,d,e,f,h,k),h),l,p);return Zr(c,d)} +function it(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,pl),e=null!=d&&(d.m&64||q===d.G)?P(U,d):d,f=D.c(e,zn),h=D.c(c,tk),k=D.c(c,fl),l=b-1;d=J(cf(Bi(function(a,b,c,d,e,f,h){return function(a){return h>a}}(l,a,c,c,d,e,f,h,k),h)),l,0);return Zr(c,d)}function jt(a){return K.l(a,im,Ve)}function kt(a){return K.l(a,im,Hr)}function lt(a,b,c){return K.l(a,b,c)}function mt(a,b,c){return Wg(O.A(jg(b,a),new R(null,1,5,T,[c],null),be([jg(H(a)-b-1,kg(b,a))])))} +function nt(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,pl),e=null!=d&&(d.m&64||q===d.G)?P(U,d):d;d=D.c(e,zn);e=D.c(e,Aj);var f=D.c(c,fl);D.c(c,no);var h=D.c(c,Oj),k=D.c(c,Rj),l=D.c(c,$l),p=D.c(c,im);p=95<b&&127>b?p.h?p.h(b):p.call(null,b):b;h=tr(p,h);return G.c(f,d+1)?t(k)?K.l(Yr(zg(c,new R(null,3,5,T,[il,e,d],null),h),d+1),vk,!0):zg(c,new R(null,3,5,T,[il,e,d],null),h):Yr(Ag.Z(c,new R(null,2,5,T,[il,e],null),t(l)?mt:lt,d,h),d+1)} +function ot(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,Rj),e=D.c(c,vk);t(t(d)?e:d)&&(c=null!=c&&(c.m&64||q===c.G)?P(U,c):c,d=D.c(c,pl),d=null!=d&&(d.m&64||q===d.G)?P(U,d):d,d=D.c(d,Aj),e=D.c(c,no),c=Yr(c,0),c=G.c(e,d+1)?Tr.h(c):$r(c,d+1));return c=nt(c,b)}function pt(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,fl),c=D.c(a,no);return K.l(a,il,Wg(qg(c,Wg(qg(b,new R(null,2,5,T,[69,Ef],null))))))} +function qt(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,pl);b=null!=b&&(b.m&64||q===b.G)?P(U,b):b;b=D.c(b,Aj);var c=D.c(a,fl),d=D.c(a,Oj);return zg(a,new R(null,2,5,T,[il,b],null),gr.c(c,d))}function rt(a,b,c){return Wg(O.c(jg(b,a),qg(H(a)-b,vr(c))))}function st(a,b,c){return Wg(O.c(qg(b+1,vr(c)),kg(b+1,a)))} +function tt(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,pl),c=null!=b&&(b.m&64||q===b.G)?P(U,b):b;b=D.c(c,zn);c=D.c(c,Aj);var d=D.c(a,fl),e=D.c(a,Oj);--d;return Ag.Z(a,new R(null,2,5,T,[il,c],null),rt,b<d?b:d,e)}function ut(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,pl),c=null!=b&&(b.m&64||q===b.G)?P(U,b):b;b=D.c(c,zn);c=D.c(c,Aj);var d=D.c(a,fl),e=D.c(a,Oj);--d;return Ag.Z(a,new R(null,2,5,T,[il,c],null),st,b<d?b:d,e)} +function vt(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,fl),c=D.c(a,no),d=D.c(a,Oj);return K.l(a,il,hr.l(b,c,d))}function wt(a){var b=null!=a&&(a.m&64||q===a.G)?P(U,a):a,c=D.c(b,pl),d=null!=c&&(c.m&64||q===c.G)?P(U,c):c,e=D.c(d,zn),f=D.c(d,Aj),h=D.c(b,fl),k=D.c(b,no),l=D.c(b,Oj);return Bg(b,il,function(a,b,c,d,e,f,h,k,l,S){return function(a){var b=jg(h,a);a=rt(Vd(a,h),f,S);var c=qg(l-h-1,gr.c(k,S));return Wg(O.A(b,new R(null,1,5,T,[a],null),be([c])))}}(a,b,b,c,d,e,f,h,k,l))} +function xt(a){var b=null!=a&&(a.m&64||q===a.G)?P(U,a):a,c=D.c(b,pl),d=null!=c&&(c.m&64||q===c.G)?P(U,c):c,e=D.c(d,zn),f=D.c(d,Aj),h=D.c(b,fl),k=D.c(b,no),l=D.c(b,Oj);return Bg(b,il,function(a,b,c,d,e,f,h,k,l,S,X){return function(b){var c=qg(k,gr.c(l,X)),d=st(Vd(b,k),a,X);return Wg(O.A(c,new R(null,1,5,T,[d],null),be([kg(k+1,b)])))}}(function(){var a=h-1;return e<a?e:a}(),a,b,b,c,d,e,f,h,k,l))} +function yt(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,pl),e=null!=d&&(d.m&64||q===d.G)?P(U,d):d,f=D.c(e,zn),h=D.c(e,Aj),k=D.c(c,fl),l=D.c(c,Oj);return Ag.l(c,new R(null,2,5,T,[il,h],null),function(a,b,c,d,e,f,h,k,l,S){return function(b){return Wg(O.A(jg(h,b),qg(a,vr(S)),be([kg(h+a,b)])))}}(function(){var a=k-f;return b<a?b:a}(),a,c,c,d,e,f,h,k,l))} +function zt(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,pl),e=null!=d&&(d.m&64||q===d.G)?P(U,d):d,f=D.c(e,zn),h=D.c(e,Aj),k=D.c(c,fl),l=D.c(c,Oj);return Ag.l(c,new R(null,2,5,T,[il,h],null),function(a,c,d,e,f,h,k,l,M){return function(a){return Wg(jg(l,O.A(jg(h,a),qg(b,new R(null,2,5,T,[32,M],null)),be([kg(h,a)]))))}}(a,c,c,d,e,f,h,k,l))} +function At(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,pl),e=null!=d&&(d.m&64||q===d.G)?P(U,d):d,f=D.c(e,Aj),h=D.c(c,Yj),k=D.c(c,fl),l=D.c(c,no),p=D.c(c,Oj),m=gr.c(k,p);return Bg(c,il,function(a,c,d,e,f,h,k,m){return function(c){return Wg(k<=m?O.A(jg(k,c),Ur(Zg(null,c,k,m+1,null),b,a),be([kg(m+1,c)])):O.c(jg(k,c),Ur(kg(k,c),b,a)))}}(m,a,c,c,d,e,f,h,k,l,p))} +function Bt(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,pl),e=null!=d&&(d.m&64||q===d.G)?P(U,d):d,f=D.c(e,Aj),h=D.c(c,Yj),k=D.c(c,fl),l=D.c(c,no),p=D.c(c,Oj),m=gr.c(k,p);return Bg(c,il,function(a,c,d,e,f,h,k,m){return function(c){return Wg(k<=m?O.A(jg(k,c),Sr(Zg(null,c,k,m+1,null),b,a),be([kg(m+1,c)])):O.c(jg(k,c),Sr(kg(k,c),b,a)))}}(m,a,c,c,d,e,f,h,k,l,p))} +function Ct(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,pl),e=null!=d&&(d.m&64||q===d.G)?P(U,d):d,f=D.c(e,zn),h=D.c(e,Aj),k=D.c(c,fl),l=D.c(c,Oj),p=f>=k?Zr(c,k-1):c,m=Mb(D,p,new R(null,2,5,T,[pl,zn],null));return Ag.l(p,new R(null,2,5,T,[il,h],null),function(a,b,c,d,e,f,h,k,m,l,p,Q){return function(a){return Wg(O.A(jg(b,a),kg(b+c,a),be([qg(c,vr(Q))])))}}(p,m,function(){var a=k-m;return b<a?b:a}(),a,c,c,d,e,f,h,k,l))} +var Dt=new R(null,1,5,T,[Yq(new R(null,1,5,T,[Nq],null),pe(Ln,new r(null,1,[Mj,new R(null,1,5,T,[fn],null)],null)))],null),Et;Et=function(a){return P(String.fromCodePoint,a)};Eq(Et,dr(Lq,new R(null,1,5,T,[Dt],null)));var Ft=new R(null,1,5,T,[new R(null,2,5,T,[Yq(Lq,"text"),Yq(lr,"text attributes")],null)],null),Gt=new R(null,1,5,T,[Yq(or,pe(Nn,new r(null,1,[Mj,nk],null)))],null),Ht; +Ht=function(a){a=E(a);var b=y(a),c=z(a);a=he;var d=new R(null,1,5,T,[y(b)],null),e=fe(b);for(b=c;;)if(c=y(b),t(c)){var f=c;c=J(f,0,null);f=J(f,1,null);G.c(f,e)?d=ge.c(d,c):(a=ge.c(a,new R(null,2,5,T,[Et(d),e],null)),d=new R(null,1,5,T,[c],null),e=f);b=vd(b)}else return ge.c(a,new R(null,2,5,T,[Et(d),e],null))};Eq(Ht,dr(Ft,new R(null,1,5,T,[Gt],null))); +function It(a){a=Wr(a);a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,no);a=K.A(a,Hn,0,be([Yj,b-1]));return K.l(K.l(K.l(Lr(a),yn,!1),Oj,Ef),Nm,Gr)};var Jt=Error();var Kt=E(ug(function(a){return Sq(a)},lh(null)));if(!wb(Kt))throw Error(Bq("extra-key-schema? can not contain required keys: %s",be([Wg(Kt)])));function Lt(a,b,c,d,e,f,h){this.Qb=a;this.Pb=b;this.Ob=c;this.screen=d;this.v=e;this.j=f;this.w=h;this.m=2229667594;this.J=139264}g=Lt.prototype;g.V=function(a,b){return this.I(null,b,null)}; +g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "parser-state":return this.Qb;case "parser-params":return this.Pb;case "parser-intermediates":return this.Ob;case "screen":return this.screen;default:return D.l(this.j,b,c)}}; +g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.vt.VT{",", ","}",c,O.c(new R(null,4,5,T,[new R(null,2,5,T,[Tl,this.Qb],null),new R(null,2,5,T,[kk,this.Pb],null),new R(null,2,5,T,[rk,this.Ob],null),new R(null,2,5,T,[V,this.screen],null)],null),this.j))};g.ba=function(){return new fh(0,this,4,new R(null,4,5,T,[Tl,kk,rk,V],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 4+H(this.j)}; +g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return-156373259^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.Qb,b.Qb)&&G.c(this.Pb,b.Pb)&&G.c(this.Ob,b.Ob)&&G.c(this.screen,b.screen)&&G.c(this.j,b.j)}; +g.ga=function(a,b){return He(new ti(null,new r(null,4,[V,null,kk,null,rk,null,Tl,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new Lt(this.Qb,this.Pb,this.Ob,this.screen,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(Tl,b):N.call(null,Tl,b))?new Lt(c,this.Pb,this.Ob,this.screen,this.v,this.j,null):t(N.c?N.c(kk,b):N.call(null,kk,b))?new Lt(this.Qb,c,this.Ob,this.screen,this.v,this.j,null):t(N.c?N.c(rk,b):N.call(null,rk,b))?new Lt(this.Qb,this.Pb,c,this.screen,this.v,this.j,null):t(N.c?N.c(V,b):N.call(null,V,b))?new Lt(this.Qb,this.Pb,this.Ob,c,this.v,this.j,null):new Lt(this.Qb,this.Pb,this.Ob,this.screen,this.v,K.l(this.j,b,c),null)}; +g.S=function(){return E(O.c(new R(null,4,5,T,[new R(null,2,5,T,[Tl,this.Qb],null),new R(null,2,5,T,[kk,this.Pb],null),new R(null,2,5,T,[rk,this.Ob],null),new R(null,2,5,T,[V,this.screen],null)],null),this.j))};g.T=function(a,b){return new Lt(this.Qb,this.Pb,this.Ob,this.screen,b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};function Mt(a){return new Lt(Tl.h(a),kk.h(a),rk.h(a),V.h(a),null,Bf(le.A(a,Tl,be([kk,rk,V]))),null)} +Eq(Lt,zq(ar(Lt,hi.A(be([new r(null,4,[Tl,Pq,kk,new R(null,1,5,T,[Oq],null),rk,new R(null,1,5,T,[Oq],null),V,qr],null),null])),function(a){return Mt(wg.c(Ef,a))})));var Nt=new R(null,2,5,T,[Yq(Nq,pe(Am,new r(null,1,[Mj,oo],null))),Yq(Nq,pe(lk,new r(null,1,[Mj,oo],null)))],null),Ot;Ot=function(a,b){return Mt(new r(null,4,[Tl,uk,kk,he,rk,he,V,Jr(a,b)],null))};Eq(Ot,dr(Lt,new R(null,1,5,T,[Nt],null))); +function Pt(a,b,c){try{if(null===b)try{if(4===c)return Bg(a,V,Kr);throw Jt;}catch(p){if(p instanceof Error){var d=p;if(d===Jt)try{if(20===c)return Bg(a,V,Mr);throw Jt;}catch(m){if(m instanceof Error){var e=m;if(e===Jt)throw Jt;throw e;}throw m;}else throw d;}else throw p;}else throw Jt;}catch(p){if(p instanceof Error)if(d=p,d===Jt)try{if(63===b)try{if(6===c)return Bg(a,V,function(){return function(a){return cs(K.l(a,yn,!0))}}(d));throw Jt;}catch(m){if(m instanceof Error)if(e=m,e===Jt)try{if(7===c)return Bg(a, +V,Or);throw Jt;}catch(u){if(u instanceof Error)if(b=u,b===Jt)try{if(25===c)return Bg(a,V,Wr);throw Jt;}catch(w){if(w instanceof Error){var f=w;if(f===Jt)try{if(47===c)return Bg(a,V,os);throw Jt;}catch(x){if(x instanceof Error){var h=x;if(h===Jt)try{if(1047===c)return Bg(a,V,os);throw Jt;}catch(C){if(C instanceof Error){var k=C;if(k===Jt)try{if(1048===c)return Bg(a,V,ms);throw Jt;}catch(F){if(F instanceof Error){var l=F;if(l===Jt)try{if(1049===c)return Bg(a,V,function(){return function(a){return os(ms(a))}}(l, +k,h,f,b,e,d));throw Jt;}catch(I){if(I instanceof Error){c=I;if(c===Jt)throw Jt;throw c;}throw I;}else throw l;}else throw F;}else throw k;}else throw C;}else throw h;}else throw x;}else throw f;}else throw w;}else throw b;else throw u;}else throw e;else throw m;}else throw Jt;}catch(m){if(m instanceof Error){e=m;if(e===Jt)return a;throw e;}throw m;}else throw d;else throw p;}} +function Qt(a,b,c){try{if(null===b)try{if(4===c)return Bg(a,V,Lr);throw Jt;}catch(p){if(p instanceof Error){var d=p;if(d===Jt)try{if(20===c)return Bg(a,V,Nr);throw Jt;}catch(m){if(m instanceof Error){var e=m;if(e===Jt)throw Jt;throw e;}throw m;}else throw d;}else throw p;}else throw Jt;}catch(p){if(p instanceof Error)if(d=p,d===Jt)try{if(63===b)try{if(6===c)return Bg(a,V,function(){return function(a){return cs(K.l(a,yn,!1))}}(d));throw Jt;}catch(m){if(m instanceof Error)if(e=m,e===Jt)try{if(7===c)return Bg(a, +V,Pr);throw Jt;}catch(u){if(u instanceof Error)if(b=u,b===Jt)try{if(25===c)return Bg(a,V,Xr);throw Jt;}catch(w){if(w instanceof Error){var f=w;if(f===Jt)try{if(47===c)return Bg(a,V,dt);throw Jt;}catch(x){if(x instanceof Error){var h=x;if(h===Jt)try{if(1047===c)return Bg(a,V,dt);throw Jt;}catch(C){if(C instanceof Error){var k=C;if(k===Jt)try{if(1048===c)return Bg(a,V,ns);throw Jt;}catch(F){if(F instanceof Error){var l=F;if(l===Jt)try{if(1049===c)return Bg(a,V,function(){return function(a){return ns(dt(a))}}(l, +k,h,f,b,e,d));throw Jt;}catch(I){if(I instanceof Error){c=I;if(c===Jt)throw Jt;throw c;}throw I;}else throw l;}else throw F;}else throw k;}else throw C;}else throw h;}else throw x;}else throw f;}else throw w;}else throw b;else throw u;}else throw e;else throw m;}else throw Jt;}catch(m){if(m instanceof Error){e=m;if(e===Jt)return a;throw e;}throw m;}else throw d;else throw p;}} +function Rt(a){a=ig.c(function(a){return a-48},a);a=ig.l(Ye,cf(a),rg(function(){return function(a){return 10*a}}(a),1));return Mb(Xe,0,a)}var St=hj(function(a){a:for(var b=he,c=he;;){var d=y(a);if(t(d))G.c(d,59)?(a=vd(a),b=ge.c(b,c),c=he):(a=vd(a),c=ge.c(c,d));else{a=E(c)?ge.c(b,c):b;break a}}return ig.c(Rt,a)});function Tt(a){a=kk.h(a);return St.h?St.h(a):St.call(null,a)}function Ut(a,b,c){a=J(Tt(a),b,0);return 0===a?c:a}function Vt(a){return Bg(a,V,es)}function Wt(a){return Cg(a,V,ht,1)} +function Xt(a){return Cg(a,V,Yr,0)}function Yt(a){return Bg(a,V,js)}function Zt(a){return Bg(a,V,kt)}function $t(a){return Bg(a,V,jt)}function au(a){return Bg(a,V,ks)}function bu(a){return Bg(a,V,et)}function cu(a){return Bg(a,V,ls)}function du(a){return Ot(fl.h(V.h(a)),no.h(V.h(a)))}function eu(a){var b=Ut(a,0,1);return Cg(a,V,zt,b)}function fu(a){var b=Ut(a,0,1);return Cg(a,V,fs,b)}function gu(a){var b=Ut(a,0,1);return Cg(a,V,gs,b)}function hu(a){var b=Ut(a,0,1);return Cg(a,V,hs,b)} +function iu(a){var b=Ut(a,0,1);return Cg(a,V,is,b)}function ju(a){var b=Ut(a,0,1);return Bg(a,V,function(a){return function(b){return Yr(gs(b,a),0)}}(b))}function ku(a){var b=Ut(a,0,1);return Bg(a,V,function(a){return function(b){return Yr(fs(b,a),0)}}(b))}function lu(a){var b=Ut(a,0,1)-1;return Cg(a,V,Zr,b)}function mu(a){var b=Ut(a,0,1)-1,c=Ut(a,1,1)-1;return Dg(a,c,b)}function nu(a){var b=Ut(a,0,1);return Cg(a,V,ht,b)} +function ou(a){var b=Ut(a,0,0);return Bg(a,V,function(){switch(b){case 0:return wt;case 1:return xt;case 2:return vt;default:return Ve}}())}function pu(a){var b=Ut(a,0,0);return Bg(a,V,function(){switch(b){case 0:return tt;case 1:return ut;case 2:return qt;default:return Ve}}())}function qu(a){var b=Ut(a,0,1);return Cg(a,V,Tr,b)}function ru(a){var b=Ut(a,0,1);return Cg(a,V,Vr,b)}function su(a){var b=Ut(a,0,1);return Cg(a,V,At,b)}function tu(a){var b=Ut(a,0,1);return Cg(a,V,Bt,b)} +function uu(a){var b=Ut(a,0,1);return Cg(a,V,Ct,b)}function vu(a){switch(Ut(a,0,0)){case 0:return Bg(a,V,et);case 2:return Bg(a,V,ft);case 5:return Bg(a,V,gt);default:return a}}function wu(a){var b=Ut(a,0,1);return Cg(a,V,yt,b)}function xu(a){var b=Ut(a,0,1);return Cg(a,V,it,b)}function yu(a){switch(Ut(a,0,0)){case 0:return Bg(a,V,ft);case 3:return Bg(a,V,gt);default:return a}}function zu(a){var b=D.c(rk.h(a),0);return Mb(function(a){return function(b,c){return Pt(b,a,c)}}(b),a,Tt(a))} +function Au(a){var b=D.c(rk.h(a),0);return Mb(function(a){return function(b,c){return Qt(b,a,c)}}(b),a,Tt(a))} +function Bu(a,b){for(var c=a,d=b;;)if(E(d)){var e=y(d);switch(e){case 0:c=K.l(c,Oj,Ef);d=vd(d);continue;case 1:c=Qr(c,Kj,!0);d=vd(d);continue;case 3:c=Qr(c,Yn,!0);d=vd(d);continue;case 4:c=Qr(c,Vl,!0);d=vd(d);continue;case 5:c=Qr(c,dk,!0);d=vd(d);continue;case 7:c=Qr(c,Nk,!0);d=vd(d);continue;case 21:c=Rr(c,Kj);d=vd(d);continue;case 22:c=Rr(c,Kj);d=vd(d);continue;case 23:c=Rr(c,Yn);d=vd(d);continue;case 24:c=Rr(c,Vl);d=vd(d);continue;case 25:c=Rr(c,dk);d=vd(d);continue;case 27:c=Rr(c,Nk);d=vd(d); +continue;case 30:case 31:case 32:case 33:case 34:case 35:case 36:case 37:c=Qr(c,Ok,e-30);d=vd(d);continue;case 38:switch(ee(d)){case 2:var f=jg(3,kg(2,d));e=J(f,0,null);var h=J(f,1,null);f=J(f,2,null);t(f)?(c=Qr(c,Ok,new R(null,3,5,T,[e,h,f],null)),d=kg(5,d)):d=kg(2,d);continue;case 5:e=y(kg(2,d));t(e)?(c=Qr(c,Ok,e),d=kg(3,d)):d=kg(2,d);continue;default:d=vd(d);continue}case 39:c=Rr(c,Ok);d=vd(d);continue;case 40:case 41:case 42:case 43:case 44:case 45:case 46:case 47:c=Qr(c,Tn,e-40);d=vd(d);continue; +case 48:switch(ee(d)){case 2:f=jg(3,kg(2,d));e=J(f,0,null);h=J(f,1,null);f=J(f,2,null);t(f)?(c=Qr(c,Tn,new R(null,3,5,T,[e,h,f],null)),d=kg(5,d)):d=kg(2,d);continue;case 5:e=y(kg(2,d));t(e)?(c=Qr(c,Tn,e),d=kg(3,d)):d=kg(2,d);continue;default:d=vd(d);continue}case 49:c=Rr(c,Tn);d=vd(d);continue;case 90:case 91:case 92:case 93:case 94:case 95:case 96:case 97:c=Qr(c,Ok,e-82);d=vd(d);continue;case 100:case 101:case 102:case 103:case 104:case 105:case 106:case 107:c=Qr(c,Tn,e-92);d=vd(d);continue;default:d= +vd(d)}}else return c}function Cu(a){var b=E(Tt(a));return Cg(a,V,Bu,b?b:new R(null,1,5,T,[0],null))}function Du(a){var b=Ut(a,0,1)-1;return Cg(a,V,bs,b)}function Eu(a){return G.c(D.c(rk.h(a),0),33)?Bg(a,V,It):a}function Fu(a){var b=Ut(a,0,1)-1,c=function(){var b=null==a?null:Ut(a,1,null);return null==b?null:b-1}();return Bg(a,V,function(a,b){return function(c){c=null!=c&&(c.m&64||q===c.G)?P(U,c):c;var d=D.c(c,no),e=t(b)?b:d-1;c=-1<a&&a<e&&e<d?K.A(c,Hn,a,be([Yj,e])):c;return cs(c)}}(b,c))} +function Gu(a,b){var c=function(){switch(b){case 8:return Vt;case 9:return Wt;case 10:return Yt;case 11:return Yt;case 12:return Yt;case 13:return Xt;case 14:return Zt;case 15:return $t;case 132:return Yt;case 133:return au;case 136:return bu;case 141:return cu;default:return null}}();return t(c)?c.h?c.h(a):c.call(null,a):a} +var Hu=Pe([zj,Pj,Wj,ak,xl,Pl,Rl,Ul,Xl,um,Fm,Fn,In,po],[function(a){return a},function(a,b){var c=D.c(rk.h(a),0);try{if(null===c)try{if(t(function(){return function(){return function(a){return 64<=a&&95>=a}}(c,b)(b)}()))return Gu(a,b+64);throw Jt;}catch(h){if(h instanceof Error){var d=h;if(d===Jt)try{if(55===b)return Bg(a,V,ms);throw Jt;}catch(k){if(k instanceof Error){var e=k;if(e===Jt)try{if(56===b)return Bg(a,V,ns);throw Jt;}catch(l){if(l instanceof Error){var f=l;if(f===Jt)try{if(99===b)return du(a); +throw Jt;}catch(p){if(p instanceof Error){d=p;if(d===Jt)throw Jt;throw d;}throw p;}else throw f;}else throw l;}else throw e;}else throw k;}else throw d;}else throw h;}else throw Jt;}catch(h){if(h instanceof Error)if(d=h,d===Jt)try{if(35===c)try{if(56===b)return Bg(a,V,pt);throw Jt;}catch(k){if(k instanceof Error){e=k;if(e===Jt)throw Jt;throw e;}throw k;}else throw Jt;}catch(k){if(k instanceof Error)if(e=k,e===Jt)try{if(40===c)try{if(48===b)return Zt(a);throw Jt;}catch(l){if(l instanceof Error){f= +l;if(f===Jt)return $t(a);throw f;}throw l;}else throw Jt;}catch(l){if(l instanceof Error){f=l;if(f===Jt)return a;throw f;}throw l;}else throw e;else throw k;}else throw d;else throw h;}},function(a){return a},function(a){return a},Gu,function(a,b){return Cg(a,V,ot,b)},function(a,b){var c=function(){switch(b){case 64:return eu;case 65:return fu;case 66:return gu;case 67:return hu;case 68:return iu;case 69:return ju;case 70:return ku;case 71:return lu;case 72:return mu;case 73:return nu;case 74:return ou; +case 75:return pu;case 76:return su;case 77:return tu;case 80:return uu;case 83:return qu;case 84:return ru;case 87:return vu;case 88:return wu;case 90:return xu;case 96:return lu;case 97:return hu;case 100:return Du;case 101:return fu;case 102:return mu;case 103:return yu;case 104:return zu;case 108:return Au;case 109:return Cu;case 112:return Eu;case 114:return Fu;default:return null}}();return t(c)?c.h?c.h(a):c.call(null,a):a},function(a){return a},function(a,b){return K.l(a,kk,ge.c(kk.h(a),b))}, +function(a){return a},function(a,b){return K.l(a,rk,ge.c(rk.h(a),b))},function(a){return a},function(a){return a},function(a){return K.A(a,rk,he,be([kk,he]))}]);function Iu(a,b){for(var c=a,d=Tl.h(c),e=b;;){var f=y(e);if(t(f)){var h=160<=f?65:f;h=D.c(d.h?d.h(xq):d.call(null,xq),h);d=J(h,0,null);h=J(h,1,null);a:for(;;)if(E(h)){var k=y(h);k=Hu.h?Hu.h(k):Hu.call(null,k);c=k.c?k.c(c,f):k.call(null,c,f);h=z(h)}else break a;e=vd(e)}else return K.l(c,Tl,d)}} +function Ju(a,b){var c=xg(function(a){return a.codePointAt(0)},b);return Iu(a,c)} +function Ku(a,b){try{if(ze(b)&&3===H(b)){var c=Vd(b,0),d=Vd(b,1),e=Vd(b,2);return[v.h(a+8),";2;",v.h(c),";",v.h(d),";",v.h(e)].join("")}throw Jt;}catch(k){if(k instanceof Error){var f=k;if(f===Jt)try{if(t(function(){return function(){return function(a){return 8>a}}(f)(b)}()))return""+v.h(a+b);throw Jt;}catch(l){if(l instanceof Error){var h=l;if(h===Jt)try{if(t(function(){return function(){return function(a){return 16>a}}(h,f)(b)}()))return""+v.h(a+52+b);throw Jt;}catch(p){if(p instanceof Error){c= +p;if(c===Jt)return[v.h(a+8),";5;",v.h(b)].join("");throw c;}throw p;}else throw h;}else throw l;}else throw f;}else throw k;}}ag.c(Ku,30);ag.c(Ku,40);var Lu=function Lu(a){if(null!=a&&null!=a.yd)return a.yd(a);var c=Lu[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Lu._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("Screen.lines",a);},Mu=function Mu(a){if(null!=a&&null!=a.xd)return a.xd(a);var c=Mu[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Mu._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("Screen.cursor",a);};function Nu(a,b){var c=0<a?a:0;return b<c?b:c}function Ou(a){return function(b){return function(){return((new Date).getTime()-b.getTime())/1E3*a}}(new Date)}function Pu(a){return document[a]} +function Qu(a){return function(b){var c=new hg(null);bd(c,c);return function(c){return function(){function d(d,e){if(B(c)===c){var f=bd(c,e);return b.c?b.c(d,f):b.call(null,d,f)}var h=bd(c,function(){var b=B(c);return a.c?a.c(b,e):a.call(null,b,e)}());return Hd(h)?Id(function(){var a=B(h);return b.c?b.c(d,a):b.call(null,d,a)}()):b.c?b.c(d,h):b.call(null,d,h)}function f(a){return B(c)===c?a:b.h?b.h(a):b.call(null,a)}function h(){return b.B?b.B():b.call(null)}var k=null;k=function(a,b){switch(arguments.length){case 0:return h.call(this); +case 1:return f.call(this,a);case 2:return d.call(this,a,b)}throw Error("Invalid arity: "+(arguments.length-1));};k.B=h;k.h=f;k.c=d;return k}()}(c)}} +function Ru(a,b){return function(c){var d=new hg(null);bd(d,d);return function(d){return function(){function e(e,f){for(;;)if(B(d)===d){var h=function(){var a=e,f=bd(d,b);return c.c?c.c(a,f):c.call(null,a,f)}();if(Hd(h))return h;var k=f;e=h;f=k}else{var m=bd(d,function(){var b=B(d),c=f;return a.c?a.c(b,c):a.call(null,b,c)}());return Hd(m)?Id(function(){var a=e,b=B(m);return c.c?c.c(a,b):c.call(null,a,b)}()):c.c?c.c(e,m):c.call(null,e,m)}}function h(a){B(d)===d&&(a=Jd(c.c?c.c(a,b):c.call(null,a,b))); +return c.h?c.h(a):c.call(null,a)}function k(){return c.B?c.B():c.call(null)}var l=null;l=function(a,b){switch(arguments.length){case 0:return k.call(this);case 1:return h.call(this,a);case 2:return e.call(this,a,b)}throw Error("Invalid arity: "+(arguments.length-1));};l.B=k;l.h=h;l.c=e;return l}()}(d)}};function Su(a,b){return ig.c(function(b){var c=J(b,0,null);b=J(b,1,null);return new R(null,2,5,T,[c,a.h?a.h(b):a.call(null,b)],null)},b)}var Tu=function Tu(a,b){return new kf(null,function(){if(E(a)){if(E(b)){var d=y(a),e=J(d,0,null);J(d,1,null);var f=y(b),h=J(f,0,null);J(f,1,null);return e<h?ae(d,function(){var d=vd(a);return Tu.c?Tu.c(d,b):Tu.call(null,d,b)}()):ae(f,function(){var d=vd(b);return Tu.c?Tu.c(a,d):Tu.call(null,a,d)}())}return a}return null},null,null)}; +function Uu(a,b){var c=J(b,0,null),d=J(b,1,null);return new R(null,2,5,T,[c+a,d],null)}function Vu(a,b){var c=J(b,0,null),d=J(b,1,null);return new R(null,2,5,T,[c/a,d],null)}function Wu(a){return ig.h(function(b){var c=J(b,0,null),d=J(b,1,null);return t(a)?new R(null,2,5,T,[c<a?c:a,d],null):b})}function Xu(a,b){return y(b)<a}function Yu(a,b,c){return Uf($f.l(mg(ag.c(Xu,a)),ig.h(ag.c(Uu,-a)),ig.h(ag.c(Vu,b))),c)}function Zu(a,b){return y(b)<=a}function $u(a,b){return fe(Bi(ag.c(Zu,a),b))} +function av(a,b){return Ru(function(b,d){J(b,0,null);var c=J(b,1,null),f=J(d,0,null),h=J(d,1,null);return new R(null,2,5,T,[f,a.c?a.c(c,h):a.call(null,c,h)],null)},new R(null,2,5,T,[0,b],null))}function bv(){return Qu(function(a,b){var c=J(a,0,null);J(a,1,null);var d=J(b,0,null),e=J(b,1,null);return new R(null,2,5,T,[c+d,e],null)})} +function cv(){return function(a){return function(b){return function(){function c(c,d){var e=J(d,0,null),f=J(d,1,null),h=e-B(b);bd(b,e);e=new R(null,2,5,T,[h,f],null);return a.c?a.c(c,e):a.call(null,c,e)}function d(b){return a.h?a.h(b):a.call(null,b)}function e(){return a.B?a.B():a.call(null)}var f=null;f=function(a,b){switch(arguments.length){case 0:return e.call(this);case 1:return d.call(this,a);case 2:return c.call(this,a,b)}throw Error("Invalid arity: "+(arguments.length-1));};f.B=e;f.h=d;f.c= +c;return f}()}(new hg(0))}};function dv(a,b,c,d){return Uf($f.A(tg(function(a){return G.c(ee(a),"o")}),ig.h(Hi(function(a){return Vd(a,2)})),cv(),be([Wu(d),bv(),av(Ju,Ot(b,c))])),a)};function ev(a){var b=be([gj,!0]);if(null!=a?q===a.lf||(a.Tc?0:Ab(dj,a)):Ab(dj,a))return ej(a,P(ci,b));if(E(b)){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b,d=D.c(c,gj);return function(a,b,c,d){return function m(e){return De(e)?Ii(ig.c(m,e)):ue(e)?wg.l(ie(e),ig.h(m),e):vb(e)?Qc(Mb(function(){return function(a,b){return uf.c(a,m(b))}}(a,b,c,d),Oc(he),e)):Bb(e)===Object?Qc(Mb(function(a,b,c,d){return function(a,b){var c=d.h?d.h(b):d.call(null,b),f=m(e[b]);return Rc(a,c,f)}}(a,b,c,d),Oc(Ef),Ea(e))):e}}(b, +c,d,t(d)?hf:v)(a)}return null};function fv(a,b,c,d,e){this.cursor=a;this.lines=b;this.v=c;this.j=d;this.w=e;this.m=2229667594;this.J=139264}g=fv.prototype;g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "cursor":return this.cursor;case "lines":return this.lines;default:return D.l(this.j,b,c)}}; +g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.player.asciicast.v0.LegacyScreen{",", ","}",c,O.c(new R(null,2,5,T,[new R(null,2,5,T,[pl,this.cursor],null),new R(null,2,5,T,[il,this.lines],null)],null),this.j))};g.ba=function(){return new fh(0,this,2,new R(null,2,5,T,[pl,il],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 2+H(this.j)}; +g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return 1528554851^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.cursor,b.cursor)&&G.c(this.lines,b.lines)&&G.c(this.j,b.j)};g.ga=function(a,b){return He(new ti(null,new r(null,2,[il,null,pl,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new fv(this.cursor,this.lines,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(pl,b):N.call(null,pl,b))?new fv(c,this.lines,this.v,this.j,null):t(N.c?N.c(il,b):N.call(null,il,b))?new fv(this.cursor,c,this.v,this.j,null):new fv(this.cursor,this.lines,this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(new R(null,2,5,T,[new R(null,2,5,T,[pl,this.cursor],null),new R(null,2,5,T,[il,this.lines],null)],null),this.j))};g.T=function(a,b){return new fv(this.cursor,this.lines,b,this.j,this.w)}; +g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};function gv(a,b){return y(fe(Uf($f.c(Wu(b),bv()),a)))}function hv(a){return wg.c(Ef,ig.c(function(a){var b=J(a,0,null);a=J(a,1,null);var d=T;b=jf(b);return new R(null,2,5,d,[parseInt(b,10),a],null)},a))}function iv(a,b){var c=Bg(b,il,hv);return ii.A(hi,be([a,c]))} +function jv(a,b){var c=new r(null,2,[il,di(),pl,new r(null,3,[zn,0,Aj,0,On,!0],null)],null);c=new fv(pl.h(c),il.h(c),null,Bf(le.A(c,pl,be([il]))),null);return Uf($f.l(Wu(b),bv(),av(iv,c)),a)}function kv(a,b){var c=il.h(fe(y(a))),d=Te(Xe,ig.c(function(){return function(a){return H(y(a))}}(c),y(mh(c))));c=H(c);return new r(null,5,[Mn,0,fl,d,no,c,wl,gv(a,b),Uk,jv(a,b)],null)}g.yd=function(){return Wg(mh(il.h(this)))};g.xd=function(){return pl.h(this)};function lv(a){return ev(JSON.parse(a))}function mv(a,b,c,d){if(G.c(Mn.h(a),1)){b=t(b)?b:fl.h(a);c=t(c)?c:no.h(a);var e=ko.h(a);a=y(fe(Uf($f.c(Wu(d),bv()),e)));d=Uf($f.l(Wu(d),bv(),av(Ju,Ot(b,c))),e);d=new r(null,5,[Mn,1,fl,b,no,c,wl,a,Uk,d],null)}else d=null;return d} +function nv(a,b,c,d){var e=y(a);G.c(Mn.h(e),2)?(e=y(a),a=vd(a),b=t(b)?b:fl.h(e),c=t(c)?c:no.h(e),d=t(d)?d:Qj.h(e),e=y(fe(Uf($f.l(cv(),Wu(d),bv()),a))),d=new r(null,5,[Mn,2,fl,b,no,c,wl,e,Uk,dv(a,b,c,d)],null)):d=t(il.h(ee(e)))?kv(a,d):null;return d}function ov(a,b,c,d){try{var e=lv(a);return we(e)?nv(e,b,c,d):xe(e)?mv(e,b,c,d):null}catch(k){try{var f=Fo(ra(a),"\n");var h=ig.c(lv,f);return nv(h,b,c,d)}catch(l){return null}}} +function pv(a,b,c,d){var e="string"===typeof a?ov:we(a)?nv:xe(a)?mv:null;a=t(e)?e.M?e.M(a,b,c,d):e.call(null,a,b,c,d):null;if(t(a))return a;throw"only asciicast v1 and v2 formats can be opened";}Lt.prototype.yd=function(){return xg(Ht,il.h(V.h(this)))};Lt.prototype.xd=function(){return pl.h(V.h(this))};var qv;a:{var rv=ba.navigator;if(rv){var sv=rv.userAgent;if(sv){qv=sv;break a}}qv=""}function tv(a){return-1!=qv.indexOf(a)};var uv; +function vv(){var a=ba.MessageChannel;"undefined"===typeof a&&"undefined"!==typeof window&&window.postMessage&&window.addEventListener&&!tv("Presto")&&(a=function(){var a=document.createElement("IFRAME");a.style.display="none";a.src="";document.documentElement.appendChild(a);var b=a.contentWindow;a=b.document;a.open();a.write("");a.close();var c="callImmediate"+Math.random(),d="file:"==b.location.protocol?"*":b.location.protocol+"//"+b.location.host;a=pa(function(a){if(("*"==d||a.origin==d)&&a.data== +c)this.port1.onmessage()},this);b.addEventListener("message",a,!1);this.port1={};this.port2={postMessage:function(){b.postMessage(c,d)}}});if("undefined"!==typeof a&&!tv("Trident")&&!tv("MSIE")){var b=new a,c={},d=c;b.port1.onmessage=function(){if(void 0!==c.next){c=c.next;var a=c.ed;c.ed=null;a()}};return function(a){d.next={ed:a};d=d.next;b.port2.postMessage(0)}}return"undefined"!==typeof document&&"onreadystatechange"in document.createElement("SCRIPT")?function(a){var b=document.createElement("SCRIPT"); +b.onreadystatechange=function(){b.onreadystatechange=null;b.parentNode.removeChild(b);b=null;a();a=null};document.documentElement.appendChild(b)}:function(a){ba.setTimeout(a,0)}};function wv(){0!=xv&&(yv[ja(this)]=this);this.od=this.od;this.Wd=this.Wd}var xv=0,yv={};wv.prototype.od=!1;wv.prototype.nd=function(){if(this.Wd)for(;this.Wd.length;)this.Wd.shift()()};function zv(){return tv("iPhone")&&!tv("iPod")&&!tv("iPad")};var Av=tv("Opera"),Bv=tv("Trident")||tv("MSIE"),Cv=tv("Edge"),Dv=tv("Gecko")&&!(-1!=qv.toLowerCase().indexOf("webkit")&&!tv("Edge"))&&!(tv("Trident")||tv("MSIE"))&&!tv("Edge"),Ev=-1!=qv.toLowerCase().indexOf("webkit")&&!tv("Edge");Ev&&tv("Mobile");tv("Macintosh");tv("Windows");tv("Linux")||tv("CrOS");var Fv=ba.navigator||null;Fv&&(Fv.appVersion||"").indexOf("X11");tv("Android");zv();tv("iPad");tv("iPod");zv()||tv("iPad")||tv("iPod");function Gv(){var a=ba.document;return a?a.documentMode:void 0}var Hv; +a:{var Iv="",Jv=function(){var a=qv;if(Dv)return/rv\:([^\);]+)(\)|;)/.exec(a);if(Cv)return/Edge\/([\d\.]+)/.exec(a);if(Bv)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if(Ev)return/WebKit\/(\S+)/.exec(a);if(Av)return/(?:Version)[ \/]?(\S+)/.exec(a)}();Jv&&(Iv=Jv?Jv[1]:"");if(Bv){var Kv=Gv();if(null!=Kv&&Kv>parseFloat(Iv)){Hv=String(Kv);break a}}Hv=Iv}var gb={}; +function Lv(a){return fb(a,function(){for(var b=0,c=ra(String(Hv)).split("."),d=ra(String(a)).split("."),e=Math.max(c.length,d.length),f=0;0==b&&f<e;f++){var h=c[f]||"",k=d[f]||"";do{h=/(\d*)(\D*)(.*)/.exec(h)||["","","",""];k=/(\d*)(\D*)(.*)/.exec(k)||["","","",""];if(0==h[0].length&&0==k[0].length)break;b=ta(0==h[1].length?0:parseInt(h[1],10),0==k[1].length?0:parseInt(k[1],10))||ta(0==h[2].length,0==k[2].length)||ta(h[2],k[2]);h=h[3];k=k[3]}while(0==b)}return 0<=b})}var Mv;var Nv=ba.document; +Mv=Nv&&Bv?Gv()||("CSS1Compat"==Nv.compatMode?parseInt(Hv,10):5):void 0;var Ov;(Ov=!Bv)||(Ov=9<=Number(Mv));var Pv=Ov,Qv=Bv&&!Lv("9");!Ev||Lv("528");Dv&&Lv("1.9b")||Bv&&Lv("8")||Av&&Lv("9.5")||Ev&&Lv("528");Dv&&!Lv("8")||Bv&&Lv("9");var Rv=function(){if(!ba.addEventListener||!Object.defineProperty)return!1;var a=!1,b=Object.defineProperty({},"passive",{get:function(){a=!0}});ba.addEventListener("test",ea,b);ba.removeEventListener("test",ea,b);return a}();function Sv(a,b){this.type=a;this.currentTarget=this.target=b;this.defaultPrevented=this.Kc=!1;this.af=!0}Sv.prototype.stopPropagation=function(){this.Kc=!0};Sv.prototype.preventDefault=function(){this.defaultPrevented=!0;this.af=!1};function Tv(a,b){Sv.call(this,a?a.type:"");this.relatedTarget=this.currentTarget=this.target=null;this.button=this.screenY=this.screenX=this.clientY=this.clientX=this.offsetY=this.offsetX=0;this.key="";this.charCode=this.keyCode=0;this.metaKey=this.shiftKey=this.altKey=this.ctrlKey=!1;this.pd=this.state=null;if(a){var c=this.type=a.type,d=a.changedTouches?a.changedTouches[0]:null;this.target=a.target||a.srcElement;this.currentTarget=b;var e=a.relatedTarget;if(e){if(Dv){a:{try{eb(e.nodeName);var f= +!0;break a}catch(h){}f=!1}f||(e=null)}}else"mouseover"==c?e=a.fromElement:"mouseout"==c&&(e=a.toElement);this.relatedTarget=e;null===d?(this.offsetX=Ev||void 0!==a.offsetX?a.offsetX:a.layerX,this.offsetY=Ev||void 0!==a.offsetY?a.offsetY:a.layerY,this.clientX=void 0!==a.clientX?a.clientX:a.pageX,this.clientY=void 0!==a.clientY?a.clientY:a.pageY,this.screenX=a.screenX||0,this.screenY=a.screenY||0):(this.clientX=void 0!==d.clientX?d.clientX:d.pageX,this.clientY=void 0!==d.clientY?d.clientY:d.pageY,this.screenX= +d.screenX||0,this.screenY=d.screenY||0);this.button=a.button;this.keyCode=a.keyCode||0;this.key=a.key||"";this.charCode=a.charCode||("keypress"==c?a.keyCode:0);this.ctrlKey=a.ctrlKey;this.altKey=a.altKey;this.shiftKey=a.shiftKey;this.metaKey=a.metaKey;this.state=a.state;this.pd=a;a.defaultPrevented&&this.preventDefault()}}qa(Tv,Sv);Tv.prototype.stopPropagation=function(){Tv.Zd.stopPropagation.call(this);this.pd.stopPropagation?this.pd.stopPropagation():this.pd.cancelBubble=!0}; +Tv.prototype.preventDefault=function(){Tv.Zd.preventDefault.call(this);var a=this.pd;if(a.preventDefault)a.preventDefault();else if(a.returnValue=!1,Qv)try{if(a.ctrlKey||112<=a.keyCode&&123>=a.keyCode)a.keyCode=-1}catch(b){}};var Uv="closure_listenable_"+(1E6*Math.random()|0),Vv=0;function Wv(a,b,c,d,e){this.listener=a;this.Xd=null;this.src=b;this.type=c;this.capture=!!d;this.Ub=e;this.key=++Vv;this.$c=this.Fd=!1}function Xv(a){a.$c=!0;a.listener=null;a.Xd=null;a.src=null;a.Ub=null};function Yv(a){this.src=a;this.rb={};this.wd=0}Yv.prototype.add=function(a,b,c,d,e){var f=a.toString();a=this.rb[f];a||(a=this.rb[f]=[],this.wd++);var h=Zv(a,b,d,e);-1<h?(b=a[h],c||(b.Fd=!1)):(b=new Wv(b,this.src,f,!!d,e),b.Fd=c,a.push(b));return b};Yv.prototype.remove=function(a,b,c,d){a=a.toString();if(!(a in this.rb))return!1;var e=this.rb[a];b=Zv(e,b,c,d);return-1<b?(Xv(e[b]),Array.prototype.splice.call(e,b,1),0==e.length&&(delete this.rb[a],this.wd--),!0):!1}; +function $v(a,b){var c=b.type;c in a.rb&&ya(a.rb[c],b)&&(Xv(b),0==a.rb[c].length&&(delete a.rb[c],a.wd--))}Yv.prototype.re=function(a,b,c,d){a=this.rb[a.toString()];var e=-1;a&&(e=Zv(a,b,c,d));return-1<e?a[e]:null};function Zv(a,b,c,d){for(var e=0;e<a.length;++e){var f=a[e];if(!f.$c&&f.listener==b&&f.capture==!!c&&f.Ub==d)return e}return-1};var aw="closure_lm_"+(1E6*Math.random()|0),bw={},cw=0;function dw(a,b,c,d,e){if(d&&d.once)ew(a,b,c,d,e);else if("array"==n(b))for(var f=0;f<b.length;f++)dw(a,b[f],c,d,e);else c=fw(c),a&&a[Uv]?a.Ib.add(String(b),c,!1,ia(d)?!!d.capture:!!d,e):gw(a,b,c,!1,d,e)} +function gw(a,b,c,d,e,f){if(!b)throw Error("Invalid event type");var h=ia(e)?!!e.capture:!!e,k=hw(a);k||(a[aw]=k=new Yv(a));c=k.add(b,c,d,h,f);if(!c.Xd){d=iw();c.Xd=d;d.src=a;d.listener=c;if(a.addEventListener)Rv||(e=h),void 0===e&&(e=!1),a.addEventListener(b.toString(),d,e);else if(a.attachEvent)a.attachEvent(jw(b.toString()),d);else throw Error("addEventListener and attachEvent are unavailable.");cw++}} +function iw(){var a=kw,b=Pv?function(c){return a.call(b.src,b.listener,c)}:function(c){c=a.call(b.src,b.listener,c);if(!c)return c};return b}function ew(a,b,c,d,e){if("array"==n(b))for(var f=0;f<b.length;f++)ew(a,b[f],c,d,e);else c=fw(c),a&&a[Uv]?a.Ib.add(String(b),c,!0,ia(d)?!!d.capture:!!d,e):gw(a,b,c,!0,d,e)} +function lw(a,b,c,d,e){if("array"==n(b))for(var f=0;f<b.length;f++)lw(a,b[f],c,d,e);else d=ia(d)?!!d.capture:!!d,c=fw(c),a&&a[Uv]?a.Ib.remove(String(b),c,d,e):a&&(a=hw(a))&&(b=a.re(b,c,d,e))&&mw(b)}function mw(a){if("number"!=typeof a&&a&&!a.$c){var b=a.src;if(b&&b[Uv])$v(b.Ib,a);else{var c=a.type,d=a.Xd;b.removeEventListener?b.removeEventListener(c,d,a.capture):b.detachEvent&&b.detachEvent(jw(c),d);cw--;(c=hw(b))?($v(c,a),0==c.wd&&(c.src=null,b[aw]=null)):Xv(a)}}} +function jw(a){return a in bw?bw[a]:bw[a]="on"+a}function nw(a,b,c,d){var e=!0;if(a=hw(a))if(b=a.rb[b.toString()])for(b=b.concat(),a=0;a<b.length;a++){var f=b[a];f&&f.capture==c&&!f.$c&&(f=ow(f,d),e=e&&!1!==f)}return e}function ow(a,b){var c=a.listener,d=a.Ub||a.src;a.Fd&&mw(a);return c.call(d,b)} +function kw(a,b){if(a.$c)return!0;if(!Pv){var c;if(!(c=b))a:{c=["window","event"];for(var d=ba,e;e=c.shift();)if(null!=d[e])d=d[e];else{c=null;break a}c=d}e=c;c=new Tv(e,this);d=!0;if(!(0>e.keyCode||void 0!=e.returnValue)){a:{var f=!1;if(0==e.keyCode)try{e.keyCode=-1;break a}catch(l){f=!0}if(f||void 0==e.returnValue)e.returnValue=!0}e=[];for(f=c.currentTarget;f;f=f.parentNode)e.push(f);f=a.type;for(var h=e.length-1;!c.Kc&&0<=h;h--){c.currentTarget=e[h];var k=nw(e[h],f,!0,c);d=d&&k}for(h=0;!c.Kc&& +h<e.length;h++)c.currentTarget=e[h],k=nw(e[h],f,!1,c),d=d&&k}return d}return ow(a,new Tv(b,this))}function hw(a){a=a[aw];return a instanceof Yv?a:null}var pw="__closure_events_fn_"+(1E9*Math.random()>>>0);function fw(a){if(ha(a))return a;a[pw]||(a[pw]=function(b){return a.handleEvent(b)});return a[pw]};function qw(){wv.call(this);this.Ib=new Yv(this);this.ff=this;this.ve=null}qa(qw,wv);qw.prototype[Uv]=!0;g=qw.prototype;g.addEventListener=function(a,b,c,d){dw(this,a,b,c,d)};g.removeEventListener=function(a,b,c,d){lw(this,a,b,c,d)}; +g.dispatchEvent=function(a){var b,c=this.ve;if(c)for(b=[];c;c=c.ve)b.push(c);c=this.ff;var d=a.type||a;if(ca(a))a=new Sv(a,c);else if(a instanceof Sv)a.target=a.target||c;else{var e=a;a=new Sv(d,c);Ia(a,e)}e=!0;if(b)for(var f=b.length-1;!a.Kc&&0<=f;f--){var h=a.currentTarget=b[f];e=rw(h,d,!0,a)&&e}a.Kc||(h=a.currentTarget=c,e=rw(h,d,!0,a)&&e,a.Kc||(e=rw(h,d,!1,a)&&e));if(b)for(f=0;!a.Kc&&f<b.length;f++)h=a.currentTarget=b[f],e=rw(h,d,!1,a)&&e;return e}; +g.nd=function(){qw.Zd.nd.call(this);if(this.Ib){var a=this.Ib,b=0,c;for(c in a.rb){for(var d=a.rb[c],e=0;e<d.length;e++)++b,Xv(d[e]);delete a.rb[c];a.wd--}}this.ve=null};function rw(a,b,c,d){b=a.Ib.rb[String(b)];if(!b)return!0;b=b.concat();for(var e=!0,f=0;f<b.length;++f){var h=b[f];if(h&&!h.$c&&h.capture==c){var k=h.listener,l=h.Ub||h.src;h.Fd&&$v(a.Ib,h);e=!1!==k.call(l,d)&&e}}return e&&0!=d.af}g.re=function(a,b,c,d){return this.Ib.re(String(a),b,c,d)};function sw(a,b,c){if(ha(a))c&&(a=pa(a,c));else if(a&&"function"==typeof a.handleEvent)a=pa(a.handleEvent,a);else throw Error("Invalid listener argument");return 2147483647<Number(b)?-1:ba.setTimeout(a,b||0)};function tw(){}tw.prototype.Ke=null;function uw(a){var b;(b=a.Ke)||(b={},vw(a)&&(b[0]=!0,b[1]=!0),b=a.Ke=b);return b};var ww;function xw(){}qa(xw,tw);function yw(a){return(a=vw(a))?new ActiveXObject(a):new XMLHttpRequest}function vw(a){if(!a.Te&&"undefined"==typeof XMLHttpRequest&&"undefined"!=typeof ActiveXObject){for(var b=["MSXML2.XMLHTTP.6.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"],c=0;c<b.length;c++){var d=b[c];try{return new ActiveXObject(d),a.Te=d}catch(e){}}throw Error("Could not create ActiveXObject. ActiveX might be disabled, or MSXML might not be installed");}return a.Te}ww=new xw;function zw(a){qw.call(this);this.headers=new Ma;this.ce=a||null;this.oc=!1;this.be=this.ca=null;this.ue="";this.Ic=this.se=this.Sd=this.qe=!1;this.Ae=0;this.$d=null;this.$e=Aw;this.Be=this.Lf=this.ef=!1}qa(zw,qw);var Aw="",Bw=/^https?$/i,Cw=["POST","PUT"],Dw=[];function Ew(a,b){var c=new zw;Dw.push(c);b&&c.Ib.add("complete",b,!1,void 0,void 0);c.Ib.add("ready",c.gf,!0,void 0,void 0);c.send(a,void 0,void 0,void 0);return c}g=zw.prototype; +g.gf=function(){if(!this.od&&(this.od=!0,this.nd(),0!=xv)){var a=ja(this);delete yv[a]}ya(Dw,this)}; +g.send=function(a,b,c,d){if(this.ca)throw Error("[goog.net.XhrIo] Object is active with another request\x3d"+this.ue+"; newUri\x3d"+a);b=b?b.toUpperCase():"GET";this.ue=a;this.qe=!1;this.oc=!0;this.ca=this.ce?yw(this.ce):yw(ww);this.be=this.ce?uw(this.ce):uw(ww);this.ca.onreadystatechange=pa(this.Ye,this);this.Lf&&"onprogress"in this.ca&&(this.ca.onprogress=pa(function(a){this.Xe(a,!0)},this),this.ca.upload&&(this.ca.upload.onprogress=pa(this.Xe,this)));try{this.se=!0,this.ca.open(b,String(a),!0), +this.se=!1}catch(f){Fw(this);return}a=c||"";var e=this.headers.clone();d&&La(d,function(a,b){e.set(b,a)});d=wa(e.Xc());c=ba.FormData&&a instanceof ba.FormData;!(0<=ua(Cw,b))||d||c||e.set("Content-Type","application/x-www-form-urlencoded;charset\x3dutf-8");e.forEach(function(a,b){this.ca.setRequestHeader(b,a)},this);this.$e&&(this.ca.responseType=this.$e);"withCredentials"in this.ca&&this.ca.withCredentials!==this.ef&&(this.ca.withCredentials=this.ef);try{Gw(this),0<this.Ae&&((this.Be=Hw(this.ca))? +(this.ca.timeout=this.Ae,this.ca.ontimeout=pa(this.cf,this)):this.$d=sw(this.cf,this.Ae,this)),this.Sd=!0,this.ca.send(a),this.Sd=!1}catch(f){Fw(this)}};function Hw(a){return Bv&&Lv(9)&&"number"==typeof a.timeout&&void 0!==a.ontimeout}function xa(a){return"content-type"==a.toLowerCase()}g.cf=function(){"undefined"!=typeof aa&&this.ca&&(this.dispatchEvent("timeout"),this.abort(8))};function Fw(a){a.oc=!1;a.ca&&(a.Ic=!0,a.ca.abort(),a.Ic=!1);Iw(a);Jw(a)} +function Iw(a){a.qe||(a.qe=!0,a.dispatchEvent("complete"),a.dispatchEvent("error"))}g.abort=function(){this.ca&&this.oc&&(this.oc=!1,this.Ic=!0,this.ca.abort(),this.Ic=!1,this.dispatchEvent("complete"),this.dispatchEvent("abort"),Jw(this))};g.nd=function(){this.ca&&(this.oc&&(this.oc=!1,this.Ic=!0,this.ca.abort(),this.Ic=!1),Jw(this,!0));zw.Zd.nd.call(this)};g.Ye=function(){this.od||(this.se||this.Sd||this.Ic?Kw(this):this.If())};g.If=function(){Kw(this)}; +function Kw(a){if(a.oc&&"undefined"!=typeof aa&&(!a.be[1]||4!=Lw(a)||2!=Mw(a)))if(a.Sd&&4==Lw(a))sw(a.Ye,0,a);else if(a.dispatchEvent("readystatechange"),4==Lw(a)){a.oc=!1;try{var b=Mw(a);a:switch(b){case 200:case 201:case 202:case 204:case 206:case 304:case 1223:var c=!0;break a;default:c=!1}var d;if(!(d=c)){var e;if(e=0===b){var f=String(a.ue).match(Pa)[1]||null;if(!f&&ba.self&&ba.self.location){var h=ba.self.location.protocol;f=h.substr(0,h.length-1)}e=!Bw.test(f?f.toLowerCase():"")}d=e}d?(a.dispatchEvent("complete"), +a.dispatchEvent("success")):Iw(a)}finally{Jw(a)}}}g.Xe=function(a,b){this.dispatchEvent(Nw(a,"progress"));this.dispatchEvent(Nw(a,b?"downloadprogress":"uploadprogress"))};function Nw(a,b){return{type:b,lengthComputable:a.lengthComputable,loaded:a.loaded,total:a.total}}function Jw(a,b){if(a.ca){Gw(a);var c=a.ca,d=a.be[0]?ea:null;a.ca=null;a.be=null;b||a.dispatchEvent("ready");try{c.onreadystatechange=d}catch(e){}}} +function Gw(a){a.ca&&a.Be&&(a.ca.ontimeout=null);"number"==typeof a.$d&&(ba.clearTimeout(a.$d),a.$d=null)}function Lw(a){return a.ca?a.ca.readyState:0}function Mw(a){try{return 2<Lw(a)?a.ca.status:-1}catch(b){return-1}}g.getResponseHeader=function(a){if(this.ca&&4==Lw(this))return a=this.ca.getResponseHeader(a),null===a?void 0:a};g.getAllResponseHeaders=function(){return this.ca&&4==Lw(this)?this.ca.getAllResponseHeaders():""};var Ow,Pw,Qw,Rw=function Rw(a,b){if(null!=a&&null!=a.oe)return a.oe(0,b);var d=Rw[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=Rw._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("ReadPort.take!",a);},Sw=function Sw(a,b,c){if(null!=a&&null!=a.Od)return a.Od(0,b,c);var e=Sw[n(null==a?null:a)];if(null!=e)return e.l?e.l(a,b,c):e.call(null,a,b,c);e=Sw._;if(null!=e)return e.l?e.l(a,b,c):e.call(null,a,b,c);throw Cb("WritePort.put!",a);},Tw=function Tw(a){if(null!=a&&null!= +a.ld)return a.ld();var c=Tw[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Tw._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("Channel.close!",a);},Uw=function Uw(a){if(null!=a&&null!=a.vb)return a.vb(a);var c=Uw[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Uw._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("Handler.active?",a);},Vw=function Vw(a){if(null!=a&&null!=a.tb)return a.tb(a);var c=Vw[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null, +a);c=Vw._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("Handler.commit",a);},Ww=function Ww(a,b){if(null!=a&&null!=a.Md)return a.Md(a,b);var d=Ww[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=Ww._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("Buffer.add!*",a);},Xw=function Xw(a){switch(arguments.length){case 1:return Xw.h(arguments[0]);case 2:return Xw.c(arguments[0],arguments[1]);default:throw Error(["Invalid arity: ",v.h(arguments.length)].join(""));}}; +Xw.h=function(a){return a};Xw.c=function(a,b){return Ww(a,b)};Xw.L=2;function Yw(a,b,c,d,e){for(var f=0;;)if(f<e)c[d+f]=a[b+f],f+=1;else break}function Zw(a,b,c,d){this.head=a;this.fa=b;this.length=c;this.o=d}Zw.prototype.pop=function(){if(0===this.length)return null;var a=this.o[this.fa];this.o[this.fa]=null;this.fa=(this.fa+1)%this.o.length;--this.length;return a};Zw.prototype.unshift=function(a){this.o[this.head]=a;this.head=(this.head+1)%this.o.length;this.length+=1;return null};function $w(a,b){a.length+1===a.o.length&&a.resize();a.unshift(b)} +Zw.prototype.resize=function(){var a=Array(2*this.o.length);return this.fa<this.head?(Yw(this.o,this.fa,a,0,this.length),this.fa=0,this.head=this.length,this.o=a):this.fa>this.head?(Yw(this.o,this.fa,a,0,this.o.length-this.fa),Yw(this.o,0,a,this.o.length-this.fa,this.head),this.fa=0,this.head=this.length,this.o=a):this.fa===this.head?(this.head=this.fa=0,this.o=a):null};function ax(a,b){for(var c=a.length,d=0;;)if(d<c){var e=a.pop();(b.h?b.h(e):b.call(null,e))&&a.unshift(e);d+=1}else break} +function bx(a){return new Zw(0,0,0,Array(a))}function cx(a,b){this.aa=a;this.n=b;this.m=2;this.J=0}g=cx.prototype;g.Nd=function(){return this.aa.length===this.n};g.Sc=function(){return this.aa.pop()};g.Md=function(a,b){$w(this.aa,b);return this};g.ne=function(){return null};g.W=function(){return this.aa.length};function dx(a,b){this.aa=a;this.n=b;this.m=2;this.J=0}g=dx.prototype;g.Nd=function(){return!1};g.Sc=function(){return this.aa.pop()}; +g.Md=function(a,b){this.aa.length!==this.n&&this.aa.unshift(b);return this};g.ne=function(){return null};g.W=function(){return this.aa.length};if("undefined"===typeof ex)var ex={};function fx(a){this.H=a;this.m=2;this.J=0}g=fx.prototype;g.Nd=function(){return!1};g.Sc=function(){return this.H};g.Md=function(a,b){t(ex===this.H)&&(this.H=b);return this};g.ne=function(){return t(ex===this.H)?this.H=null:null};g.W=function(){return t(ex===this.H)?0:1};var gx=bx(32),hx=!1,ix=!1;function jx(){hx=!0;ix=!1;for(var a=0;;){var b=gx.pop();if(null!=b&&(b.B?b.B():b.call(null),1024>a)){a+=1;continue}break}hx=!1;return 0<gx.length?kx.B?kx.B():kx.call(null):null}function kx(){if(ix&&hx)return null;ix=!0;!ha(ba.setImmediate)||ba.Window&&ba.Window.prototype&&!tv("Edge")&&ba.Window.prototype.setImmediate==ba.setImmediate?(uv||(uv=vv()),uv(jx)):ba.setImmediate(jx)}function lx(a){$w(gx,a);kx()}function mx(a,b){setTimeout(a,b)};var nx; +function ox(a){"undefined"===typeof nx&&(nx=function(a,c){this.H=a;this.Af=c;this.m=425984;this.J=0},nx.prototype.T=function(a,c){return new nx(this.H,c)},nx.prototype.P=function(){return this.Af},nx.prototype.pc=function(){return this.H},nx.Wc=function(){return new R(null,2,5,T,[Km,qo],null)},nx.qc=!0,nx.Tb="cljs.core.async.impl.channels/t_cljs$core$async$impl$channels36582",nx.Ec=function(a,c){return Jc(c,"cljs.core.async.impl.channels/t_cljs$core$async$impl$channels36582")});return new nx(a,Ef)} +function px(a,b){this.Ub=a;this.H=b}function qx(a){return Uw(a.Ub)}function rx(a,b,c,d,e,f,h){this.bd=a;this.Qd=b;this.jc=c;this.Pd=d;this.aa=e;this.closed=f;this.Ab=h}function sx(a){for(;;){var b=a.jc.pop();if(null!=b){var c=b.Ub,d=b.H;if(c.vb(null)){var e=c.tb(null);lx(function(a){return function(){return a.h?a.h(!0):a.call(null,!0)}}(e,c,d,b,a))}else continue}break}ax(a.jc,Zf(!1));a.ld()} +rx.prototype.Od=function(a,b,c){var d=this,e=this,f=d.closed;if(f||!c.vb(null))return ox(!f);if(t(function(){var a=d.aa;return t(a)?wb(d.aa.Nd(null)):a}())){c.tb(null);var h=Hd(d.Ab.c?d.Ab.c(d.aa,b):d.Ab.call(null,d.aa,b));c=function(){for(var a=he;;)if(0<d.bd.length&&0<H(d.aa)){var b=d.bd.pop();if(b.vb(null)){var c=b.tb(null),k=d.aa.Sc(null);a=ge.c(a,function(a,b,c){return function(){return b.h?b.h(c):b.call(null,c)}}(a,c,k,b,h,f,e))}}else return a}();h&&sx(e);if(E(c)){c=E(c);a=null;for(var k=0, +l=0;;)if(l<k){var p=a.$(null,l);lx(p);l+=1}else if(c=E(c))a=c,Ae(a)?(c=Wc(a),l=Xc(a),a=c,k=H(c),c=l):(c=y(a),lx(c),c=z(a),a=null,k=0),l=0;else break}return ox(!0)}a=function(){for(;;){var a=d.bd.pop();if(t(a)){if(t(a.vb(null)))return a}else return null}}();if(t(a))return k=Vw(a),c.tb(null),lx(function(a){return function(){return a.h?a.h(b):a.call(null,b)}}(k,a,f,e)),ox(!0);64<d.Pd?(d.Pd=0,ax(d.jc,qx)):d.Pd+=1;t(c.md(null))&&$w(d.jc,new px(c,b));return null}; +rx.prototype.oe=function(a,b){var c=this;if(b.vb(null)){if(null!=c.aa&&0<H(c.aa)){var d=b.tb(null);if(t(d)){var e=c.aa.Sc(null),f=0<c.jc.length?function(){for(var a=he;;){var b=c.jc.pop(),d=b.Ub;b=b.H;var e=d.vb(null);d=e?d.tb(null):e;a=t(d)?ge.c(a,d):a;b=t(d)?Hd(c.Ab.c?c.Ab.c(c.aa,b):c.Ab.call(null,c.aa,b)):null;if(!(wb(b)&&wb(c.aa.Nd(null))&&0<c.jc.length))return new R(null,2,5,T,[b,a],null)}}():null,h=J(f,0,null),k=J(f,1,null);t(h)&&sx(this);for(var l=E(k),p=null,m=0,u=0;;)if(u<m){var w=p.$(null, +u);lx(function(a,b,c,d,e){return function(){return e.h?e.h(!0):e.call(null,!0)}}(l,p,m,u,w,e,f,h,k,d,d,this));u+=1}else{var x=E(l);if(x){w=x;if(Ae(w))l=Wc(w),u=Xc(w),p=l,m=H(l),l=u;else{var C=y(w);lx(function(a,b,c,d,e){return function(){return e.h?e.h(!0):e.call(null,!0)}}(l,p,m,u,C,w,x,e,f,h,k,d,d,this));l=z(w);p=null;m=0}u=0}else break}return ox(e)}return null}d=function(){for(;;){var a=c.jc.pop();if(t(a)){if(Uw(a.Ub))return a}else return null}}();if(t(d))return e=Vw(d.Ub),b.tb(null),lx(function(a){return function(){return a.h? +a.h(!0):a.call(null,!0)}}(e,d,this)),ox(d.H);if(t(c.closed))return t(c.aa)&&(c.Ab.h?c.Ab.h(c.aa):c.Ab.call(null,c.aa)),t(function(){var a=b.vb(null);return t(a)?b.tb(null):a}())?(d=function(){var a=c.aa;return t(a)?0<H(c.aa):a}(),e=t(d)?c.aa.Sc(null):null,ox(e)):null;64<c.Qd?(c.Qd=0,ax(c.bd,Uw)):c.Qd+=1;t(b.md(null))&&$w(c.bd,b)}return null}; +rx.prototype.ld=function(){var a=this;if(!a.closed){a.closed=!0;for(t(function(){var b=a.aa;return t(b)?0===a.jc.length:b}())&&(a.Ab.h?a.Ab.h(a.aa):a.Ab.call(null,a.aa));;){var b=a.bd.pop();if(null!=b){if(b.vb(null)){var c=b.tb(null),d=t(function(){var b=a.aa;return t(b)?0<H(a.aa):b}())?a.aa.Sc(null):null;lx(function(a,b){return function(){return a.h?a.h(b):a.call(null,b)}}(c,d,b,this))}}else break}t(a.aa)&&a.aa.ne(null)}return null};function tx(a){console.log(a);return null} +function ux(a,b){var c=t(null)?null:tx;c=c.h?c.h(b):c.call(null,b);return null==c?a:Xw.c(a,c)} +function vx(a,b){return new rx(bx(32),0,bx(32),0,a,!1,function(){return function(a){return function(){function b(b,c){try{return a.c?a.c(b,c):a.call(null,b,c)}catch(l){return ux(b,l)}}function c(b){try{return a.h?a.h(b):a.call(null,b)}catch(k){return ux(b,k)}}var f=null;f=function(a,d){switch(arguments.length){case 1:return c.call(this,a);case 2:return b.call(this,a,d)}throw Error("Invalid arity: "+(arguments.length-1));};f.h=c;f.c=b;return f}()}(t(b)?b.h?b.h(Xw):b.call(null,Xw):Xw)}())};var wx; +function xx(a){"undefined"===typeof wx&&(wx=function(a,c){this.Cb=a;this.Cf=c;this.m=393216;this.J=0},wx.prototype.T=function(a,c){return new wx(this.Cb,c)},wx.prototype.P=function(){return this.Cf},wx.prototype.vb=function(){return!0},wx.prototype.md=function(){return!0},wx.prototype.tb=function(){return this.Cb},wx.Wc=function(){return new R(null,2,5,T,[to,Um],null)},wx.qc=!0,wx.Tb="cljs.core.async.impl.ioc-helpers/t_cljs$core$async$impl$ioc_helpers42956",wx.Ec=function(a,c){return Jc(c,"cljs.core.async.impl.ioc-helpers/t_cljs$core$async$impl$ioc_helpers42956")}); +return new wx(a,Ef)}function yx(a){try{var b=a[0];return b.h?b.h(a):b.call(null,a)}catch(c){if(c instanceof Object)throw b=c,a[6].ld(),b;throw c;}}function zx(a,b,c){c=c.oe(0,xx(function(c){a[2]=c;a[1]=b;return yx(a)}));return t(c)?(a[2]=B(c),a[1]=b,Z):null}function Ax(a,b,c,d){c=c.Od(0,d,xx(function(c){a[2]=c;a[1]=b;return yx(a)}));return t(c)?(a[2]=B(c),a[1]=b,Z):null}function Bx(a,b){var c=a[6];null!=b&&c.Od(0,b,xx(function(){return function(){return null}}(c)));c.ld();return c} +function Cx(a){for(;;){var b=a[4],c=ul.h(b),d=Pm.h(b),e=a[5];if(t(function(){var a=e;return t(a)?wb(b):a}()))throw e;if(t(function(){var a=e;return t(a)?(a=c,t(a)?G.c(Ik,d)||e instanceof d:a):a}())){a[1]=c;a[2]=e;a[5]=null;a[4]=K.A(b,ul,null,be([Pm,null]));break}if(t(function(){var a=e;return t(a)?wb(c)&&wb(Lk.h(b)):a}()))a[4]=Xm.h(b);else{if(t(function(){var a=e;return t(a)?(a=wb(c))?Lk.h(b):a:a}())){a[1]=Lk.h(b);a[4]=K.l(b,Lk,null);break}if(t(function(){var a=wb(e);return a?Lk.h(b):a}())){a[1]= +Lk.h(b);a[4]=K.l(b,Lk,null);break}if(wb(e)&&wb(Lk.h(b))){a[1]=cn.h(b);a[4]=Xm.h(b);break}throw Error("No matching clause");}}};function Dx(a,b,c){this.key=a;this.H=b;this.forward=c;this.m=2155872256;this.J=0}Dx.prototype.S=function(){var a=this.key;return Tb(Tb(wd,this.H),a)};Dx.prototype.R=function(a,b,c){return Y(b,Qi,"["," ","]",c,this)};function Ex(a,b,c){c=Array(c+1);for(var d=0;;)if(d<c.length)c[d]=null,d+=1;else break;return new Dx(a,b,c)}function Fx(a,b,c,d){for(;;){if(0>c)return a;a:for(;;){var e=c<a.forward.length?a.forward[c]:null;if(t(e))if(e.key<b)a=e;else break a;else break a}null!=d&&(d[c]=a);--c}} +function Gx(a,b){this.header=a;this.level=b;this.m=2155872256;this.J=0}Gx.prototype.put=function(a,b){var c=Array(15),d=Fx(this.header,a,this.level,c).forward[0];if(null!=d&&d.key===a)return d.H=b;a:for(d=0;;)if(.5>Math.random()&&15>d)d+=1;else break a;if(d>this.level){for(var e=this.level+1;;)if(e<=d+1)c[e]=this.header,e+=1;else break;this.level=d}for(d=Ex(a,b,Array(d));;)return 0<=this.level?(c=c[0].forward,d.forward[0]=c[0],c[0]=d):null}; +Gx.prototype.remove=function(a){var b=Array(15),c=Fx(this.header,a,this.level,b);c=0===c.forward.length?null:c.forward[0];if(null!=c&&c.key===a){for(a=0;;)if(a<=this.level){var d=b[a].forward;c===(a<d.length?d[a]:null)&&(d[a]=c.forward[a]);a+=1}else break;for(;;)if(0<this.level&&this.level<this.header.forward.length&&null==this.header.forward[this.level])--this.level;else return null}else return null}; +function Hx(a){for(var b=Ix,c=b.header,d=b.level;;){if(0>d)return c===b.header?null:c;var e;a:for(e=c;;){e=d<e.forward.length?e.forward[d]:null;if(null==e){e=null;break a}if(e.key>=a)break a}null!=e?(--d,c=e):--d}}Gx.prototype.S=function(){return function(a){return function d(c){return new kf(null,function(){return function(){return null==c?null:ae(new R(null,2,5,T,[c.key,c.H],null),d(c.forward[0]))}}(a),null,null)}}(this)(this.header.forward[0])}; +Gx.prototype.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"{",", ","}",c,this)};var Ix=new Gx(Ex(null,null,0),0);function Jx(a){var b=(new Date).valueOf()+a,c=Hx(b),d=t(t(c)?c.key<b+10:c)?c.H:null;if(t(d))return d;var e=vx(null,null);Ix.put(b,e);mx(function(a,b,c){return function(){Ix.remove(c);return Tw(a)}}(e,d,b,c),a);return e};function Kx(a){return Lx(a,null)}function Mx(a,b){return Lx(a,b)}function Lx(a,b){var c=G.c(a,0)?null:a;return vx("number"===typeof c?new cx(bx(c),c):c,b)} +var Nx=function(a){"undefined"===typeof Ow&&(Ow=function(a,c,d){this.Cb=a;this.Je=c;this.Df=d;this.m=393216;this.J=0},Ow.prototype.T=function(a,c){return new Ow(this.Cb,this.Je,c)},Ow.prototype.P=function(){return this.Df},Ow.prototype.vb=function(){return!0},Ow.prototype.md=function(){return this.Je},Ow.prototype.tb=function(){return this.Cb},Ow.Wc=function(){return new R(null,3,5,T,[to,jk,gk],null)},Ow.qc=!0,Ow.Tb="cljs.core.async/t_cljs$core$async43104",Ow.Ec=function(a,c){return Jc(c,"cljs.core.async/t_cljs$core$async43104")}); +return new Ow(a,!0,Ef)}(function(){return null});function Ox(a,b){var c=Sw(a,b,Nx);return t(c)?B(c):!0}function Px(a){for(var b=Array(a),c=0;;)if(c<a)b[c]=0,c+=1;else break;for(c=1;;){if(G.c(c,a))return b;var d=Math.floor(Math.random()*c);b[c]=b[d];b[d]=c;c+=1}} +function Qx(){var a=dg.h(!0);"undefined"===typeof Pw&&(Pw=function(a,c){this.Hc=a;this.Ef=c;this.m=393216;this.J=0},Pw.prototype.T=function(){return function(a,c){return new Pw(this.Hc,c)}}(a),Pw.prototype.P=function(){return function(){return this.Ef}}(a),Pw.prototype.vb=function(){return function(){return B(this.Hc)}}(a),Pw.prototype.md=function(){return function(){return!0}}(a),Pw.prototype.tb=function(){return function(){fg(this.Hc,null);return!0}}(a),Pw.Wc=function(){return function(){return new R(null, +2,5,T,[em,ek],null)}}(a),Pw.qc=!0,Pw.Tb="cljs.core.async/t_cljs$core$async43126",Pw.Ec=function(){return function(a,c){return Jc(c,"cljs.core.async/t_cljs$core$async43126")}}(a));return new Pw(a,Ef)} +function Rx(a,b){"undefined"===typeof Qw&&(Qw=function(a,b,e){this.Hc=a;this.ed=b;this.Ff=e;this.m=393216;this.J=0},Qw.prototype.T=function(a,b){return new Qw(this.Hc,this.ed,b)},Qw.prototype.P=function(){return this.Ff},Qw.prototype.vb=function(){return Uw(this.Hc)},Qw.prototype.md=function(){return!0},Qw.prototype.tb=function(){Vw(this.Hc);return this.ed},Qw.Wc=function(){return new R(null,3,5,T,[em,Mk,hl],null)},Qw.qc=!0,Qw.Tb="cljs.core.async/t_cljs$core$async43129",Qw.Ec=function(a,b){return Jc(b, +"cljs.core.async/t_cljs$core$async43129")});return new Qw(a,b,Ef)} +function Sx(a,b,c){var d=Qx(),e=H(b),f=Px(e),h=Im.h(c),k=function(){for(var c=0;;)if(c<e){var k=t(h)?c:f[c],m=Vd(b,k),u=ze(m)?m.h?m.h(0):m.call(null,0):null,w=t(u)?function(){var b=m.h?m.h(1):m.call(null,1);return Sw(u,b,Rx(d,function(b,c,d,e,f){return function(b){b=new R(null,2,5,T,[b,f],null);return a.h?a.h(b):a.call(null,b)}}(c,b,k,m,u,d,e,f,h)))}():Rw(m,Rx(d,function(b,c,d){return function(b){b=new R(null,2,5,T,[b,d],null);return a.h?a.h(b):a.call(null,b)}}(c,k,m,u,d,e,f,h)));if(t(w))return ox(new R(null, +2,5,T,[B(w),function(){var a=u;return t(a)?a:m}()],null));c+=1}else return null}();return t(k)?k:He(c,Ik)&&(k=function(){var a=Uw(d);return t(a)?Vw(d):a}(),t(k))?ox(new R(null,2,5,T,[Ik.h(c),Ik],null)):null} +function Tx(a,b){var c=Kx(1);lx(function(c){return function(){var d=function(){return function(a){return function(){function b(b){for(;;){a:try{for(;;){var c=a(b);if(!N(c,Z)){var d=c;break a}}}catch(x){if(x instanceof Object)b[5]=x,Cx(b),d=Z;else throw x;}if(!N(d,Z))return d}}function c(){var a=[null,null,null,null,null,null,null,null];a[0]=d;a[1]=1;return a}var d=null;d=function(a){switch(arguments.length){case 0:return c.call(this);case 1:return b.call(this,a)}throw Error("Invalid arity: "+(arguments.length- +1));};d.B=c;d.h=b;return d}()}(function(){return function(c){var d=c[1];return 7===d?(c[2]=c[2],c[1]=3,Z):1===d?(c[2]=null,c[1]=2,Z):4===d?(d=c[2],c[7]=d,c[1]=t(null==d)?5:6,Z):13===d?(c[2]=null,c[1]=14,Z):6===d?(d=c[7],Ax(c,11,b,d)):3===d?Bx(c,c[2]):12===d?(c[2]=null,c[1]=2,Z):2===d?zx(c,4,a):11===d?(c[1]=t(c[2])?12:13,Z):9===d?(c[2]=null,c[1]=10,Z):5===d?(c[1]=t(!0)?8:9,Z):14===d||10===d?(c[2]=c[2],c[1]=7,Z):8===d?(d=Tw(b),c[2]=d,c[1]=10,Z):null}}(c),c)}(),f=function(){var a=d.B?d.B():d.call(null); +a[6]=c;return a}();return yx(f)}}(c))}function Ux(a){for(var b=[],c=arguments.length,d=0;;)if(d<c)b.push(arguments[d]),d+=1;else break;return Vx(arguments[0],arguments[1],arguments[2],3<b.length?new Jb(b.slice(3),0,null):null)}function Vx(a,b,c,d){var e=null!=d&&(d.m&64||q===d.G)?P(U,d):d;a[1]=b;b=Sx(function(){return function(b){a[2]=b;return yx(a)}}(d,e,e),c,e);return t(b)?(a[2]=B(b),Z):null};function Wx(){}var Xx=function Xx(a,b){if(null!=a&&null!=a.qb)return a.qb(a,b);var d=Xx[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=Xx._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("Update.update-player",a);};function Yx(){}var Zx=function Zx(a,b){if(null!=a&&null!=a.de)return a.de(a,b);var d=Zx[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=Zx._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("ChannelSource.get-channels",a);}; +function $x(a,b,c){this.v=a;this.j=b;this.w=c;this.m=2229667594;this.J=139264}g=$x.prototype;g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){return D.l(this.j,b,c)};g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.player.messages.FastForward{",", ","}",c,O.c(he,this.j))};g.ba=function(){return new fh(0,this,0,he,t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 0+H(this.j)}; +g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return 1082393681^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.j,b.j)};g.ga=function(a,b){return He(vi,b)?le.c(tc(wg.c(Ef,this),this.v),b):new $x(this.v,Bf(le.c(this.j,b)),null)};g.O=function(a,b,c){return new $x(this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(he,this.j))}; +g.T=function(a,b){return new $x(b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};function ay(a,b,c){this.v=a;this.j=b;this.w=c;this.m=2229667594;this.J=139264}g=ay.prototype;g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){return D.l(this.j,b,c)};g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.player.messages.Rewind{",", ","}",c,O.c(he,this.j))}; +g.ba=function(){return new fh(0,this,0,he,t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 0+H(this.j)};g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return-1020675721^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.j,b.j)};g.ga=function(a,b){return He(vi,b)?le.c(tc(wg.c(Ef,this),this.v),b):new ay(this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return new ay(this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(he,this.j))};g.T=function(a,b){return new ay(b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};function by(a,b,c,d){this.position=a;this.v=b;this.j=c;this.w=d;this.m=2229667594;this.J=139264}g=by.prototype;g.V=function(a,b){return this.I(null,b,null)}; +g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "position":return this.position;default:return D.l(this.j,b,c)}};g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.player.messages.Seek{",", ","}",c,O.c(new R(null,1,5,T,[new R(null,2,5,T,[nn,this.position],null)],null),this.j))};g.ba=function(){return new fh(0,this,1,new R(null,1,5,T,[nn],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 1+H(this.j)}; +g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return-2136325183^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.position,b.position)&&G.c(this.j,b.j)};g.ga=function(a,b){return He(new ti(null,new r(null,1,[nn,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new by(this.position,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(nn,b):N.call(null,nn,b))?new by(c,this.v,this.j,null):new by(this.position,this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(new R(null,1,5,T,[new R(null,2,5,T,[nn,this.position],null)],null),this.j))};g.T=function(a,b){return new by(this.position,b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};function cy(a){return new by(a,null,null,null)} +function dy(a,b,c){this.v=a;this.j=b;this.w=c;this.m=2229667594;this.J=139264}g=dy.prototype;g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){return D.l(this.j,b,c)};g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.player.messages.SpeedDown{",", ","}",c,O.c(he,this.j))};g.ba=function(){return new fh(0,this,0,he,t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 0+H(this.j)}; +g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return 1945704126^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.j,b.j)};g.ga=function(a,b){return He(vi,b)?le.c(tc(wg.c(Ef,this),this.v),b):new dy(this.v,Bf(le.c(this.j,b)),null)};g.O=function(a,b,c){return new dy(this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(he,this.j))}; +g.T=function(a,b){return new dy(b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};function ey(a,b,c){this.v=a;this.j=b;this.w=c;this.m=2229667594;this.J=139264}g=ey.prototype;g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){return D.l(this.j,b,c)};g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.player.messages.SpeedUp{",", ","}",c,O.c(he,this.j))}; +g.ba=function(){return new fh(0,this,0,he,t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 0+H(this.j)};g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return 2001377313^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.j,b.j)};g.ga=function(a,b){return He(vi,b)?le.c(tc(wg.c(Ef,this),this.v),b):new ey(this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return new ey(this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(he,this.j))};g.T=function(a,b){return new ey(b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};function fy(a,b,c){this.v=a;this.j=b;this.w=c;this.m=2229667594;this.J=139264}g=fy.prototype;g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){return D.l(this.j,b,c)}; +g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.player.messages.TogglePlay{",", ","}",c,O.c(he,this.j))};g.ba=function(){return new fh(0,this,0,he,t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 0+H(this.j)};g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return 1662385780^Dd(a)}}(b,a)(a)}();return this.w=c}; +g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.j,b.j)};g.ga=function(a,b){return He(vi,b)?le.c(tc(wg.c(Ef,this),this.v),b):new fy(this.v,Bf(le.c(this.j,b)),null)};g.O=function(a,b,c){return new fy(this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(he,this.j))};g.T=function(a,b){return new fy(b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)}; +function gy(a,b,c,d){this.show=a;this.v=b;this.j=c;this.w=d;this.m=2229667594;this.J=139264}g=gy.prototype;g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "show":return this.show;default:return D.l(this.j,b,c)}};g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.player.messages.ShowCursor{",", ","}",c,O.c(new R(null,1,5,T,[new R(null,2,5,T,[so,this.show],null)],null),this.j))}; +g.ba=function(){return new fh(0,this,1,new R(null,1,5,T,[so],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 1+H(this.j)};g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return 1380979759^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.show,b.show)&&G.c(this.j,b.j)}; +g.ga=function(a,b){return He(new ti(null,new r(null,1,[so,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new gy(this.show,this.v,Bf(le.c(this.j,b)),null)};g.O=function(a,b,c){return t(N.c?N.c(so,b):N.call(null,so,b))?new gy(c,this.v,this.j,null):new gy(this.show,this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(new R(null,1,5,T,[new R(null,2,5,T,[so,this.show],null)],null),this.j))};g.T=function(a,b){return new gy(this.show,b,this.j,this.w)}; +g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};function hy(a,b,c,d){this.show=a;this.v=b;this.j=c;this.w=d;this.m=2229667594;this.J=139264}g=hy.prototype;g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "show":return this.show;default:return D.l(this.j,b,c)}}; +g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.player.messages.ShowHud{",", ","}",c,O.c(new R(null,1,5,T,[new R(null,2,5,T,[so,this.show],null)],null),this.j))};g.ba=function(){return new fh(0,this,1,new R(null,1,5,T,[so],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 1+H(this.j)}; +g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return-1875838466^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.show,b.show)&&G.c(this.j,b.j)};g.ga=function(a,b){return He(new ti(null,new r(null,1,[so,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new hy(this.show,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(so,b):N.call(null,so,b))?new hy(c,this.v,this.j,null):new hy(this.show,this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(new R(null,1,5,T,[new R(null,2,5,T,[so,this.show],null)],null),this.j))};g.T=function(a,b){return new hy(this.show,b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};function iy(a){return new hy(a,null,null,null)} +function jy(a,b,c,d,e,f){this.width=a;this.height=b;this.duration=c;this.v=d;this.j=e;this.w=f;this.m=2229667594;this.J=139264}g=jy.prototype;g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "width":return this.width;case "height":return this.height;case "duration":return this.duration;default:return D.l(this.j,b,c)}}; +g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.player.messages.SetMetadata{",", ","}",c,O.c(new R(null,3,5,T,[new R(null,2,5,T,[fl,this.width],null),new R(null,2,5,T,[no,this.height],null),new R(null,2,5,T,[wl,this.duration],null)],null),this.j))};g.ba=function(){return new fh(0,this,3,new R(null,3,5,T,[fl,no,wl],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 3+H(this.j)}; +g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return 2110730596^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.width,b.width)&&G.c(this.height,b.height)&&G.c(this.duration,b.duration)&&G.c(this.j,b.j)}; +g.ga=function(a,b){return He(new ti(null,new r(null,3,[fl,null,wl,null,no,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new jy(this.width,this.height,this.duration,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(fl,b):N.call(null,fl,b))?new jy(c,this.height,this.duration,this.v,this.j,null):t(N.c?N.c(no,b):N.call(null,no,b))?new jy(this.width,c,this.duration,this.v,this.j,null):t(N.c?N.c(wl,b):N.call(null,wl,b))?new jy(this.width,this.height,c,this.v,this.j,null):new jy(this.width,this.height,this.duration,this.v,K.l(this.j,b,c),null)}; +g.S=function(){return E(O.c(new R(null,3,5,T,[new R(null,2,5,T,[fl,this.width],null),new R(null,2,5,T,[no,this.height],null),new R(null,2,5,T,[wl,this.duration],null)],null),this.j))};g.T=function(a,b){return new jy(this.width,this.height,this.duration,b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};function ky(a,b,c,d){this.tc=a;this.v=b;this.j=c;this.w=d;this.m=2229667594;this.J=139264}g=ky.prototype;g.V=function(a,b){return this.I(null,b,null)}; +g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "loading":return this.tc;default:return D.l(this.j,b,c)}};g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.player.messages.SetLoading{",", ","}",c,O.c(new R(null,1,5,T,[new R(null,2,5,T,[Hm,this.tc],null)],null),this.j))};g.ba=function(){return new fh(0,this,1,new R(null,1,5,T,[Hm],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 1+H(this.j)}; +g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return 1609009220^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.tc,b.tc)&&G.c(this.j,b.j)};g.ga=function(a,b){return He(new ti(null,new r(null,1,[Hm,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new ky(this.tc,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(Hm,b):N.call(null,Hm,b))?new ky(c,this.v,this.j,null):new ky(this.tc,this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(new R(null,1,5,T,[new R(null,2,5,T,[Hm,this.tc],null)],null),this.j))};g.T=function(a,b){return new ky(this.tc,b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};function ly(a){return new ky(a,null,null,null)} +function my(a,b,c,d){this.uc=a;this.v=b;this.j=c;this.w=d;this.m=2229667594;this.J=139264}g=my.prototype;g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "playing":return this.uc;default:return D.l(this.j,b,c)}};g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.player.messages.SetPlaying{",", ","}",c,O.c(new R(null,1,5,T,[new R(null,2,5,T,[jn,this.uc],null)],null),this.j))}; +g.ba=function(){return new fh(0,this,1,new R(null,1,5,T,[jn],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 1+H(this.j)};g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return-2119286176^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.uc,b.uc)&&G.c(this.j,b.j)}; +g.ga=function(a,b){return He(new ti(null,new r(null,1,[jn,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new my(this.uc,this.v,Bf(le.c(this.j,b)),null)};g.O=function(a,b,c){return t(N.c?N.c(jn,b):N.call(null,jn,b))?new my(c,this.v,this.j,null):new my(this.uc,this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(new R(null,1,5,T,[new R(null,2,5,T,[jn,this.uc],null)],null),this.j))};g.T=function(a,b){return new my(this.uc,b,this.j,this.w)}; +g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};function ny(a){return new my(a,null,null,null)}function oy(a,b,c){this.v=a;this.j=b;this.w=c;this.m=2229667594;this.J=139264}g=oy.prototype;g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){return D.l(this.j,b,c)};g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.player.messages.TriggerCanPlay{",", ","}",c,O.c(he,this.j))}; +g.ba=function(){return new fh(0,this,0,he,t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 0+H(this.j)};g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return-1080034109^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.j,b.j)};g.ga=function(a,b){return He(vi,b)?le.c(tc(wg.c(Ef,this),this.v),b):new oy(this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return new oy(this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(he,this.j))};g.T=function(a,b){return new oy(b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};function py(a,b,c,d){this.screen=a;this.v=b;this.j=c;this.w=d;this.m=2229667594;this.J=139264}g=py.prototype;g.V=function(a,b){return this.I(null,b,null)}; +g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "screen":return this.screen;default:return D.l(this.j,b,c)}};g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.player.messages.UpdateScreen{",", ","}",c,O.c(new R(null,1,5,T,[new R(null,2,5,T,[V,this.screen],null)],null),this.j))};g.ba=function(){return new fh(0,this,1,new R(null,1,5,T,[V],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 1+H(this.j)}; +g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return-1861248332^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.screen,b.screen)&&G.c(this.j,b.j)};g.ga=function(a,b){return He(new ti(null,new r(null,1,[V,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new py(this.screen,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(V,b):N.call(null,V,b))?new py(c,this.v,this.j,null):new py(this.screen,this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(new R(null,1,5,T,[new R(null,2,5,T,[V,this.screen],null)],null),this.j))};g.T=function(a,b){return new py(this.screen,b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};function qy(a){return new py(a,null,null,null)} +function ry(a,b,c,d){this.time=a;this.v=b;this.j=c;this.w=d;this.m=2229667594;this.J=139264}g=ry.prototype;g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "time":return this.time;default:return D.l(this.j,b,c)}};g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.player.messages.UpdateTime{",", ","}",c,O.c(new R(null,1,5,T,[new R(null,2,5,T,[Zk,this.time],null)],null),this.j))}; +g.ba=function(){return new fh(0,this,1,new R(null,1,5,T,[Zk],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 1+H(this.j)};g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return 463038319^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.time,b.time)&&G.c(this.j,b.j)}; +g.ga=function(a,b){return He(new ti(null,new r(null,1,[Zk,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new ry(this.time,this.v,Bf(le.c(this.j,b)),null)};g.O=function(a,b,c){return t(N.c?N.c(Zk,b):N.call(null,Zk,b))?new ry(c,this.v,this.j,null):new ry(this.time,this.v,K.l(this.j,b,c),null)};g.S=function(){return E(O.c(new R(null,1,5,T,[new R(null,2,5,T,[Zk,this.time],null)],null),this.j))};g.T=function(a,b){return new ry(this.time,b,this.j,this.w)}; +g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};function sy(a){return new ry(a,null,null,null)};var ty=function ty(a){if(null!=a&&null!=a.Bd)return a.Bd(a);var c=ty[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=ty._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("Source.init",a);},uy=function uy(a){if(null!=a&&null!=a.Ad)return a.Ad(a);var c=uy[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=uy._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("Source.close",a);},vy=function vy(a){if(null!=a&&null!=a.ac)return a.ac(a);var c=vy[n(null==a?null:a)]; +if(null!=c)return c.h?c.h(a):c.call(null,a);c=vy._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("Source.start",a);},wy=function wy(a){if(null!=a&&null!=a.wc)return a.wc(a);var c=wy[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=wy._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("Source.stop",a);},xy=function xy(a){if(null!=a&&null!=a.Dd)return a.Dd(a);var c=xy[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=xy._;if(null!=c)return c.h?c.h(a):c.call(null, +a);throw Cb("Source.toggle",a);},yy=function yy(a,b){if(null!=a&&null!=a.Cd)return a.Cd(a,b);var d=yy[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=yy._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("Source.seek",a);},zy=function zy(a,b){if(null!=a&&null!=a.zd)return a.zd(a,b);var d=zy[n(null==a?null:a)];if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);d=zy._;if(null!=d)return d.c?d.c(a,b):d.call(null,a,b);throw Cb("Source.change-speed",a);}; +if("undefined"===typeof xj)var xj=function(){var a=dg.h(Ef),b=dg.h(Ef),c=dg.h(Ef),d=dg.h(Ef),e=D.l(Ef,Qn,jj());return new uj(td.c("asciinema.player.source","make-source"),function(){return function(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b;c=D.c(c,rl);return t(c)?c:ok}}(a,b,c,d,e),Ik,e,a,b,c,d)}();function Ay(){return ig.c(function(a){return function(b){b*=a;return new R(null,2,5,T,[b,b],null)}}(1/3),Fi(0,Number.MAX_VALUE,1))} +function By(a){var b=Kx(null),c=Lx(new fx(ex),null),d=Kx(1);lx(function(b,c,d){return function(){var e=function(){return function(a){return function(){function b(b){for(;;){a:try{for(;;){var c=a(b);if(!N(c,Z)){var d=c;break a}}}catch(I){if(I instanceof Object)b[5]=I,Cx(b),d=Z;else throw I;}if(!N(d,Z))return d}}function c(){var a=[null,null,null,null,null,null,null,null];a[0]=d;a[1]=1;return a}var d=null;d=function(a){switch(arguments.length){case 0:return c.call(this);case 1:return b.call(this,a)}throw Error("Invalid arity: "+ +(arguments.length-1));};d.B=c;d.h=b;return d}()}(function(b,c,d){return function(e){var f=e[1];if(1===f)return zx(e,2,c);if(2===f){var h=e[2],k=function(){return function(a,b,c,d,e){return function(a){return Ox(e,a)}}(h,f,b,c,d)}();k=a.h?a.h(k):a.call(null,k);e[7]=h;return Bx(e,k)}return null}}(b,c,d),b,c,d)}(),f=function(){var a=e.B?e.B():e.call(null);a[6]=b;return a}();return yx(f)}}(d,b,c));return function(a,b){return function(c){t(c)&&Tw(a);return b}}(b,c)} +function Cy(a,b,c,d){return By(function(e){if("string"===typeof a)return Ew(a,function(){return function(a){a=a.target;try{var f=a.ca?a.ca.responseText:""}catch(l){f=""}f=pv(f,b,c,d);return e.h?e.h(f):e.call(null,f)}}(a));var f=pv(a,b,c,d);return e.h?e.h(f):e.call(null,f)})} +function Dy(a){var b=Kx(null),c=Kx(1);lx(function(b,c){return function(){var d=function(){return function(a){return function(){function b(b){for(;;){a:try{for(;;){var c=a(b);if(!N(c,Z)){var d=c;break a}}}catch(C){if(C instanceof Object)b[5]=C,Cx(b),d=Z;else throw C;}if(!N(d,Z))return d}}function c(){var a=[null,null,null,null,null,null,null,null,null,null,null,null,null,null];a[0]=d;a[1]=1;return a}var d=null;d=function(a){switch(arguments.length){case 0:return c.call(this);case 1:return b.call(this, +a)}throw Error("Invalid arity: "+(arguments.length-1));};d.B=c;d.h=b;return d}()}(function(b,c){return function(b){var d=b[1];if(7===d)return d=Jx(1E3*b[7]),zx(b,10,d);if(1===d){d=Ou(1);var e=d.B?d.B():d.call(null),f=a;b[8]=d;b[9]=e;b[10]=f;b[2]=null;b[1]=2;return Z}return 4===d?(e=b[11],d=b[9],f=J(e,0,null),e=J(e,1,null),d=f-d,b[12]=e,b[7]=d,b[1]=t(0<d)?7:8,Z):15===d?(b[1]=t(b[2])?16:17,Z):13===d?(b[2]=null,b[1]=14,Z):6===d?(b[2]=b[2],b[1]=3,Z):17===d?(b[2]=null,b[1]=18,Z):3===d?Bx(b,b[2]):12=== +d?(d=b[8],f=b[10],f=vd(f),d=d.B?d.B():d.call(null),b[9]=d,b[10]=f,b[2]=null,b[1]=2,Z):2===d?(f=b[10],d=y(f),b[11]=d,b[1]=t(d)?4:5,Z):11===d?(b[1]=t(b[2])?12:13,Z):9===d?(b[2]=b[2],b[1]=6,Z):5===d?(d=Tw(c),b[2]=d,b[1]=6,Z):14===d?(b[2]=b[2],b[1]=9,Z):16===d?(d=b[9],f=b[10],f=vd(f),b[9]=d,b[10]=f,b[2]=null,b[1]=2,Z):10===d?(e=b[12],b[13]=b[2],Ax(b,11,c,e)):18===d?(b[2]=b[2],b[1]=9,Z):8===d?(e=b[12],Ax(b,15,c,e)):null}}(b,c),b,c)}(),e=function(){var a=d.B?d.B():d.call(null);a[6]=b;return a}();return yx(e)}}(c, +b));return b} +function Ey(a,b,c,d,e,f){var h=Kx(1);lx(function(h){return function(){var k=function(){return function(a){return function(){function b(b){for(;;){a:try{for(;;){var c=a(b);if(!N(c,Z)){var d=c;break a}}}catch(M){if(M instanceof Object)b[5]=M,Cx(b),d=Z;else throw M;}if(!N(d,Z))return d}}function c(){var a=[null,null,null,null,null,null,null,null,null,null,null,null,null,null];a[0]=d;a[1]=1;return a}var d=null;d=function(a){switch(arguments.length){case 0:return c.call(this);case 1:return b.call(this,a)}throw Error("Invalid arity: "+ +(arguments.length-1));};d.B=c;d.h=b;return d}()}(function(){return function(h){var k=h[1];if(7===k)return h[2]=h[2],h[1]=3,Z;if(1===k){k=Yu(c,d,b);var l=Dy(k);k=c;var m=Ou(d);h[7]=l;h[8]=m;h[9]=k;h[2]=null;h[1]=2;return Z}if(4===k)return l=h[7],m=h[2],k=J(m,0,null),m=J(m,1,null),l=G.c(l,m),h[11]=k,h[10]=m,h[1]=l?5:6,Z;if(15===k)return l=h[7],m=h[8],k=h[9],l=Tw(l),m=m.B?m.B():m.call(null),h[12]=l,h[2]=k+m,h[1]=17,Z;if(13===k)return h[2]=null,h[1]=14,Z;if(6===k)return k=h[10],k=G.c(f,k),h[1]=k?15:16, +Z;if(17===k)return h[2]=h[2],h[1]=7,Z;if(3===k)return Bx(h,h[2]);if(12===k)return k=Yu(0,d,b),k=Dy(k),l=Ou(d),h[7]=k,h[8]=l,h[9]=0,h[2]=null,h[1]=2,Z;if(2===k)return l=h[7],Ux(h,4,new R(null,2,5,T,[l,f],null));if(11===k)return l=h[7],m=h[8],k=h[9],h[13]=h[2],h[7]=l,h[8]=m,h[9]=k,h[2]=null,h[1]=2,Z;if(9===k)return h[1]=t(e)?12:13,Z;if(5===k)return k=h[11],h[1]=t(k)?8:9,Z;if(14===k)return h[2]=h[2],h[1]=10,Z;if(16===k)throw k=h[10],h=["No matching clause: ",v.h(k)].join(""),Error(h);return 10===k?(h[2]= +h[2],h[1]=7,Z):8===k?(k=h[11],Ax(h,11,a,k)):null}}(h),h)}(),p=function(){var a=k.B?k.B():k.call(null);a[6]=h;return a}();return yx(p)}}(h));return h} +function Fy(a,b,c,d,e,f,h){var k=Kx(1);lx(function(k){return function(){var l=function(){return function(a){return function(){function b(b){for(;;){a:try{for(;;){var c=a(b);if(!N(c,Z)){var d=c;break a}}}catch(S){if(S instanceof Object)b[5]=S,Cx(b),d=Z;else throw S;}if(!N(d,Z))return d}}function c(){var a=[null,null,null,null,null,null,null,null,null,null,null,null,null];a[0]=d;a[1]=1;return a}var d=null;d=function(a){switch(arguments.length){case 0:return c.call(this);case 1:return b.call(this,a)}throw Error("Invalid arity: "+ +(arguments.length-1));};d.B=c;d.h=b;return d}()}(function(){return function(k){var l=k[1];if(7===l)return l=k[7],k[2]=l,k[1]=9,Z;if(1===l)return Ax(k,2,a,ny(!0));if(4===l){l=k[2];var m=Su(qy,b),p=Ay();p=Su(sy,p);m=Ey(a,Tu(m,p),d,e,f,h);k[8]=l;return zx(k,5,m)}return 6===l?(l=ny(!1),k[9]=k[2],Ax(k,10,a,l)):3===l?(l=k[2],m=fe($u(d,b)),m=qy(m),k[10]=l,Ax(k,4,a,m)):2===l?(l=sy(d),k[11]=k[2],Ax(k,3,a,l)):9===l?Ax(k,6,a,sy(k[2])):5===l?(l=k[2],k[7]=l,k[1]=t(l)?7:8,Z):10===l?(l=k[7],k[12]=k[2],Bx(k,l)): +8===l?(k[2]=c,k[1]=9,Z):null}}(k),k)}(),m=function(){var a=l.B?l.B():l.call(null);a[6]=k;return a}();return yx(m)}}(k));return k} +function Gy(a,b,c){var d=null!=a&&(a.m&64||q===a.G)?P(U,a):a,e=D.c(d,Hk),f=D.c(d,Ak),h=D.c(d,dn),k=D.c(d,Jl),l=Kx(10),p=Kx(1);lx(function(a,d,e,f,h,k,l,p){return function(){var m=function(){return function(a){return function(){function b(b){for(;;){a:try{for(;;){var c=a(b);if(!N(c,Z)){var d=c;break a}}}catch(Ba){if(Ba instanceof Object)b[5]=Ba,Cx(b),d=Z;else throw Ba;}if(!N(d,Z))return d}}function c(){var a=[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null, +null,null,null,null,null,null,null];a[0]=d;a[1]=1;return a}var d=null;d=function(a){switch(arguments.length){case 0:return c.call(this);case 1:return b.call(this,a)}throw Error("Invalid arity: "+(arguments.length-1));};d.B=c;d.h=b;return d}()}(function(a,d,e,f,h,k,l,m){return function(a){var e=a[1];if(65===e){var f=a,p=f;p[2]=a[2];p[1]=62;return Z}if(70===e){var u=f=a;u[2]=!1;u[1]=71;return Z}if(62===e){var w=a[2],x=f=a;x[2]=w;x[1]=59;return Z}if(74===e){var C=a[7],F=a[8],I=a[2],M=D.c(I,Uk),S=D.c(I, +wl),Q=Nu(F,S),X=sy(Q);a[7]=Q;a[9]=M;f=a;return Ax(f,75,b,X)}if(7===e){var W=a[10],Ha=a[2],Ba=J(Ha,0,null);F=J(Ha,1,null);var Ga=G.c(gl,Ba);a[8]=F;a[10]=Ba;f=a;f[1]=Ga?8:9;return Z}if(59===e){var Oa=a[2],Ja=f=a;Ja[2]=Oa;Ja[1]=51;return Z}if(20===e){var db=P(U,c),xb=f=a;xb[2]=db;xb[1]=22;return Z}if(72===e){var az=P(U,c),ps=f=a;ps[2]=az;ps[1]=74;return Z}if(58===e){W=a[10];var bz=G.c(Xj,W);f=a;f[1]=bz?60:61;return Z}if(60===e){var ac=a[11],bc=0,Dc=ac,Eb=null,bb=null;a[11]=Dc;a[12]=bb;a[13]=bc;a[14]= +Eb;var qs=f=a;qs[2]=null;qs[1]=2;return Z}if(27===e){ac=a[11];bb=a[12];bc=a[13];Eb=a[14];var cz=bb,dz=Eb,Rd=bc;Dc=ac;var Sd=dz,Td=cz;a[11]=Dc;a[12]=Td;a[13]=Rd;a[14]=Sd;var rs=f=a;rs[2]=null;rs[1]=2;return Z}if(1===e){bc=h;ac=k;bb=Eb=null;a[11]=ac;a[12]=bb;a[13]=bc;a[14]=Eb;var ss=f=a;ss[2]=null;ss[1]=2;return Z}if(69===e){var ts=f=a;ts[2]=!0;ts[1]=71;return Z}if(24===e){W=a[10];var ez=G.c(Nl,W);f=a;f[1]=ez?30:31;return Z}if(55===e){var fz=new R(null,1,5,T,[gl],null);a[15]=a[2];f=a;return Ax(f,56, +d,fz)}if(39===e){var gz=a[2],us=f=a;us[2]=gz;us[1]=32;return Z}if(46===e){var vs=f=a;vs[2]=null;vs[1]=47;return Z}if(4===e){Eb=a[14];var ws=a[2],Ci=J(ws,0,null),hz=J(ws,1,null),iz=G.c(hz,Eb);a[16]=Ci;f=a;f[1]=iz?5:6;return Z}if(54===e){F=a[8];bb=a[12];bc=a[13];Eb=a[14];var jz=a[2],kz=bb,lz=Eb;Rd=bc;ac=F;Sd=lz;Td=kz;a[11]=ac;a[17]=jz;a[12]=Td;a[13]=Rd;a[14]=Sd;var xs=f=a;xs[2]=null;xs[1]=2;return Z}if(15===e){var ys=f=a;ys[2]=!1;ys[1]=16;return Z}if(48===e){var mz=a[2],zs=f=a;zs[2]=mz;zs[1]=47;return Z}if(50=== +e){W=a[10];var nz=G.c(qk,W);f=a;f[1]=nz?57:58;return Z}if(75===e){C=a[7];M=a[9];var oz=a[2],pz=fe($u(C,M)),qz=qy(pz);a[18]=oz;f=a;return Ax(f,76,b,qz)}if(21===e){var As=f=a;As[2]=c;As[1]=22;return Z}if(31===e){W=a[10];var rz=G.c(Kn,W);f=a;f[1]=rz?37:38;return Z}if(32===e){var sz=a[2],Bs=f=a;Bs[2]=sz;Bs[1]=25;return Z}if(40===e){var tz=new R(null,1,5,T,[wm],null);f=a;return Ax(f,43,d,tz)}if(56===e){var uz=a[2],Cs=f=a;Cs[2]=uz;Cs[1]=54;return Z}if(33===e){var Ds=f=a;Ds[2]=wm;Ds[1]=35;return Z}if(13=== +e){var vz=a[2],Es=f=a;Es[2]=vz;Es[1]=10;return Z}if(22===e){ac=a[11];bc=a[13];var Fs=a[2],wz=D.c(Fs,Uk),xz=D.c(Fs,wl),Gs=Kx(null),yz=Fy(b,wz,xz,bc,ac,l,Gs),zz=ac;Rd=null;Dc=zz;Eb=yz;bb=Gs;a[11]=Dc;a[12]=bb;a[13]=Rd;a[14]=Eb;var Hs=f=a;Hs[2]=null;Hs[1]=2;return Z}if(36===e){ac=a[11];bb=a[12];bc=a[13];Eb=a[14];var Az=a[2],Bz=ac,Cz=bb,Dz=Eb;Rd=bc;Dc=Bz;Sd=Dz;Td=Cz;a[11]=Dc;a[19]=Az;a[12]=Td;a[13]=Rd;a[14]=Sd;var Is=f=a;Is[2]=null;Is[1]=2;return Z}if(41===e){var Js=f=a;Js[2]=null;Js[1]=42;return Z}if(43=== +e){var Ez=a[2],Ks=f=a;Ks[2]=Ez;Ks[1]=42;return Z}if(61===e){W=a[10];var Fz=G.c(go,W);f=a;f[1]=Fz?63:64;return Z}if(29===e){var Gz=ac=a[11];bc=a[2];Dc=Gz;bb=Eb=null;a[11]=Dc;a[12]=bb;a[13]=bc;a[14]=Eb;var Ls=f=a;Ls[2]=null;Ls[1]=2;return Z}if(44===e)return bb=a[12],a[20]=a[2],f=a,f[1]=t(bb)?45:46,Z;if(6===e){Ci=a[16];var Ms=f=a;Ms[2]=Ci;Ms[1]=7;return Z}if(28===e){var Hz=a[2],Ns=f=a;Ns[2]=Hz;Ns[1]=25;return Z}if(64===e){W=a[10];var Iz=["No matching clause: ",v.h(W)].join("");throw Error(Iz);}if(51=== +e){var Jz=a[2],Os=f=a;Os[2]=Jz;Os[1]=39;return Z}if(25===e){var Kz=a[2],Ps=f=a;Ps[2]=Kz;Ps[1]=10;return Z}if(34===e){var Qs=f=a;Qs[2]=gl;Qs[1]=35;return Z}if(17===e){var Rs=f=a;Rs[2]=!0;Rs[1]=19;return Z}if(3===e){var Lz=a[2];f=a;return Bx(f,Lz)}if(12===e){var Mz=wb(null==c);f=a;f[1]=Mz?14:15;return Z}if(2===e){Eb=a[14];var Nz=vg(ub,new R(null,3,5,T,[d,m,Eb],null));f=a;return Vx(f,4,Nz,be([Im,!0]))}if(66===e){var Oz=q===c.G,Pz=c.m&64||Oz;f=a;f[1]=t(Pz)?69:70;return Z}if(23===e)return bb=a[12],f=a, +f[1]=t(bb)?26:27,Z;if(47===e){ac=a[11];bb=a[12];bc=a[13];Eb=a[14];var Qz=a[2],Rz=ac,Sz=bb,Tz=Eb;Rd=bc;Dc=Rz;Sd=Tz;Td=Sz;a[11]=Dc;a[21]=Qz;a[12]=Td;a[13]=Rd;a[14]=Sd;var Ss=f=a;Ss[2]=null;Ss[1]=2;return Z}if(35===e){var Uz=new R(null,1,5,T,[a[2]],null);f=a;return Ax(f,36,d,Uz)}if(76===e){ac=a[11];C=a[7];bb=a[12];Eb=a[14];var Vz=a[2],Wz=ac,Xz=bb,Yz=Eb;bc=C;Dc=Wz;Sd=Yz;Td=Xz;a[11]=Dc;a[22]=Vz;a[12]=Td;a[13]=bc;a[14]=Sd;var Ts=f=a;Ts[2]=null;Ts[1]=2;return Z}if(19===e){var Zz=a[2],Us=f=a;Us[2]=Zz;Us[1]= +16;return Z}if(57===e){var Vs=f=a;Vs[2]=null;Vs[1]=59;return Z}if(68===e){var $z=a[2];f=a;f[1]=t($z)?72:73;return Z}if(11===e){ac=a[11];bb=a[12];bc=a[13];Eb=a[14];var aA=ac,bA=bb,cA=Eb;Rd=bc;Dc=aA;Sd=cA;Td=bA;a[11]=Dc;a[12]=Td;a[13]=Rd;a[14]=Sd;var Ws=f=a;Ws[2]=null;Ws[1]=2;return Z}if(9===e){W=a[10];var dA=G.c(wm,W);f=a;f[1]=dA?23:24;return Z}if(5===e){Ci=a[16];var eA=new R(null,2,5,T,[Xj,Ci],null),Xs=f=a;Xs[2]=eA;Xs[1]=7;return Z}if(14===e){var fA=q===c.G,gA=c.m&64||fA;f=a;f[1]=t(gA)?17:18;return Z}if(45=== +e){var hA=new R(null,1,5,T,[gl],null);f=a;return Ax(f,48,d,hA)}if(53===e){var Ys=f=a;Ys[2]=null;Ys[1]=54;return Z}if(26===e){bb=a[12];Eb=a[14];var iA=Tw(bb);a[23]=iA;f=a;return zx(f,29,Eb)}if(16===e){var jA=a[2];f=a;f[1]=t(jA)?20:21;return Z}if(38===e){W=a[10];var kA=G.c(lm,W);f=a;f[1]=kA?49:50;return Z}if(30===e)return bb=a[12],f=a,f[1]=t(bb)?33:34,Z;if(73===e){var Zs=f=a;Zs[2]=c;Zs[1]=74;return Z}if(10===e){var lA=a[2],$s=f=a;$s[2]=lA;$s[1]=3;return Z}if(18===e){var at=f=a;at[2]=!1;at[1]=19;return Z}if(52=== +e){var mA=new R(null,1,5,T,[wm],null);f=a;return Ax(f,55,d,mA)}if(67===e){var bt=f=a;bt[2]=!1;bt[1]=68;return Z}if(71===e){var nA=a[2],ct=f=a;ct[2]=nA;ct[1]=68;return Z}if(42===e){F=a[8];var oA=new R(null,2,5,T,[go,F],null);a[24]=a[2];f=a;return Ax(f,44,d,oA)}if(37===e)return bb=a[12],f=a,f[1]=t(bb)?40:41,Z;if(63===e){var pA=wb(null==c);f=a;f[1]=pA?66:67;return Z}return 8===e?(bb=a[12],f=a,f[1]=t(bb)?11:12,Z):49===e?(bb=a[12],f=a,f[1]=t(bb)?52:53,Z):null}}(a,d,e,f,h,k,l,p),a,d,e,f,h,k,l,p)}(),u=function(){var b= +m.B?m.B():m.call(null);b[6]=a;return b}();return yx(u)}}(p,l,a,d,e,f,h,k));return p}function Hy(a){var b=window.requestIdleCallback;return t(b)?(a=function(a,b){return function h(c){return function(a){return function(){if(E(c)){var b=h(vd(c));return a.h?a.h(b):a.call(null,b)}return null}}(a,b)}}(b,b)(a),b.h?b.h(a):b.call(null,a)):null} +function Iy(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,bl),e=D.c(c,Jl),f=D.c(c,Hj),h=D.c(c,Sj),k=D.c(c,Mm),l=Kx(1);lx(function(a,c,d,e,f,h,k,l,M){return function(){var m=function(){return function(a){return function(){function b(b){for(;;){a:try{for(;;){var c=a(b);if(!N(c,Z)){var d=c;break a}}}catch(Ba){if(Ba instanceof Object)b[5]=Ba,Cx(b),d=Z;else throw Ba;}if(!N(d,Z))return d}}function c(){var a=[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]; +a[0]=d;a[1]=1;return a}var d=null;d=function(a){switch(arguments.length){case 0:return c.call(this);case 1:return b.call(this,a)}throw Error("Invalid arity: "+(arguments.length-1));};d.B=c;d.h=b;return d}()}(function(a,c,d,e,f,h,k,l,m){return function(a){var c=a[1];if(7===c)return c=a[7],c=G.c(k,c),a[1]=c?9:10,Z;if(1===c)return a[1]=t(l)?2:3,Z;if(4===c){c=a[2];c=f.h?f.h(c):f.call(null,c);var d=new R(null,2,5,T,[c,k],null);a[8]=c;return Ux(a,5,d)}if(15===c)return c=d=a[9],c=null!=c&&(c.m&64||q===c.G)? +P(U,c):c,c=D.c(c,Uk),c=Ox(b,qy(fe($u(m,c)))),a[2]=c,a[1]=17,Z;if(13===c)return c=a[2],d=ly(!1),a[10]=c,Ax(a,14,b,d);if(6===c)return c=a[11],a[2]=c,a[1]=8,Z;if(17===c){d=a[9];c=a[2];var h=d;var p=null!=h&&(h.m&64||q===h.G)?P(U,h):h;h=D.c(p,fl);var u=D.c(p,no);p=D.c(p,wl);Ox(b,new jy(h,u,p,null,null,null));h=Ox(b,new oy(null,null,null));u=Gy(e,b,d);d=Uk.h(d);d=Hy(d);a[12]=c;a[13]=u;a[14]=h;return Bx(a,d)}if(3===c)return a[2]=m,a[1]=4,Z;if(12===c)return c=a[2],d=f.h?f.h(!0):f.call(null,!0),a[15]=c,zx(a, +13,d);if(2===c)return a[2]=l,a[1]=4,Z;if(11===c)return a[2]=a[2],a[1]=8,Z;if(9===c)return Ax(a,12,b,ly(!0));if(5===c)return d=a[8],h=a[2],c=J(h,0,null),h=J(h,1,null),d=G.c(d,h),a[7]=h,a[11]=c,a[1]=d?6:7,Z;if(14===c)return c=a[10],a[16]=a[2],a[2]=c,a[1]=11,Z;if(16===c)return a[2]=null,a[1]=17,Z;if(10===c)throw c=a[7],a=["No matching clause: ",v.h(c)].join(""),Error(a);return 8===c?(d=a[2],a[9]=d,a[1]=t(m)?15:16,Z):null}}(a,c,d,e,f,h,k,l,M),a,c,d,e,f,h,k,l,M)}(),p=function(){var b=m.B?m.B():m.call(null); +b[6]=a;return b}();return yx(p)}}(l,a,c,c,d,e,f,h,k))}function Jy(a,b,c,d,e,f,h,k,l,p,m,u){this.nb=a;this.Ea=b;this.$a=c;this.ob=d;this.speed=e;this.Y=f;this.jb=h;this.mb=k;this.lb=l;this.v=p;this.j=m;this.w=u;this.m=2229667594;this.J=139264}g=Jy.prototype;g.Bd=function(){var a=Kx(null);Iy(this,a);t(this.Y)&&this.ac(null);return a};g.Ad=function(){Ox(this.Ea,new R(null,1,5,T,[wm],null));return Ox(this.Ea,new R(null,1,5,T,[qk],null))}; +g.ac=function(){Tw(this.$a);return Ox(this.Ea,new R(null,1,5,T,[gl],null))};g.wc=function(){return Ox(this.Ea,new R(null,1,5,T,[wm],null))};g.Dd=function(){Tw(this.$a);return Ox(this.Ea,new R(null,1,5,T,[Nl],null))};g.Cd=function(a,b){Tw(this.$a);return Ox(this.Ea,new R(null,2,5,T,[Kn,b],null))};g.zd=function(a,b){return Ox(this.Ea,new R(null,2,5,T,[lm,b],null))};g.V=function(a,b){return this.I(null,b,null)}; +g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "recording-ch-fn":return this.nb;case "command-ch":return this.Ea;case "force-load-ch":return this.$a;case "start-at":return this.ob;case "speed":return this.speed;case "auto-play?":return this.Y;case "loop?":return this.jb;case "preload?":return this.mb;case "poster-time":return this.lb;default:return D.l(this.j,b,c)}}; +g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.player.source.Recording{",", ","}",c,O.c(new R(null,9,5,T,[new R(null,2,5,T,[bl,this.nb],null),new R(null,2,5,T,[Jl,this.Ea],null),new R(null,2,5,T,[Hj,this.$a],null),new R(null,2,5,T,[Hk,this.ob],null),new R(null,2,5,T,[Ak,this.speed],null),new R(null,2,5,T,[Jm,this.Y],null),new R(null,2,5,T,[dn,this.jb],null),new R(null,2,5,T,[Sj,this.mb],null),new R(null,2,5,T,[Mm,this.lb],null)],null), +this.j))};g.ba=function(){return new fh(0,this,9,new R(null,9,5,T,[bl,Jl,Hj,Hk,Ak,Jm,dn,Sj,Mm],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 9+H(this.j)};g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return 1201370539^Dd(a)}}(b,a)(a)}();return this.w=c}; +g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.nb,b.nb)&&G.c(this.Ea,b.Ea)&&G.c(this.$a,b.$a)&&G.c(this.ob,b.ob)&&G.c(this.speed,b.speed)&&G.c(this.Y,b.Y)&&G.c(this.jb,b.jb)&&G.c(this.mb,b.mb)&&G.c(this.lb,b.lb)&&G.c(this.j,b.j)}; +g.ga=function(a,b){return He(new ti(null,new r(null,9,[Hj,null,Sj,null,Ak,null,Hk,null,bl,null,Jl,null,Jm,null,Mm,null,dn,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new Jy(this.nb,this.Ea,this.$a,this.ob,this.speed,this.Y,this.jb,this.mb,this.lb,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(bl,b):N.call(null,bl,b))?new Jy(c,this.Ea,this.$a,this.ob,this.speed,this.Y,this.jb,this.mb,this.lb,this.v,this.j,null):t(N.c?N.c(Jl,b):N.call(null,Jl,b))?new Jy(this.nb,c,this.$a,this.ob,this.speed,this.Y,this.jb,this.mb,this.lb,this.v,this.j,null):t(N.c?N.c(Hj,b):N.call(null,Hj,b))?new Jy(this.nb,this.Ea,c,this.ob,this.speed,this.Y,this.jb,this.mb,this.lb,this.v,this.j,null):t(N.c?N.c(Hk,b):N.call(null,Hk,b))?new Jy(this.nb,this.Ea,this.$a,c,this.speed,this.Y, +this.jb,this.mb,this.lb,this.v,this.j,null):t(N.c?N.c(Ak,b):N.call(null,Ak,b))?new Jy(this.nb,this.Ea,this.$a,this.ob,c,this.Y,this.jb,this.mb,this.lb,this.v,this.j,null):t(N.c?N.c(Jm,b):N.call(null,Jm,b))?new Jy(this.nb,this.Ea,this.$a,this.ob,this.speed,c,this.jb,this.mb,this.lb,this.v,this.j,null):t(N.c?N.c(dn,b):N.call(null,dn,b))?new Jy(this.nb,this.Ea,this.$a,this.ob,this.speed,this.Y,c,this.mb,this.lb,this.v,this.j,null):t(N.c?N.c(Sj,b):N.call(null,Sj,b))?new Jy(this.nb,this.Ea,this.$a,this.ob, +this.speed,this.Y,this.jb,c,this.lb,this.v,this.j,null):t(N.c?N.c(Mm,b):N.call(null,Mm,b))?new Jy(this.nb,this.Ea,this.$a,this.ob,this.speed,this.Y,this.jb,this.mb,c,this.v,this.j,null):new Jy(this.nb,this.Ea,this.$a,this.ob,this.speed,this.Y,this.jb,this.mb,this.lb,this.v,K.l(this.j,b,c),null)}; +g.S=function(){return E(O.c(new R(null,9,5,T,[new R(null,2,5,T,[bl,this.nb],null),new R(null,2,5,T,[Jl,this.Ea],null),new R(null,2,5,T,[Hj,this.$a],null),new R(null,2,5,T,[Hk,this.ob],null),new R(null,2,5,T,[Ak,this.speed],null),new R(null,2,5,T,[Jm,this.Y],null),new R(null,2,5,T,[dn,this.jb],null),new R(null,2,5,T,[Sj,this.mb],null),new R(null,2,5,T,[Mm,this.lb],null)],null),this.j))}; +g.T=function(a,b){return new Jy(this.nb,this.Ea,this.$a,this.ob,this.speed,this.Y,this.jb,this.mb,this.lb,b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};wj(ok,function(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b,d=D.c(c,fl),e=D.c(c,no),f=D.c(c,Hk),h=D.c(c,Ak),k=D.c(c,qm),l=D.c(c,Em),p=D.c(c,cm),m=D.c(c,vm);c=D.c(c,Mm);d=Cy(a,d,e,k);e=Kx(10);k=Kx(null);return new Jy(d,e,k,f,h,l,p,m,c,null,null,null)}); +function Ky(a,b,c){var d=Kx(null),e=Kx(1);lx(function(d,e){return function(){var f=function(){return function(a){return function(){function b(b){for(;;){a:try{for(;;){var c=a(b);if(!N(c,Z)){var d=c;break a}}}catch(I){if(I instanceof Object)b[5]=I,Cx(b),d=Z;else throw I;}if(!N(d,Z))return d}}function c(){var a=[null,null,null,null,null,null,null,null,null,null,null];a[0]=d;a[1]=1;return a}var d=null;d=function(a){switch(arguments.length){case 0:return c.call(this);case 1:return b.call(this,a)}throw Error("Invalid arity: "+ +(arguments.length-1));};d.B=c;d.h=b;return d}()}(function(d,e){return function(d){var f=d[1];if(1===f)return f=Ot(a,b),d[7]=f,d[2]=null,d[1]=2,Z;if(2===f)return zx(d,4,e);if(3===f)return Bx(d,d[2]);if(4===f)return f=d[2],d[8]=f,d[1]=t(f)?5:6,Z;if(5===f){var h=d[8];f=d[7];f=Ju(f,h);h=qy(f);d[9]=f;return Ax(d,8,c,h)}return 6===f?(d[2]=null,d[1]=7,Z):7===f?(d[2]=d[2],d[1]=3,Z):8===f?(f=d[9],h=d[2],d[10]=h,d[7]=f,d[2]=null,d[1]=2,Z):null}}(d,e),d,e)}(),h=function(){var a=f.B?f.B():f.call(null);a[6]=d; +return a}();return yx(h)}}(e,d));return d} +function Ly(a,b,c,d){var e=Kx(1);lx(function(e){return function(){var f=function(){return function(a){return function(){function b(b){for(;;){a:try{for(;;){var c=a(b);if(!N(c,Z)){var d=c;break a}}}catch(F){if(F instanceof Object)b[5]=F,Cx(b),d=Z;else throw F;}if(!N(d,Z))return d}}function c(){var a=[null,null,null,null,null,null,null,null,null,null,null];a[0]=d;a[1]=1;return a}var d=null;d=function(a){switch(arguments.length){case 0:return c.call(this);case 1:return b.call(this,a)}throw Error("Invalid arity: "+ +(arguments.length-1));};d.B=c;d.h=b;return d}()}(function(){return function(e){var f=e[1];if(7===f)return Ax(e,9,b,String.fromCharCode(Math.floor(160*Math.random())));if(1===f)return Ax(e,2,a,ny(!0));if(4===f)return f=ny(!1),e[7]=e[2],Ax(e,10,a,f);if(6===f)return e[2]=null,e[1]=8,Z;if(3===f)return f=Jx(100*Math.random()/c),Ux(e,5,new R(null,2,5,T,[d,f],null));if(2===f)return e[8]=e[2],e[2]=null,e[1]=3,Z;if(9===f)return e[9]=e[2],e[2]=null,e[1]=3,Z;if(5===f){var h=e[2];f=J(h,0,null);h=J(h,1,null); +h=G.c(h,d);e[10]=f;e[1]=h?6:7;return Z}return 10===f?Bx(e,e[2]):8===f?(e[2]=e[2],e[1]=4,Z):null}}(e),e)}(),k=function(){var a=f.B?f.B():f.call(null);a[6]=e;return a}();return yx(k)}}(e));return e}function My(a,b,c,d,e,f,h,k,l,p){this.speed=a;this.Y=b;this.width=c;this.height=d;this.ha=e;this.pb=f;this.La=h;this.v=k;this.j=l;this.w=p;this.m=2229667594;this.J=139264}g=My.prototype;g.Bd=function(){fg(this.ha,Kx(null));fg(this.pb,Ky(this.width,this.height,B(this.ha)));t(this.Y)&&this.ac(null);return B(this.ha)}; +g.Ad=function(){return this.wc(null)};g.ac=function(){if(t(B(this.La)))return null;var a=Kx(null);fg(this.La,a);return Ly(B(this.ha),B(this.pb),this.speed,a)};g.wc=function(){return t(B(this.La))?(Tw(B(this.La)),fg(this.La,null)):null};g.Dd=function(){return t(B(this.La))?this.wc(null):this.ac(null)};g.Cd=function(){return null};g.zd=function(){return null};g.V=function(a,b){return this.I(null,b,null)}; +g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "speed":return this.speed;case "auto-play?":return this.Y;case "width":return this.width;case "height":return this.height;case "msg-ch":return this.ha;case "stdout-ch":return this.pb;case "stop-ch":return this.La;default:return D.l(this.j,b,c)}}; +g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.player.source.JunkPrinter{",", ","}",c,O.c(new R(null,7,5,T,[new R(null,2,5,T,[Ak,this.speed],null),new R(null,2,5,T,[Jm,this.Y],null),new R(null,2,5,T,[fl,this.width],null),new R(null,2,5,T,[no,this.height],null),new R(null,2,5,T,[Dl,this.ha],null),new R(null,2,5,T,[rn,this.pb],null),new R(null,2,5,T,[Zl,this.La],null)],null),this.j))}; +g.ba=function(){return new fh(0,this,7,new R(null,7,5,T,[Ak,Jm,fl,no,Dl,rn,Zl],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 7+H(this.j)};g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return 1937333797^Dd(a)}}(b,a)(a)}();return this.w=c}; +g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.speed,b.speed)&&G.c(this.Y,b.Y)&&G.c(this.width,b.width)&&G.c(this.height,b.height)&&G.c(this.ha,b.ha)&&G.c(this.pb,b.pb)&&G.c(this.La,b.La)&&G.c(this.j,b.j)};g.ga=function(a,b){return He(new ti(null,new r(null,7,[Ak,null,fl,null,Dl,null,Zl,null,Jm,null,rn,null,no,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new My(this.speed,this.Y,this.width,this.height,this.ha,this.pb,this.La,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(Ak,b):N.call(null,Ak,b))?new My(c,this.Y,this.width,this.height,this.ha,this.pb,this.La,this.v,this.j,null):t(N.c?N.c(Jm,b):N.call(null,Jm,b))?new My(this.speed,c,this.width,this.height,this.ha,this.pb,this.La,this.v,this.j,null):t(N.c?N.c(fl,b):N.call(null,fl,b))?new My(this.speed,this.Y,c,this.height,this.ha,this.pb,this.La,this.v,this.j,null):t(N.c?N.c(no,b):N.call(null,no,b))?new My(this.speed,this.Y,this.width,c,this.ha,this.pb,this.La,this.v,this.j,null): +t(N.c?N.c(Dl,b):N.call(null,Dl,b))?new My(this.speed,this.Y,this.width,this.height,c,this.pb,this.La,this.v,this.j,null):t(N.c?N.c(rn,b):N.call(null,rn,b))?new My(this.speed,this.Y,this.width,this.height,this.ha,c,this.La,this.v,this.j,null):t(N.c?N.c(Zl,b):N.call(null,Zl,b))?new My(this.speed,this.Y,this.width,this.height,this.ha,this.pb,c,this.v,this.j,null):new My(this.speed,this.Y,this.width,this.height,this.ha,this.pb,this.La,this.v,K.l(this.j,b,c),null)}; +g.S=function(){return E(O.c(new R(null,7,5,T,[new R(null,2,5,T,[Ak,this.speed],null),new R(null,2,5,T,[Jm,this.Y],null),new R(null,2,5,T,[fl,this.width],null),new R(null,2,5,T,[no,this.height],null),new R(null,2,5,T,[Dl,this.ha],null),new R(null,2,5,T,[rn,this.pb],null),new R(null,2,5,T,[Zl,this.La],null)],null),this.j))};g.T=function(a,b){return new My(this.speed,this.Y,this.width,this.height,this.ha,this.pb,this.La,b,this.j,this.w)}; +g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};wj(mn,function(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b;D.c(c,$m);var d=D.c(c,fl),e=D.c(c,no),f=D.c(c,Ak);c=D.c(c,Em);var h=dg.h(null),k=dg.h(null),l=dg.h(null);return new My(f,c,d,e,h,k,l,null,null,null)});function Ny(a){return ev(JSON.parse(a))} +function Oy(a,b){var c=Kx(1);lx(function(c){return function(){var d=function(){return function(a){return function(){function b(b){for(;;){a:try{for(;;){var c=a(b);if(!N(c,Z)){var d=c;break a}}}catch(x){if(x instanceof Object)b[5]=x,Cx(b),d=Z;else throw x;}if(!N(d,Z))return d}}function c(){var a=[null,null,null,null,null,null,null,null,null,null,null,null,null];a[0]=d;a[1]=1;return a}var d=null;d=function(a){switch(arguments.length){case 0:return c.call(this);case 1:return b.call(this,a)}throw Error("Invalid arity: "+ +(arguments.length-1));};d.B=c;d.h=b;return d}()}(function(){return function(c){var d=c[1];if(7===d)return c[2]=!1,c[1]=8,Z;if(20===d)return c[2]=!1,c[1]=21,Z;if(27===d){d=c[7];var e=D.c(c[2],ko);return Ax(c,28,d,e)}if(1===d)return zx(c,2,a);if(24===d)return c[2]=c[2],c[1]=21,Z;if(4===d)return c[2]=!1,c[1]=5,Z;if(15===d)return d=c[2],c[8]=d,c[1]=t(d)?16:17,Z;if(21===d)return c[1]=t(c[2])?25:26,Z;if(13===d)return zx(c,15,a);if(22===d)return c[2]=!0,c[1]=24,Z;if(6===d)return c[2]=!0,c[1]=8,Z;if(28=== +d)return c[9]=c[2],c[2]=null,c[1]=13,Z;if(25===d)return d=c[8],d=P(U,d),c[2]=d,c[1]=27,Z;if(17===d)return c[2]=null,c[1]=18,Z;if(3===d)return d=c[10],e=q===d.G,c[1]=t(d.m&64||e)?6:7,Z;if(12===d)return c[11]=c[2],c[2]=null,c[1]=13,Z;if(2===d)return d=c[2],e=wb(null==d),c[10]=d,c[1]=e?3:4,Z;if(23===d)return c[2]=!1,c[1]=24,Z;if(19===d)return d=c[8],e=q===d.G,c[1]=t(d.m&64||e)?22:23,Z;if(11===d){var f=c[2];d=D.c(f,Zk);e=D.c(f,fl);var h=D.c(f,no);f=D.c(f,ko);e=Ky(e,h,b);c[7]=e;c[12]=d;return Ax(c,12, +e,f)}return 9===d?(d=c[10],d=P(U,d),c[2]=d,c[1]=11,Z):5===d?(c[1]=t(c[2])?9:10,Z):14===d?Bx(c,c[2]):26===d?(d=c[8],c[2]=d,c[1]=27,Z):16===d?(d=c[8],c[1]=wb(null==d)?19:20,Z):10===d?(d=c[10],c[2]=d,c[1]=11,Z):18===d?(c[2]=c[2],c[1]=14,Z):8===d?(c[2]=c[2],c[1]=5,Z):null}}(c),c)}(),f=function(){var a=d.B?d.B():d.call(null);a[6]=c;return a}();return yx(f)}}(c))} +function Py(a,b){var c=new EventSource(a),d=dg.h(null);Ox(b,ly(!0));c.onopen=function(a,c){return function(){var a=Mx(1E4,ig.h(Ny));fg(c,a);Oy(a,b);Ox(b,ny(!0));return Ox(b,ly(!1))}}(c,d);c.onerror=function(a,c){return function(){Tw(B(c));fg(c,null);return Ox(b,ly(!0))}}(c,d);return c.onmessage=function(a,b){return function(a){var c=B(b);return t(c)?Ox(c,a.data):null}}(c,d)} +function Qy(a,b,c,d,e,f,h){this.ha=a;this.url=b;this.Y=c;this.yb=d;this.v=e;this.j=f;this.w=h;this.m=2229667594;this.J=139264}g=Qy.prototype;g.Bd=function(){fg(this.ha,Kx(null));return t(this.Y)?this.ac(null):null};g.Ad=function(){return this.wc(null)};g.ac=function(){if(t(B(this.yb)))return null;fg(this.yb,!0);return Py(this.url,B(this.ha))};g.wc=function(){return null};g.Dd=function(){return this.ac(null)};g.Cd=function(){return null};g.zd=function(){return null}; +g.V=function(a,b){return this.I(null,b,null)};g.I=function(a,b,c){switch(b instanceof L?b.ea:null){case "msg-ch":return this.ha;case "url":return this.url;case "auto-play?":return this.Y;case "started?":return this.yb;default:return D.l(this.j,b,c)}}; +g.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"#asciinema.player.source.Stream{",", ","}",c,O.c(new R(null,4,5,T,[new R(null,2,5,T,[Dl,this.ha],null),new R(null,2,5,T,[$m,this.url],null),new R(null,2,5,T,[Jm,this.Y],null),new R(null,2,5,T,[rm,this.yb],null)],null),this.j))};g.ba=function(){return new fh(0,this,4,new R(null,4,5,T,[Dl,$m,Jm,rm],null),t(this.j)?dd(this.j):Cf())};g.P=function(){return this.v};g.W=function(){return 4+H(this.j)}; +g.U=function(){var a=this,b=this.w;if(null!=b)return b;var c=function(){return function(){return function(a){return 187678783^Dd(a)}}(b,a)(a)}();return this.w=c};g.K=function(a,b){return null!=b&&this.constructor===b.constructor&&G.c(this.ha,b.ha)&&G.c(this.url,b.url)&&G.c(this.Y,b.Y)&&G.c(this.yb,b.yb)&&G.c(this.j,b.j)}; +g.ga=function(a,b){return He(new ti(null,new r(null,4,[Dl,null,rm,null,Jm,null,$m,null],null),null),b)?le.c(tc(wg.c(Ef,this),this.v),b):new Qy(this.ha,this.url,this.Y,this.yb,this.v,Bf(le.c(this.j,b)),null)}; +g.O=function(a,b,c){return t(N.c?N.c(Dl,b):N.call(null,Dl,b))?new Qy(c,this.url,this.Y,this.yb,this.v,this.j,null):t(N.c?N.c($m,b):N.call(null,$m,b))?new Qy(this.ha,c,this.Y,this.yb,this.v,this.j,null):t(N.c?N.c(Jm,b):N.call(null,Jm,b))?new Qy(this.ha,this.url,c,this.yb,this.v,this.j,null):t(N.c?N.c(rm,b):N.call(null,rm,b))?new Qy(this.ha,this.url,this.Y,c,this.v,this.j,null):new Qy(this.ha,this.url,this.Y,this.yb,this.v,K.l(this.j,b,c),null)}; +g.S=function(){return E(O.c(new R(null,4,5,T,[new R(null,2,5,T,[Dl,this.ha],null),new R(null,2,5,T,[$m,this.url],null),new R(null,2,5,T,[Jm,this.Y],null),new R(null,2,5,T,[rm,this.yb],null)],null),this.j))};g.T=function(a,b){return new Qy(this.ha,this.url,this.Y,this.yb,b,this.j,this.w)};g.X=function(a,b){return ze(b)?this.O(null,A.c(b,0),A.c(b,1)):Mb(Tb,this,b)};wj(hm,function(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b;c=D.c(c,Em);var d=dg.h(null),e=dg.h(!1);return new Qy(d,a,c,e,null,null,null)});function Ry(a){var b=new R(null,5,5,T,["fullscreenElement","mozFullScreenElement","webkitFullscreenElement","webkitCurrentFullScreenElement","msFullscreenElement"],null);b=Wf($f.c(Ee,Pu),b);t(b)?(a=Wf(Pu,new R(null,5,5,T,["exitFullscreen","webkitExitFullscreen","webkitCancelFullScreen","mozCancelFullScreen","msExitFullscreen"],null)),a=t(a)?a.call(document):null):(b=new R(null,5,5,T,["requestFullscreen","webkitRequestFullscreen","webkitRequestFullScreen","mozRequestFullScreen","msRequestFullscreen"], +null),b=Wf(ag.c(Hb,a),b),a=t(b)?b.call(a):null);return a};r.prototype.yd=function(){return il.h(this)};r.prototype.xd=function(){return pl.h(this)};function Sy(a,b){return function(c){var d=b.h?b.h(c):b.call(null,c);return t(d)?(Ox(a,d),c.stopPropagation()):null}}function Ty(a,b){return Sy(a,function(){return b})}function Uy(a,b,c){var d="number"===typeof a||G.c(a,"fg")||G.c(a,"bg");return t(d)?(a=t(t(b)?8>a:b)?a+8:a,[v.h(c),v.h(a)].join("")):null} +function Vy(a){var b=J(a,0,null),c=J(a,1,null);a=J(a,2,null);return["rgb(",v.h(b),",",v.h(c),",",v.h(a),")"].join("")} +var Wy=hj(function(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,Nk),c=D.c(a,pl);a=K.l(a,Nk,t(c)?wb(b):b);var d=null!=a&&(a.m&64||q===a.G)?P(U,a):a,e=D.c(d,Ok),f=D.c(d,Tn);b=D.c(d,Kj);var h=D.c(d,dk);c=D.c(d,Vl);var k=D.c(d,Nk),l=D.c(d,Yn);d=D.c(d,pl);var p=t(k)?t(e)?e:"fg":f;e=Uy(t(k)?t(f)?f:"bg":e,b,"fg-");h=Uy(p,h,"bg-");c=vg(ub,new R(null,6,5,T,[e,h,t(b)?"bright":null,t(l)?"italic":null,t(c)?"underline":null,t(d)?"cursor":null],null));if(E(c))a:for(b=new cb,c=E(c);;)if(null!=c)b.append(""+ +v.h(y(c))),c=z(c),null!=c&&b.append(" ");else{b=b.toString();break a}else b=null;l=null!=a&&(a.m&64||q===a.G)?P(U,a):a;a=D.c(l,Ok);c=D.c(l,Tn);h=D.c(l,Nk);l=t(h)?c:a;a=t(h)?a:c;a=hi.A(be([t(ze.h?ze.h(l):ze.call(null,l))?new r(null,1,[ik,Vy(l)],null):null,t(ze.h?ze.h(a):ze.call(null,a))?new r(null,1,[al,Vy(a)],null):null]));return hi.A(be([t(b)?new r(null,1,[vn,b],null):null,t(a)?new r(null,1,[fm,a],null):null]))}); +function Xy(a,b){var c=J(a,0,null),d=J(a,1,null);d=Bg(d,pl,function(){return function(a){return t(a)?B(b):a}}(a,c,d));return new R(null,3,5,T,[ro,Wy.h?Wy.h(d):Wy.call(null,d),c],null)}function Yy(a,b){var c=J(a,0,null),d=J(a,1,null),e=jg(b,c);e=E(e)?new R(null,2,5,T,[Eo(e),d],null):null;var f=K.l(d,pl,!0);f=new R(null,2,5,T,[Vd(c,b),f],null);c=kg(b+1,c);d=E(c)?new R(null,2,5,T,[Eo(c),d],null):null;return vg(ub,new R(null,3,5,T,[e,f,d],null))} +function Zy(a,b){for(var c=he,d=a,e=b;;)if(E(d)){var f=y(d),h=J(f,0,null);J(f,1,null);h=H(h);if(h<=e)c=ge.c(c,f),d=vd(d),e-=h;else return O.A(c,Yy(f,e),be([vd(d)]))}else return c}function $y(a,b,c){a=t(B(b))?Zy(B(a),B(b)):B(a);return new R(null,2,5,T,[Lm,Ii(bg(function(){return function(a,b){return pe(new R(null,3,5,T,[Xy,b,c],null),new r(null,1,[mk,a],null))}}(a),a))],null)}var qA=new ti(null,new r(null,3,["small",null,"medium",null,"big",null],null),null); +function rA(a,b,c,d,e){var f=yp(function(){var a=B(c);return t(qA.h?qA.h(a):qA.call(null,a))?["font-",v.h(a)].join(""):null}),h=yp(function(){return function(){var d=B(a),e=B(b),f=B(c);f=t(qA.h?qA.h(f):qA.call(null,f))?null:new r(null,1,[wk,f],null);return hi.A(be([new r(null,2,[fl,[v.h(d),"ch"].join(""),no,[v.h(1.3333333333*e),"em"].join("")],null),f]))}}(f)),k=yp(function(){return function(){return Lu(B(d))}}(f,h)),l=yp(function(a,c,d){return function(){return xg(function(a,b,c){return function(d){return yp(function(a, +b,c){return function(){return D.c(B(c),d)}}(a,b,c))}}(a,c,d),Fi(0,B(b),1))}}(f,h,k)),p=yp(function(){return function(){return Mu(B(d))}}(f,h,k,l)),m=yp(function(a,b,c,d,e){return function(){return zn.h(B(e))}}(f,h,k,l,p)),u=yp(function(a,b,c,d,e){return function(){return Aj.h(B(e))}}(f,h,k,l,p,m)),w=yp(function(a,b,c,d,e){return function(){return On.h(B(e))}}(f,h,k,l,p,m,u));return function(a,b,c,d,f,h,k,l){return function(){return new R(null,3,5,T,[Gm,new r(null,2,[vn,B(a),fm,B(b)],null),bg(function(a, +b,c,d,f,h,k,l){return function(m,p){var u=yp(function(a,b,c,d,e,f,h,k){return function(){var a=B(k);return t(a)?(a=G.c(m,B(h)))?B(f):a:a}}(a,b,c,d,f,h,k,l));return pe(new R(null,4,5,T,[$y,p,u,e],null),new r(null,1,[mk,m],null))}}(a,b,c,d,f,h,k,l),B(d))],null)}}(f,h,k,l,p,m,u,w)} +function sA(){return new R(null,2,5,T,[Ym,new r(null,4,[Mn,"1.1",Fl,"0 0 866.0254037844387 866.0254037844387",vn,"icon",mo,new r(null,1,[An,'\x3cdefs\x3e \x3cmask id\x3d"small-triangle-mask"\x3e \x3crect width\x3d"100%" height\x3d"100%" fill\x3d"white"/\x3e \x3cpolygon points\x3d"508.01270189221935 433.01270189221935, 208.0127018922194 259.8076211353316, 208.01270189221927 606.217782649107" fill\x3d"black"\x3e\x3c/polygon\x3e \x3c/mask\x3e \x3c/defs\x3e \x3cpolygon points\x3d"808.0127018922194 433.01270189221935, 58.01270189221947 -1.1368683772161603e-13, 58.01270189221913 866.0254037844386" mask\x3d"url(#small-triangle-mask)" fill\x3d"white"\x3e\x3c/polygon\x3e \x3cpolyline points\x3d"481.2177826491071 333.0127018922194, 134.80762113533166 533.0127018922194" stroke\x3d"white" stroke-width\x3d"90"\x3e\x3c/polyline\x3e'],null)], +null)],null)}function tA(){return new R(null,3,5,T,[Ym,new r(null,3,[Mn,"1.1",Fl,"0 0 12 12",vn,"icon"],null),new R(null,2,5,T,[Fj,new r(null,1,[pn,"M1,0 L11,6 L1,12 Z"],null)],null)],null)}function uA(){return new R(null,4,5,T,[Ym,new r(null,3,[Mn,"1.1",Fl,"0 0 12 12",vn,"icon"],null),new R(null,2,5,T,[Fj,new r(null,1,[pn,"M1,0 L4,0 L4,12 L1,12 Z"],null)],null),new R(null,2,5,T,[Fj,new r(null,1,[pn,"M8,0 L11,0 L11,12 L8,12 Z"],null)],null)],null)} +function vA(){return new R(null,4,5,T,[Ym,new r(null,3,[Mn,"1.1",Fl,"0 0 12 12",vn,"icon"],null),new R(null,2,5,T,[Fj,new r(null,1,[pn,"M12,0 L7,0 L9,2 L7,4 L8,5 L10,3 L12,5 Z"],null)],null),new R(null,2,5,T,[Fj,new r(null,1,[pn,"M0,12 L0,7 L2,9 L4,7 L5,8 L3,10 L5,12 Z"],null)],null)],null)} +function wA(){return new R(null,4,5,T,[Ym,new r(null,3,[Mn,"1.1",Fl,"0 0 12 12",vn,"icon"],null),new R(null,2,5,T,[Fj,new r(null,1,[pn,"M7,5 L7,0 L9,2 L11,0 L12,1 L10,3 L12,5 Z"],null)],null),new R(null,2,5,T,[Fj,new r(null,1,[pn,"M5,7 L0,7 L2,9 L0,11 L1,12 L3,10 L5,12 Z"],null)],null)],null)}function xA(a,b){return function(b){return function(){return new R(null,3,5,T,[cl,new r(null,1,[Sl,b],null),new R(null,1,5,T,[t(B(a))?uA:tA],null)],null)}}(Ty(b,new fy(null,null,null)))} +function yA(a){return 10>a?["0",v.h(a)].join(""):a}function zA(a){var b=Math.floor((a%60+60)%60);return[v.h(yA(Math.floor(a/60))),":",v.h(yA(b))].join("")}function AA(a,b){var c=T,d=new R(null,2,5,T,[Yk,zA(B(a))],null),e=T;var f=B(a);var h=B(b);f=["-",v.h(zA(h-f))].join("");return new R(null,3,5,c,[Ml,d,new R(null,2,5,e,[co,f],null)],null)} +function BA(){function a(a){a.preventDefault();return Ry(a.currentTarget.parentNode.parentNode.parentNode)}return function(){return new R(null,4,5,T,[un,new r(null,1,[Sl,a],null),new R(null,1,5,T,[vA],null),new R(null,1,5,T,[wA],null)],null)}} +function CA(a,b){var c=Sy(b,function(a){var b=a.currentTarget.offsetWidth,c=a.currentTarget.getBoundingClientRect();return cy(Nu(a.clientX-c.left,b)/b)}),d=yp(function(){return function(){return[v.h(100*B(a)),"%"].join("")}}(c));return function(a,b){return function(){return new R(null,2,5,T,[Vj,new R(null,3,5,T,[Bl,new r(null,1,[Ql,a],null),new R(null,2,5,T,[Cj,new R(null,2,5,T,[ro,new r(null,1,[fm,new r(null,1,[fl,B(b)],null)],null)],null)],null)],null)],null)}}(c,d)} +function DA(a,b,c,d){return function(e){return function(){return new R(null,5,5,T,[Kk,new R(null,3,5,T,[xA,a,d],null),new R(null,3,5,T,[AA,b,c],null),new R(null,1,5,T,[BA],null),new R(null,3,5,T,[CA,e,d],null)],null)}}(yp(function(){return B(b)/B(c)}))} +function EA(a){return function(a){return function(){return new R(null,3,5,T,[ol,new r(null,1,[Sl,a],null),new R(null,2,5,T,[Xk,new R(null,2,5,T,[km,new R(null,2,5,T,[ro,new R(null,1,5,T,[sA],null)],null)],null)],null)],null)}}(Ty(a,new fy(null,null,null)))}function FA(){return new R(null,2,5,T,[Ek,new R(null,1,5,T,[xn],null)],null)}function GA(a){return Wf(function(b){return a[b]},new R(null,4,5,T,["altKey","shiftKey","metaKey","ctrlKey"],null))} +function HA(a){var b=t(GA(a))?null:function(){switch(a.key){case " ":return new fy(null,null,null);case "f":return bm;case "0":return cy(0);case "1":return cy(.1);case "2":return cy(.2);case "3":return cy(.3);case "4":return cy(.4);case "5":return cy(.5);case "6":return cy(.6);case "7":return cy(.7);case "8":return cy(.8);case "9":return cy(.9);default:return null}}();if(t(b))return b;switch(a.key){case "\x3e":return new ey(null,null,null);case "\x3c":return new dy(null,null,null);default:return null}} +function IA(a){if(t(GA(a)))return null;switch(a.which){case 37:return new ay(null,null,null);case 39:return new $x(null,null,null);default:return null}}function JA(a){var b=HA(a);return t(b)?(a.preventDefault(),G.c(b,bm)?(Ry(a.currentTarget),null):b):null}function KA(a){var b=IA(a);return t(b)?(a.preventDefault(),b):null} +function LA(a,b,c,d){a=t(a)?['"',v.h(a),'"'].join(""):"untitled";return new R(null,4,5,T,[dl,t(d)?new R(null,2,5,T,[jo,new r(null,1,[zl,d],null)],null):null,a,t(b)?new R(null,3,5,T,[ro," by ",t(c)?new R(null,3,5,T,[lo,new r(null,1,[ho,c],null),b],null):b],null):null],null)} +function MA(a){var b=Mx(1,ig.h(iy)),c=Kx(1);lx(function(c){return function(){var d=function(){return function(a){return function(){function b(b){for(;;){a:try{for(;;){var c=a(b);if(!N(c,Z)){var d=c;break a}}}catch(x){if(x instanceof Object)b[5]=x,Cx(b),d=Z;else throw x;}if(!N(d,Z))return d}}function c(){var a=[null,null,null,null,null,null,null,null,null,null,null,null];a[0]=d;a[1]=1;return a}var d=null;d=function(a){switch(arguments.length){case 0:return c.call(this);case 1:return b.call(this,a)}throw Error("Invalid arity: "+ +(arguments.length-1));};d.B=c;d.h=b;return d}()}(function(){return function(c){var d=c[1];if(7===d)return c[7]=c[2],Ax(c,12,b,!1);if(1===d)return c[2]=null,c[1]=2,Z;if(4===d)return c[8]=c[2],Ax(c,5,b,!0);if(6===d)return d=Jx(3E3),Ux(c,8,new R(null,2,5,T,[a,d],null));if(3===d)return Bx(c,c[2]);if(12===d)return c[9]=c[2],c[2]=null,c[1]=2,Z;if(2===d)return zx(c,4,a);if(11===d)return c[2]=c[2],c[1]=7,Z;if(9===d)return c[2]=null,c[1]=6,Z;if(5===d)return c[10]=c[2],c[2]=null,c[1]=6,Z;if(10===d)return c[2]= +null,c[1]=11,Z;if(8===d){var e=c[2];d=J(e,0,null);e=J(e,1,null);e=G.c(e,a);c[11]=d;c[1]=e?9:10;return Z}return null}}(c),c)}(),f=function(){var a=d.B?d.B():d.call(null);a[6]=c;return a}();return yx(f)}}(c));return b} +function NA(a,b){var c=dg.h(b),d=Kx(1);lx(function(b,c){return function(){var d=function(){return function(a){return function(){function b(b){for(;;){a:try{for(;;){var c=a(b);if(!N(c,Z)){var d=c;break a}}}catch(F){if(F instanceof Object)b[5]=F,Cx(b),d=Z;else throw F;}if(!N(d,Z))return d}}function c(){var a=[null,null,null,null,null,null,null,null,null,null,null,null,null];a[0]=d;a[1]=1;return a}var d=null;d=function(a){switch(arguments.length){case 0:return c.call(this);case 1:return b.call(this, +a)}throw Error("Invalid arity: "+(arguments.length-1));};d.B=c;d.h=b;return d}()}(function(b,c){return function(d){var e=d[1];if(7===e){var f=d[7],h=wb(null==f);d[8]=d[2];d[1]=h?8:9;return Z}if(20===e)return f=d[7],d[1]=t(q===f.Fe)?23:24,Z;if(27===e)return d[2]=!1,d[1]=28,Z;if(1===e)return d[2]=null,d[1]=2,Z;if(24===e)return f=d[7],d[1]=t(!f.Tc)?26:27,Z;if(4===e){f=d[7];var k=d[9];h=d[2];var l=J(h,0,null),m=J(h,1,null);d[10]=m;d[7]=l;d[9]=h;d[1]=t(null==l)?5:6;return Z}return 15===e?(d[2]=!1,d[1]= +16,Z):21===e?(f=d[7],h=Ab(Yx,f),d[2]=h,d[1]=22,Z):31===e?(d[11]=d[2],d[2]=null,d[1]=2,Z):13===e?(d[2]=d[2],d[1]=10,Z):22===e?(d[1]=t(d[2])?29:30,Z):29===e?(f=d[7],h=B(a),h=Zx(f,h),h=gg.l(c,wo,h),d[2]=h,d[1]=31,Z):6===e?(d[2]=null,d[1]=7,Z):28===e?(d[2]=d[2],d[1]=25,Z):25===e?(d[2]=d[2],d[1]=22,Z):17===e?(m=d[10],f=d[7],k=d[9],h=gg.c(a,function(){return function(a,b){return function(a){return Xx(b,a)}}(k,f,m,m,f,k,e,b,c)}()),d[2]=h,d[1]=19,Z):3===e?Bx(d,d[2]):12===e?(f=d[7],d[1]=t(!f.Tc)?14:15,Z): +2===e?(h=B(c),h=E(h),Ux(d,4,h)):23===e?(d[2]=!0,d[1]=25,Z):19===e?(f=d[7],h=wb(null==f),d[12]=d[2],d[1]=h?20:21,Z):11===e?(d[2]=!0,d[1]=13,Z):9===e?(f=d[7],h=Ab(Wx,f),d[2]=h,d[1]=10,Z):5===e?(m=d[10],h=gg.l(c,re,m),d[2]=h,d[1]=7,Z):14===e?(f=d[7],h=Ab(Wx,f),d[2]=h,d[1]=16,Z):26===e?(f=d[7],h=Ab(Yx,f),d[2]=h,d[1]=28,Z):16===e?(d[2]=d[2],d[1]=13,Z):30===e?(d[2]=null,d[1]=31,Z):10===e?(d[1]=t(d[2])?17:18,Z):18===e?(d[2]=null,d[1]=19,Z):8===e?(f=d[7],d[1]=t(q===f.sb)?11:12,Z):null}}(b,c),b,c)}(),e=function(){var a= +d.B?d.B():d.call(null);a[6]=b;return a}();return yx(e)}}(d,c));return d} +function OA(a,b,c){c=Ty(c,!0);var d=Sy(b,JA),e=Sy(b,KA),f=yp(function(){return function(){return Hm.h(B(a))}}(c,d,e)),h=yp(function(){return function(){return el.h(B(a))}}(c,d,e,f)),k=yp(function(a,b,c,d,e){return function(){var a=B(d);return t(a)?a:B(e)}}(c,d,e,f,h)),l=yp(function(b,c,d,e,f,h){return function(){var b=Gk.h(B(a));b=t(b)?b:wb(B(h));return t(b)?"hud":null}}(c,d,e,f,h,k)),p=yp(function(){return function(){return["asciinema-theme-",v.h(gm.h(B(a)))].join("")}}(c,d,e,f,h,k,l)),m=yp(function(){return function(){var b= +fl.h(B(a));return t(b)?b:80}}(c,d,e,f,h,k,l,p)),u=yp(function(){return function(){var b=no.h(B(a));return t(b)?b:24}}(c,d,e,f,h,k,l,p,m)),w=yp(function(){return function(){return wk.h(B(a))}}(c,d,e,f,h,k,l,p,m,u)),x=yp(function(){return function(){return V.h(B(a))}}(c,d,e,f,h,k,l,p,m,u,w)),C=yp(function(){return function(){return ml.h(B(a))}}(c,d,e,f,h,k,l,p,m,u,w,x)),F=yp(function(){return function(){return jn.h(B(a))}}(c,d,e,f,h,k,l,p,m,u,w,x,C)),I=yp(function(){return function(){return Uj.h(B(a))}}(c, +d,e,f,h,k,l,p,m,u,w,x,C,F)),M=yp(function(){return function(){return wl.h(B(a))}}(c,d,e,f,h,k,l,p,m,u,w,x,C,F,I)),S=B(a),X=null!=S&&(S.m&64||q===S.G)?P(U,S):S,Ga=D.c(X,ki),db=D.c(X,li),Q=D.c(X,mi),xb=D.c(X,ni);return function(a,c,d,e,f,h,k,l,m,p,u,w,x,C,F,I,M,S,Q,X,Ga,db){return function(){return new R(null,3,5,T,[Cn,new r(null,5,[Jj,-1,Zj,c,Rn,d,Vm,a,vn,B(k)],null),new R(null,7,5,T,[Sm,new r(null,1,[vn,B(l)],null),new R(null,6,5,T,[rA,m,p,u,w,x],null),new R(null,5,5,T,[DA,C,F,I,b],null),t(t(Q)?Q: +X)?new R(null,5,5,T,[LA,Q,X,Ga,db],null):null,t(B(h))?null:new R(null,2,5,T,[EA,b],null),t(B(e))?new R(null,1,5,T,[FA],null):null],null)],null)}}(c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X,Ga,db,Q,xb)} +function PA(a){var b=Kx(null),c=Kx(new dx(bx(1),1));return function(b,c){return function(){return Pp(new r(null,4,[ln,"asciinema-player",Dm,function(b,c){return function(){return OA(a,b,c)}}(b,c),$k,function(b,c){return function(){var d=ty(Gl.h(B(a))),e=MA(c);Tx(e,b);return NA(a,Je([b,d]))}}(b,c),Wm,function(){return function(){return uy(Gl.h(B(a)))}}(b,c)],null))}}(b,c)};function QA(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b,d=D.c(c,Ak),e=D.c(c,Gl);d=a.h?a.h(d):a.call(null,d);zy(e,d);return K.l(c,Ak,d)}$x.prototype.sb=q;$x.prototype.qb=function(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b,d=D.c(c,Uj),e=D.c(c,wl),f=D.c(c,Gl);t(e)&&yy(f,Nu(d+5,e));return c};ay.prototype.sb=q;ay.prototype.qb=function(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b,d=D.c(c,Uj),e=D.c(c,wl),f=D.c(c,Gl);t(e)&&yy(f,Nu(d+-5,e));return c};by.prototype.sb=q; +by.prototype.qb=function(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b,d=D.c(c,wl),e=D.c(c,Gl);t(d)&&(d*=nn.h(this),yy(e,d));return c};dy.prototype.sb=q;dy.prototype.qb=function(a,b){return QA(function(){return function(a){return a/2}}(this),b)};ey.prototype.sb=q;ey.prototype.qb=function(a,b){return QA(function(){return function(a){return 2*a}}(this),b)};fy.prototype.sb=q;fy.prototype.qb=function(a,b){xy(Gl.h(b));return b};gy.prototype.sb=q;gy.prototype.qb=function(a,b){return K.l(b,ml,so.h(this))}; +hy.prototype.sb=q;hy.prototype.qb=function(a,b){return K.l(b,Gk,so.h(this))};jy.prototype.sb=q;jy.prototype.qb=function(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a;D.c(c,fl);D.c(c,no);D.c(c,wl);c=null!=b&&(b.m&64||q===b.G)?P(U,b):b;var d=D.c(c,fl),e=D.c(c,no),f=null!=this&&(this.m&64||q===this.G)?P(U,this):this,h=D.c(f,fl),k=D.c(f,no);f=D.c(f,wl);return K.A(c,fl,t(d)?d:h,be([no,t(e)?e:k,wl,f]))};ky.prototype.sb=q;ky.prototype.qb=function(a,b){return K.l(b,Hm,Hm.h(this))};oy.prototype.sb=q; +oy.prototype.qb=function(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b,d=D.c(c,oi);t(d)&&(ap(bp),d.B?d.B():d.call(null));return c};ry.prototype.sb=q;ry.prototype.qb=function(a,b){return K.l(b,Uj,Zk.h(this))};function RA(){return ig.l(function(a,b){return new R(null,2,5,T,[a,new gy(b,null,null,null)],null)},rg(function(a){return a+.5},.5),og(new R(null,2,5,T,[!1,!0],null)))}function SA(a){var b=Dy(RA());return K.l(K.l(a,ml,!0),Ol,b)} +function TA(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,Ol);Tw(b);return K.l(K.l(a,ml,!0),Ol,null)}function UA(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;a=D.c(a,Ol);return t(a)?Je([a]):vi}my.prototype.sb=q; +my.prototype.qb=function(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a;D.c(c,jn);var d=null!=b&&(b.m&64||q===b.G)?P(U,b):b,e=D.c(d,jn);c=D.c(d,pi);var f=D.c(d,qi),h=null!=this&&(this.m&64||q===this.G)?P(U,this):this;h=D.c(h,jn);if(G.c(e,h))return d;d=K.A(d,jn,h,be([el,!0]));if(t(h))return t(c)&&(c.B?c.B():c.call(null)),SA(d);t(f)&&(f.B?f.B():f.call(null));return TA(d)};my.prototype.Fe=q;my.prototype.de=function(a,b){return UA(b)};py.prototype.sb=q; +py.prototype.qb=function(a,b){var c=K.l(b,V,V.h(this));c=null!=c&&(c.m&64||q===c.G)?P(U,c):c;var d=D.c(c,Ol);return t(d)?SA(TA(c)):c};py.prototype.Fe=q;py.prototype.de=function(a,b){return UA(b)};function VA(a){return t(a)?(a=ig.c(parseFloat,Fo(""+v.h(a),/:/)),a=ig.l(Ye,cf(a),rg(function(){return function(a){return 60*a}}(a),1)),P(Xe,a)):null} +function WA(a,b,c){t(a)?"string"===typeof a?t(0===a.indexOf("data:application/json;base64,"))?(b=a.substring(29).replace(RegExp("\\s","g"),""),b=JSON.parse(atob(b)),b=fj(b),b=new r(null,1,[V,new r(null,1,[il,b],null)],null)):t(0===a.indexOf("data:text/plain,"))?(a=a.substring(16),b=Ju(Ot(t(b)?b:80,t(c)?c:24),a),b=new r(null,1,[V,b],null)):b=t(0===a.indexOf("npt:"))?new r(null,1,[Zk,VA(a.substring(4))],null):null:b=new r(null,1,[V,new r(null,1,[il,a],null)],null):b=null;return b} +var XA=new r(null,2,[pl,new r(null,1,[On,!1],null),il,he],null); +function YA(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b,d=D.c(c,no),e=D.l(c,wk,"small"),f=D.l(c,Ak,1),h=D.c(c,Hk),k=D.c(c,fl),l=D.c(c,rl),p=D.l(c,cm,!1),m=D.l(c,gm,"asciinema"),u=D.c(c,qm),w=D.c(c,Bm),x=D.l(c,vm,!1),C=D.l(c,Em,!1),F=function(){var a=VA(h);return t(a)?a:0}();w=WA(w,k,d);var I=null!=w&&(w.m&64||q===w.G)?P(U,w):w;w=D.c(I,V);I=D.c(I,Zk);var M=t(I)?I:wb(w)&&0<F?F:null;I=function(){var b=Pe([Ak,Hk,fl,rl,cm,qm,vm,Em,Mm,no],[f,F,k,l,p,u,x,C,M,d]);return xj.c?xj.c(a,b):xj.call(null,a,b)}(); +return hi.A(be([Pe([Uj,V,wk,Ak,Gk,el,fl,wl,Gl,Ol,gm,Hm,jn,no],[F,t(w)?w:XA,e,f,!1,!1,k,null,I,null,m,!1,!1,d]),ji(c)]))}function ZA(a,b,c){a="string"===typeof a?document.getElementById(a):a;b=tp.h(P(YA,be([b,c])));c=new R(null,2,5,T,[PA,b],null);qq?oq(c,a,null):pq.call(null,c,a);return b} +ib=function(){function a(a){var c=null;if(0<arguments.length){c=0;for(var e=Array(arguments.length-0);c<e.length;)e[c]=arguments[c+0],++c;c=new Jb(e,0,null)}return b.call(this,c)}function b(a){return console.log.apply(console,Lb(a))}a.L=0;a.N=function(a){a=E(a);return b(a)};a.A=b;return a}(); +kb=function(){function a(a){var c=null;if(0<arguments.length){c=0;for(var e=Array(arguments.length-0);c<e.length;)e[c]=arguments[c+0],++c;c=new Jb(e,0,null)}return b.call(this,c)}function b(a){return console.error.apply(console,Lb(a))}a.L=0;a.N=function(a){a=E(a);return b(a)};a.A=b;return a}();var $A=function $A(a){switch(arguments.length){case 2:return $A.c(arguments[0],arguments[1]);case 3:return $A.l(arguments[0],arguments[1],arguments[2]);default:throw Error(["Invalid arity: ",v.h(arguments.length)].join(""));}};da("asciinema.player.js.CreatePlayer",$A);$A.c=function(a,b){return $A.l(a,b,Ef)}; +$A.l=function(a,b,c){b=fj(b);c=yo(fj(c));a=ZA(a,b,c);return cj(new r(null,5,[En,function(a,b,c){return function(){return Uj.h(B(c))}}(b,c,a),Bj,function(a,b,c){return function(a){var b=B(c);b=null!=b&&(b.m&64||q===b.G)?P(U,b):b;D.c(b,wl);b=D.c(b,Gl);return yy(b,a)}}(b,c,a),Zm,function(a,b,c){return function(){return wl.h(B(c))}}(b,c,a),Jn,function(a,b,c){return function(){var a=B(c);a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;a=D.c(a,Gl);return vy(a)}}(b,c,a),sn,function(a,b,c){return function(){var a= +B(c);a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;a=D.c(a,Gl);return wy(a)}}(b,c,a)],null))};$A.L=3;da("asciinema.player.js.UnmountPlayer",function(a){a="string"===typeof a?document.getElementById(a):a;gg.l(lq,le,a);return kq().unmountComponentAtNode(a)});registerAsciinemaPlayerElement(); +})(); + +//# sourceMappingURL=asciinema-player.js.map + diff --git a/refs/pull/405/merge/_static/basic.css b/refs/pull/405/merge/_static/basic.css new file mode 100644 index 00000000..607b5f55 --- /dev/null +++ b/refs/pull/405/merge/_static/basic.css @@ -0,0 +1,648 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + width: 170px; +} + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +div.code-block-caption { + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +div.code-block-caption + div > div.highlight > pre { + margin-top: 0; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + padding: 1em 1em 0; +} + +div.literal-block-wrapper div.highlight { + margin: 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: relative; + left: 0px; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/refs/pull/405/merge/_static/comment-bright.png b/refs/pull/405/merge/_static/comment-bright.png new file mode 100644 index 00000000..15e27edb Binary files /dev/null and b/refs/pull/405/merge/_static/comment-bright.png differ diff --git a/refs/pull/405/merge/_static/comment-close.png b/refs/pull/405/merge/_static/comment-close.png new file mode 100644 index 00000000..4d91bcf5 Binary files /dev/null and b/refs/pull/405/merge/_static/comment-close.png differ diff --git a/refs/pull/405/merge/_static/comment.png b/refs/pull/405/merge/_static/comment.png new file mode 100644 index 00000000..dfbc0cbd Binary files /dev/null and b/refs/pull/405/merge/_static/comment.png differ diff --git a/refs/pull/405/merge/_static/common.js b/refs/pull/405/merge/_static/common.js new file mode 100644 index 00000000..9ec85fa9 --- /dev/null +++ b/refs/pull/405/merge/_static/common.js @@ -0,0 +1,129 @@ +var PERMANENT_URL_PREFIX = DOCUMENTATION_OPTIONS.URL_ROOT + '_static/'; + +var SLIDE_CLASSES = ['far-past', 'past', 'current', 'next', 'far-next']; +var SLIDES_SELECTOR = 'section.slides > article'; + +var PM_TOUCH_SENSITIVITY = 15; +var TABLE_CLASS = 'table'; + +/* ---------------------------------------------------------------------- */ +/* classList polyfill by Eli Grey + * (http://purl.eligrey.com/github/classList.js/blob/master/classList.js) */ + +if (typeof document !== "undefined" && !("classList" in document.createElement("a"))) { + +(function (view) { + +var + classListProp = "classList" + , protoProp = "prototype" + , elemCtrProto = (view.HTMLElement || view.Element)[protoProp] + , objCtr = Object + strTrim = String[protoProp].trim || function () { + return this.replace(/^\s+|\s+$/g, ""); + } + , arrIndexOf = Array[protoProp].indexOf || function (item) { + for (var i = 0, len = this.length; i < len; i++) { + if (i in this && this[i] === item) { + return i; + } + } + return -1; + } + // Vendors: please allow content code to instantiate DOMExceptions + , DOMEx = function (type, message) { + this.name = type; + this.code = DOMException[type]; + this.message = message; + } + , checkTokenAndGetIndex = function (classList, token) { + if (token === "") { + throw new DOMEx( + "SYNTAX_ERR" + , "An invalid or illegal string was specified" + ); + } + if (/\s/.test(token)) { + throw new DOMEx( + "INVALID_CHARACTER_ERR" + , "String contains an invalid character" + ); + } + return arrIndexOf.call(classList, token); + } + , ClassList = function (elem) { + var + trimmedClasses = strTrim.call(elem.className) + , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : [] + ; + for (var i = 0, len = classes.length; i < len; i++) { + this.push(classes[i]); + } + this._updateClassName = function () { + elem.className = this.toString(); + }; + } + , classListProto = ClassList[protoProp] = [] + , classListGetter = function () { + return new ClassList(this); + } +; +// Most DOMException implementations don't allow calling DOMException's toString() +// on non-DOMExceptions. Error's toString() is sufficient here. +DOMEx[protoProp] = Error[protoProp]; +classListProto.item = function (i) { + return this[i] || null; +}; +classListProto.contains = function (token) { + token += ""; + return checkTokenAndGetIndex(this, token) !== -1; +}; +classListProto.add = function (token) { + token += ""; + if (checkTokenAndGetIndex(this, token) === -1) { + this.push(token); + this._updateClassName(); + } +}; +classListProto.remove = function (token) { + token += ""; + var index = checkTokenAndGetIndex(this, token); + if (index !== -1) { + this.splice(index, 1); + this._updateClassName(); + } +}; +classListProto.toggle = function (token) { + token += ""; + if (checkTokenAndGetIndex(this, token) === -1) { + this.add(token); + } else { + this.remove(token); + } +}; +classListProto.toString = function () { + return this.join(" "); +}; + +if (objCtr.defineProperty) { + var classListPropDesc = { + get: classListGetter + , enumerable: true + , configurable: true + }; + try { + objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); + } catch (ex) { // IE 8 doesn't support enumerable:true + if (ex.number === -0x7FF5EC54) { + classListPropDesc.enumerable = false; + objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); + } + } +} else if (objCtr[protoProp].__defineGetter__) { + elemCtrProto.__defineGetter__(classListProp, classListGetter); +} + +}(self)); + +} +/* ---------------------------------------------------------------------- */ diff --git a/refs/pull/405/merge/_static/console.css b/refs/pull/405/merge/_static/console.css new file mode 100644 index 00000000..32730124 --- /dev/null +++ b/refs/pull/405/merge/_static/console.css @@ -0,0 +1,64 @@ +#controls { + text-align: center; + width: 100%; + margin: 10px; + font-size: 1.5em; + font-family: sans-serif; +} + +.slides.table > article { + display: inline-block; +} + +article.placeholder { + background: #ddd; +} + +.slides.table > article { + position: absolute; + left: 50%; + margin-left: -225px; +} + +.slides.table > article.past { + transform: translate(-325px); + -o-transform: translate(-325px); + -moz-transform: translate(-325px); + -webkit-transform: translate3d(-325px, 0, 0); + +} + +.slides.table > article.next { + transform: translate(475px); + -o-transform: translate(475px); + -moz-transform: translate(475px); + -webkit-transform: translate3d(475px, 0, 0); +} + +.slides > article.past, +.slides > article.next { + height: 230px; + width: 300px; + + margin-top: 60px; +} + +div.presenter_notes { + position: absolute; + top: 420px; + left: 10%; + background-color: white; + color: black; + padding: 1em; + width: 80%; + font-size: 130%; + + border-radius: 10px; + -o-border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; +} + +div.presenter_notes p.admonition-title { + display: none; +} \ No newline at end of file diff --git a/refs/pull/405/merge/_static/console.js b/refs/pull/405/merge/_static/console.js new file mode 100644 index 00000000..583b9a5b --- /dev/null +++ b/refs/pull/405/merge/_static/console.js @@ -0,0 +1,91 @@ +document.addEventListener('DOMContentLoaded', function() { + + var + + handleKey = function(event) { + switch (event.keyCode) { + case 39: // right arrow + case 13: // Enter + case 32: // space + case 34: // PgDn + nextSlide(); + event.preventDefault(); + break; + + case 37: // left arrow + case 8: // Backspace + case 33: // PgUp + prevSlide(); + event.preventDefault(); + break; + } + }, + + handleUpdateSlides = function(slide_index, prev_slide, cur_slide, next_slide) { + document.querySelector('#cur_slide_num').innerHTML = Number(slide_index) + 1; + + // make sure we have a previous and next slide to show; + // if not add dummy placeholders + if (!prev_slide) { + prev_slide = '<article class="past placeholder"></article>'; + } + if (!next_slide) { + next_slide = '<article class="next placeholder"></article>'; + } + + document.querySelector('#slide_container').innerHTML = prev_slide + cur_slide + next_slide; + + // Copy the presenter notes into place + $('#presenter_notes').empty(); + $('article.current').find('div.admonition.note').each( + function(i, node) { + $('#presenter_notes').append($(node).html()); + } + ); + + var slides = document.querySelector('section.slides > article'); + for (var i=0; i < slides.length; i++) { + + } + }, + + handleMessage = function(e) { + switch (e.data.command) { + case 'num_slides': + document.querySelector('#num_slides').innerHTML = e.data.content; + break; + case 'cur_slide': + handleUpdateSlides(e.data.content, e.data.prev_slide, e.data.slide, e.data.next_slide); + break; + } + }, + + nextSlide = function(e) { + if (e) { + e.preventDefault(); + } + window.opener.postMessage({command: 'nextSlide'}, '*'); + }, + + prevSlide = function(e) { + if (e) { + e.preventDefault(); + } + + window.opener.postMessage({command: 'prevSlide'}, '*'); + }, + + init = function(e) { + window.addEventListener('message', handleMessage, false); + document.addEventListener('keydown', handleKey, false); + + document.querySelector('#next').addEventListener('click', nextSlide); + document.querySelector('#prev').addEventListener('click', prevSlide); + + window.opener.postMessage({command: 'register'}, '*'); + + }; + + init(); + + }, false); diff --git a/refs/pull/405/merge/_static/controller.js b/refs/pull/405/merge/_static/controller.js new file mode 100644 index 00000000..e5fda6b9 --- /dev/null +++ b/refs/pull/405/merge/_static/controller.js @@ -0,0 +1,57 @@ +var SlideController = ( + function(){ + + var + slidedeck, + + onKeyDown = function (event) { + + switch (event.keyCode) { + case 39: // right arrow + case 13: // Enter + case 32: // space + case 34: // PgDn + slidedeck.nextSlide(); + event.preventDefault(); + break; + + case 37: // left arrow + case 8: // Backspace + case 33: // PgUp + slidedeck.prevSlide(); + event.preventDefault(); + break; + + case 40: // down arrow + if (isChromeVoxActive()) { + slidedeck.speakNextItem(); + } else { + slidedeck.nextSlide(); + } + event.preventDefault(); + break; + + case 38: // up arrow + if (isChromeVoxActive()) { + slidedeck.speakPrevItem(); + } else { + slidedeck.prevSlide(); + } + event.preventDefault(); + break; + + } + }; + + init = function(slides) { + slidedeck = slides; + + document.addEventListener('keydown', onKeyDown, false); + + }; + + return { + init: init + }; + + }()); diff --git a/refs/pull/405/merge/_static/css/badge_only.css b/refs/pull/405/merge/_static/css/badge_only.css new file mode 100644 index 00000000..c718cee4 --- /dev/null +++ b/refs/pull/405/merge/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/refs/pull/405/merge/_static/css/fonts/Roboto-Slab-Bold.woff b/refs/pull/405/merge/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 00000000..6cb60000 Binary files /dev/null and b/refs/pull/405/merge/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/refs/pull/405/merge/_static/css/fonts/Roboto-Slab-Bold.woff2 b/refs/pull/405/merge/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 00000000..7059e231 Binary files /dev/null and b/refs/pull/405/merge/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/refs/pull/405/merge/_static/css/fonts/Roboto-Slab-Regular.woff b/refs/pull/405/merge/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 00000000..f815f63f Binary files /dev/null and b/refs/pull/405/merge/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/refs/pull/405/merge/_static/css/fonts/Roboto-Slab-Regular.woff2 b/refs/pull/405/merge/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 00000000..f2c76e5b Binary files /dev/null and b/refs/pull/405/merge/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/refs/pull/405/merge/_static/css/fonts/fontawesome-webfont.eot b/refs/pull/405/merge/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 00000000..e9f60ca9 Binary files /dev/null and b/refs/pull/405/merge/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/refs/pull/405/merge/_static/css/fonts/fontawesome-webfont.svg b/refs/pull/405/merge/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 00000000..855c845e --- /dev/null +++ b/refs/pull/405/merge/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg> +<metadata> +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. +</metadata> +<defs> +<font id="FontAwesome" horiz-adv-x="1536" > + <font-face + font-family="FontAwesome" + font-weight="400" + font-stretch="normal" + units-per-em="1792" + panose-1="0 0 0 0 0 0 0 0 0 0" + ascent="1536" + descent="-256" + bbox="-1.02083 -256.962 2304.6 1537.02" + underline-thickness="0" + underline-position="0" + unicode-range="U+0020-F500" + /> +<missing-glyph horiz-adv-x="896" +d="M224 112h448v1312h-448v-1312zM112 0v1536h672v-1536h-672z" /> + <glyph glyph-name=".notdef" horiz-adv-x="896" +d="M224 112h448v1312h-448v-1312zM112 0v1536h672v-1536h-672z" /> + <glyph glyph-name=".null" horiz-adv-x="0" + /> + <glyph glyph-name="nonmarkingreturn" horiz-adv-x="597" + /> + <glyph glyph-name="space" unicode=" " horiz-adv-x="448" + /> + <glyph glyph-name="dieresis" unicode="¨" horiz-adv-x="1792" + /> + <glyph glyph-name="copyright" unicode="©" horiz-adv-x="1792" + /> + <glyph glyph-name="registered" unicode="®" horiz-adv-x="1792" + /> + <glyph glyph-name="acute" unicode="´" horiz-adv-x="1792" + /> + <glyph glyph-name="AE" unicode="Æ" horiz-adv-x="1792" + /> + <glyph glyph-name="Oslash" unicode="Ø" horiz-adv-x="1792" + /> + <glyph glyph-name="trademark" unicode="™" horiz-adv-x="1792" + /> + <glyph glyph-name="infinity" unicode="∞" horiz-adv-x="1792" + /> + <glyph glyph-name="notequal" unicode="≠" horiz-adv-x="1792" + /> + <glyph glyph-name="glass" unicode="" horiz-adv-x="1792" +d="M1699 1350q0 -35 -43 -78l-632 -632v-768h320q26 0 45 -19t19 -45t-19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45t45 19h320v768l-632 632q-43 43 -43 78q0 23 18 36.5t38 17.5t43 4h1408q23 0 43 -4t38 -17.5t18 -36.5z" /> + <glyph glyph-name="music" unicode="" +d="M1536 1312v-1120q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v537l-768 -237v-709q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89 +t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v967q0 31 19 56.5t49 35.5l832 256q12 4 28 4q40 0 68 -28t28 -68z" /> + <glyph glyph-name="search" unicode="" horiz-adv-x="1664" +d="M1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -52 -38 -90t-90 -38q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5 +t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" /> + <glyph glyph-name="envelope" unicode="" horiz-adv-x="1792" +d="M1664 32v768q-32 -36 -69 -66q-268 -206 -426 -338q-51 -43 -83 -67t-86.5 -48.5t-102.5 -24.5h-1h-1q-48 0 -102.5 24.5t-86.5 48.5t-83 67q-158 132 -426 338q-37 30 -69 66v-768q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1664 1083v11v13.5t-0.5 13 +t-3 12.5t-5.5 9t-9 7.5t-14 2.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5q0 -168 147 -284q193 -152 401 -317q6 -5 35 -29.5t46 -37.5t44.5 -31.5t50.5 -27.5t43 -9h1h1q20 0 43 9t50.5 27.5t44.5 31.5t46 37.5t35 29.5q208 165 401 317q54 43 100.5 115.5t46.5 131.5z +M1792 1120v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" /> + <glyph glyph-name="heart" unicode="" horiz-adv-x="1792" +d="M896 -128q-26 0 -44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124t127 -344q0 -221 -229 -450l-623 -600 +q-18 -18 -44 -18z" /> + <glyph glyph-name="star" unicode="" horiz-adv-x="1664" +d="M1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -21 -10.5 -35.5t-30.5 -14.5q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455 +l502 -73q56 -9 56 -46z" /> + <glyph glyph-name="star_empty" unicode="" horiz-adv-x="1664" +d="M1137 532l306 297l-422 62l-189 382l-189 -382l-422 -62l306 -297l-73 -421l378 199l377 -199zM1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -50 -41 -50q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500 +l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455l502 -73q56 -9 56 -46z" /> + <glyph glyph-name="user" unicode="" horiz-adv-x="1280" +d="M1280 137q0 -109 -62.5 -187t-150.5 -78h-854q-88 0 -150.5 78t-62.5 187q0 85 8.5 160.5t31.5 152t58.5 131t94 89t134.5 34.5q131 -128 313 -128t313 128q76 0 134.5 -34.5t94 -89t58.5 -131t31.5 -152t8.5 -160.5zM1024 1024q0 -159 -112.5 -271.5t-271.5 -112.5 +t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" /> + <glyph glyph-name="film" unicode="" horiz-adv-x="1920" +d="M384 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 320v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 704v128q0 26 -19 45t-45 19h-128 +q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 -64v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM384 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45 +t45 -19h128q26 0 45 19t19 45zM1792 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 704v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1792 320v128 +q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 704v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19 +t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1920 1248v-1344q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1344q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" /> + <glyph glyph-name="th_large" unicode="" horiz-adv-x="1664" +d="M768 512v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM768 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 512v-384q0 -52 -38 -90t-90 -38 +h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" /> + <glyph glyph-name="th" unicode="" horiz-adv-x="1792" +d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 288v-192q0 -40 -28 -68t-68 -28h-320 +q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 +h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192 +q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68z" /> + <glyph glyph-name="th_list" unicode="" horiz-adv-x="1792" +d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-960 +q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 +h960q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68z" /> + <glyph glyph-name="ok" unicode="" horiz-adv-x="1792" +d="M1671 970q0 -40 -28 -68l-724 -724l-136 -136q-28 -28 -68 -28t-68 28l-136 136l-362 362q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -295l656 657q28 28 68 28t68 -28l136 -136q28 -28 28 -68z" /> + <glyph glyph-name="remove" unicode="" horiz-adv-x="1408" +d="M1298 214q0 -40 -28 -68l-136 -136q-28 -28 -68 -28t-68 28l-294 294l-294 -294q-28 -28 -68 -28t-68 28l-136 136q-28 28 -28 68t28 68l294 294l-294 294q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -294l294 294q28 28 68 28t68 -28l136 -136q28 -28 28 -68 +t-28 -68l-294 -294l294 -294q28 -28 28 -68z" /> + <glyph glyph-name="zoom_in" unicode="" horiz-adv-x="1664" +d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-224q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v224h-224q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h224v224q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5v-224h224 +q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5 +t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" /> + <glyph glyph-name="zoom_out" unicode="" horiz-adv-x="1664" +d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-576q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h576q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5z +M1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z +" /> + <glyph glyph-name="off" unicode="" +d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61t-298 61t-245 164t-164 245t-61 298q0 182 80.5 343t226.5 270q43 32 95.5 25t83.5 -50q32 -42 24.5 -94.5t-49.5 -84.5q-98 -74 -151.5 -181t-53.5 -228q0 -104 40.5 -198.5t109.5 -163.5t163.5 -109.5 +t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5q0 121 -53.5 228t-151.5 181q-42 32 -49.5 84.5t24.5 94.5q31 43 84 50t95 -25q146 -109 226.5 -270t80.5 -343zM896 1408v-640q0 -52 -38 -90t-90 -38t-90 38t-38 90v640q0 52 38 90t90 38t90 -38t38 -90z" /> + <glyph glyph-name="signal" unicode="" horiz-adv-x="1792" +d="M256 96v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 224v-320q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 480v-576q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 +v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1408 864v-960q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1376v-1472q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1472q0 14 9 23t23 9h192q14 0 23 -9t9 -23z" /> + <glyph glyph-name="cog" unicode="" +d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1536 749v-222q0 -12 -8 -23t-20 -13l-185 -28q-19 -54 -39 -91q35 -50 107 -138q10 -12 10 -25t-9 -23q-27 -37 -99 -108t-94 -71q-12 0 -26 9l-138 108q-44 -23 -91 -38 +q-16 -136 -29 -186q-7 -28 -36 -28h-222q-14 0 -24.5 8.5t-11.5 21.5l-28 184q-49 16 -90 37l-141 -107q-10 -9 -25 -9q-14 0 -25 11q-126 114 -165 168q-7 10 -7 23q0 12 8 23q15 21 51 66.5t54 70.5q-27 50 -41 99l-183 27q-13 2 -21 12.5t-8 23.5v222q0 12 8 23t19 13 +l186 28q14 46 39 92q-40 57 -107 138q-10 12 -10 24q0 10 9 23q26 36 98.5 107.5t94.5 71.5q13 0 26 -10l138 -107q44 23 91 38q16 136 29 186q7 28 36 28h222q14 0 24.5 -8.5t11.5 -21.5l28 -184q49 -16 90 -37l142 107q9 9 24 9q13 0 25 -10q129 -119 165 -170q7 -8 7 -22 +q0 -12 -8 -23q-15 -21 -51 -66.5t-54 -70.5q26 -50 41 -98l183 -28q13 -2 21 -12.5t8 -23.5z" /> + <glyph glyph-name="trash" unicode="" horiz-adv-x="1408" +d="M512 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM768 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1024 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576 +q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1152 76v948h-896v-948q0 -22 7 -40.5t14.5 -27t10.5 -8.5h832q3 0 10.5 8.5t14.5 27t7 40.5zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832 +q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" /> + <glyph glyph-name="home" unicode="" horiz-adv-x="1664" +d="M1408 544v-480q0 -26 -19 -45t-45 -19h-384v384h-256v-384h-384q-26 0 -45 19t-19 45v480q0 1 0.5 3t0.5 3l575 474l575 -474q1 -2 1 -6zM1631 613l-62 -74q-8 -9 -21 -11h-3q-13 0 -21 7l-692 577l-692 -577q-12 -8 -24 -7q-13 2 -21 11l-62 74q-8 10 -7 23.5t11 21.5 +l719 599q32 26 76 26t76 -26l244 -204v195q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-408l219 -182q10 -8 11 -21.5t-7 -23.5z" /> + <glyph glyph-name="file_alt" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +" /> + <glyph glyph-name="time" unicode="" +d="M896 992v-448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 +q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="road" unicode="" horiz-adv-x="1920" +d="M1111 540v4l-24 320q-1 13 -11 22.5t-23 9.5h-186q-13 0 -23 -9.5t-11 -22.5l-24 -320v-4q-1 -12 8 -20t21 -8h244q12 0 21 8t8 20zM1870 73q0 -73 -46 -73h-704q13 0 22 9.5t8 22.5l-20 256q-1 13 -11 22.5t-23 9.5h-272q-13 0 -23 -9.5t-11 -22.5l-20 -256 +q-1 -13 8 -22.5t22 -9.5h-704q-46 0 -46 73q0 54 26 116l417 1044q8 19 26 33t38 14h339q-13 0 -23 -9.5t-11 -22.5l-15 -192q-1 -14 8 -23t22 -9h166q13 0 22 9t8 23l-15 192q-1 13 -11 22.5t-23 9.5h339q20 0 38 -14t26 -33l417 -1044q26 -62 26 -116z" /> + <glyph glyph-name="download_alt" unicode="" horiz-adv-x="1664" +d="M1280 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 416v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h465l135 -136 +q58 -56 136 -56t136 56l136 136h464q40 0 68 -28t28 -68zM1339 985q17 -41 -14 -70l-448 -448q-18 -19 -45 -19t-45 19l-448 448q-31 29 -14 70q17 39 59 39h256v448q0 26 19 45t45 19h256q26 0 45 -19t19 -45v-448h256q42 0 59 -39z" /> + <glyph glyph-name="download" unicode="" +d="M1120 608q0 -12 -10 -24l-319 -319q-11 -9 -23 -9t-23 9l-320 320q-15 16 -7 35q8 20 30 20h192v352q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-352h192q14 0 23 -9t9 -23zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273 +t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="upload" unicode="" +d="M1118 660q-8 -20 -30 -20h-192v-352q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v352h-192q-14 0 -23 9t-9 23q0 12 10 24l319 319q11 9 23 9t23 -9l320 -320q15 -16 7 -35zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198 +t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="inbox" unicode="" +d="M1023 576h316q-1 3 -2.5 8.5t-2.5 7.5l-212 496h-708l-212 -496q-1 -3 -2.5 -8.5t-2.5 -7.5h316l95 -192h320zM1536 546v-482q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v482q0 62 25 123l238 552q10 25 36.5 42t52.5 17h832q26 0 52.5 -17t36.5 -42l238 -552 +q25 -61 25 -123z" /> + <glyph glyph-name="play_circle" unicode="" +d="M1184 640q0 -37 -32 -55l-544 -320q-15 -9 -32 -9q-16 0 -32 8q-32 19 -32 56v640q0 37 32 56q33 18 64 -1l544 -320q32 -18 32 -55zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 +q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="repeat" unicode="" +d="M1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l138 138q-148 137 -349 137q-104 0 -198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5q119 0 225 52t179 147q7 10 23 12q15 0 25 -9 +l137 -138q9 -8 9.5 -20.5t-7.5 -22.5q-109 -132 -264 -204.5t-327 -72.5q-156 0 -298 61t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q147 0 284.5 -55.5t244.5 -156.5l130 129q29 31 70 14q39 -17 39 -59z" /> + <glyph glyph-name="refresh" unicode="" +d="M1511 480q0 -5 -1 -7q-64 -268 -268 -434.5t-478 -166.5q-146 0 -282.5 55t-243.5 157l-129 -129q-19 -19 -45 -19t-45 19t-19 45v448q0 26 19 45t45 19h448q26 0 45 -19t19 -45t-19 -45l-137 -137q71 -66 161 -102t187 -36q134 0 250 65t186 179q11 17 53 117 +q8 23 30 23h192q13 0 22.5 -9.5t9.5 -22.5zM1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-26 0 -45 19t-19 45t19 45l138 138q-148 137 -349 137q-134 0 -250 -65t-186 -179q-11 -17 -53 -117q-8 -23 -30 -23h-199q-13 0 -22.5 9.5t-9.5 22.5v7q65 268 270 434.5t480 166.5 +q146 0 284 -55.5t245 -156.5l130 129q19 19 45 19t45 -19t19 -45z" /> + <glyph glyph-name="list_alt" unicode="" horiz-adv-x="1792" +d="M384 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M384 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1536 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5z +M1536 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5zM1536 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5 +t9.5 -22.5zM1664 160v832q0 13 -9.5 22.5t-22.5 9.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 1248v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47 +t47 -113z" /> + <glyph glyph-name="lock" unicode="" horiz-adv-x="1152" +d="M320 768h512v192q0 106 -75 181t-181 75t-181 -75t-75 -181v-192zM1152 672v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v192q0 184 132 316t316 132t316 -132t132 -316v-192h32q40 0 68 -28t28 -68z" /> + <glyph glyph-name="flag" unicode="" horiz-adv-x="1792" +d="M320 1280q0 -72 -64 -110v-1266q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v1266q-64 38 -64 110q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -25 -12.5 -38.5t-39.5 -27.5q-215 -116 -369 -116q-61 0 -123.5 22t-108.5 48 +t-115.5 48t-142.5 22q-192 0 -464 -146q-17 -9 -33 -9q-26 0 -45 19t-19 45v742q0 32 31 55q21 14 79 43q236 120 421 120q107 0 200 -29t219 -88q38 -19 88 -19q54 0 117.5 21t110 47t88 47t54.5 21q26 0 45 -19t19 -45z" /> + <glyph glyph-name="headphones" unicode="" horiz-adv-x="1664" +d="M1664 650q0 -166 -60 -314l-20 -49l-185 -33q-22 -83 -90.5 -136.5t-156.5 -53.5v-32q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-32q71 0 130 -35.5t93 -95.5l68 12q29 95 29 193q0 148 -88 279t-236.5 209t-315.5 78 +t-315.5 -78t-236.5 -209t-88 -279q0 -98 29 -193l68 -12q34 60 93 95.5t130 35.5v32q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v32q-88 0 -156.5 53.5t-90.5 136.5l-185 33l-20 49q-60 148 -60 314q0 151 67 291t179 242.5 +t266 163.5t320 61t320 -61t266 -163.5t179 -242.5t67 -291z" /> + <glyph glyph-name="volume_off" unicode="" horiz-adv-x="768" +d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45z" /> + <glyph glyph-name="volume_down" unicode="" horiz-adv-x="1152" +d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 36 +t12 56.5t-12 56.5t-29 36t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142z" /> + <glyph glyph-name="volume_up" unicode="" horiz-adv-x="1664" +d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 36 +t12 56.5t-12 56.5t-29 36t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142zM1408 640q0 -153 -85 -282.5t-225 -188.5q-13 -5 -25 -5q-27 0 -46 19t-19 45q0 39 39 59q56 29 76 44q74 54 115.5 135.5t41.5 173.5t-41.5 173.5 +t-115.5 135.5q-20 15 -76 44q-39 20 -39 59q0 26 19 45t45 19q13 0 26 -5q140 -59 225 -188.5t85 -282.5zM1664 640q0 -230 -127 -422.5t-338 -283.5q-13 -5 -26 -5q-26 0 -45 19t-19 45q0 36 39 59q7 4 22.5 10.5t22.5 10.5q46 25 82 51q123 91 192 227t69 289t-69 289 +t-192 227q-36 26 -82 51q-7 4 -22.5 10.5t-22.5 10.5q-39 23 -39 59q0 26 19 45t45 19q13 0 26 -5q211 -91 338 -283.5t127 -422.5z" /> + <glyph glyph-name="qrcode" unicode="" horiz-adv-x="1408" +d="M384 384v-128h-128v128h128zM384 1152v-128h-128v128h128zM1152 1152v-128h-128v128h128zM128 129h384v383h-384v-383zM128 896h384v384h-384v-384zM896 896h384v384h-384v-384zM640 640v-640h-640v640h640zM1152 128v-128h-128v128h128zM1408 128v-128h-128v128h128z +M1408 640v-384h-384v128h-128v-384h-128v640h384v-128h128v128h128zM640 1408v-640h-640v640h640zM1408 1408v-640h-640v640h640z" /> + <glyph glyph-name="barcode" unicode="" horiz-adv-x="1792" +d="M63 0h-63v1408h63v-1408zM126 1h-32v1407h32v-1407zM220 1h-31v1407h31v-1407zM377 1h-31v1407h31v-1407zM534 1h-62v1407h62v-1407zM660 1h-31v1407h31v-1407zM723 1h-31v1407h31v-1407zM786 1h-31v1407h31v-1407zM943 1h-63v1407h63v-1407zM1100 1h-63v1407h63v-1407z +M1226 1h-63v1407h63v-1407zM1352 1h-63v1407h63v-1407zM1446 1h-63v1407h63v-1407zM1635 1h-94v1407h94v-1407zM1698 1h-32v1407h32v-1407zM1792 0h-63v1408h63v-1408z" /> + <glyph glyph-name="tag" unicode="" +d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 +l715 -714q37 -39 37 -91z" /> + <glyph glyph-name="tags" unicode="" horiz-adv-x="1920" +d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 +l715 -714q37 -39 37 -91zM1899 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-36 0 -59 14t-53 45l470 470q37 37 37 90q0 52 -37 91l-715 714q-38 38 -102 64.5t-117 26.5h224q53 0 117 -26.5t102 -64.5l715 -714q37 -39 37 -91z" /> + <glyph glyph-name="book" unicode="" horiz-adv-x="1664" +d="M1639 1058q40 -57 18 -129l-275 -906q-19 -64 -76.5 -107.5t-122.5 -43.5h-923q-77 0 -148.5 53.5t-99.5 131.5q-24 67 -2 127q0 4 3 27t4 37q1 8 -3 21.5t-3 19.5q2 11 8 21t16.5 23.5t16.5 23.5q23 38 45 91.5t30 91.5q3 10 0.5 30t-0.5 28q3 11 17 28t17 23 +q21 36 42 92t25 90q1 9 -2.5 32t0.5 28q4 13 22 30.5t22 22.5q19 26 42.5 84.5t27.5 96.5q1 8 -3 25.5t-2 26.5q2 8 9 18t18 23t17 21q8 12 16.5 30.5t15 35t16 36t19.5 32t26.5 23.5t36 11.5t47.5 -5.5l-1 -3q38 9 51 9h761q74 0 114 -56t18 -130l-274 -906 +q-36 -119 -71.5 -153.5t-128.5 -34.5h-869q-27 0 -38 -15q-11 -16 -1 -43q24 -70 144 -70h923q29 0 56 15.5t35 41.5l300 987q7 22 5 57q38 -15 59 -43zM575 1056q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5 +t-16.5 -22.5zM492 800q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5t-16.5 -22.5z" /> + <glyph glyph-name="bookmark" unicode="" horiz-adv-x="1280" +d="M1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289q0 34 19.5 62t52.5 41q21 9 44 9h1048z" /> + <glyph glyph-name="print" unicode="" horiz-adv-x="1664" +d="M384 0h896v256h-896v-256zM384 640h896v384h-160q-40 0 -68 28t-28 68v160h-640v-640zM1536 576q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 576v-416q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-160q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68 +v160h-224q-13 0 -22.5 9.5t-9.5 22.5v416q0 79 56.5 135.5t135.5 56.5h64v544q0 40 28 68t68 28h672q40 0 88 -20t76 -48l152 -152q28 -28 48 -76t20 -88v-256h64q79 0 135.5 -56.5t56.5 -135.5z" /> + <glyph glyph-name="camera" unicode="" horiz-adv-x="1920" +d="M960 864q119 0 203.5 -84.5t84.5 -203.5t-84.5 -203.5t-203.5 -84.5t-203.5 84.5t-84.5 203.5t84.5 203.5t203.5 84.5zM1664 1280q106 0 181 -75t75 -181v-896q0 -106 -75 -181t-181 -75h-1408q-106 0 -181 75t-75 181v896q0 106 75 181t181 75h224l51 136 +q19 49 69.5 84.5t103.5 35.5h512q53 0 103.5 -35.5t69.5 -84.5l51 -136h224zM960 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> + <glyph glyph-name="font" unicode="" horiz-adv-x="1664" +d="M725 977l-170 -450q33 0 136.5 -2t160.5 -2q19 0 57 2q-87 253 -184 452zM0 -128l2 79q23 7 56 12.5t57 10.5t49.5 14.5t44.5 29t31 50.5l237 616l280 724h75h53q8 -14 11 -21l205 -480q33 -78 106 -257.5t114 -274.5q15 -34 58 -144.5t72 -168.5q20 -45 35 -57 +q19 -15 88 -29.5t84 -20.5q6 -38 6 -57q0 -5 -0.5 -13.5t-0.5 -12.5q-63 0 -190 8t-191 8q-76 0 -215 -7t-178 -8q0 43 4 78l131 28q1 0 12.5 2.5t15.5 3.5t14.5 4.5t15 6.5t11 8t9 11t2.5 14q0 16 -31 96.5t-72 177.5t-42 100l-450 2q-26 -58 -76.5 -195.5t-50.5 -162.5 +q0 -22 14 -37.5t43.5 -24.5t48.5 -13.5t57 -8.5t41 -4q1 -19 1 -58q0 -9 -2 -27q-58 0 -174.5 10t-174.5 10q-8 0 -26.5 -4t-21.5 -4q-80 -14 -188 -14z" /> + <glyph glyph-name="bold" unicode="" horiz-adv-x="1408" +d="M555 15q74 -32 140 -32q376 0 376 335q0 114 -41 180q-27 44 -61.5 74t-67.5 46.5t-80.5 25t-84 10.5t-94.5 2q-73 0 -101 -10q0 -53 -0.5 -159t-0.5 -158q0 -8 -1 -67.5t-0.5 -96.5t4.5 -83.5t12 -66.5zM541 761q42 -7 109 -7q82 0 143 13t110 44.5t74.5 89.5t25.5 142 +q0 70 -29 122.5t-79 82t-108 43.5t-124 14q-50 0 -130 -13q0 -50 4 -151t4 -152q0 -27 -0.5 -80t-0.5 -79q0 -46 1 -69zM0 -128l2 94q15 4 85 16t106 27q7 12 12.5 27t8.5 33.5t5.5 32.5t3 37.5t0.5 34v35.5v30q0 982 -22 1025q-4 8 -22 14.5t-44.5 11t-49.5 7t-48.5 4.5 +t-30.5 3l-4 83q98 2 340 11.5t373 9.5q23 0 68 -0.5t68 -0.5q70 0 136.5 -13t128.5 -42t108 -71t74 -104.5t28 -137.5q0 -52 -16.5 -95.5t-39 -72t-64.5 -57.5t-73 -45t-84 -40q154 -35 256.5 -134t102.5 -248q0 -100 -35 -179.5t-93.5 -130.5t-138 -85.5t-163.5 -48.5 +t-176 -14q-44 0 -132 3t-132 3q-106 0 -307 -11t-231 -12z" /> + <glyph glyph-name="italic" unicode="" horiz-adv-x="1024" +d="M0 -126l17 85q22 7 61.5 16.5t72 19t59.5 23.5q28 35 41 101q1 7 62 289t114 543.5t52 296.5v25q-24 13 -54.5 18.5t-69.5 8t-58 5.5l19 103q33 -2 120 -6.5t149.5 -7t120.5 -2.5q48 0 98.5 2.5t121 7t98.5 6.5q-5 -39 -19 -89q-30 -10 -101.5 -28.5t-108.5 -33.5 +q-8 -19 -14 -42.5t-9 -40t-7.5 -45.5t-6.5 -42q-27 -148 -87.5 -419.5t-77.5 -355.5q-2 -9 -13 -58t-20 -90t-16 -83.5t-6 -57.5l1 -18q17 -4 185 -31q-3 -44 -16 -99q-11 0 -32.5 -1.5t-32.5 -1.5q-29 0 -87 10t-86 10q-138 2 -206 2q-51 0 -143 -9t-121 -11z" /> + <glyph glyph-name="text_height" unicode="" horiz-adv-x="1792" +d="M1744 128q33 0 42 -18.5t-11 -44.5l-126 -162q-20 -26 -49 -26t-49 26l-126 162q-20 26 -11 44.5t42 18.5h80v1024h-80q-33 0 -42 18.5t11 44.5l126 162q20 26 49 26t49 -26l126 -162q20 -26 11 -44.5t-42 -18.5h-80v-1024h80zM81 1407l54 -27q12 -5 211 -5q44 0 132 2 +t132 2q36 0 107.5 -0.5t107.5 -0.5h293q6 0 21 -0.5t20.5 0t16 3t17.5 9t15 17.5l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 48t-14.5 73.5t-7.5 35.5q-6 8 -12 12.5t-15.5 6t-13 2.5t-18 0.5t-16.5 -0.5 +q-17 0 -66.5 0.5t-74.5 0.5t-64 -2t-71 -6q-9 -81 -8 -136q0 -94 2 -388t2 -455q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 +q19 42 19 383q0 101 -3 303t-3 303v117q0 2 0.5 15.5t0.5 25t-1 25.5t-3 24t-5 14q-11 12 -162 12q-33 0 -93 -12t-80 -26q-19 -13 -34 -72.5t-31.5 -111t-42.5 -53.5q-42 26 -56 44v383z" /> + <glyph glyph-name="text_width" unicode="" +d="M81 1407l54 -27q12 -5 211 -5q44 0 132 2t132 2q70 0 246.5 1t304.5 0.5t247 -4.5q33 -1 56 31l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 47.5t-15 73.5t-7 36q-10 13 -27 19q-5 2 -66 2q-30 0 -93 1t-103 1 +t-94 -2t-96 -7q-9 -81 -8 -136l1 -152v52q0 -55 1 -154t1.5 -180t0.5 -153q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 +q7 16 11.5 74t6 145.5t1.5 155t-0.5 153.5t-0.5 89q0 7 -2.5 21.5t-2.5 22.5q0 7 0.5 44t1 73t0 76.5t-3 67.5t-6.5 32q-11 12 -162 12q-41 0 -163 -13.5t-138 -24.5q-19 -12 -34 -71.5t-31.5 -111.5t-42.5 -54q-42 26 -56 44v383zM1310 125q12 0 42 -19.5t57.5 -41.5 +t59.5 -49t36 -30q26 -21 26 -49t-26 -49q-4 -3 -36 -30t-59.5 -49t-57.5 -41.5t-42 -19.5q-13 0 -20.5 10.5t-10 28.5t-2.5 33.5t1.5 33t1.5 19.5h-1024q0 -2 1.5 -19.5t1.5 -33t-2.5 -33.5t-10 -28.5t-20.5 -10.5q-12 0 -42 19.5t-57.5 41.5t-59.5 49t-36 30q-26 21 -26 49 +t26 49q4 3 36 30t59.5 49t57.5 41.5t42 19.5q13 0 20.5 -10.5t10 -28.5t2.5 -33.5t-1.5 -33t-1.5 -19.5h1024q0 2 -1.5 19.5t-1.5 33t2.5 33.5t10 28.5t20.5 10.5z" /> + <glyph glyph-name="align_left" unicode="" horiz-adv-x="1792" +d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45 +t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" /> + <glyph glyph-name="align_center" unicode="" horiz-adv-x="1792" +d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h896q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45t-45 -19 +h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h640q26 0 45 -19t19 -45z" /> + <glyph glyph-name="align_right" unicode="" horiz-adv-x="1792" +d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 +t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" /> + <glyph glyph-name="align_justify" unicode="" horiz-adv-x="1792" +d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 +t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" /> + <glyph glyph-name="list" unicode="" horiz-adv-x="1792" +d="M256 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM256 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5 +t9.5 -22.5zM256 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344 +q13 0 22.5 -9.5t9.5 -22.5zM256 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 +t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192 +q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5z" /> + <glyph glyph-name="indent_left" unicode="" horiz-adv-x="1792" +d="M384 992v-576q0 -13 -9.5 -22.5t-22.5 -9.5q-14 0 -23 9l-288 288q-9 9 -9 23t9 23l288 288q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 +t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 +q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" /> + <glyph glyph-name="indent_right" unicode="" horiz-adv-x="1792" +d="M352 704q0 -14 -9 -23l-288 -288q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v576q0 13 9.5 22.5t22.5 9.5q14 0 23 -9l288 -288q9 -9 9 -23zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 +t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 +q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" /> + <glyph glyph-name="facetime_video" unicode="" horiz-adv-x="1792" +d="M1792 1184v-1088q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-403 403v-166q0 -119 -84.5 -203.5t-203.5 -84.5h-704q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h704q119 0 203.5 -84.5t84.5 -203.5v-165l403 402q18 19 45 19q12 0 25 -5 +q39 -17 39 -59z" /> + <glyph glyph-name="picture" unicode="" horiz-adv-x="1920" +d="M640 960q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 576v-448h-1408v192l320 320l160 -160l512 512zM1760 1280h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5v1216 +q0 13 -9.5 22.5t-22.5 9.5zM1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" /> + <glyph glyph-name="pencil" unicode="" +d="M363 0l91 91l-235 235l-91 -91v-107h128v-128h107zM886 928q0 22 -22 22q-10 0 -17 -7l-542 -542q-7 -7 -7 -17q0 -22 22 -22q10 0 17 7l542 542q7 7 7 17zM832 1120l416 -416l-832 -832h-416v416zM1515 1024q0 -53 -37 -90l-166 -166l-416 416l166 165q36 38 90 38 +q53 0 91 -38l235 -234q37 -39 37 -91z" /> + <glyph glyph-name="map_marker" unicode="" horiz-adv-x="1024" +d="M768 896q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1024 896q0 -109 -33 -179l-364 -774q-16 -33 -47.5 -52t-67.5 -19t-67.5 19t-46.5 52l-365 774q-33 70 -33 179q0 212 150 362t362 150t362 -150t150 -362z" /> + <glyph glyph-name="adjust" unicode="" +d="M768 96v1088q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="tint" unicode="" horiz-adv-x="1024" +d="M512 384q0 36 -20 69q-1 1 -15.5 22.5t-25.5 38t-25 44t-21 50.5q-4 16 -21 16t-21 -16q-7 -23 -21 -50.5t-25 -44t-25.5 -38t-15.5 -22.5q-20 -33 -20 -69q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 512q0 -212 -150 -362t-362 -150t-362 150t-150 362 +q0 145 81 275q6 9 62.5 90.5t101 151t99.5 178t83 201.5q9 30 34 47t51 17t51.5 -17t33.5 -47q28 -93 83 -201.5t99.5 -178t101 -151t62.5 -90.5q81 -127 81 -275z" /> + <glyph glyph-name="edit" unicode="" horiz-adv-x="1792" +d="M888 352l116 116l-152 152l-116 -116v-56h96v-96h56zM1328 1072q-16 16 -33 -1l-350 -350q-17 -17 -1 -33t33 1l350 350q17 17 1 33zM1408 478v-190q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 +q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-14 -14 -32 -8q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v126q0 13 9 22l64 64q15 15 35 7t20 -29zM1312 1216l288 -288l-672 -672h-288v288zM1756 1084l-92 -92 +l-288 288l92 92q28 28 68 28t68 -28l152 -152q28 -28 28 -68t-28 -68z" /> + <glyph glyph-name="share" unicode="" horiz-adv-x="1664" +d="M1408 547v-259q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h255v0q13 0 22.5 -9.5t9.5 -22.5q0 -27 -26 -32q-77 -26 -133 -60q-10 -4 -16 -4h-112q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832 +q66 0 113 47t47 113v214q0 19 18 29q28 13 54 37q16 16 35 8q21 -9 21 -29zM1645 1043l-384 -384q-18 -19 -45 -19q-12 0 -25 5q-39 17 -39 59v192h-160q-323 0 -438 -131q-119 -137 -74 -473q3 -23 -20 -34q-8 -2 -12 -2q-16 0 -26 13q-10 14 -21 31t-39.5 68.5t-49.5 99.5 +t-38.5 114t-17.5 122q0 49 3.5 91t14 90t28 88t47 81.5t68.5 74t94.5 61.5t124.5 48.5t159.5 30.5t196.5 11h160v192q0 42 39 59q13 5 25 5q26 0 45 -19l384 -384q19 -19 19 -45t-19 -45z" /> + <glyph glyph-name="check" unicode="" horiz-adv-x="1664" +d="M1408 606v-318q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-10 -10 -23 -10q-3 0 -9 2q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832 +q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v254q0 13 9 22l64 64q10 10 23 10q6 0 12 -3q20 -8 20 -29zM1639 1095l-814 -814q-24 -24 -57 -24t-57 24l-430 430q-24 24 -24 57t24 57l110 110q24 24 57 24t57 -24l263 -263l647 647q24 24 57 24t57 -24l110 -110 +q24 -24 24 -57t-24 -57z" /> + <glyph glyph-name="move" unicode="" horiz-adv-x="1792" +d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-384v-384h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v384h-384v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45 +t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h384v384h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45t-19 -45t-45 -19h-128v-384h384v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" /> + <glyph glyph-name="step_backward" unicode="" horiz-adv-x="1024" +d="M979 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 10 13 19z" /> + <glyph glyph-name="fast_backward" unicode="" horiz-adv-x="1792" +d="M1747 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 10 13 19l710 710 +q19 19 32 13t13 -32v-710q4 10 13 19z" /> + <glyph glyph-name="backward" unicode="" horiz-adv-x="1664" +d="M1619 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-19 19 -19 45t19 45l710 710q19 19 32 13t13 -32v-710q4 10 13 19z" /> + <glyph glyph-name="play" unicode="" horiz-adv-x="1408" +d="M1384 609l-1328 -738q-23 -13 -39.5 -3t-16.5 36v1472q0 26 16.5 36t39.5 -3l1328 -738q23 -13 23 -31t-23 -31z" /> + <glyph glyph-name="pause" unicode="" +d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45zM640 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45z" /> + <glyph glyph-name="stop" unicode="" +d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" /> + <glyph glyph-name="forward" unicode="" horiz-adv-x="1664" +d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q9 -9 13 -19v710q0 26 13 32t32 -13l710 -710q19 -19 19 -45t-19 -45l-710 -710q-19 -19 -32 -13t-13 32v710q-4 -10 -13 -19z" /> + <glyph glyph-name="fast_forward" unicode="" horiz-adv-x="1792" +d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q9 -9 13 -19v710q0 26 13 32t32 -13l710 -710q9 -9 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-4 -10 -13 -19l-710 -710 +q-19 -19 -32 -13t-13 32v710q-4 -10 -13 -19z" /> + <glyph glyph-name="step_forward" unicode="" horiz-adv-x="1024" +d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q9 -9 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-4 -10 -13 -19z" /> + <glyph glyph-name="eject" unicode="" horiz-adv-x="1538" +d="M14 557l710 710q19 19 45 19t45 -19l710 -710q19 -19 13 -32t-32 -13h-1472q-26 0 -32 13t13 32zM1473 0h-1408q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1408q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19z" /> + <glyph glyph-name="chevron_left" unicode="" horiz-adv-x="1280" +d="M1171 1235l-531 -531l531 -531q19 -19 19 -45t-19 -45l-166 -166q-19 -19 -45 -19t-45 19l-742 742q-19 19 -19 45t19 45l742 742q19 19 45 19t45 -19l166 -166q19 -19 19 -45t-19 -45z" /> + <glyph glyph-name="chevron_right" unicode="" horiz-adv-x="1280" +d="M1107 659l-742 -742q-19 -19 -45 -19t-45 19l-166 166q-19 19 -19 45t19 45l531 531l-531 531q-19 19 -19 45t19 45l166 166q19 19 45 19t45 -19l742 -742q19 -19 19 -45t-19 -45z" /> + <glyph glyph-name="plus_sign" unicode="" +d="M1216 576v128q0 26 -19 45t-45 19h-256v256q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-256h-256q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h256v-256q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v256h256q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5 +t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="minus_sign" unicode="" +d="M1216 576v128q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 +t103 -385.5z" /> + <glyph glyph-name="remove_sign" unicode="" +d="M1149 414q0 26 -19 45l-181 181l181 181q19 19 19 45q0 27 -19 46l-90 90q-19 19 -46 19q-26 0 -45 -19l-181 -181l-181 181q-19 19 -45 19q-27 0 -46 -19l-90 -90q-19 -19 -19 -46q0 -26 19 -45l181 -181l-181 -181q-19 -19 -19 -45q0 -27 19 -46l90 -90q19 -19 46 -19 +q26 0 45 19l181 181l181 -181q19 -19 45 -19q27 0 46 19l90 90q19 19 19 46zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="ok_sign" unicode="" +d="M1284 802q0 28 -18 46l-91 90q-19 19 -45 19t-45 -19l-408 -407l-226 226q-19 19 -45 19t-45 -19l-91 -90q-18 -18 -18 -46q0 -27 18 -45l362 -362q19 -19 45 -19q27 0 46 19l543 543q18 18 18 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 +t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="question_sign" unicode="" +d="M896 160v192q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1152 832q0 88 -55.5 163t-138.5 116t-170 41q-243 0 -371 -213q-15 -24 8 -42l132 -100q7 -6 19 -6q16 0 25 12q53 68 86 92q34 24 86 24q48 0 85.5 -26t37.5 -59 +q0 -38 -20 -61t-68 -45q-63 -28 -115.5 -86.5t-52.5 -125.5v-36q0 -14 9 -23t23 -9h192q14 0 23 9t9 23q0 19 21.5 49.5t54.5 49.5q32 18 49 28.5t46 35t44.5 48t28 60.5t12.5 81zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 +t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="info_sign" unicode="" +d="M1024 160v160q0 14 -9 23t-23 9h-96v512q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h96v-320h-96q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h448q14 0 23 9t9 23zM896 1056v160q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23 +t23 -9h192q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="screenshot" unicode="" +d="M1197 512h-109q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h109q-32 108 -112.5 188.5t-188.5 112.5v-109q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v109q-108 -32 -188.5 -112.5t-112.5 -188.5h109q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-109 +q32 -108 112.5 -188.5t188.5 -112.5v109q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-109q108 32 188.5 112.5t112.5 188.5zM1536 704v-128q0 -26 -19 -45t-45 -19h-143q-37 -161 -154.5 -278.5t-278.5 -154.5v-143q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v143 +q-161 37 -278.5 154.5t-154.5 278.5h-143q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h143q37 161 154.5 278.5t278.5 154.5v143q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-143q161 -37 278.5 -154.5t154.5 -278.5h143q26 0 45 -19t19 -45z" /> + <glyph glyph-name="remove_circle" unicode="" +d="M1097 457l-146 -146q-10 -10 -23 -10t-23 10l-137 137l-137 -137q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l137 137l-137 137q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l137 -137l137 137q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23 +l-137 -137l137 -137q10 -10 10 -23t-10 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5 +t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="ok_circle" unicode="" +d="M1171 723l-422 -422q-19 -19 -45 -19t-45 19l-294 294q-19 19 -19 45t19 45l102 102q19 19 45 19t45 -19l147 -147l275 275q19 19 45 19t45 -19l102 -102q19 -19 19 -45t-19 -45zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198 +t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="ban_circle" unicode="" +d="M1312 643q0 161 -87 295l-754 -753q137 -89 297 -89q111 0 211.5 43.5t173.5 116.5t116 174.5t43 212.5zM313 344l755 754q-135 91 -300 91q-148 0 -273 -73t-198 -199t-73 -274q0 -162 89 -299zM1536 643q0 -157 -61 -300t-163.5 -246t-245 -164t-298.5 -61t-298.5 61 +t-245 164t-163.5 246t-61 300t61 299.5t163.5 245.5t245 164t298.5 61t298.5 -61t245 -164t163.5 -245.5t61 -299.5z" /> + <glyph glyph-name="arrow_left" unicode="" +d="M1536 640v-128q0 -53 -32.5 -90.5t-84.5 -37.5h-704l293 -294q38 -36 38 -90t-38 -90l-75 -76q-37 -37 -90 -37q-52 0 -91 37l-651 652q-37 37 -37 90q0 52 37 91l651 650q38 38 91 38q52 0 90 -38l75 -74q38 -38 38 -91t-38 -91l-293 -293h704q52 0 84.5 -37.5 +t32.5 -90.5z" /> + <glyph glyph-name="arrow_right" unicode="" +d="M1472 576q0 -54 -37 -91l-651 -651q-39 -37 -91 -37q-51 0 -90 37l-75 75q-38 38 -38 91t38 91l293 293h-704q-52 0 -84.5 37.5t-32.5 90.5v128q0 53 32.5 90.5t84.5 37.5h704l-293 294q-38 36 -38 90t38 90l75 75q38 38 90 38q53 0 91 -38l651 -651q37 -35 37 -90z" /> + <glyph glyph-name="arrow_up" unicode="" horiz-adv-x="1664" +d="M1611 565q0 -51 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-294 293v-704q0 -52 -37.5 -84.5t-90.5 -32.5h-128q-53 0 -90.5 32.5t-37.5 84.5v704l-294 -293q-36 -38 -90 -38t-90 38l-75 75q-38 38 -38 90q0 53 38 91l651 651q35 37 90 37q54 0 91 -37l651 -651 +q37 -39 37 -91z" /> + <glyph glyph-name="arrow_down" unicode="" horiz-adv-x="1664" +d="M1611 704q0 -53 -37 -90l-651 -652q-39 -37 -91 -37q-53 0 -90 37l-651 652q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l294 -294v704q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-704l294 294q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" /> + <glyph glyph-name="share_alt" unicode="" horiz-adv-x="1792" +d="M1792 896q0 -26 -19 -45l-512 -512q-19 -19 -45 -19t-45 19t-19 45v256h-224q-98 0 -175.5 -6t-154 -21.5t-133 -42.5t-105.5 -69.5t-80 -101t-48.5 -138.5t-17.5 -181q0 -55 5 -123q0 -6 2.5 -23.5t2.5 -26.5q0 -15 -8.5 -25t-23.5 -10q-16 0 -28 17q-7 9 -13 22 +t-13.5 30t-10.5 24q-127 285 -127 451q0 199 53 333q162 403 875 403h224v256q0 26 19 45t45 19t45 -19l512 -512q19 -19 19 -45z" /> + <glyph glyph-name="resize_full" unicode="" +d="M755 480q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23zM1536 1344v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332 +q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45z" /> + <glyph glyph-name="resize_small" unicode="" +d="M768 576v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45zM1523 1248q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45 +t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23z" /> + <glyph glyph-name="plus" unicode="" horiz-adv-x="1408" +d="M1408 800v-192q0 -40 -28 -68t-68 -28h-416v-416q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v416h-416q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h416v416q0 40 28 68t68 28h192q40 0 68 -28t28 -68v-416h416q40 0 68 -28t28 -68z" /> + <glyph glyph-name="minus" unicode="" horiz-adv-x="1408" +d="M1408 800v-192q0 -40 -28 -68t-68 -28h-1216q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h1216q40 0 68 -28t28 -68z" /> + <glyph glyph-name="asterisk" unicode="" horiz-adv-x="1664" +d="M1482 486q46 -26 59.5 -77.5t-12.5 -97.5l-64 -110q-26 -46 -77.5 -59.5t-97.5 12.5l-266 153v-307q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v307l-266 -153q-46 -26 -97.5 -12.5t-77.5 59.5l-64 110q-26 46 -12.5 97.5t59.5 77.5l266 154l-266 154 +q-46 26 -59.5 77.5t12.5 97.5l64 110q26 46 77.5 59.5t97.5 -12.5l266 -153v307q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-307l266 153q46 26 97.5 12.5t77.5 -59.5l64 -110q26 -46 12.5 -97.5t-59.5 -77.5l-266 -154z" /> + <glyph glyph-name="exclamation_sign" unicode="" +d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM896 161v190q0 14 -9 23.5t-22 9.5h-192q-13 0 -23 -10t-10 -23v-190q0 -13 10 -23t23 -10h192 +q13 0 22 9.5t9 23.5zM894 505l18 621q0 12 -10 18q-10 8 -24 8h-220q-14 0 -24 -8q-10 -6 -10 -18l17 -621q0 -10 10 -17.5t24 -7.5h185q14 0 23.5 7.5t10.5 17.5z" /> + <glyph glyph-name="gift" unicode="" +d="M928 180v56v468v192h-320v-192v-468v-56q0 -25 18 -38.5t46 -13.5h192q28 0 46 13.5t18 38.5zM472 1024h195l-126 161q-26 31 -69 31q-40 0 -68 -28t-28 -68t28 -68t68 -28zM1160 1120q0 40 -28 68t-68 28q-43 0 -69 -31l-125 -161h194q40 0 68 28t28 68zM1536 864v-320 +q0 -14 -9 -23t-23 -9h-96v-416q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v416h-96q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h440q-93 0 -158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5q107 0 168 -77l128 -165l128 165q61 77 168 77q93 0 158.5 -65.5t65.5 -158.5 +t-65.5 -158.5t-158.5 -65.5h440q14 0 23 -9t9 -23z" /> + <glyph glyph-name="leaf" unicode="" horiz-adv-x="1792" +d="M1280 832q0 26 -19 45t-45 19q-172 0 -318 -49.5t-259.5 -134t-235.5 -219.5q-19 -21 -19 -45q0 -26 19 -45t45 -19q24 0 45 19q27 24 74 71t67 66q137 124 268.5 176t313.5 52q26 0 45 19t19 45zM1792 1030q0 -95 -20 -193q-46 -224 -184.5 -383t-357.5 -268 +q-214 -108 -438 -108q-148 0 -286 47q-15 5 -88 42t-96 37q-16 0 -39.5 -32t-45 -70t-52.5 -70t-60 -32q-43 0 -63.5 17.5t-45.5 59.5q-2 4 -6 11t-5.5 10t-3 9.5t-1.5 13.5q0 35 31 73.5t68 65.5t68 56t31 48q0 4 -14 38t-16 44q-9 51 -9 104q0 115 43.5 220t119 184.5 +t170.5 139t204 95.5q55 18 145 25.5t179.5 9t178.5 6t163.5 24t113.5 56.5l29.5 29.5t29.5 28t27 20t36.5 16t43.5 4.5q39 0 70.5 -46t47.5 -112t24 -124t8 -96z" /> + <glyph glyph-name="fire" unicode="" horiz-adv-x="1408" +d="M1408 -160v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1152 896q0 -78 -24.5 -144t-64 -112.5t-87.5 -88t-96 -77.5t-87.5 -72t-64 -81.5t-24.5 -96.5q0 -96 67 -224l-4 1l1 -1 +q-90 41 -160 83t-138.5 100t-113.5 122.5t-72.5 150.5t-27.5 184q0 78 24.5 144t64 112.5t87.5 88t96 77.5t87.5 72t64 81.5t24.5 96.5q0 94 -66 224l3 -1l-1 1q90 -41 160 -83t138.5 -100t113.5 -122.5t72.5 -150.5t27.5 -184z" /> + <glyph glyph-name="eye_open" unicode="" horiz-adv-x="1792" +d="M1664 576q-152 236 -381 353q61 -104 61 -225q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 121 61 225q-229 -117 -381 -353q133 -205 333.5 -326.5t434.5 -121.5t434.5 121.5t333.5 326.5zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5 +t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1792 576q0 -34 -20 -69q-140 -230 -376.5 -368.5t-499.5 -138.5t-499.5 139t-376.5 368q-20 35 -20 69t20 69q140 229 376.5 368t499.5 139t499.5 -139t376.5 -368q20 -35 20 -69z" /> + <glyph glyph-name="eye_close" unicode="" horiz-adv-x="1792" +d="M555 201l78 141q-87 63 -136 159t-49 203q0 121 61 225q-229 -117 -381 -353q167 -258 427 -375zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1307 1151q0 -7 -1 -9 +q-106 -189 -316 -567t-315 -566l-49 -89q-10 -16 -28 -16q-12 0 -134 70q-16 10 -16 28q0 12 44 87q-143 65 -263.5 173t-208.5 245q-20 31 -20 69t20 69q153 235 380 371t496 136q89 0 180 -17l54 97q10 16 28 16q5 0 18 -6t31 -15.5t33 -18.5t31.5 -18.5t19.5 -11.5 +q16 -10 16 -27zM1344 704q0 -139 -79 -253.5t-209 -164.5l280 502q8 -45 8 -84zM1792 576q0 -35 -20 -69q-39 -64 -109 -145q-150 -172 -347.5 -267t-419.5 -95l74 132q212 18 392.5 137t301.5 307q-115 179 -282 294l63 112q95 -64 182.5 -153t144.5 -184q20 -34 20 -69z +" /> + <glyph glyph-name="warning_sign" unicode="" horiz-adv-x="1792" +d="M1024 161v190q0 14 -9.5 23.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -23.5v-190q0 -14 9.5 -23.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 23.5zM1022 535l18 459q0 12 -10 19q-13 11 -24 11h-220q-11 0 -24 -11q-10 -7 -10 -21l17 -457q0 -10 10 -16.5t24 -6.5h185 +q14 0 23.5 6.5t10.5 16.5zM1008 1469l768 -1408q35 -63 -2 -126q-17 -29 -46.5 -46t-63.5 -17h-1536q-34 0 -63.5 17t-46.5 46q-37 63 -2 126l768 1408q17 31 47 49t65 18t65 -18t47 -49z" /> + <glyph glyph-name="plane" unicode="" horiz-adv-x="1408" +d="M1376 1376q44 -52 12 -148t-108 -172l-161 -161l160 -696q5 -19 -12 -33l-128 -96q-7 -6 -19 -6q-4 0 -7 1q-15 3 -21 16l-279 508l-259 -259l53 -194q5 -17 -8 -31l-96 -96q-9 -9 -23 -9h-2q-15 2 -24 13l-189 252l-252 189q-11 7 -13 23q-1 13 9 25l96 97q9 9 23 9 +q6 0 8 -1l194 -53l259 259l-508 279q-14 8 -17 24q-2 16 9 27l128 128q14 13 30 8l665 -159l160 160q76 76 172 108t148 -12z" /> + <glyph glyph-name="calendar" unicode="" horiz-adv-x="1664" +d="M128 -128h288v288h-288v-288zM480 -128h320v288h-320v-288zM128 224h288v320h-288v-320zM480 224h320v320h-320v-320zM128 608h288v288h-288v-288zM864 -128h320v288h-320v-288zM480 608h320v288h-320v-288zM1248 -128h288v288h-288v-288zM864 224h320v320h-320v-320z +M512 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1248 224h288v320h-288v-320zM864 608h320v288h-320v-288zM1248 608h288v288h-288v-288zM1280 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64 +q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47 +h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" /> + <glyph glyph-name="random" unicode="" horiz-adv-x="1792" +d="M666 1055q-60 -92 -137 -273q-22 45 -37 72.5t-40.5 63.5t-51 56.5t-63 35t-81.5 14.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q250 0 410 -225zM1792 256q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192q-32 0 -85 -0.5t-81 -1t-73 1 +t-71 5t-64 10.5t-63 18.5t-58 28.5t-59 40t-55 53.5t-56 69.5q59 93 136 273q22 -45 37 -72.5t40.5 -63.5t51 -56.5t63 -35t81.5 -14.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1792 1152q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5 +v192h-256q-48 0 -87 -15t-69 -45t-51 -61.5t-45 -77.5q-32 -62 -78 -171q-29 -66 -49.5 -111t-54 -105t-64 -100t-74 -83t-90 -68.5t-106.5 -42t-128 -16.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q48 0 87 15t69 45t51 61.5t45 77.5q32 62 78 171q29 66 49.5 111 +t54 105t64 100t74 83t90 68.5t106.5 42t128 16.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" /> + <glyph glyph-name="comment" unicode="" horiz-adv-x="1792" +d="M1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22q-17 -2 -30.5 9t-17.5 29v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281 +q0 130 71 248.5t191 204.5t286 136.5t348 50.5q244 0 450 -85.5t326 -233t120 -321.5z" /> + <glyph glyph-name="magnet" unicode="" +d="M1536 704v-128q0 -201 -98.5 -362t-274 -251.5t-395.5 -90.5t-395.5 90.5t-274 251.5t-98.5 362v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-128q0 -52 23.5 -90t53.5 -57t71 -30t64 -13t44 -2t44 2t64 13t71 30t53.5 57t23.5 90v128q0 26 19 45t45 19h384 +q26 0 45 -19t19 -45zM512 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45zM1536 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45z" /> + <glyph glyph-name="chevron_up" unicode="" horiz-adv-x="1792" +d="M1683 205l-166 -165q-19 -19 -45 -19t-45 19l-531 531l-531 -531q-19 -19 -45 -19t-45 19l-166 165q-19 19 -19 45.5t19 45.5l742 741q19 19 45 19t45 -19l742 -741q19 -19 19 -45.5t-19 -45.5z" /> + <glyph glyph-name="chevron_down" unicode="" horiz-adv-x="1792" +d="M1683 728l-742 -741q-19 -19 -45 -19t-45 19l-742 741q-19 19 -19 45.5t19 45.5l166 165q19 19 45 19t45 -19l531 -531l531 531q19 19 45 19t45 -19l166 -165q19 -19 19 -45.5t-19 -45.5z" /> + <glyph glyph-name="retweet" unicode="" horiz-adv-x="1920" +d="M1280 32q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-8 0 -13.5 2t-9 7t-5.5 8t-3 11.5t-1 11.5v13v11v160v416h-192q-26 0 -45 19t-19 45q0 24 15 41l320 384q19 22 49 22t49 -22l320 -384q15 -17 15 -41q0 -26 -19 -45t-45 -19h-192v-384h576q16 0 25 -11l160 -192q7 -10 7 -21 +zM1920 448q0 -24 -15 -41l-320 -384q-20 -23 -49 -23t-49 23l-320 384q-15 17 -15 41q0 26 19 45t45 19h192v384h-576q-16 0 -25 12l-160 192q-7 9 -7 20q0 13 9.5 22.5t22.5 9.5h960q8 0 13.5 -2t9 -7t5.5 -8t3 -11.5t1 -11.5v-13v-11v-160v-416h192q26 0 45 -19t19 -45z +" /> + <glyph glyph-name="shopping_cart" unicode="" horiz-adv-x="1664" +d="M640 0q0 -52 -38 -90t-90 -38t-90 38t-38 90t38 90t90 38t90 -38t38 -90zM1536 0q0 -52 -38 -90t-90 -38t-90 38t-38 90t38 90t90 38t90 -38t38 -90zM1664 1088v-512q0 -24 -16.5 -42.5t-40.5 -21.5l-1044 -122q13 -60 13 -70q0 -16 -24 -64h920q26 0 45 -19t19 -45 +t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 11 8 31.5t16 36t21.5 40t15.5 29.5l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t19.5 -15.5t13 -24.5t8 -26t5.5 -29.5t4.5 -26h1201q26 0 45 -19t19 -45z" /> + <glyph glyph-name="folder_close" unicode="" horiz-adv-x="1664" +d="M1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" /> + <glyph glyph-name="folder_open" unicode="" horiz-adv-x="1920" +d="M1879 584q0 -31 -31 -66l-336 -396q-43 -51 -120.5 -86.5t-143.5 -35.5h-1088q-34 0 -60.5 13t-26.5 43q0 31 31 66l336 396q43 51 120.5 86.5t143.5 35.5h1088q34 0 60.5 -13t26.5 -43zM1536 928v-160h-832q-94 0 -197 -47.5t-164 -119.5l-337 -396l-5 -6q0 4 -0.5 12.5 +t-0.5 12.5v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158z" /> + <glyph glyph-name="resize_vertical" unicode="" horiz-adv-x="768" +d="M704 1216q0 -26 -19 -45t-45 -19h-128v-1024h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v1024h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45z" /> + <glyph glyph-name="resize_horizontal" unicode="" horiz-adv-x="1792" +d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-1024v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h1024v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" /> + <glyph glyph-name="bar_chart" unicode="" horiz-adv-x="2048" +d="M640 640v-512h-256v512h256zM1024 1152v-1024h-256v1024h256zM2048 0v-128h-2048v1536h128v-1408h1920zM1408 896v-768h-256v768h256zM1792 1280v-1152h-256v1152h256z" /> + <glyph glyph-name="twitter_sign" unicode="" +d="M1280 926q-56 -25 -121 -34q68 40 93 117q-65 -38 -134 -51q-61 66 -153 66q-87 0 -148.5 -61.5t-61.5 -148.5q0 -29 5 -48q-129 7 -242 65t-192 155q-29 -50 -29 -106q0 -114 91 -175q-47 1 -100 26v-2q0 -75 50 -133.5t123 -72.5q-29 -8 -51 -8q-13 0 -39 4 +q21 -63 74.5 -104t121.5 -42q-116 -90 -261 -90q-26 0 -50 3q148 -94 322 -94q112 0 210 35.5t168 95t120.5 137t75 162t24.5 168.5q0 18 -1 27q63 45 105 109zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5 +t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="facebook_sign" unicode="" +d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-188v595h199l30 232h-229v148q0 56 23.5 84t91.5 28l122 1v207q-63 9 -178 9q-136 0 -217.5 -80t-81.5 -226v-171h-200v-232h200v-595h-532q-119 0 -203.5 84.5t-84.5 203.5v960 +q0 119 84.5 203.5t203.5 84.5h960z" /> + <glyph glyph-name="camera_retro" unicode="" horiz-adv-x="1792" +d="M928 704q0 14 -9 23t-23 9q-66 0 -113 -47t-47 -113q0 -14 9 -23t23 -9t23 9t9 23q0 40 28 68t68 28q14 0 23 9t9 23zM1152 574q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM128 0h1536v128h-1536v-128zM1280 574q0 159 -112.5 271.5 +t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM256 1216h384v128h-384v-128zM128 1024h1536v118v138h-828l-64 -128h-644v-128zM1792 1280v-1280q0 -53 -37.5 -90.5t-90.5 -37.5h-1536q-53 0 -90.5 37.5t-37.5 90.5v1280 +q0 53 37.5 90.5t90.5 37.5h1536q53 0 90.5 -37.5t37.5 -90.5z" /> + <glyph glyph-name="key" unicode="" horiz-adv-x="1792" +d="M832 1024q0 80 -56 136t-136 56t-136 -56t-56 -136q0 -42 19 -83q-41 19 -83 19q-80 0 -136 -56t-56 -136t56 -136t136 -56t136 56t56 136q0 42 -19 83q41 -19 83 -19q80 0 136 56t56 136zM1683 320q0 -17 -49 -66t-66 -49q-9 0 -28.5 16t-36.5 33t-38.5 40t-24.5 26 +l-96 -96l220 -220q28 -28 28 -68q0 -42 -39 -81t-81 -39q-40 0 -68 28l-671 671q-176 -131 -365 -131q-163 0 -265.5 102.5t-102.5 265.5q0 160 95 313t248 248t313 95q163 0 265.5 -102.5t102.5 -265.5q0 -189 -131 -365l355 -355l96 96q-3 3 -26 24.5t-40 38.5t-33 36.5 +t-16 28.5q0 17 49 66t66 49q13 0 23 -10q6 -6 46 -44.5t82 -79.5t86.5 -86t73 -78t28.5 -41z" /> + <glyph glyph-name="cogs" unicode="" horiz-adv-x="1920" +d="M896 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1664 128q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1152q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5 +t90.5 37.5t37.5 90.5zM1280 731v-185q0 -10 -7 -19.5t-16 -10.5l-155 -24q-11 -35 -32 -76q34 -48 90 -115q7 -11 7 -20q0 -12 -7 -19q-23 -30 -82.5 -89.5t-78.5 -59.5q-11 0 -21 7l-115 90q-37 -19 -77 -31q-11 -108 -23 -155q-7 -24 -30 -24h-186q-11 0 -20 7.5t-10 17.5 +l-23 153q-34 10 -75 31l-118 -89q-7 -7 -20 -7q-11 0 -21 8q-144 133 -144 160q0 9 7 19q10 14 41 53t47 61q-23 44 -35 82l-152 24q-10 1 -17 9.5t-7 19.5v185q0 10 7 19.5t16 10.5l155 24q11 35 32 76q-34 48 -90 115q-7 11 -7 20q0 12 7 20q22 30 82 89t79 59q11 0 21 -7 +l115 -90q34 18 77 32q11 108 23 154q7 24 30 24h186q11 0 20 -7.5t10 -17.5l23 -153q34 -10 75 -31l118 89q8 7 20 7q11 0 21 -8q144 -133 144 -160q0 -8 -7 -19q-12 -16 -42 -54t-45 -60q23 -48 34 -82l152 -23q10 -2 17 -10.5t7 -19.5zM1920 198v-140q0 -16 -149 -31 +q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20 +t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31zM1920 1222v-140q0 -16 -149 -31q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68 +q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70 +q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31z" /> + <glyph glyph-name="comments" unicode="" horiz-adv-x="1792" +d="M1408 768q0 -139 -94 -257t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224 +q0 139 94 257t256.5 186.5t353.5 68.5t353.5 -68.5t256.5 -186.5t94 -257zM1792 512q0 -120 -71 -224.5t-195 -176.5q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7 +q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230z" /> + <glyph glyph-name="thumbs_up_alt" unicode="" +d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 768q0 51 -39 89.5t-89 38.5h-352q0 58 48 159.5t48 160.5q0 98 -32 145t-128 47q-26 -26 -38 -85t-30.5 -125.5t-59.5 -109.5q-22 -23 -77 -91q-4 -5 -23 -30t-31.5 -41t-34.5 -42.5 +t-40 -44t-38.5 -35.5t-40 -27t-35.5 -9h-32v-640h32q13 0 31.5 -3t33 -6.5t38 -11t35 -11.5t35.5 -12.5t29 -10.5q211 -73 342 -73h121q192 0 192 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5q32 1 53.5 47t21.5 81zM1536 769 +q0 -89 -49 -163q9 -33 9 -69q0 -77 -38 -144q3 -21 3 -43q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5h-36h-93q-96 0 -189.5 22.5t-216.5 65.5q-116 40 -138 40h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h274q36 24 137 155q58 75 107 128 +q24 25 35.5 85.5t30.5 126.5t62 108q39 37 90 37q84 0 151 -32.5t102 -101.5t35 -186q0 -93 -48 -192h176q104 0 180 -76t76 -179z" /> + <glyph glyph-name="thumbs_down_alt" unicode="" +d="M256 1088q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 512q0 35 -21.5 81t-53.5 47q15 17 25 47.5t10 55.5q0 69 -53 119q18 31 18 69q0 37 -17.5 73.5t-47.5 52.5q5 30 5 56q0 85 -49 126t-136 41h-128q-131 0 -342 -73q-5 -2 -29 -10.5 +t-35.5 -12.5t-35 -11.5t-38 -11t-33 -6.5t-31.5 -3h-32v-640h32q16 0 35.5 -9t40 -27t38.5 -35.5t40 -44t34.5 -42.5t31.5 -41t23 -30q55 -68 77 -91q41 -43 59.5 -109.5t30.5 -125.5t38 -85q96 0 128 47t32 145q0 59 -48 160.5t-48 159.5h352q50 0 89 38.5t39 89.5z +M1536 511q0 -103 -76 -179t-180 -76h-176q48 -99 48 -192q0 -118 -35 -186q-35 -69 -102 -101.5t-151 -32.5q-51 0 -90 37q-34 33 -54 82t-25.5 90.5t-17.5 84.5t-31 64q-48 50 -107 127q-101 131 -137 155h-274q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5 +h288q22 0 138 40q128 44 223 66t200 22h112q140 0 226.5 -79t85.5 -216v-5q60 -77 60 -178q0 -22 -3 -43q38 -67 38 -144q0 -36 -9 -69q49 -73 49 -163z" /> + <glyph glyph-name="star_half" unicode="" horiz-adv-x="896" +d="M832 1504v-1339l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41z" /> + <glyph glyph-name="heart_empty" unicode="" horiz-adv-x="1792" +d="M1664 940q0 81 -21.5 143t-55 98.5t-81.5 59.5t-94 31t-98 8t-112 -25.5t-110.5 -64t-86.5 -72t-60 -61.5q-18 -22 -49 -22t-49 22q-24 28 -60 61.5t-86.5 72t-110.5 64t-112 25.5t-98 -8t-94 -31t-81.5 -59.5t-55 -98.5t-21.5 -143q0 -168 187 -355l581 -560l580 559 +q188 188 188 356zM1792 940q0 -221 -229 -450l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5 +q224 0 351 -124t127 -344z" /> + <glyph glyph-name="signout" unicode="" horiz-adv-x="1664" +d="M640 96q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h320q13 0 22.5 -9.5t9.5 -22.5q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-66 0 -113 -47t-47 -113v-704 +q0 -66 47 -113t113 -47h288h11h13t11.5 -1t11.5 -3t8 -5.5t7 -9t2 -13.5zM1568 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45z" /> + <glyph glyph-name="linkedin_sign" unicode="" +d="M237 122h231v694h-231v-694zM483 1030q-1 52 -36 86t-93 34t-94.5 -34t-36.5 -86q0 -51 35.5 -85.5t92.5 -34.5h1q59 0 95 34.5t36 85.5zM1068 122h231v398q0 154 -73 233t-193 79q-136 0 -209 -117h2v101h-231q3 -66 0 -694h231v388q0 38 7 56q15 35 45 59.5t74 24.5 +q116 0 116 -157v-371zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="pushpin" unicode="" horiz-adv-x="1152" +d="M480 672v448q0 14 -9 23t-23 9t-23 -9t-9 -23v-448q0 -14 9 -23t23 -9t23 9t9 23zM1152 320q0 -26 -19 -45t-45 -19h-429l-51 -483q-2 -12 -10.5 -20.5t-20.5 -8.5h-1q-27 0 -32 27l-76 485h-404q-26 0 -45 19t-19 45q0 123 78.5 221.5t177.5 98.5v512q-52 0 -90 38 +t-38 90t38 90t90 38h640q52 0 90 -38t38 -90t-38 -90t-90 -38v-512q99 0 177.5 -98.5t78.5 -221.5z" /> + <glyph glyph-name="external_link" unicode="" horiz-adv-x="1792" +d="M1408 608v-320q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v320 +q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1792 1472v-512q0 -26 -19 -45t-45 -19t-45 19l-176 176l-652 -652q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l652 652l-176 176q-19 19 -19 45t19 45t45 19h512q26 0 45 -19t19 -45z" /> + <glyph glyph-name="signin" unicode="" +d="M1184 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45zM1536 992v-704q0 -119 -84.5 -203.5t-203.5 -84.5h-320q-13 0 -22.5 9.5t-9.5 22.5 +q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q66 0 113 47t47 113v704q0 66 -47 113t-113 47h-288h-11h-13t-11.5 1t-11.5 3t-8 5.5t-7 9t-2 13.5q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="trophy" unicode="" horiz-adv-x="1664" +d="M458 653q-74 162 -74 371h-256v-96q0 -78 94.5 -162t235.5 -113zM1536 928v96h-256q0 -209 -74 -371q141 29 235.5 113t94.5 162zM1664 1056v-128q0 -71 -41.5 -143t-112 -130t-173 -97.5t-215.5 -44.5q-42 -54 -95 -95q-38 -34 -52.5 -72.5t-14.5 -89.5q0 -54 30.5 -91 +t97.5 -37q75 0 133.5 -45.5t58.5 -114.5v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 69 58.5 114.5t133.5 45.5q67 0 97.5 37t30.5 91q0 51 -14.5 89.5t-52.5 72.5q-53 41 -95 95q-113 5 -215.5 44.5t-173 97.5t-112 130t-41.5 143v128q0 40 28 68t68 28h288v96 +q0 66 47 113t113 47h576q66 0 113 -47t47 -113v-96h288q40 0 68 -28t28 -68z" /> + <glyph glyph-name="github_sign" unicode="" +d="M519 336q4 6 -3 13q-9 7 -14 2q-4 -6 3 -13q9 -7 14 -2zM491 377q-5 7 -12 4q-6 -4 0 -12q7 -8 12 -5q6 4 0 13zM450 417q2 4 -5 8q-7 2 -8 -2q-3 -5 4 -8q8 -2 9 2zM471 394q2 1 1.5 4.5t-3.5 5.5q-6 7 -10 3t1 -11q6 -6 11 -2zM557 319q2 7 -9 11q-9 3 -13 -4 +q-2 -7 9 -11q9 -3 13 4zM599 316q0 8 -12 8q-10 0 -10 -8t11 -8t11 8zM638 323q-2 7 -13 5t-9 -9q2 -8 12 -6t10 10zM1280 640q0 212 -150 362t-362 150t-362 -150t-150 -362q0 -167 98 -300.5t252 -185.5q18 -3 26.5 5t8.5 20q0 52 -1 95q-6 -1 -15.5 -2.5t-35.5 -2t-48 4 +t-43.5 20t-29.5 41.5q-23 59 -57 74q-2 1 -4.5 3.5l-8 8t-7 9.5t4 7.5t19.5 3.5q6 0 15 -2t30 -15.5t33 -35.5q16 -28 37.5 -42t43.5 -14t38 3.5t30 9.5q7 47 33 69q-49 6 -86 18.5t-73 39t-55.5 76t-19.5 119.5q0 79 53 137q-24 62 5 136q19 6 54.5 -7.5t60.5 -29.5l26 -16 +q58 17 128 17t128 -17q11 7 28.5 18t55.5 26t57 9q29 -74 5 -136q53 -58 53 -137q0 -57 -14 -100.5t-35.5 -70t-53.5 -44.5t-62.5 -26t-68.5 -12q35 -31 35 -95q0 -40 -0.5 -89t-0.5 -51q0 -12 8.5 -20t26.5 -5q154 52 252 185.5t98 300.5zM1536 1120v-960 +q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="upload_alt" unicode="" horiz-adv-x="1664" +d="M1280 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 288v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h427q21 -56 70.5 -92 +t110.5 -36h256q61 0 110.5 36t70.5 92h427q40 0 68 -28t28 -68zM1339 936q-17 -40 -59 -40h-256v-448q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v448h-256q-42 0 -59 40q-17 39 14 69l448 448q18 19 45 19t45 -19l448 -448q31 -30 14 -69z" /> + <glyph glyph-name="lemon" unicode="" +d="M1407 710q0 44 -7 113.5t-18 96.5q-12 30 -17 44t-9 36.5t-4 48.5q0 23 5 68.5t5 67.5q0 37 -10 55q-4 1 -13 1q-19 0 -58 -4.5t-59 -4.5q-60 0 -176 24t-175 24q-43 0 -94.5 -11.5t-85 -23.5t-89.5 -34q-137 -54 -202 -103q-96 -73 -159.5 -189.5t-88 -236t-24.5 -248.5 +q0 -40 12.5 -120t12.5 -121q0 -23 -11 -66.5t-11 -65.5t12 -36.5t34 -14.5q24 0 72.5 11t73.5 11q57 0 169.5 -15.5t169.5 -15.5q181 0 284 36q129 45 235.5 152.5t166 245.5t59.5 275zM1535 712q0 -165 -70 -327.5t-196 -288t-281 -180.5q-124 -44 -326 -44 +q-57 0 -170 14.5t-169 14.5q-24 0 -72.5 -14.5t-73.5 -14.5q-73 0 -123.5 55.5t-50.5 128.5q0 24 11 68t11 67q0 40 -12.5 120.5t-12.5 121.5q0 111 18 217.5t54.5 209.5t100.5 194t150 156q78 59 232 120q194 78 316 78q60 0 175.5 -24t173.5 -24q19 0 57 5t58 5 +q81 0 118 -50.5t37 -134.5q0 -23 -5 -68t-5 -68q0 -13 2 -25t3.5 -16.5t7.5 -20.5t8 -20q16 -40 25 -118.5t9 -136.5z" /> + <glyph glyph-name="phone" unicode="" horiz-adv-x="1408" +d="M1408 296q0 -27 -10 -70.5t-21 -68.5q-21 -50 -122 -106q-94 -51 -186 -51q-27 0 -53 3.5t-57.5 12.5t-47 14.5t-55.5 20.5t-49 18q-98 35 -175 83q-127 79 -264 216t-216 264q-48 77 -83 175q-3 9 -18 49t-20.5 55.5t-14.5 47t-12.5 57.5t-3.5 53q0 92 51 186 +q56 101 106 122q25 11 68.5 21t70.5 10q14 0 21 -3q18 -6 53 -76q11 -19 30 -54t35 -63.5t31 -53.5q3 -4 17.5 -25t21.5 -35.5t7 -28.5q0 -20 -28.5 -50t-62 -55t-62 -53t-28.5 -46q0 -9 5 -22.5t8.5 -20.5t14 -24t11.5 -19q76 -137 174 -235t235 -174q2 -1 19 -11.5t24 -14 +t20.5 -8.5t22.5 -5q18 0 46 28.5t53 62t55 62t50 28.5q14 0 28.5 -7t35.5 -21.5t25 -17.5q25 -15 53.5 -31t63.5 -35t54 -30q70 -35 76 -53q3 -7 3 -21z" /> + <glyph glyph-name="check_empty" unicode="" horiz-adv-x="1408" +d="M1120 1280h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v832q0 66 -47 113t-113 47zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 +q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="bookmark_empty" unicode="" horiz-adv-x="1280" +d="M1152 1280h-1024v-1242l423 406l89 85l89 -85l423 -406v1242zM1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289 +q0 34 19.5 62t52.5 41q21 9 44 9h1048z" /> + <glyph glyph-name="phone_sign" unicode="" +d="M1280 343q0 11 -2 16t-18 16.5t-40.5 25t-47.5 26.5t-45.5 25t-28.5 15q-5 3 -19 13t-25 15t-21 5q-15 0 -36.5 -20.5t-39.5 -45t-38.5 -45t-33.5 -20.5q-7 0 -16.5 3.5t-15.5 6.5t-17 9.5t-14 8.5q-99 55 -170 126.5t-127 170.5q-2 3 -8.5 14t-9.5 17t-6.5 15.5 +t-3.5 16.5q0 13 20.5 33.5t45 38.5t45 39.5t20.5 36.5q0 10 -5 21t-15 25t-13 19q-3 6 -15 28.5t-25 45.5t-26.5 47.5t-25 40.5t-16.5 18t-16 2q-48 0 -101 -22q-46 -21 -80 -94.5t-34 -130.5q0 -16 2.5 -34t5 -30.5t9 -33t10 -29.5t12.5 -33t11 -30q60 -164 216.5 -320.5 +t320.5 -216.5q6 -2 30 -11t33 -12.5t29.5 -10t33 -9t30.5 -5t34 -2.5q57 0 130.5 34t94.5 80q22 53 22 101zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z +" /> + <glyph glyph-name="twitter" unicode="" horiz-adv-x="1664" +d="M1620 1128q-67 -98 -162 -167q1 -14 1 -42q0 -130 -38 -259.5t-115.5 -248.5t-184.5 -210.5t-258 -146t-323 -54.5q-271 0 -496 145q35 -4 78 -4q225 0 401 138q-105 2 -188 64.5t-114 159.5q33 -5 61 -5q43 0 85 11q-112 23 -185.5 111.5t-73.5 205.5v4q68 -38 146 -41 +q-66 44 -105 115t-39 154q0 88 44 163q121 -149 294.5 -238.5t371.5 -99.5q-8 38 -8 74q0 134 94.5 228.5t228.5 94.5q140 0 236 -102q109 21 205 78q-37 -115 -142 -178q93 10 186 50z" /> + <glyph glyph-name="facebook" unicode="" horiz-adv-x="1024" +d="M959 1524v-264h-157q-86 0 -116 -36t-30 -108v-189h293l-39 -296h-254v-759h-306v759h-255v296h255v218q0 186 104 288.5t277 102.5q147 0 228 -12z" /> + <glyph glyph-name="github" unicode="" +d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -40 7t-13 30q0 3 0.5 76.5t0.5 134.5q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 119 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24 +q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-85 13.5q-45 -113 -8 -204q-79 -87 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-39 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5 +t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -88.5t0.5 -54.5q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103zM291 305q3 7 -7 12 +q-10 3 -13 -2q-3 -7 7 -12q9 -6 13 2zM322 271q7 5 -2 16q-10 9 -16 3q-7 -5 2 -16q10 -10 16 -3zM352 226q9 7 0 19q-8 13 -17 6q-9 -5 0 -18t17 -7zM394 184q8 8 -4 19q-12 12 -20 3q-9 -8 4 -19q12 -12 20 -3zM451 159q3 11 -13 16q-15 4 -19 -7t13 -15q15 -6 19 6z +M514 154q0 13 -17 11q-16 0 -16 -11q0 -13 17 -11q16 0 16 11zM572 164q-2 11 -18 9q-16 -3 -14 -15t18 -8t14 14z" /> + <glyph glyph-name="unlock" unicode="" horiz-adv-x="1664" +d="M1664 960v-256q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-192h96q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h672v192q0 185 131.5 316.5t316.5 131.5 +t316.5 -131.5t131.5 -316.5z" /> + <glyph glyph-name="credit_card" unicode="" horiz-adv-x="1920" +d="M1760 1408q66 0 113 -47t47 -113v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600zM160 1280q-13 0 -22.5 -9.5t-9.5 -22.5v-224h1664v224q0 13 -9.5 22.5t-22.5 9.5h-1600zM1760 0q13 0 22.5 9.5t9.5 22.5v608h-1664v-608 +q0 -13 9.5 -22.5t22.5 -9.5h1600zM256 128v128h256v-128h-256zM640 128v128h384v-128h-384z" /> + <glyph glyph-name="rss" unicode="" horiz-adv-x="1408" +d="M384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 69q2 -28 -17 -48q-18 -21 -47 -21h-135q-25 0 -43 16.5t-20 41.5q-22 229 -184.5 391.5t-391.5 184.5q-25 2 -41.5 20t-16.5 43v135q0 29 21 47q17 17 43 17h5q160 -13 306 -80.5 +t259 -181.5q114 -113 181.5 -259t80.5 -306zM1408 67q2 -27 -18 -47q-18 -20 -46 -20h-143q-26 0 -44.5 17.5t-19.5 42.5q-12 215 -101 408.5t-231.5 336t-336 231.5t-408.5 102q-25 1 -42.5 19.5t-17.5 43.5v143q0 28 20 46q18 18 44 18h3q262 -13 501.5 -120t425.5 -294 +q187 -186 294 -425.5t120 -501.5z" /> + <glyph glyph-name="hdd" unicode="" +d="M1040 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1296 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1408 160v320q0 13 -9.5 22.5t-22.5 9.5 +h-1216q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5zM178 640h1180l-157 482q-4 13 -16 21.5t-26 8.5h-782q-14 0 -26 -8.5t-16 -21.5zM1536 480v-320q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v320q0 25 16 75 +l197 606q17 53 63 86t101 33h782q55 0 101 -33t63 -86l197 -606q16 -50 16 -75z" /> + <glyph glyph-name="bullhorn" unicode="" horiz-adv-x="1792" +d="M1664 896q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5v-384q0 -52 -38 -90t-90 -38q-417 347 -812 380q-58 -19 -91 -66t-31 -100.5t40 -92.5q-20 -33 -23 -65.5t6 -58t33.5 -55t48 -50t61.5 -50.5q-29 -58 -111.5 -83t-168.5 -11.5t-132 55.5q-7 23 -29.5 87.5 +t-32 94.5t-23 89t-15 101t3.5 98.5t22 110.5h-122q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h480q435 0 896 384q52 0 90 -38t38 -90v-384zM1536 292v954q-394 -302 -768 -343v-270q377 -42 768 -341z" /> + <glyph glyph-name="bell" unicode="" horiz-adv-x="1792" +d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM246 128h1300q-266 300 -266 832q0 51 -24 105t-69 103t-121.5 80.5t-169.5 31.5t-169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -532 -266 -832z +M1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5 +t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" /> + <glyph glyph-name="certificate" unicode="" +d="M1376 640l138 -135q30 -28 20 -70q-12 -41 -52 -51l-188 -48l53 -186q12 -41 -19 -70q-29 -31 -70 -19l-186 53l-48 -188q-10 -40 -51 -52q-12 -2 -19 -2q-31 0 -51 22l-135 138l-135 -138q-28 -30 -70 -20q-41 11 -51 52l-48 188l-186 -53q-41 -12 -70 19q-31 29 -19 70 +l53 186l-188 48q-40 10 -52 51q-10 42 20 70l138 135l-138 135q-30 28 -20 70q12 41 52 51l188 48l-53 186q-12 41 19 70q29 31 70 19l186 -53l48 188q10 41 51 51q41 12 70 -19l135 -139l135 139q29 30 70 19q41 -10 51 -51l48 -188l186 53q41 12 70 -19q31 -29 19 -70 +l-53 -186l188 -48q40 -10 52 -51q10 -42 -20 -70z" /> + <glyph glyph-name="hand_right" unicode="" horiz-adv-x="1792" +d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 768q0 51 -39 89.5t-89 38.5h-576q0 20 15 48.5t33 55t33 68t15 84.5q0 67 -44.5 97.5t-115.5 30.5q-24 0 -90 -139q-24 -44 -37 -65q-40 -64 -112 -145q-71 -81 -101 -106 +q-69 -57 -140 -57h-32v-640h32q72 0 167 -32t193.5 -64t179.5 -32q189 0 189 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5h331q52 0 90 38t38 90zM1792 769q0 -105 -75.5 -181t-180.5 -76h-169q-4 -62 -37 -119q3 -21 3 -43 +q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5q-133 0 -322 69q-164 59 -223 59h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h288q10 0 21.5 4.5t23.5 14t22.5 18t24 22.5t20.5 21.5t19 21.5t14 17q65 74 100 129q13 21 33 62t37 72t40.5 63t55 49.5 +t69.5 17.5q125 0 206.5 -67t81.5 -189q0 -68 -22 -128h374q104 0 180 -76t76 -179z" /> + <glyph glyph-name="hand_left" unicode="" horiz-adv-x="1792" +d="M1376 128h32v640h-32q-35 0 -67.5 12t-62.5 37t-50 46t-49 54q-8 9 -12 14q-72 81 -112 145q-14 22 -38 68q-1 3 -10.5 22.5t-18.5 36t-20 35.5t-21.5 30.5t-18.5 11.5q-71 0 -115.5 -30.5t-44.5 -97.5q0 -43 15 -84.5t33 -68t33 -55t15 -48.5h-576q-50 0 -89 -38.5 +t-39 -89.5q0 -52 38 -90t90 -38h331q-15 -17 -25 -47.5t-10 -55.5q0 -69 53 -119q-18 -32 -18 -69t17.5 -73.5t47.5 -52.5q-4 -24 -4 -56q0 -85 48.5 -126t135.5 -41q84 0 183 32t194 64t167 32zM1664 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45z +M1792 768v-640q0 -53 -37.5 -90.5t-90.5 -37.5h-288q-59 0 -223 -59q-190 -69 -317 -69q-142 0 -230 77.5t-87 217.5l1 5q-61 76 -61 178q0 22 3 43q-33 57 -37 119h-169q-105 0 -180.5 76t-75.5 181q0 103 76 179t180 76h374q-22 60 -22 128q0 122 81.5 189t206.5 67 +q38 0 69.5 -17.5t55 -49.5t40.5 -63t37 -72t33 -62q35 -55 100 -129q2 -3 14 -17t19 -21.5t20.5 -21.5t24 -22.5t22.5 -18t23.5 -14t21.5 -4.5h288q53 0 90.5 -37.5t37.5 -90.5z" /> + <glyph glyph-name="hand_up" unicode="" +d="M1280 -64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 700q0 189 -167 189q-26 0 -56 -5q-16 30 -52.5 47.5t-73.5 17.5t-69 -18q-50 53 -119 53q-25 0 -55.5 -10t-47.5 -25v331q0 52 -38 90t-90 38q-51 0 -89.5 -39t-38.5 -89v-576 +q-20 0 -48.5 15t-55 33t-68 33t-84.5 15q-67 0 -97.5 -44.5t-30.5 -115.5q0 -24 139 -90q44 -24 65 -37q64 -40 145 -112q81 -71 106 -101q57 -69 57 -140v-32h640v32q0 72 32 167t64 193.5t32 179.5zM1536 705q0 -133 -69 -322q-59 -164 -59 -223v-288q0 -53 -37.5 -90.5 +t-90.5 -37.5h-640q-53 0 -90.5 37.5t-37.5 90.5v288q0 10 -4.5 21.5t-14 23.5t-18 22.5t-22.5 24t-21.5 20.5t-21.5 19t-17 14q-74 65 -129 100q-21 13 -62 33t-72 37t-63 40.5t-49.5 55t-17.5 69.5q0 125 67 206.5t189 81.5q68 0 128 -22v374q0 104 76 180t179 76 +q105 0 181 -75.5t76 -180.5v-169q62 -4 119 -37q21 3 43 3q101 0 178 -60q139 1 219.5 -85t80.5 -227z" /> + <glyph glyph-name="hand_down" unicode="" +d="M1408 576q0 84 -32 183t-64 194t-32 167v32h-640v-32q0 -35 -12 -67.5t-37 -62.5t-46 -50t-54 -49q-9 -8 -14 -12q-81 -72 -145 -112q-22 -14 -68 -38q-3 -1 -22.5 -10.5t-36 -18.5t-35.5 -20t-30.5 -21.5t-11.5 -18.5q0 -71 30.5 -115.5t97.5 -44.5q43 0 84.5 15t68 33 +t55 33t48.5 15v-576q0 -50 38.5 -89t89.5 -39q52 0 90 38t38 90v331q46 -35 103 -35q69 0 119 53q32 -18 69 -18t73.5 17.5t52.5 47.5q24 -4 56 -4q85 0 126 48.5t41 135.5zM1280 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 580 +q0 -142 -77.5 -230t-217.5 -87l-5 1q-76 -61 -178 -61q-22 0 -43 3q-54 -30 -119 -37v-169q0 -105 -76 -180.5t-181 -75.5q-103 0 -179 76t-76 180v374q-54 -22 -128 -22q-121 0 -188.5 81.5t-67.5 206.5q0 38 17.5 69.5t49.5 55t63 40.5t72 37t62 33q55 35 129 100 +q3 2 17 14t21.5 19t21.5 20.5t22.5 24t18 22.5t14 23.5t4.5 21.5v288q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-288q0 -59 59 -223q69 -190 69 -317z" /> + <glyph glyph-name="circle_arrow_left" unicode="" +d="M1280 576v128q0 26 -19 45t-45 19h-502l189 189q19 19 19 45t-19 45l-91 91q-18 18 -45 18t-45 -18l-362 -362l-91 -91q-18 -18 -18 -45t18 -45l91 -91l362 -362q18 -18 45 -18t45 18l91 91q18 18 18 45t-18 45l-189 189h502q26 0 45 19t19 45zM1536 640 +q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="circle_arrow_right" unicode="" +d="M1285 640q0 27 -18 45l-91 91l-362 362q-18 18 -45 18t-45 -18l-91 -91q-18 -18 -18 -45t18 -45l189 -189h-502q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h502l-189 -189q-19 -19 -19 -45t19 -45l91 -91q18 -18 45 -18t45 18l362 362l91 91q18 18 18 45zM1536 640 +q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="circle_arrow_up" unicode="" +d="M1284 641q0 27 -18 45l-362 362l-91 91q-18 18 -45 18t-45 -18l-91 -91l-362 -362q-18 -18 -18 -45t18 -45l91 -91q18 -18 45 -18t45 18l189 189v-502q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v502l189 -189q19 -19 45 -19t45 19l91 91q18 18 18 45zM1536 640 +q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="circle_arrow_down" unicode="" +d="M1284 639q0 27 -18 45l-91 91q-18 18 -45 18t-45 -18l-189 -189v502q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-502l-189 189q-19 19 -45 19t-45 -19l-91 -91q-18 -18 -18 -45t18 -45l362 -362l91 -91q18 -18 45 -18t45 18l91 91l362 362q18 18 18 45zM1536 640 +q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="globe" unicode="" +d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1042 887q-2 -1 -9.5 -9.5t-13.5 -9.5q2 0 4.5 5t5 11t3.5 7q6 7 22 15q14 6 52 12q34 8 51 -11 +q-2 2 9.5 13t14.5 12q3 2 15 4.5t15 7.5l2 22q-12 -1 -17.5 7t-6.5 21q0 -2 -6 -8q0 7 -4.5 8t-11.5 -1t-9 -1q-10 3 -15 7.5t-8 16.5t-4 15q-2 5 -9.5 11t-9.5 10q-1 2 -2.5 5.5t-3 6.5t-4 5.5t-5.5 2.5t-7 -5t-7.5 -10t-4.5 -5q-3 2 -6 1.5t-4.5 -1t-4.5 -3t-5 -3.5 +q-3 -2 -8.5 -3t-8.5 -2q15 5 -1 11q-10 4 -16 3q9 4 7.5 12t-8.5 14h5q-1 4 -8.5 8.5t-17.5 8.5t-13 6q-8 5 -34 9.5t-33 0.5q-5 -6 -4.5 -10.5t4 -14t3.5 -12.5q1 -6 -5.5 -13t-6.5 -12q0 -7 14 -15.5t10 -21.5q-3 -8 -16 -16t-16 -12q-5 -8 -1.5 -18.5t10.5 -16.5 +q2 -2 1.5 -4t-3.5 -4.5t-5.5 -4t-6.5 -3.5l-3 -2q-11 -5 -20.5 6t-13.5 26q-7 25 -16 30q-23 8 -29 -1q-5 13 -41 26q-25 9 -58 4q6 1 0 15q-7 15 -19 12q3 6 4 17.5t1 13.5q3 13 12 23q1 1 7 8.5t9.5 13.5t0.5 6q35 -4 50 11q5 5 11.5 17t10.5 17q9 6 14 5.5t14.5 -5.5 +t14.5 -5q14 -1 15.5 11t-7.5 20q12 -1 3 17q-4 7 -8 9q-12 4 -27 -5q-8 -4 2 -8q-1 1 -9.5 -10.5t-16.5 -17.5t-16 5q-1 1 -5.5 13.5t-9.5 13.5q-8 0 -16 -15q3 8 -11 15t-24 8q19 12 -8 27q-7 4 -20.5 5t-19.5 -4q-5 -7 -5.5 -11.5t5 -8t10.5 -5.5t11.5 -4t8.5 -3 +q14 -10 8 -14q-2 -1 -8.5 -3.5t-11.5 -4.5t-6 -4q-3 -4 0 -14t-2 -14q-5 5 -9 17.5t-7 16.5q7 -9 -25 -6l-10 1q-4 0 -16 -2t-20.5 -1t-13.5 8q-4 8 0 20q1 4 4 2q-4 3 -11 9.5t-10 8.5q-46 -15 -94 -41q6 -1 12 1q5 2 13 6.5t10 5.5q34 14 42 7l5 5q14 -16 20 -25 +q-7 4 -30 1q-20 -6 -22 -12q7 -12 5 -18q-4 3 -11.5 10t-14.5 11t-15 5q-16 0 -22 -1q-146 -80 -235 -222q7 -7 12 -8q4 -1 5 -9t2.5 -11t11.5 3q9 -8 3 -19q1 1 44 -27q19 -17 21 -21q3 -11 -10 -18q-1 2 -9 9t-9 4q-3 -5 0.5 -18.5t10.5 -12.5q-7 0 -9.5 -16t-2.5 -35.5 +t-1 -23.5l2 -1q-3 -12 5.5 -34.5t21.5 -19.5q-13 -3 20 -43q6 -8 8 -9q3 -2 12 -7.5t15 -10t10 -10.5q4 -5 10 -22.5t14 -23.5q-2 -6 9.5 -20t10.5 -23q-1 0 -2.5 -1t-2.5 -1q3 -7 15.5 -14t15.5 -13q1 -3 2 -10t3 -11t8 -2q2 20 -24 62q-15 25 -17 29q-3 5 -5.5 15.5 +t-4.5 14.5q2 0 6 -1.5t8.5 -3.5t7.5 -4t2 -3q-3 -7 2 -17.5t12 -18.5t17 -19t12 -13q6 -6 14 -19.5t0 -13.5q9 0 20 -10.5t17 -19.5q5 -8 8 -26t5 -24q2 -7 8.5 -13.5t12.5 -9.5l16 -8t13 -7q5 -2 18.5 -10.5t21.5 -11.5q10 -4 16 -4t14.5 2.5t13.5 3.5q15 2 29 -15t21 -21 +q36 -19 55 -11q-2 -1 0.5 -7.5t8 -15.5t9 -14.5t5.5 -8.5q5 -6 18 -15t18 -15q6 4 7 9q-3 -8 7 -20t18 -10q14 3 14 32q-31 -15 -49 18q0 1 -2.5 5.5t-4 8.5t-2.5 8.5t0 7.5t5 3q9 0 10 3.5t-2 12.5t-4 13q-1 8 -11 20t-12 15q-5 -9 -16 -8t-16 9q0 -1 -1.5 -5.5t-1.5 -6.5 +q-13 0 -15 1q1 3 2.5 17.5t3.5 22.5q1 4 5.5 12t7.5 14.5t4 12.5t-4.5 9.5t-17.5 2.5q-19 -1 -26 -20q-1 -3 -3 -10.5t-5 -11.5t-9 -7q-7 -3 -24 -2t-24 5q-13 8 -22.5 29t-9.5 37q0 10 2.5 26.5t3 25t-5.5 24.5q3 2 9 9.5t10 10.5q2 1 4.5 1.5t4.5 0t4 1.5t3 6q-1 1 -4 3 +q-3 3 -4 3q7 -3 28.5 1.5t27.5 -1.5q15 -11 22 2q0 1 -2.5 9.5t-0.5 13.5q5 -27 29 -9q3 -3 15.5 -5t17.5 -5q3 -2 7 -5.5t5.5 -4.5t5 0.5t8.5 6.5q10 -14 12 -24q11 -40 19 -44q7 -3 11 -2t4.5 9.5t0 14t-1.5 12.5l-1 8v18l-1 8q-15 3 -18.5 12t1.5 18.5t15 18.5q1 1 8 3.5 +t15.5 6.5t12.5 8q21 19 15 35q7 0 11 9q-1 0 -5 3t-7.5 5t-4.5 2q9 5 2 16q5 3 7.5 11t7.5 10q9 -12 21 -2q8 8 1 16q5 7 20.5 10.5t18.5 9.5q7 -2 8 2t1 12t3 12q4 5 15 9t13 5l17 11q3 4 0 4q18 -2 31 11q10 11 -6 20q3 6 -3 9.5t-15 5.5q3 1 11.5 0.5t10.5 1.5 +q15 10 -7 16q-17 5 -43 -12zM879 10q206 36 351 189q-3 3 -12.5 4.5t-12.5 3.5q-18 7 -24 8q1 7 -2.5 13t-8 9t-12.5 8t-11 7q-2 2 -7 6t-7 5.5t-7.5 4.5t-8.5 2t-10 -1l-3 -1q-3 -1 -5.5 -2.5t-5.5 -3t-4 -3t0 -2.5q-21 17 -36 22q-5 1 -11 5.5t-10.5 7t-10 1.5t-11.5 -7 +q-5 -5 -6 -15t-2 -13q-7 5 0 17.5t2 18.5q-3 6 -10.5 4.5t-12 -4.5t-11.5 -8.5t-9 -6.5t-8.5 -5.5t-8.5 -7.5q-3 -4 -6 -12t-5 -11q-2 4 -11.5 6.5t-9.5 5.5q2 -10 4 -35t5 -38q7 -31 -12 -48q-27 -25 -29 -40q-4 -22 12 -26q0 -7 -8 -20.5t-7 -21.5q0 -6 2 -16z" /> + <glyph glyph-name="wrench" unicode="" horiz-adv-x="1664" +d="M384 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1028 484l-682 -682q-37 -37 -90 -37q-52 0 -91 37l-106 108q-38 36 -38 90q0 53 38 91l681 681q39 -98 114.5 -173.5t173.5 -114.5zM1662 919q0 -39 -23 -106q-47 -134 -164.5 -217.5 +t-258.5 -83.5q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q58 0 121.5 -16.5t107.5 -46.5q16 -11 16 -28t-16 -28l-293 -169v-224l193 -107q5 3 79 48.5t135.5 81t70.5 35.5q15 0 23.5 -10t8.5 -25z" /> + <glyph glyph-name="tasks" unicode="" horiz-adv-x="1792" +d="M1024 128h640v128h-640v-128zM640 640h1024v128h-1024v-128zM1280 1152h384v128h-384v-128zM1792 320v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 832v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19 +t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" /> + <glyph glyph-name="filter" unicode="" horiz-adv-x="1408" +d="M1403 1241q17 -41 -14 -70l-493 -493v-742q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-256 256q-19 19 -19 45v486l-493 493q-31 29 -14 70q17 39 59 39h1280q42 0 59 -39z" /> + <glyph glyph-name="briefcase" unicode="" horiz-adv-x="1792" +d="M640 1280h512v128h-512v-128zM1792 640v-480q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v480h672v-160q0 -26 19 -45t45 -19h320q26 0 45 19t19 45v160h672zM1024 640v-128h-256v128h256zM1792 1120v-384h-1792v384q0 66 47 113t113 47h352v160q0 40 28 68 +t68 28h576q40 0 68 -28t28 -68v-160h352q66 0 113 -47t47 -113z" /> + <glyph glyph-name="fullscreen" unicode="" +d="M1283 995l-355 -355l355 -355l144 144q29 31 70 14q39 -17 39 -59v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l144 144l-355 355l-355 -355l144 -144q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l144 -144 +l355 355l-355 355l-144 -144q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v448q0 26 19 45t45 19h448q42 0 59 -40q17 -39 -14 -69l-144 -144l355 -355l355 355l-144 144q-31 30 -14 69q17 40 59 40h448q26 0 45 -19t19 -45v-448q0 -42 -39 -59q-13 -5 -25 -5q-26 0 -45 19z +" /> + <glyph glyph-name="group" unicode="" horiz-adv-x="1920" +d="M593 640q-162 -5 -265 -128h-134q-82 0 -138 40.5t-56 118.5q0 353 124 353q6 0 43.5 -21t97.5 -42.5t119 -21.5q67 0 133 23q-5 -37 -5 -66q0 -139 81 -256zM1664 3q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5 +t43 97.5t62 81t85.5 53.5t111.5 20q10 0 43 -21.5t73 -48t107 -48t135 -21.5t135 21.5t107 48t73 48t43 21.5q61 0 111.5 -20t85.5 -53.5t62 -81t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM640 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75 +t75 -181zM1344 896q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5zM1920 671q0 -78 -56 -118.5t-138 -40.5h-134q-103 123 -265 128q81 117 81 256q0 29 -5 66q66 -23 133 -23q59 0 119 21.5t97.5 42.5 +t43.5 21q124 0 124 -353zM1792 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181z" /> + <glyph glyph-name="link" unicode="" horiz-adv-x="1664" +d="M1456 320q0 40 -28 68l-208 208q-28 28 -68 28q-42 0 -72 -32q3 -3 19 -18.5t21.5 -21.5t15 -19t13 -25.5t3.5 -27.5q0 -40 -28 -68t-68 -28q-15 0 -27.5 3.5t-25.5 13t-19 15t-21.5 21.5t-18.5 19q-33 -31 -33 -73q0 -40 28 -68l206 -207q27 -27 68 -27q40 0 68 26 +l147 146q28 28 28 67zM753 1025q0 40 -28 68l-206 207q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l208 -208q27 -27 68 -27q42 0 72 31q-3 3 -19 18.5t-21.5 21.5t-15 19t-13 25.5t-3.5 27.5q0 40 28 68t68 28q15 0 27.5 -3.5t25.5 -13t19 -15 +t21.5 -21.5t18.5 -19q33 31 33 73zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-206 207q-83 83 -83 203q0 123 88 209l-88 88q-86 -88 -208 -88q-120 0 -204 84l-208 208q-84 84 -84 204t85 203l147 146q83 83 203 83q121 0 204 -85l206 -207 +q83 -83 83 -203q0 -123 -88 -209l88 -88q86 88 208 88q120 0 204 -84l208 -208q84 -84 84 -204z" /> + <glyph glyph-name="cloud" unicode="" horiz-adv-x="1920" +d="M1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088q-185 0 -316.5 131.5t-131.5 316.5q0 132 71 241.5t187 163.5q-2 28 -2 43q0 212 150 362t362 150q158 0 286.5 -88t187.5 -230q70 62 166 62q106 0 181 -75t75 -181q0 -75 -41 -138q129 -30 213 -134.5t84 -239.5z +" /> + <glyph glyph-name="beaker" unicode="" horiz-adv-x="1664" +d="M1527 88q56 -89 21.5 -152.5t-140.5 -63.5h-1152q-106 0 -140.5 63.5t21.5 152.5l503 793v399h-64q-26 0 -45 19t-19 45t19 45t45 19h512q26 0 45 -19t19 -45t-19 -45t-45 -19h-64v-399zM748 813l-272 -429h712l-272 429l-20 31v37v399h-128v-399v-37z" /> + <glyph glyph-name="cut" unicode="" horiz-adv-x="1792" +d="M960 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1260 576l507 -398q28 -20 25 -56q-5 -35 -35 -51l-128 -64q-13 -7 -29 -7q-17 0 -31 8l-690 387l-110 -66q-8 -4 -12 -5q14 -49 10 -97q-7 -77 -56 -147.5t-132 -123.5q-132 -84 -277 -84 +q-136 0 -222 78q-90 84 -79 207q7 76 56 147t131 124q132 84 278 84q83 0 151 -31q9 13 22 22l122 73l-122 73q-13 9 -22 22q-68 -31 -151 -31q-146 0 -278 84q-82 53 -131 124t-56 147q-5 59 15.5 113t63.5 93q85 79 222 79q145 0 277 -84q83 -52 132 -123t56 -148 +q4 -48 -10 -97q4 -1 12 -5l110 -66l690 387q14 8 31 8q16 0 29 -7l128 -64q30 -16 35 -51q3 -36 -25 -56zM579 836q46 42 21 108t-106 117q-92 59 -192 59q-74 0 -113 -36q-46 -42 -21 -108t106 -117q92 -59 192 -59q74 0 113 36zM494 91q81 51 106 117t-21 108 +q-39 36 -113 36q-100 0 -192 -59q-81 -51 -106 -117t21 -108q39 -36 113 -36q100 0 192 59zM672 704l96 -58v11q0 36 33 56l14 8l-79 47l-26 -26q-3 -3 -10 -11t-12 -12q-2 -2 -4 -3.5t-3 -2.5zM896 480l96 -32l736 576l-128 64l-768 -431v-113l-160 -96l9 -8q2 -2 7 -6 +q4 -4 11 -12t11 -12l26 -26zM1600 64l128 64l-520 408l-177 -138q-2 -3 -13 -7z" /> + <glyph glyph-name="copy" unicode="" horiz-adv-x="1792" +d="M1696 1152q40 0 68 -28t28 -68v-1216q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v288h-544q-40 0 -68 28t-28 68v672q0 40 20 88t48 76l408 408q28 28 76 48t88 20h416q40 0 68 -28t28 -68v-328q68 40 128 40h416zM1152 939l-299 -299h299v299zM512 1323l-299 -299 +h299v299zM708 676l316 316v416h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h512v256q0 40 20 88t48 76zM1664 -128v1152h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h896z" /> + <glyph glyph-name="paper_clip" unicode="" horiz-adv-x="1408" +d="M1404 151q0 -117 -79 -196t-196 -79q-135 0 -235 100l-777 776q-113 115 -113 271q0 159 110 270t269 111q158 0 273 -113l605 -606q10 -10 10 -22q0 -16 -30.5 -46.5t-46.5 -30.5q-13 0 -23 10l-606 607q-79 77 -181 77q-106 0 -179 -75t-73 -181q0 -105 76 -181 +l776 -777q63 -63 145 -63q64 0 106 42t42 106q0 82 -63 145l-581 581q-26 24 -60 24q-29 0 -48 -19t-19 -48q0 -32 25 -59l410 -410q10 -10 10 -22q0 -16 -31 -47t-47 -31q-12 0 -22 10l-410 410q-63 61 -63 149q0 82 57 139t139 57q88 0 149 -63l581 -581q100 -98 100 -235 +z" /> + <glyph glyph-name="save" unicode="" +d="M384 0h768v384h-768v-384zM1280 0h128v896q0 14 -10 38.5t-20 34.5l-281 281q-10 10 -34 20t-39 10v-416q0 -40 -28 -68t-68 -28h-576q-40 0 -68 28t-28 68v416h-128v-1280h128v416q0 40 28 68t68 28h832q40 0 68 -28t28 -68v-416zM896 928v320q0 13 -9.5 22.5t-22.5 9.5 +h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5zM1536 896v-928q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h928q40 0 88 -20t76 -48l280 -280q28 -28 48 -76t20 -88z" /> + <glyph glyph-name="sign_blank" unicode="" +d="M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="reorder" unicode="" +d="M1536 192v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 704v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 1216v-128q0 -26 -19 -45 +t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" /> + <glyph glyph-name="ul" unicode="" horiz-adv-x="1792" +d="M384 128q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 640q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 +t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1152q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z +M1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" /> + <glyph glyph-name="ol" unicode="" horiz-adv-x="1792" +d="M381 -84q0 -80 -54.5 -126t-135.5 -46q-106 0 -172 66l57 88q49 -45 106 -45q29 0 50.5 14.5t21.5 42.5q0 64 -105 56l-26 56q8 10 32.5 43.5t42.5 54t37 38.5v1q-16 0 -48.5 -1t-48.5 -1v-53h-106v152h333v-88l-95 -115q51 -12 81 -49t30 -88zM383 543v-159h-362 +q-6 36 -6 54q0 51 23.5 93t56.5 68t66 47.5t56.5 43.5t23.5 45q0 25 -14.5 38.5t-39.5 13.5q-46 0 -81 -58l-85 59q24 51 71.5 79.5t105.5 28.5q73 0 123 -41.5t50 -112.5q0 -50 -34 -91.5t-75 -64.5t-75.5 -50.5t-35.5 -52.5h127v60h105zM1792 224v-192q0 -13 -9.5 -22.5 +t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1123v-99h-335v99h107q0 41 0.5 121.5t0.5 121.5v12h-2q-8 -17 -50 -54l-71 76l136 127h106v-404h108zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216 +q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" /> + <glyph glyph-name="strikethrough" unicode="" horiz-adv-x="1792" +d="M1760 640q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h1728zM483 704q-28 35 -51 80q-48 98 -48 188q0 181 134 309q133 127 393 127q50 0 167 -19q66 -12 177 -48q10 -38 21 -118q14 -123 14 -183q0 -18 -5 -45l-12 -3l-84 6 +l-14 2q-50 149 -103 205q-88 91 -210 91q-114 0 -182 -59q-67 -58 -67 -146q0 -73 66 -140t279 -129q69 -20 173 -66q58 -28 95 -52h-743zM990 448h411q7 -39 7 -92q0 -111 -41 -212q-23 -56 -71 -104q-37 -35 -109 -81q-80 -48 -153 -66q-80 -21 -203 -21q-114 0 -195 23 +l-140 40q-57 16 -72 28q-8 8 -8 22v13q0 108 -2 156q-1 30 0 68l2 37v44l102 2q15 -34 30 -71t22.5 -56t12.5 -27q35 -57 80 -94q43 -36 105 -57q59 -22 132 -22q64 0 139 27q77 26 122 86q47 61 47 129q0 84 -81 157q-34 29 -137 71z" /> + <glyph glyph-name="underline" unicode="" +d="M48 1313q-37 2 -45 4l-3 88q13 1 40 1q60 0 112 -4q132 -7 166 -7q86 0 168 3q116 4 146 5q56 0 86 2l-1 -14l2 -64v-9q-60 -9 -124 -9q-60 0 -79 -25q-13 -14 -13 -132q0 -13 0.5 -32.5t0.5 -25.5l1 -229l14 -280q6 -124 51 -202q35 -59 96 -92q88 -47 177 -47 +q104 0 191 28q56 18 99 51q48 36 65 64q36 56 53 114q21 73 21 229q0 79 -3.5 128t-11 122.5t-13.5 159.5l-4 59q-5 67 -24 88q-34 35 -77 34l-100 -2l-14 3l2 86h84l205 -10q76 -3 196 10l18 -2q6 -38 6 -51q0 -7 -4 -31q-45 -12 -84 -13q-73 -11 -79 -17q-15 -15 -15 -41 +q0 -7 1.5 -27t1.5 -31q8 -19 22 -396q6 -195 -15 -304q-15 -76 -41 -122q-38 -65 -112 -123q-75 -57 -182 -89q-109 -33 -255 -33q-167 0 -284 46q-119 47 -179 122q-61 76 -83 195q-16 80 -16 237v333q0 188 -17 213q-25 36 -147 39zM1536 -96v64q0 14 -9 23t-23 9h-1472 +q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h1472q14 0 23 9t9 23z" /> + <glyph glyph-name="table" unicode="" horiz-adv-x="1664" +d="M512 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23 +v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 160v192 +q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192 +q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1664 1248v-1088q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1344q66 0 113 -47t47 -113 +z" /> + <glyph glyph-name="magic" unicode="" horiz-adv-x="1664" +d="M1190 955l293 293l-107 107l-293 -293zM1637 1248q0 -27 -18 -45l-1286 -1286q-18 -18 -45 -18t-45 18l-198 198q-18 18 -18 45t18 45l1286 1286q18 18 45 18t45 -18l198 -198q18 -18 18 -45zM286 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM636 1276 +l196 -60l-196 -60l-60 -196l-60 196l-196 60l196 60l60 196zM1566 798l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM926 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98z" /> + <glyph glyph-name="truck" unicode="" horiz-adv-x="1792" +d="M640 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM256 640h384v256h-158q-13 0 -22 -9l-195 -195q-9 -9 -9 -22v-30zM1536 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1792 1216v-1024q0 -15 -4 -26.5t-13.5 -18.5 +t-16.5 -11.5t-23.5 -6t-22.5 -2t-25.5 0t-22.5 0.5q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-64q-3 0 -22.5 -0.5t-25.5 0t-22.5 2t-23.5 6t-16.5 11.5t-13.5 18.5t-4 26.5q0 26 19 45t45 19v320q0 8 -0.5 35t0 38 +t2.5 34.5t6.5 37t14 30.5t22.5 30l198 198q19 19 50.5 32t58.5 13h160v192q0 26 19 45t45 19h1024q26 0 45 -19t19 -45z" /> + <glyph glyph-name="pinterest" unicode="" +d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103q-111 0 -218 32q59 93 78 164q9 34 54 211q20 -39 73 -67.5t114 -28.5q121 0 216 68.5t147 188.5t52 270q0 114 -59.5 214t-172.5 163t-255 63q-105 0 -196 -29t-154.5 -77t-109 -110.5t-67 -129.5t-21.5 -134 +q0 -104 40 -183t117 -111q30 -12 38 20q2 7 8 31t8 30q6 23 -11 43q-51 61 -51 151q0 151 104.5 259.5t273.5 108.5q151 0 235.5 -82t84.5 -213q0 -170 -68.5 -289t-175.5 -119q-61 0 -98 43.5t-23 104.5q8 35 26.5 93.5t30 103t11.5 75.5q0 50 -27 83t-77 33 +q-62 0 -105 -57t-43 -142q0 -73 25 -122l-99 -418q-17 -70 -13 -177q-206 91 -333 281t-127 423q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="pinterest_sign" unicode="" +d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-725q85 122 108 210q9 34 53 209q21 -39 73.5 -67t112.5 -28q181 0 295.5 147.5t114.5 373.5q0 84 -35 162.5t-96.5 139t-152.5 97t-197 36.5q-104 0 -194.5 -28.5t-153 -76.5 +t-107.5 -109.5t-66.5 -128t-21.5 -132.5q0 -102 39.5 -180t116.5 -110q13 -5 23.5 0t14.5 19q10 44 15 61q6 23 -11 42q-50 62 -50 150q0 150 103.5 256.5t270.5 106.5q149 0 232.5 -81t83.5 -210q0 -168 -67.5 -286t-173.5 -118q-60 0 -97 43.5t-23 103.5q8 34 26.5 92.5 +t29.5 102t11 74.5q0 49 -26.5 81.5t-75.5 32.5q-61 0 -103.5 -56.5t-42.5 -139.5q0 -72 24 -121l-98 -414q-24 -100 -7 -254h-183q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960z" /> + <glyph glyph-name="google_plus_sign" unicode="" +d="M917 631q0 26 -6 64h-362v-132h217q-3 -24 -16.5 -50t-37.5 -53t-66.5 -44.5t-96.5 -17.5q-99 0 -169 71t-70 171t70 171t169 71q92 0 153 -59l104 101q-108 100 -257 100q-160 0 -272 -112.5t-112 -271.5t112 -271.5t272 -112.5q165 0 266.5 105t101.5 270zM1262 585 +h109v110h-109v110h-110v-110h-110v-110h110v-110h110v110zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="google_plus" unicode="" horiz-adv-x="2304" +d="M1437 623q0 -208 -87 -370.5t-248 -254t-369 -91.5q-149 0 -285 58t-234 156t-156 234t-58 285t58 285t156 234t234 156t285 58q286 0 491 -192l-199 -191q-117 113 -292 113q-123 0 -227.5 -62t-165.5 -168.5t-61 -232.5t61 -232.5t165.5 -168.5t227.5 -62 +q83 0 152.5 23t114.5 57.5t78.5 78.5t49 83t21.5 74h-416v252h692q12 -63 12 -122zM2304 745v-210h-209v-209h-210v209h-209v210h209v209h210v-209h209z" /> + <glyph glyph-name="money" unicode="" horiz-adv-x="1920" +d="M768 384h384v96h-128v448h-114l-148 -137l77 -80q42 37 55 57h2v-288h-128v-96zM1280 640q0 -70 -21 -142t-59.5 -134t-101.5 -101t-138 -39t-138 39t-101.5 101t-59.5 134t-21 142t21 142t59.5 134t101.5 101t138 39t138 -39t101.5 -101t59.5 -134t21 -142zM1792 384 +v512q-106 0 -181 75t-75 181h-1152q0 -106 -75 -181t-181 -75v-512q106 0 181 -75t75 -181h1152q0 106 75 181t181 75zM1920 1216v-1152q0 -26 -19 -45t-45 -19h-1792q-26 0 -45 19t-19 45v1152q0 26 19 45t45 19h1792q26 0 45 -19t19 -45z" /> + <glyph glyph-name="caret_down" unicode="" horiz-adv-x="1024" +d="M1024 832q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" /> + <glyph glyph-name="caret_up" unicode="" horiz-adv-x="1024" +d="M1024 320q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" /> + <glyph glyph-name="caret_left" unicode="" horiz-adv-x="640" +d="M640 1088v-896q0 -26 -19 -45t-45 -19t-45 19l-448 448q-19 19 -19 45t19 45l448 448q19 19 45 19t45 -19t19 -45z" /> + <glyph glyph-name="caret_right" unicode="" horiz-adv-x="640" +d="M576 640q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19t-19 45v896q0 26 19 45t45 19t45 -19l448 -448q19 -19 19 -45z" /> + <glyph glyph-name="columns" unicode="" horiz-adv-x="1664" +d="M160 0h608v1152h-640v-1120q0 -13 9.5 -22.5t22.5 -9.5zM1536 32v1120h-640v-1152h608q13 0 22.5 9.5t9.5 22.5zM1664 1248v-1216q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1344q66 0 113 -47t47 -113z" /> + <glyph glyph-name="sort" unicode="" horiz-adv-x="1024" +d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45zM1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" /> + <glyph glyph-name="sort_down" unicode="" horiz-adv-x="1024" +d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" /> + <glyph glyph-name="sort_up" unicode="" horiz-adv-x="1024" +d="M1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" /> + <glyph glyph-name="envelope_alt" unicode="" horiz-adv-x="1792" +d="M1792 826v-794q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v794q44 -49 101 -87q362 -246 497 -345q57 -42 92.5 -65.5t94.5 -48t110 -24.5h1h1q51 0 110 24.5t94.5 48t92.5 65.5q170 123 498 345q57 39 100 87zM1792 1120q0 -79 -49 -151t-122 -123 +q-376 -261 -468 -325q-10 -7 -42.5 -30.5t-54 -38t-52 -32.5t-57.5 -27t-50 -9h-1h-1q-23 0 -50 9t-57.5 27t-52 32.5t-54 38t-42.5 30.5q-91 64 -262 182.5t-205 142.5q-62 42 -117 115.5t-55 136.5q0 78 41.5 130t118.5 52h1472q65 0 112.5 -47t47.5 -113z" /> + <glyph glyph-name="linkedin" unicode="" +d="M349 911v-991h-330v991h330zM370 1217q1 -73 -50.5 -122t-135.5 -49h-2q-82 0 -132 49t-50 122q0 74 51.5 122.5t134.5 48.5t133 -48.5t51 -122.5zM1536 488v-568h-329v530q0 105 -40.5 164.5t-126.5 59.5q-63 0 -105.5 -34.5t-63.5 -85.5q-11 -30 -11 -81v-553h-329 +q2 399 2 647t-1 296l-1 48h329v-144h-2q20 32 41 56t56.5 52t87 43.5t114.5 15.5q171 0 275 -113.5t104 -332.5z" /> + <glyph glyph-name="undo" unicode="" +d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 +t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298z" /> + <glyph glyph-name="legal" unicode="" horiz-adv-x="1792" +d="M1771 0q0 -53 -37 -90l-107 -108q-39 -37 -91 -37q-53 0 -90 37l-363 364q-38 36 -38 90q0 53 43 96l-256 256l-126 -126q-14 -14 -34 -14t-34 14q2 -2 12.5 -12t12.5 -13t10 -11.5t10 -13.5t6 -13.5t5.5 -16.5t1.5 -18q0 -38 -28 -68q-3 -3 -16.5 -18t-19 -20.5 +t-18.5 -16.5t-22 -15.5t-22 -9t-26 -4.5q-40 0 -68 28l-408 408q-28 28 -28 68q0 13 4.5 26t9 22t15.5 22t16.5 18.5t20.5 19t18 16.5q30 28 68 28q10 0 18 -1.5t16.5 -5.5t13.5 -6t13.5 -10t11.5 -10t13 -12.5t12 -12.5q-14 14 -14 34t14 34l348 348q14 14 34 14t34 -14 +q-2 2 -12.5 12t-12.5 13t-10 11.5t-10 13.5t-6 13.5t-5.5 16.5t-1.5 18q0 38 28 68q3 3 16.5 18t19 20.5t18.5 16.5t22 15.5t22 9t26 4.5q40 0 68 -28l408 -408q28 -28 28 -68q0 -13 -4.5 -26t-9 -22t-15.5 -22t-16.5 -18.5t-20.5 -19t-18 -16.5q-30 -28 -68 -28 +q-10 0 -18 1.5t-16.5 5.5t-13.5 6t-13.5 10t-11.5 10t-13 12.5t-12 12.5q14 -14 14 -34t-14 -34l-126 -126l256 -256q43 43 96 43q52 0 91 -37l363 -363q37 -39 37 -91z" /> + <glyph glyph-name="dashboard" unicode="" horiz-adv-x="1792" +d="M384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM576 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1004 351l101 382q6 26 -7.5 48.5t-38.5 29.5 +t-48 -6.5t-30 -39.5l-101 -382q-60 -5 -107 -43.5t-63 -98.5q-20 -77 20 -146t117 -89t146 20t89 117q16 60 -6 117t-72 91zM1664 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 1024q0 53 -37.5 90.5 +t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1472 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 384q0 -261 -141 -483q-19 -29 -54 -29h-1402q-35 0 -54 29 +q-141 221 -141 483q0 182 71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="comment_alt" unicode="" horiz-adv-x="1792" +d="M896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640 +q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 174 120 321.5 +t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" /> + <glyph glyph-name="comments_alt" unicode="" horiz-adv-x="1792" +d="M704 1152q-153 0 -286 -52t-211.5 -141t-78.5 -191q0 -82 53 -158t149 -132l97 -56l-35 -84q34 20 62 39l44 31l53 -10q78 -14 153 -14q153 0 286 52t211.5 141t78.5 191t-78.5 191t-211.5 141t-286 52zM704 1280q191 0 353.5 -68.5t256.5 -186.5t94 -257t-94 -257 +t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224q0 139 94 257t256.5 186.5 +t353.5 68.5zM1526 111q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129 +q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230q0 -120 -71 -224.5t-195 -176.5z" /> + <glyph glyph-name="bolt" unicode="" horiz-adv-x="896" +d="M885 970q18 -20 7 -44l-540 -1157q-13 -25 -42 -25q-4 0 -14 2q-17 5 -25.5 19t-4.5 30l197 808l-406 -101q-4 -1 -12 -1q-18 0 -31 11q-18 15 -13 39l201 825q4 14 16 23t28 9h328q19 0 32 -12.5t13 -29.5q0 -8 -5 -18l-171 -463l396 98q8 2 12 2q19 0 34 -15z" /> + <glyph glyph-name="sitemap" unicode="" horiz-adv-x="1792" +d="M1792 288v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320 +q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192q0 52 38 90t90 38h512v192h-96q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h320q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-96v-192h512q52 0 90 -38t38 -90v-192h96q40 0 68 -28t28 -68 +z" /> + <glyph glyph-name="umbrella" unicode="" horiz-adv-x="1664" +d="M896 708v-580q0 -104 -76 -180t-180 -76t-180 76t-76 180q0 26 19 45t45 19t45 -19t19 -45q0 -50 39 -89t89 -39t89 39t39 89v580q33 11 64 11t64 -11zM1664 681q0 -13 -9.5 -22.5t-22.5 -9.5q-11 0 -23 10q-49 46 -93 69t-102 23q-68 0 -128 -37t-103 -97 +q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -28 -17q-18 0 -29 17q-4 6 -14.5 24t-17.5 28q-43 60 -102.5 97t-127.5 37t-127.5 -37t-102.5 -97q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -29 -17q-17 0 -28 17q-4 6 -14.5 24t-17.5 28q-43 60 -103 97t-128 37q-58 0 -102 -23t-93 -69 +q-12 -10 -23 -10q-13 0 -22.5 9.5t-9.5 22.5q0 5 1 7q45 183 172.5 319.5t298 204.5t360.5 68q140 0 274.5 -40t246.5 -113.5t194.5 -187t115.5 -251.5q1 -2 1 -7zM896 1408v-98q-42 2 -64 2t-64 -2v98q0 26 19 45t45 19t45 -19t19 -45z" /> + <glyph glyph-name="paste" unicode="" horiz-adv-x="1792" +d="M768 -128h896v640h-416q-40 0 -68 28t-28 68v416h-384v-1152zM1024 1312v64q0 13 -9.5 22.5t-22.5 9.5h-704q-13 0 -22.5 -9.5t-9.5 -22.5v-64q0 -13 9.5 -22.5t22.5 -9.5h704q13 0 22.5 9.5t9.5 22.5zM1280 640h299l-299 299v-299zM1792 512v-672q0 -40 -28 -68t-68 -28 +h-960q-40 0 -68 28t-28 68v160h-544q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1088q40 0 68 -28t28 -68v-328q21 -13 36 -28l408 -408q28 -28 48 -76t20 -88z" /> + <glyph glyph-name="light_bulb" unicode="" horiz-adv-x="1024" +d="M736 960q0 -13 -9.5 -22.5t-22.5 -9.5t-22.5 9.5t-9.5 22.5q0 46 -54 71t-106 25q-13 0 -22.5 9.5t-9.5 22.5t9.5 22.5t22.5 9.5q50 0 99.5 -16t87 -54t37.5 -90zM896 960q0 72 -34.5 134t-90 101.5t-123 62t-136.5 22.5t-136.5 -22.5t-123 -62t-90 -101.5t-34.5 -134 +q0 -101 68 -180q10 -11 30.5 -33t30.5 -33q128 -153 141 -298h228q13 145 141 298q10 11 30.5 33t30.5 33q68 79 68 180zM1024 960q0 -155 -103 -268q-45 -49 -74.5 -87t-59.5 -95.5t-34 -107.5q47 -28 47 -82q0 -37 -25 -64q25 -27 25 -64q0 -52 -45 -81q13 -23 13 -47 +q0 -46 -31.5 -71t-77.5 -25q-20 -44 -60 -70t-87 -26t-87 26t-60 70q-46 0 -77.5 25t-31.5 71q0 24 13 47q-45 29 -45 81q0 37 25 64q-25 27 -25 64q0 54 47 82q-4 50 -34 107.5t-59.5 95.5t-74.5 87q-103 113 -103 268q0 99 44.5 184.5t117 142t164 89t186.5 32.5 +t186.5 -32.5t164 -89t117 -142t44.5 -184.5z" /> + <glyph glyph-name="exchange" unicode="" horiz-adv-x="1792" +d="M1792 352v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5q-12 0 -24 10l-319 320q-9 9 -9 22q0 14 9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h1376q13 0 22.5 -9.5t9.5 -22.5zM1792 896q0 -14 -9 -23l-320 -320q-9 -9 -23 -9 +q-13 0 -22.5 9.5t-9.5 22.5v192h-1376q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1376v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" /> + <glyph glyph-name="cloud_download" unicode="" horiz-adv-x="1920" +d="M1280 608q0 14 -9 23t-23 9h-224v352q0 13 -9.5 22.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-352h-224q-13 0 -22.5 -9.5t-9.5 -22.5q0 -14 9 -23l352 -352q9 -9 23 -9t23 9l351 351q10 12 10 24zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 +q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" /> + <glyph glyph-name="cloud_upload" unicode="" horiz-adv-x="1920" +d="M1280 672q0 14 -9 23l-352 352q-9 9 -23 9t-23 -9l-351 -351q-10 -12 -10 -24q0 -14 9 -23t23 -9h224v-352q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5v352h224q13 0 22.5 9.5t9.5 22.5zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 +q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" /> + <glyph glyph-name="user_md" unicode="" horiz-adv-x="1408" +d="M384 192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 68 5.5 131t24 138t47.5 132.5t81 103t120 60.5q-22 -52 -22 -120v-203q-58 -20 -93 -70t-35 -111q0 -80 56 -136t136 -56 +t136 56t56 136q0 61 -35.5 111t-92.5 70v203q0 62 25 93q132 -104 295 -104t295 104q25 -31 25 -93v-64q-106 0 -181 -75t-75 -181v-89q-32 -29 -32 -71q0 -40 28 -68t68 -28t68 28t28 68q0 42 -32 71v89q0 52 38 90t90 38t90 -38t38 -90v-89q-32 -29 -32 -71q0 -40 28 -68 +t68 -28t68 28t28 68q0 42 -32 71v89q0 68 -34.5 127.5t-93.5 93.5q0 10 0.5 42.5t0 48t-2.5 41.5t-7 47t-13 40q68 -15 120 -60.5t81 -103t47.5 -132.5t24 -138t5.5 -131zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 +t271.5 -112.5t112.5 -271.5z" /> + <glyph glyph-name="stethoscope" unicode="" horiz-adv-x="1408" +d="M1280 832q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 832q0 -62 -35.5 -111t-92.5 -70v-395q0 -159 -131.5 -271.5t-316.5 -112.5t-316.5 112.5t-131.5 271.5v132q-164 20 -274 128t-110 252v512q0 26 19 45t45 19q6 0 16 -2q17 30 47 48 +t65 18q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5q-33 0 -64 18v-402q0 -106 94 -181t226 -75t226 75t94 181v402q-31 -18 -64 -18q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5q35 0 65 -18t47 -48q10 2 16 2q26 0 45 -19t19 -45v-512q0 -144 -110 -252 +t-274 -128v-132q0 -106 94 -181t226 -75t226 75t94 181v395q-57 21 -92.5 70t-35.5 111q0 80 56 136t136 56t136 -56t56 -136z" /> + <glyph glyph-name="suitcase" unicode="" horiz-adv-x="1792" +d="M640 1152h512v128h-512v-128zM288 1152v-1280h-64q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h64zM1408 1152v-1280h-1024v1280h128v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h128zM1792 928v-832q0 -92 -66 -158t-158 -66h-64v1280h64q92 0 158 -66 +t66 -158z" /> + <glyph glyph-name="bell_alt" unicode="" horiz-adv-x="1792" +d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5 +t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" /> + <glyph glyph-name="coffee" unicode="" horiz-adv-x="1920" +d="M1664 896q0 80 -56 136t-136 56h-64v-384h64q80 0 136 56t56 136zM0 128h1792q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181zM1856 896q0 -159 -112.5 -271.5t-271.5 -112.5h-64v-32q0 -92 -66 -158t-158 -66h-704q-92 0 -158 66t-66 158v736q0 26 19 45 +t45 19h1152q159 0 271.5 -112.5t112.5 -271.5z" /> + <glyph glyph-name="food" unicode="" horiz-adv-x="1408" +d="M640 1472v-640q0 -61 -35.5 -111t-92.5 -70v-779q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v779q-57 20 -92.5 70t-35.5 111v640q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45 +t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45zM1408 1472v-1600q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v512h-224q-13 0 -22.5 9.5t-9.5 22.5v800q0 132 94 226t226 94h256q26 0 45 -19t19 -45z" /> + <glyph glyph-name="file_text_alt" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +M384 736q0 14 9 23t23 9h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64zM1120 512q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704zM1120 256q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704 +q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704z" /> + <glyph glyph-name="building" unicode="" horiz-adv-x="1408" +d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M640 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M640 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M896 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M896 -128h384v1536h-1152v-1536h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM1408 1472v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280q26 0 45 -19t19 -45z" /> + <glyph glyph-name="hospital" unicode="" horiz-adv-x="1408" +d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M896 -128h384v1152h-256v-32q0 -40 -28 -68t-68 -28h-448q-40 0 -68 28t-28 68v32h-256v-1152h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM896 1056v320q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-96h-128v96q0 13 -9.5 22.5 +t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5v96h128v-96q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1408 1088v-1280q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1280q0 26 19 45t45 19h320 +v288q0 40 28 68t68 28h448q40 0 68 -28t28 -68v-288h320q26 0 45 -19t19 -45z" /> + <glyph glyph-name="ambulance" unicode="" horiz-adv-x="1920" +d="M640 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM256 640h384v256h-158q-14 -2 -22 -9l-195 -195q-7 -12 -9 -22v-30zM1536 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5 +t90.5 37.5t37.5 90.5zM1664 800v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM1920 1344v-1152 +q0 -26 -19 -45t-45 -19h-192q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-128q-26 0 -45 19t-19 45t19 45t45 19v416q0 26 13 58t32 51l198 198q19 19 51 32t58 13h160v320q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" /> + <glyph glyph-name="medkit" unicode="" horiz-adv-x="1792" +d="M1280 416v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM640 1152h512v128h-512v-128zM256 1152v-1280h-32 +q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h32zM1440 1152v-1280h-1088v1280h160v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h160zM1792 928v-832q0 -92 -66 -158t-158 -66h-32v1280h32q92 0 158 -66t66 -158z" /> + <glyph glyph-name="fighter_jet" unicode="" horiz-adv-x="1920" +d="M1920 576q-1 -32 -288 -96l-352 -32l-224 -64h-64l-293 -352h69q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-96h-160h-64v32h64v416h-160l-192 -224h-96l-32 32v192h32v32h128v8l-192 24v128l192 24v8h-128v32h-32v192l32 32h96l192 -224h160v416h-64v32h64h160h96 +q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-69l293 -352h64l224 -64l352 -32q128 -28 200 -52t80 -34z" /> + <glyph glyph-name="beer" unicode="" horiz-adv-x="1664" +d="M640 640v384h-256v-256q0 -53 37.5 -90.5t90.5 -37.5h128zM1664 192v-192h-1152v192l128 192h-128q-159 0 -271.5 112.5t-112.5 271.5v320l-64 64l32 128h480l32 128h960l32 -192l-64 -32v-800z" /> + <glyph glyph-name="h_sign" unicode="" +d="M1280 192v896q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-512v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-896q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h512v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1536 1120v-960 +q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="f0fe" unicode="" +d="M1280 576v128q0 26 -19 45t-45 19h-320v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-320q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h320v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h320q26 0 45 19t19 45zM1536 1120v-960 +q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="double_angle_left" unicode="" horiz-adv-x="1024" +d="M627 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23zM1011 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 +t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23z" /> + <glyph glyph-name="double_angle_right" unicode="" horiz-adv-x="1024" +d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM979 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23 +l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" /> + <glyph glyph-name="double_angle_up" unicode="" horiz-adv-x="1152" +d="M1075 224q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM1075 608q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393 +q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" /> + <glyph glyph-name="double_angle_down" unicode="" horiz-adv-x="1152" +d="M1075 672q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23zM1075 1056q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 +t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" /> + <glyph glyph-name="angle_left" unicode="" horiz-adv-x="640" +d="M627 992q0 -13 -10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" /> + <glyph glyph-name="angle_right" unicode="" horiz-adv-x="640" +d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" /> + <glyph glyph-name="angle_up" unicode="" horiz-adv-x="1152" +d="M1075 352q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" /> + <glyph glyph-name="angle_down" unicode="" horiz-adv-x="1152" +d="M1075 800q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" /> + <glyph glyph-name="desktop" unicode="" horiz-adv-x="1920" +d="M1792 544v832q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1376v-1088q0 -66 -47 -113t-113 -47h-544q0 -37 16 -77.5t32 -71t16 -43.5q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19 +t-19 45q0 14 16 44t32 70t16 78h-544q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" /> + <glyph glyph-name="laptop" unicode="" horiz-adv-x="1920" +d="M416 256q-66 0 -113 47t-47 113v704q0 66 47 113t113 47h1088q66 0 113 -47t47 -113v-704q0 -66 -47 -113t-113 -47h-1088zM384 1120v-704q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5v704q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5z +M1760 192h160v-96q0 -40 -47 -68t-113 -28h-1600q-66 0 -113 28t-47 68v96h160h1600zM1040 96q16 0 16 16t-16 16h-160q-16 0 -16 -16t16 -16h160z" /> + <glyph glyph-name="tablet" unicode="" horiz-adv-x="1152" +d="M640 128q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1024 288v960q0 13 -9.5 22.5t-22.5 9.5h-832q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h832q13 0 22.5 9.5t9.5 22.5zM1152 1248v-1088q0 -66 -47 -113t-113 -47h-832 +q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h832q66 0 113 -47t47 -113z" /> + <glyph glyph-name="mobile_phone" unicode="" horiz-adv-x="768" +d="M464 128q0 33 -23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5t56.5 23.5t23.5 56.5zM672 288v704q0 13 -9.5 22.5t-22.5 9.5h-512q-13 0 -22.5 -9.5t-9.5 -22.5v-704q0 -13 9.5 -22.5t22.5 -9.5h512q13 0 22.5 9.5t9.5 22.5zM480 1136 +q0 16 -16 16h-160q-16 0 -16 -16t16 -16h160q16 0 16 16zM768 1152v-1024q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v1024q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" /> + <glyph glyph-name="circle_blank" unicode="" +d="M768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103 +t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="quote_left" unicode="" horiz-adv-x="1664" +d="M768 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z +M1664 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z" /> + <glyph glyph-name="quote_right" unicode="" horiz-adv-x="1664" +d="M768 1216v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136zM1664 1216 +v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136z" /> + <glyph glyph-name="spinner" unicode="" horiz-adv-x="1792" +d="M526 142q0 -53 -37.5 -90.5t-90.5 -37.5q-52 0 -90 38t-38 90q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1024 -64q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM320 640q0 -53 -37.5 -90.5t-90.5 -37.5 +t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1522 142q0 -52 -38 -90t-90 -38q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM558 1138q0 -66 -47 -113t-113 -47t-113 47t-47 113t47 113t113 47t113 -47t47 -113z +M1728 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1088 1344q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1618 1138q0 -93 -66 -158.5t-158 -65.5q-93 0 -158.5 65.5t-65.5 158.5 +q0 92 65.5 158t158.5 66q92 0 158 -66t66 -158z" /> + <glyph glyph-name="circle" unicode="" +d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="reply" unicode="" horiz-adv-x="1792" +d="M1792 416q0 -166 -127 -451q-3 -7 -10.5 -24t-13.5 -30t-13 -22q-12 -17 -28 -17q-15 0 -23.5 10t-8.5 25q0 9 2.5 26.5t2.5 23.5q5 68 5 123q0 101 -17.5 181t-48.5 138.5t-80 101t-105.5 69.5t-133 42.5t-154 21.5t-175.5 6h-224v-256q0 -26 -19 -45t-45 -19t-45 19 +l-512 512q-19 19 -19 45t19 45l512 512q19 19 45 19t45 -19t19 -45v-256h224q713 0 875 -403q53 -134 53 -333z" /> + <glyph glyph-name="github_alt" unicode="" horiz-adv-x="1664" +d="M640 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1280 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1440 320 +q0 120 -69 204t-187 84q-41 0 -195 -21q-71 -11 -157 -11t-157 11q-152 21 -195 21q-118 0 -187 -84t-69 -204q0 -88 32 -153.5t81 -103t122 -60t140 -29.5t149 -7h168q82 0 149 7t140 29.5t122 60t81 103t32 153.5zM1664 496q0 -207 -61 -331q-38 -77 -105.5 -133t-141 -86 +t-170 -47.5t-171.5 -22t-167 -4.5q-78 0 -142 3t-147.5 12.5t-152.5 30t-137 51.5t-121 81t-86 115q-62 123 -62 331q0 237 136 396q-27 82 -27 170q0 116 51 218q108 0 190 -39.5t189 -123.5q147 35 309 35q148 0 280 -32q105 82 187 121t189 39q51 -102 51 -218 +q0 -87 -27 -168q136 -160 136 -398z" /> + <glyph glyph-name="folder_close_alt" unicode="" horiz-adv-x="1664" +d="M1536 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68v-960q0 -40 28 -68t68 -28h1216q40 0 68 28t28 68zM1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320 +q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" /> + <glyph glyph-name="folder_open_alt" unicode="" horiz-adv-x="1920" +d="M1781 605q0 35 -53 35h-1088q-40 0 -85.5 -21.5t-71.5 -52.5l-294 -363q-18 -24 -18 -40q0 -35 53 -35h1088q40 0 86 22t71 53l294 363q18 22 18 39zM640 768h768v160q0 40 -28 68t-68 28h-576q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68 +v-853l256 315q44 53 116 87.5t140 34.5zM1909 605q0 -62 -46 -120l-295 -363q-43 -53 -116 -87.5t-140 -34.5h-1088q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158v-160h192q54 0 99 -24.5t67 -70.5q15 -32 15 -68z +" /> + <glyph glyph-name="expand_alt" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="collapse_alt" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="smile" unicode="" +d="M1134 461q-37 -121 -138 -195t-228 -74t-228 74t-138 195q-8 25 4 48.5t38 31.5q25 8 48.5 -4t31.5 -38q25 -80 92.5 -129.5t151.5 -49.5t151.5 49.5t92.5 129.5q8 26 32 38t49 4t37 -31.5t4 -48.5zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 +t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5 +t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="frown" unicode="" +d="M1134 307q8 -25 -4 -48.5t-37 -31.5t-49 4t-32 38q-25 80 -92.5 129.5t-151.5 49.5t-151.5 -49.5t-92.5 -129.5q-8 -26 -31.5 -38t-48.5 -4q-26 8 -38 31.5t-4 48.5q37 121 138 195t228 74t228 -74t138 -195zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 +t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204 +t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="meh" unicode="" +d="M1152 448q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h640q26 0 45 -19t19 -45zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 +t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 +q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="gamepad" unicode="" horiz-adv-x="1920" +d="M832 448v128q0 14 -9 23t-23 9h-192v192q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-192h-192q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h192v-192q0 -14 9 -23t23 -9h128q14 0 23 9t9 23v192h192q14 0 23 9t9 23zM1408 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 +t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1920 512q0 -212 -150 -362t-362 -150q-192 0 -338 128h-220q-146 -128 -338 -128q-212 0 -362 150 +t-150 362t150 362t362 150h896q212 0 362 -150t150 -362z" /> + <glyph glyph-name="keyboard" unicode="" horiz-adv-x="1920" +d="M384 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM512 624v-96q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h224q16 0 16 -16zM384 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 368v-96q0 -16 -16 -16 +h-864q-16 0 -16 16v96q0 16 16 16h864q16 0 16 -16zM768 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM640 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1024 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16 +h96q16 0 16 -16zM896 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1280 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1152 880v-96 +q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 880v-352q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h112v240q0 16 16 16h96q16 0 16 -16zM1792 128v896h-1664v-896 +h1664zM1920 1024v-896q0 -53 -37.5 -90.5t-90.5 -37.5h-1664q-53 0 -90.5 37.5t-37.5 90.5v896q0 53 37.5 90.5t90.5 37.5h1664q53 0 90.5 -37.5t37.5 -90.5z" /> + <glyph glyph-name="flag_alt" unicode="" horiz-adv-x="1792" +d="M1664 491v616q-169 -91 -306 -91q-82 0 -145 32q-100 49 -184 76.5t-178 27.5q-173 0 -403 -127v-599q245 113 433 113q55 0 103.5 -7.5t98 -26t77 -31t82.5 -39.5l28 -14q44 -22 101 -22q120 0 293 92zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9 +h-64q-14 0 -23 9t-9 23v1266q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102 +q-15 -9 -33 -9q-16 0 -32 8q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" /> + <glyph glyph-name="flag_checkered" unicode="" horiz-adv-x="1792" +d="M832 536v192q-181 -16 -384 -117v-185q205 96 384 110zM832 954v197q-172 -8 -384 -126v-189q215 111 384 118zM1664 491v184q-235 -116 -384 -71v224q-20 6 -39 15q-5 3 -33 17t-34.5 17t-31.5 15t-34.5 15.5t-32.5 13t-36 12.5t-35 8.5t-39.5 7.5t-39.5 4t-44 2 +q-23 0 -49 -3v-222h19q102 0 192.5 -29t197.5 -82q19 -9 39 -15v-188q42 -17 91 -17q120 0 293 92zM1664 918v189q-169 -91 -306 -91q-45 0 -78 8v-196q148 -42 384 90zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v1266 +q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102q-15 -9 -33 -9q-16 0 -32 8 +q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" /> + <glyph glyph-name="terminal" unicode="" horiz-adv-x="1664" +d="M585 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23zM1664 96v-64q0 -14 -9 -23t-23 -9h-960q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h960q14 0 23 -9 +t9 -23z" /> + <glyph glyph-name="code" unicode="" horiz-adv-x="1920" +d="M617 137l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23zM1208 1204l-373 -1291q-4 -13 -15.5 -19.5t-23.5 -2.5l-62 17q-13 4 -19.5 15.5t-2.5 24.5 +l373 1291q4 13 15.5 19.5t23.5 2.5l62 -17q13 -4 19.5 -15.5t2.5 -24.5zM1865 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23z" /> + <glyph glyph-name="reply_all" unicode="" horiz-adv-x="1792" +d="M640 454v-70q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-69l-397 -398q-19 -19 -19 -45t19 -45zM1792 416q0 -58 -17 -133.5t-38.5 -138t-48 -125t-40.5 -90.5l-20 -40q-8 -17 -28 -17q-6 0 -9 1 +q-25 8 -23 34q43 400 -106 565q-64 71 -170.5 110.5t-267.5 52.5v-251q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-262q411 -28 599 -221q169 -173 169 -509z" /> + <glyph glyph-name="star_half_empty" unicode="" horiz-adv-x="1664" +d="M1186 579l257 250l-356 52l-66 10l-30 60l-159 322v-963l59 -31l318 -168l-60 355l-12 66zM1638 841l-363 -354l86 -500q5 -33 -6 -51.5t-34 -18.5q-17 0 -40 12l-449 236l-449 -236q-23 -12 -40 -12q-23 0 -34 18.5t-6 51.5l86 500l-364 354q-32 32 -23 59.5t54 34.5 +l502 73l225 455q20 41 49 41q28 0 49 -41l225 -455l502 -73q45 -7 54 -34.5t-24 -59.5z" /> + <glyph glyph-name="location_arrow" unicode="" horiz-adv-x="1408" +d="M1401 1187l-640 -1280q-17 -35 -57 -35q-5 0 -15 2q-22 5 -35.5 22.5t-13.5 39.5v576h-576q-22 0 -39.5 13.5t-22.5 35.5t4 42t29 30l1280 640q13 7 29 7q27 0 45 -19q15 -14 18.5 -34.5t-6.5 -39.5z" /> + <glyph glyph-name="crop" unicode="" horiz-adv-x="1664" +d="M557 256h595v595zM512 301l595 595h-595v-595zM1664 224v-192q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v224h-864q-14 0 -23 9t-9 23v864h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224v224q0 14 9 23t23 9h192q14 0 23 -9t9 -23 +v-224h851l246 247q10 9 23 9t23 -9q9 -10 9 -23t-9 -23l-247 -246v-851h224q14 0 23 -9t9 -23z" /> + <glyph glyph-name="code_fork" unicode="" horiz-adv-x="1024" +d="M288 64q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM288 1216q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM928 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1024 1088q0 -52 -26 -96.5t-70 -69.5 +q-2 -287 -226 -414q-67 -38 -203 -81q-128 -40 -169.5 -71t-41.5 -100v-26q44 -25 70 -69.5t26 -96.5q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 52 26 96.5t70 69.5v820q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136q0 -52 -26 -96.5t-70 -69.5v-497 +q54 26 154 57q55 17 87.5 29.5t70.5 31t59 39.5t40.5 51t28 69.5t8.5 91.5q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136z" /> + <glyph glyph-name="unlink" unicode="" horiz-adv-x="1664" +d="M439 265l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23zM608 224v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM384 448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23t9 23t23 9h320 +q14 0 23 -9t9 -23zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-334 335q-21 21 -42 56l239 18l273 -274q27 -27 68 -27.5t68 26.5l147 146q28 28 28 67q0 40 -28 68l-274 275l18 239q35 -21 56 -42l336 -336q84 -86 84 -204zM1031 1044l-239 -18 +l-273 274q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l274 -274l-18 -240q-35 21 -56 42l-336 336q-84 86 -84 204q0 120 85 203l147 146q83 83 203 83q121 0 204 -85l334 -335q21 -21 42 -56zM1664 960q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9 +t-9 23t9 23t23 9h320q14 0 23 -9t9 -23zM1120 1504v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM1527 1353l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" /> + <glyph glyph-name="question" unicode="" horiz-adv-x="1024" +d="M704 280v-240q0 -16 -12 -28t-28 -12h-240q-16 0 -28 12t-12 28v240q0 16 12 28t28 12h240q16 0 28 -12t12 -28zM1020 880q0 -54 -15.5 -101t-35 -76.5t-55 -59.5t-57.5 -43.5t-61 -35.5q-41 -23 -68.5 -65t-27.5 -67q0 -17 -12 -32.5t-28 -15.5h-240q-15 0 -25.5 18.5 +t-10.5 37.5v45q0 83 65 156.5t143 108.5q59 27 84 56t25 76q0 42 -46.5 74t-107.5 32q-65 0 -108 -29q-35 -25 -107 -115q-13 -16 -31 -16q-12 0 -25 8l-164 125q-13 10 -15.5 25t5.5 28q160 266 464 266q80 0 161 -31t146 -83t106 -127.5t41 -158.5z" /> + <glyph glyph-name="_279" unicode="" horiz-adv-x="640" +d="M640 192v-128q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64v384h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-576h64q26 0 45 -19t19 -45zM512 1344v-192q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v192 +q0 26 19 45t45 19h256q26 0 45 -19t19 -45z" /> + <glyph glyph-name="exclamation" unicode="" horiz-adv-x="640" +d="M512 288v-224q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v224q0 26 19 45t45 19h256q26 0 45 -19t19 -45zM542 1344l-28 -768q-1 -26 -20.5 -45t-45.5 -19h-256q-26 0 -45.5 19t-20.5 45l-28 768q-1 26 17.5 45t44.5 19h320q26 0 44.5 -19t17.5 -45z" /> + <glyph glyph-name="superscript" unicode="" +d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3q-1 -3 -2.5 -6.5t-3.5 -8t-3 -6.5q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109z +M1534 846v-206h-514l-3 27q-4 28 -4 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q83 65 188 65q110 0 178 -59.5t68 -158.5q0 -56 -24.5 -103t-62 -76.5t-81.5 -58.5t-82 -50.5 +t-65.5 -51.5t-30.5 -63h232v80h126z" /> + <glyph glyph-name="subscript" unicode="" +d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3q-1 -3 -2.5 -6.5t-3.5 -8t-3 -6.5q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109z +M1536 -50v-206h-514l-4 27q-3 45 -3 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q80 65 188 65q110 0 178 -59.5t68 -158.5q0 -66 -34.5 -118.5t-84 -86t-99.5 -62.5t-87 -63t-41 -73 +h232v80h126z" /> + <glyph glyph-name="_283" unicode="" horiz-adv-x="1920" +d="M896 128l336 384h-768l-336 -384h768zM1909 1205q15 -34 9.5 -71.5t-30.5 -65.5l-896 -1024q-38 -44 -96 -44h-768q-38 0 -69.5 20.5t-47.5 54.5q-15 34 -9.5 71.5t30.5 65.5l896 1024q38 44 96 44h768q38 0 69.5 -20.5t47.5 -54.5z" /> + <glyph glyph-name="puzzle_piece" unicode="" horiz-adv-x="1664" +d="M1664 438q0 -81 -44.5 -135t-123.5 -54q-41 0 -77.5 17.5t-59 38t-56.5 38t-71 17.5q-110 0 -110 -124q0 -39 16 -115t15 -115v-5q-22 0 -33 -1q-34 -3 -97.5 -11.5t-115.5 -13.5t-98 -5q-61 0 -103 26.5t-42 83.5q0 37 17.5 71t38 56.5t38 59t17.5 77.5q0 79 -54 123.5 +t-135 44.5q-84 0 -143 -45.5t-59 -127.5q0 -43 15 -83t33.5 -64.5t33.5 -53t15 -50.5q0 -45 -46 -89q-37 -35 -117 -35q-95 0 -245 24q-9 2 -27.5 4t-27.5 4l-13 2q-1 0 -3 1q-2 0 -2 1v1024q2 -1 17.5 -3.5t34 -5t21.5 -3.5q150 -24 245 -24q80 0 117 35q46 44 46 89 +q0 22 -15 50.5t-33.5 53t-33.5 64.5t-15 83q0 82 59 127.5t144 45.5q80 0 134 -44.5t54 -123.5q0 -41 -17.5 -77.5t-38 -59t-38 -56.5t-17.5 -71q0 -57 42 -83.5t103 -26.5q64 0 180 15t163 17v-2q-1 -2 -3.5 -17.5t-5 -34t-3.5 -21.5q-24 -150 -24 -245q0 -80 35 -117 +q44 -46 89 -46q22 0 50.5 15t53 33.5t64.5 33.5t83 15q82 0 127.5 -59t45.5 -143z" /> + <glyph glyph-name="microphone" unicode="" horiz-adv-x="1152" +d="M1152 832v-128q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-217 24 -364.5 187.5t-147.5 384.5v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -185 131.5 -316.5t316.5 -131.5 +t316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45zM896 1216v-512q0 -132 -94 -226t-226 -94t-226 94t-94 226v512q0 132 94 226t226 94t226 -94t94 -226z" /> + <glyph glyph-name="microphone_off" unicode="" horiz-adv-x="1408" +d="M271 591l-101 -101q-42 103 -42 214v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -53 15 -113zM1385 1193l-361 -361v-128q0 -132 -94 -226t-226 -94q-55 0 -109 19l-96 -96q97 -51 205 -51q185 0 316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45v-128 +q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-125 13 -235 81l-254 -254q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l1234 1234q10 10 23 10t23 -10l82 -82q10 -10 10 -23 +t-10 -23zM1005 1325l-621 -621v512q0 132 94 226t226 94q102 0 184.5 -59t116.5 -152z" /> + <glyph glyph-name="shield" unicode="" horiz-adv-x="1280" +d="M1088 576v640h-448v-1137q119 63 213 137q235 184 235 360zM1280 1344v-768q0 -86 -33.5 -170.5t-83 -150t-118 -127.5t-126.5 -103t-121 -77.5t-89.5 -49.5t-42.5 -20q-12 -6 -26 -6t-26 6q-16 7 -42.5 20t-89.5 49.5t-121 77.5t-126.5 103t-118 127.5t-83 150 +t-33.5 170.5v768q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" /> + <glyph glyph-name="calendar_empty" unicode="" horiz-adv-x="1664" +d="M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 +q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" /> + <glyph glyph-name="fire_extinguisher" unicode="" horiz-adv-x="1408" +d="M512 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 1376v-320q0 -16 -12 -25q-8 -7 -20 -7q-4 0 -7 1l-448 96q-11 2 -18 11t-7 20h-256v-102q111 -23 183.5 -111t72.5 -203v-800q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v800 +q0 106 62.5 190.5t161.5 114.5v111h-32q-59 0 -115 -23.5t-91.5 -53t-66 -66.5t-40.5 -53.5t-14 -24.5q-17 -35 -57 -35q-16 0 -29 7q-23 12 -31.5 37t3.5 49q5 10 14.5 26t37.5 53.5t60.5 70t85 67t108.5 52.5q-25 42 -25 86q0 66 47 113t113 47t113 -47t47 -113 +q0 -33 -14 -64h302q0 11 7 20t18 11l448 96q3 1 7 1q12 0 20 -7q12 -9 12 -25z" /> + <glyph glyph-name="rocket" unicode="" horiz-adv-x="1664" +d="M1440 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1664 1376q0 -249 -75.5 -430.5t-253.5 -360.5q-81 -80 -195 -176l-20 -379q-2 -16 -16 -26l-384 -224q-7 -4 -16 -4q-12 0 -23 9l-64 64q-13 14 -8 32l85 276l-281 281l-276 -85q-3 -1 -9 -1 +q-14 0 -23 9l-64 64q-17 19 -5 39l224 384q10 14 26 16l379 20q96 114 176 195q188 187 358 258t431 71q14 0 24 -9.5t10 -22.5z" /> + <glyph glyph-name="maxcdn" unicode="" horiz-adv-x="1792" +d="M1745 763l-164 -763h-334l178 832q13 56 -15 88q-27 33 -83 33h-169l-204 -953h-334l204 953h-286l-204 -953h-334l204 953l-153 327h1276q101 0 189.5 -40.5t147.5 -113.5q60 -73 81 -168.5t0 -194.5z" /> + <glyph glyph-name="chevron_sign_left" unicode="" +d="M909 141l102 102q19 19 19 45t-19 45l-307 307l307 307q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 +t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="chevron_sign_right" unicode="" +d="M717 141l454 454q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l307 -307l-307 -307q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 +t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="chevron_sign_up" unicode="" +d="M1165 397l102 102q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l307 307l307 -307q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 +t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="chevron_sign_down" unicode="" +d="M813 237l454 454q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-307 -307l-307 307q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 +t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="html5" unicode="" horiz-adv-x="1408" +d="M1130 939l16 175h-884l47 -534h612l-22 -228l-197 -53l-196 53l-13 140h-175l22 -278l362 -100h4v1l359 99l50 544h-644l-15 181h674zM0 1408h1408l-128 -1438l-578 -162l-574 162z" /> + <glyph glyph-name="css3" unicode="" horiz-adv-x="1792" +d="M275 1408h1505l-266 -1333l-804 -267l-698 267l71 356h297l-29 -147l422 -161l486 161l68 339h-1208l58 297h1209l38 191h-1208z" /> + <glyph glyph-name="anchor" unicode="" horiz-adv-x="1792" +d="M960 1280q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1792 352v-352q0 -22 -20 -30q-8 -2 -12 -2q-12 0 -23 9l-93 93q-119 -143 -318.5 -226.5t-429.5 -83.5t-429.5 83.5t-318.5 226.5l-93 -93q-9 -9 -23 -9q-4 0 -12 2q-20 8 -20 30v352 +q0 14 9 23t23 9h352q22 0 30 -20q8 -19 -7 -35l-100 -100q67 -91 189.5 -153.5t271.5 -82.5v647h-192q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h192v163q-58 34 -93 92.5t-35 128.5q0 106 75 181t181 75t181 -75t75 -181q0 -70 -35 -128.5t-93 -92.5v-163h192q26 0 45 -19 +t19 -45v-128q0 -26 -19 -45t-45 -19h-192v-647q149 20 271.5 82.5t189.5 153.5l-100 100q-15 16 -7 35q8 20 30 20h352q14 0 23 -9t9 -23z" /> + <glyph glyph-name="unlock_alt" unicode="" horiz-adv-x="1152" +d="M1056 768q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v320q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45q0 106 -75 181t-181 75t-181 -75t-75 -181 +v-320h736z" /> + <glyph glyph-name="bullseye" unicode="" +d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM1152 640q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1280 640q0 -212 -150 -362t-362 -150t-362 150 +t-150 362t150 362t362 150t362 -150t150 -362zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 +q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="ellipsis_horizontal" unicode="" horiz-adv-x="1408" +d="M384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM896 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM1408 800v-192q0 -40 -28 -68t-68 -28h-192 +q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" /> + <glyph glyph-name="ellipsis_vertical" unicode="" horiz-adv-x="384" +d="M384 288v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 1312v-192q0 -40 -28 -68t-68 -28h-192 +q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" /> + <glyph glyph-name="_303" unicode="" +d="M512 256q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM863 162q-13 233 -176.5 396.5t-396.5 176.5q-14 1 -24 -9t-10 -23v-128q0 -13 8.5 -22t21.5 -10q154 -11 264 -121t121 -264q1 -13 10 -21.5t22 -8.5h128 +q13 0 23 10t9 24zM1247 161q-5 154 -56 297.5t-139.5 260t-205 205t-260 139.5t-297.5 56q-14 1 -23 -9q-10 -10 -10 -23v-128q0 -13 9 -22t22 -10q204 -7 378 -111.5t278.5 -278.5t111.5 -378q1 -13 10 -22t22 -9h128q13 0 23 10q11 9 9 23zM1536 1120v-960 +q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="play_sign" unicode="" +d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1152 585q32 18 32 55t-32 55l-544 320q-31 19 -64 1q-32 -19 -32 -56v-640q0 -37 32 -56 +q16 -8 32 -8q17 0 32 9z" /> + <glyph glyph-name="ticket" unicode="" horiz-adv-x="1792" +d="M1024 1084l316 -316l-572 -572l-316 316zM813 105l618 618q19 19 19 45t-19 45l-362 362q-18 18 -45 18t-45 -18l-618 -618q-19 -19 -19 -45t19 -45l362 -362q18 -18 45 -18t45 18zM1702 742l-907 -908q-37 -37 -90.5 -37t-90.5 37l-126 126q56 56 56 136t-56 136 +t-136 56t-136 -56l-125 126q-37 37 -37 90.5t37 90.5l907 906q37 37 90.5 37t90.5 -37l125 -125q-56 -56 -56 -136t56 -136t136 -56t136 56l126 -125q37 -37 37 -90.5t-37 -90.5z" /> + <glyph glyph-name="minus_sign_alt" unicode="" +d="M1280 576v128q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h896q26 0 45 19t19 45zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 +t84.5 -203.5z" /> + <glyph glyph-name="check_minus" unicode="" horiz-adv-x="1408" +d="M1152 736v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h832q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5 +t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="level_up" unicode="" horiz-adv-x="1024" +d="M1018 933q-18 -37 -58 -37h-192v-864q0 -14 -9 -23t-23 -9h-704q-21 0 -29 18q-8 20 4 35l160 192q9 11 25 11h320v640h-192q-40 0 -58 37q-17 37 9 68l320 384q18 22 49 22t49 -22l320 -384q27 -32 9 -68z" /> + <glyph glyph-name="level_down" unicode="" horiz-adv-x="1024" +d="M32 1280h704q13 0 22.5 -9.5t9.5 -23.5v-863h192q40 0 58 -37t-9 -69l-320 -384q-18 -22 -49 -22t-49 22l-320 384q-26 31 -9 69q18 37 58 37h192v640h-320q-14 0 -25 11l-160 192q-13 14 -4 34q9 19 29 19z" /> + <glyph glyph-name="check_sign" unicode="" +d="M685 237l614 614q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-467 -467l-211 211q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l358 -358q19 -19 45 -19t45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5 +t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="edit_sign" unicode="" +d="M404 428l152 -152l-52 -52h-56v96h-96v56zM818 818q14 -13 -3 -30l-291 -291q-17 -17 -30 -3q-14 13 3 30l291 291q17 17 30 3zM544 128l544 544l-288 288l-544 -544v-288h288zM1152 736l92 92q28 28 28 68t-28 68l-152 152q-28 28 -68 28t-68 -28l-92 -92zM1536 1120 +v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_312" unicode="" +d="M1280 608v480q0 26 -19 45t-45 19h-480q-42 0 -59 -39q-17 -41 14 -70l144 -144l-534 -534q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l534 534l144 -144q18 -19 45 -19q12 0 25 5q39 17 39 59zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 +q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="share_sign" unicode="" +d="M1005 435l352 352q19 19 19 45t-19 45l-352 352q-30 31 -69 14q-40 -17 -40 -59v-160q-119 0 -216 -19.5t-162.5 -51t-114 -79t-76.5 -95.5t-44.5 -109t-21.5 -111.5t-5 -110.5q0 -181 167 -404q11 -12 25 -12q7 0 13 3q22 9 19 33q-44 354 62 473q46 52 130 75.5 +t224 23.5v-160q0 -42 40 -59q12 -5 24 -5q26 0 45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="compass" unicode="" +d="M640 448l256 128l-256 128v-256zM1024 1039v-542l-512 -256v542zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 +t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="collapse" unicode="" +d="M1145 861q18 -35 -5 -66l-320 -448q-19 -27 -52 -27t-52 27l-320 448q-23 31 -5 66q17 35 57 35h640q40 0 57 -35zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120 +v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="collapse_top" unicode="" +d="M1145 419q-17 -35 -57 -35h-640q-40 0 -57 35q-18 35 5 66l320 448q19 27 52 27t52 -27l320 -448q23 -31 5 -66zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120v-960 +q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_317" unicode="" +d="M1088 640q0 -33 -27 -52l-448 -320q-31 -23 -66 -5q-35 17 -35 57v640q0 40 35 57q35 18 66 -5l448 -320q27 -19 27 -52zM1280 160v960q0 14 -9 23t-23 9h-960q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h960q14 0 23 9t9 23zM1536 1120v-960q0 -119 -84.5 -203.5 +t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="eur" unicode="" horiz-adv-x="1024" +d="M976 229l35 -159q3 -12 -3 -22.5t-17 -14.5l-5 -1q-4 -2 -10.5 -3.5t-16 -4.5t-21.5 -5.5t-25.5 -5t-30 -5t-33.5 -4.5t-36.5 -3t-38.5 -1q-234 0 -409 130.5t-238 351.5h-95q-13 0 -22.5 9.5t-9.5 22.5v113q0 13 9.5 22.5t22.5 9.5h66q-2 57 1 105h-67q-14 0 -23 9 +t-9 23v114q0 14 9 23t23 9h98q67 210 243.5 338t400.5 128q102 0 194 -23q11 -3 20 -15q6 -11 3 -24l-43 -159q-3 -13 -14 -19.5t-24 -2.5l-4 1q-4 1 -11.5 2.5l-17.5 3.5t-22.5 3.5t-26 3t-29 2.5t-29.5 1q-126 0 -226 -64t-150 -176h468q16 0 25 -12q10 -12 7 -26 +l-24 -114q-5 -26 -32 -26h-488q-3 -37 0 -105h459q15 0 25 -12q9 -12 6 -27l-24 -112q-2 -11 -11 -18.5t-20 -7.5h-387q48 -117 149.5 -185.5t228.5 -68.5q18 0 36 1.5t33.5 3.5t29.5 4.5t24.5 5t18.5 4.5l12 3l5 2q13 5 26 -2q12 -7 15 -21z" /> + <glyph glyph-name="gbp" unicode="" horiz-adv-x="1024" +d="M1020 399v-367q0 -14 -9 -23t-23 -9h-956q-14 0 -23 9t-9 23v150q0 13 9.5 22.5t22.5 9.5h97v383h-95q-14 0 -23 9.5t-9 22.5v131q0 14 9 23t23 9h95v223q0 171 123.5 282t314.5 111q185 0 335 -125q9 -8 10 -20.5t-7 -22.5l-103 -127q-9 -11 -22 -12q-13 -2 -23 7 +q-5 5 -26 19t-69 32t-93 18q-85 0 -137 -47t-52 -123v-215h305q13 0 22.5 -9t9.5 -23v-131q0 -13 -9.5 -22.5t-22.5 -9.5h-305v-379h414v181q0 13 9 22.5t23 9.5h162q14 0 23 -9.5t9 -22.5z" /> + <glyph glyph-name="usd" unicode="" horiz-adv-x="1024" +d="M978 351q0 -153 -99.5 -263.5t-258.5 -136.5v-175q0 -14 -9 -23t-23 -9h-135q-13 0 -22.5 9.5t-9.5 22.5v175q-66 9 -127.5 31t-101.5 44.5t-74 48t-46.5 37.5t-17.5 18q-17 21 -2 41l103 135q7 10 23 12q15 2 24 -9l2 -2q113 -99 243 -125q37 -8 74 -8q81 0 142.5 43 +t61.5 122q0 28 -15 53t-33.5 42t-58.5 37.5t-66 32t-80 32.5q-39 16 -61.5 25t-61.5 26.5t-62.5 31t-56.5 35.5t-53.5 42.5t-43.5 49t-35.5 58t-21 66.5t-8.5 78q0 138 98 242t255 134v180q0 13 9.5 22.5t22.5 9.5h135q14 0 23 -9t9 -23v-176q57 -6 110.5 -23t87 -33.5 +t63.5 -37.5t39 -29t15 -14q17 -18 5 -38l-81 -146q-8 -15 -23 -16q-14 -3 -27 7q-3 3 -14.5 12t-39 26.5t-58.5 32t-74.5 26t-85.5 11.5q-95 0 -155 -43t-60 -111q0 -26 8.5 -48t29.5 -41.5t39.5 -33t56 -31t60.5 -27t70 -27.5q53 -20 81 -31.5t76 -35t75.5 -42.5t62 -50 +t53 -63.5t31.5 -76.5t13 -94z" /> + <glyph glyph-name="inr" unicode="" horiz-adv-x="898" +d="M898 1066v-102q0 -14 -9 -23t-23 -9h-168q-23 -144 -129 -234t-276 -110q167 -178 459 -536q14 -16 4 -34q-8 -18 -29 -18h-195q-16 0 -25 12q-306 367 -498 571q-9 9 -9 22v127q0 13 9.5 22.5t22.5 9.5h112q132 0 212.5 43t102.5 125h-427q-14 0 -23 9t-9 23v102 +q0 14 9 23t23 9h413q-57 113 -268 113h-145q-13 0 -22.5 9.5t-9.5 22.5v133q0 14 9 23t23 9h832q14 0 23 -9t9 -23v-102q0 -14 -9 -23t-23 -9h-233q47 -61 64 -144h171q14 0 23 -9t9 -23z" /> + <glyph glyph-name="jpy" unicode="" horiz-adv-x="1027" +d="M603 0h-172q-13 0 -22.5 9t-9.5 23v330h-288q-13 0 -22.5 9t-9.5 23v103q0 13 9.5 22.5t22.5 9.5h288v85h-288q-13 0 -22.5 9t-9.5 23v104q0 13 9.5 22.5t22.5 9.5h214l-321 578q-8 16 0 32q10 16 28 16h194q19 0 29 -18l215 -425q19 -38 56 -125q10 24 30.5 68t27.5 61 +l191 420q8 19 29 19h191q17 0 27 -16q9 -14 1 -31l-313 -579h215q13 0 22.5 -9.5t9.5 -22.5v-104q0 -14 -9.5 -23t-22.5 -9h-290v-85h290q13 0 22.5 -9.5t9.5 -22.5v-103q0 -14 -9.5 -23t-22.5 -9h-290v-330q0 -13 -9.5 -22.5t-22.5 -9.5z" /> + <glyph glyph-name="rub" unicode="" horiz-adv-x="1280" +d="M1043 971q0 100 -65 162t-171 62h-320v-448h320q106 0 171 62t65 162zM1280 971q0 -193 -126.5 -315t-326.5 -122h-340v-118h505q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-505v-192q0 -14 -9.5 -23t-22.5 -9h-167q-14 0 -23 9t-9 23v192h-224q-14 0 -23 9t-9 23v128 +q0 14 9 23t23 9h224v118h-224q-14 0 -23 9t-9 23v149q0 13 9 22.5t23 9.5h224v629q0 14 9 23t23 9h539q200 0 326.5 -122t126.5 -315z" /> + <glyph glyph-name="krw" unicode="" horiz-adv-x="1792" +d="M514 341l81 299h-159l75 -300q1 -1 1 -3t1 -3q0 1 0.5 3.5t0.5 3.5zM630 768l35 128h-292l32 -128h225zM822 768h139l-35 128h-70zM1271 340l78 300h-162l81 -299q0 -1 0.5 -3.5t1.5 -3.5q0 1 0.5 3t0.5 3zM1382 768l33 128h-297l34 -128h230zM1792 736v-64q0 -14 -9 -23 +t-23 -9h-213l-164 -616q-7 -24 -31 -24h-159q-24 0 -31 24l-166 616h-209l-167 -616q-7 -24 -31 -24h-159q-11 0 -19.5 7t-10.5 17l-160 616h-208q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h175l-33 128h-142q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h109l-89 344q-5 15 5 28 +q10 12 26 12h137q26 0 31 -24l90 -360h359l97 360q7 24 31 24h126q24 0 31 -24l98 -360h365l93 360q5 24 31 24h137q16 0 26 -12q10 -13 5 -28l-91 -344h111q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-145l-34 -128h179q14 0 23 -9t9 -23z" /> + <glyph glyph-name="btc" unicode="" horiz-adv-x="1280" +d="M1167 896q18 -182 -131 -258q117 -28 175 -103t45 -214q-7 -71 -32.5 -125t-64.5 -89t-97 -58.5t-121.5 -34.5t-145.5 -15v-255h-154v251q-80 0 -122 1v-252h-154v255q-18 0 -54 0.5t-55 0.5h-200l31 183h111q50 0 58 51v402h16q-6 1 -16 1v287q-13 68 -89 68h-111v164 +l212 -1q64 0 97 1v252h154v-247q82 2 122 2v245h154v-252q79 -7 140 -22.5t113 -45t82.5 -78t36.5 -114.5zM952 351q0 36 -15 64t-37 46t-57.5 30.5t-65.5 18.5t-74 9t-69 3t-64.5 -1t-47.5 -1v-338q8 0 37 -0.5t48 -0.5t53 1.5t58.5 4t57 8.5t55.5 14t47.5 21t39.5 30 +t24.5 40t9.5 51zM881 827q0 33 -12.5 58.5t-30.5 42t-48 28t-55 16.5t-61.5 8t-58 2.5t-54 -1t-39.5 -0.5v-307q5 0 34.5 -0.5t46.5 0t50 2t55 5.5t51.5 11t48.5 18.5t37 27t27 38.5t9 51z" /> + <glyph glyph-name="file" unicode="" +d="M1024 1024v472q22 -14 36 -28l408 -408q14 -14 28 -36h-472zM896 992q0 -40 28 -68t68 -28h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544z" /> + <glyph glyph-name="file_text" unicode="" +d="M1468 1060q14 -14 28 -36h-472v472q22 -14 36 -28zM992 896h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544q0 -40 28 -68t68 -28zM1152 160v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704 +q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23z" /> + <glyph glyph-name="sort_by_alphabet" unicode="" horiz-adv-x="1664" +d="M1191 1128h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1572 -23 +v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -11v-2l14 2q9 2 30 2h248v119h121zM1661 874v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162 +l230 -662h70z" /> + <glyph glyph-name="_329" unicode="" horiz-adv-x="1664" +d="M1191 104h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1661 -150 +v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162l230 -662h70zM1572 1001v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -10v-3l14 3q9 1 30 1h248 +v119h121z" /> + <glyph glyph-name="sort_by_attributes" unicode="" horiz-adv-x="1792" +d="M736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1792 -32v-192q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832 +q14 0 23 -9t9 -23zM1600 480v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1408 992v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1216 1504v-192q0 -14 -9 -23t-23 -9h-256 +q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23z" /> + <glyph glyph-name="sort_by_attributes_alt" unicode="" horiz-adv-x="1792" +d="M1216 -32v-192q0 -14 -9 -23t-23 -9h-256q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192 +q14 0 23 -9t9 -23zM1408 480v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1600 992v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1792 1504v-192q0 -14 -9 -23t-23 -9h-832 +q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832q14 0 23 -9t9 -23z" /> + <glyph glyph-name="sort_by_order" unicode="" +d="M1346 223q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23 +zM1486 165q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5 +t82 -252.5zM1456 882v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165z" /> + <glyph glyph-name="sort_by_order_alt" unicode="" +d="M1346 1247q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9 +t9 -23zM1456 -142v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165zM1486 1189q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13 +q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5t82 -252.5z" /> + <glyph glyph-name="_334" unicode="" horiz-adv-x="1664" +d="M256 192q0 26 -19 45t-45 19q-27 0 -45.5 -19t-18.5 -45q0 -27 18.5 -45.5t45.5 -18.5q26 0 45 18.5t19 45.5zM416 704v-640q0 -26 -19 -45t-45 -19h-288q-26 0 -45 19t-19 45v640q0 26 19 45t45 19h288q26 0 45 -19t19 -45zM1600 704q0 -86 -55 -149q15 -44 15 -76 +q3 -76 -43 -137q17 -56 0 -117q-15 -57 -54 -94q9 -112 -49 -181q-64 -76 -197 -78h-36h-76h-17q-66 0 -144 15.5t-121.5 29t-120.5 39.5q-123 43 -158 44q-26 1 -45 19.5t-19 44.5v641q0 25 18 43.5t43 20.5q24 2 76 59t101 121q68 87 101 120q18 18 31 48t17.5 48.5 +t13.5 60.5q7 39 12.5 61t19.5 52t34 50q19 19 45 19q46 0 82.5 -10.5t60 -26t40 -40.5t24 -45t12 -50t5 -45t0.5 -39q0 -38 -9.5 -76t-19 -60t-27.5 -56q-3 -6 -10 -18t-11 -22t-8 -24h277q78 0 135 -57t57 -135z" /> + <glyph glyph-name="_335" unicode="" horiz-adv-x="1664" +d="M256 960q0 -26 -19 -45t-45 -19q-27 0 -45.5 19t-18.5 45q0 27 18.5 45.5t45.5 18.5q26 0 45 -18.5t19 -45.5zM416 448v640q0 26 -19 45t-45 19h-288q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h288q26 0 45 19t19 45zM1545 597q55 -61 55 -149q-1 -78 -57.5 -135 +t-134.5 -57h-277q4 -14 8 -24t11 -22t10 -18q18 -37 27 -57t19 -58.5t10 -76.5q0 -24 -0.5 -39t-5 -45t-12 -50t-24 -45t-40 -40.5t-60 -26t-82.5 -10.5q-26 0 -45 19q-20 20 -34 50t-19.5 52t-12.5 61q-9 42 -13.5 60.5t-17.5 48.5t-31 48q-33 33 -101 120q-49 64 -101 121 +t-76 59q-25 2 -43 20.5t-18 43.5v641q0 26 19 44.5t45 19.5q35 1 158 44q77 26 120.5 39.5t121.5 29t144 15.5h17h76h36q133 -2 197 -78q58 -69 49 -181q39 -37 54 -94q17 -61 0 -117q46 -61 43 -137q0 -32 -15 -76z" /> + <glyph glyph-name="youtube_sign" unicode="" +d="M919 233v157q0 50 -29 50q-17 0 -33 -16v-224q16 -16 33 -16q29 0 29 49zM1103 355h66v34q0 51 -33 51t-33 -51v-34zM532 621v-70h-80v-423h-74v423h-78v70h232zM733 495v-367h-67v40q-39 -45 -76 -45q-33 0 -42 28q-6 17 -6 54v290h66v-270q0 -24 1 -26q1 -15 15 -15 +q20 0 42 31v280h67zM985 384v-146q0 -52 -7 -73q-12 -42 -53 -42q-35 0 -68 41v-36h-67v493h67v-161q32 40 68 40q41 0 53 -42q7 -21 7 -74zM1236 255v-9q0 -29 -2 -43q-3 -22 -15 -40q-27 -40 -80 -40q-52 0 -81 38q-21 27 -21 86v129q0 59 20 86q29 38 80 38t78 -38 +q21 -29 21 -86v-76h-133v-65q0 -51 34 -51q24 0 30 26q0 1 0.5 7t0.5 16.5v21.5h68zM785 1079v-156q0 -51 -32 -51t-32 51v156q0 52 32 52t32 -52zM1318 366q0 177 -19 260q-10 44 -43 73.5t-76 34.5q-136 15 -412 15q-275 0 -411 -15q-44 -5 -76.5 -34.5t-42.5 -73.5 +q-20 -87 -20 -260q0 -176 20 -260q10 -43 42.5 -73t75.5 -35q137 -15 412 -15t412 15q43 5 75.5 35t42.5 73q20 84 20 260zM563 1017l90 296h-75l-51 -195l-53 195h-78q7 -23 23 -69l24 -69q35 -103 46 -158v-201h74v201zM852 936v130q0 58 -21 87q-29 38 -78 38 +q-51 0 -78 -38q-21 -29 -21 -87v-130q0 -58 21 -87q27 -38 78 -38q49 0 78 38q21 27 21 87zM1033 816h67v370h-67v-283q-22 -31 -42 -31q-15 0 -16 16q-1 2 -1 26v272h-67v-293q0 -37 6 -55q11 -27 43 -27q36 0 77 45v-40zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5 +h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="youtube" unicode="" +d="M971 292v-211q0 -67 -39 -67q-23 0 -45 22v301q22 22 45 22q39 0 39 -67zM1309 291v-46h-90v46q0 68 45 68t45 -68zM343 509h107v94h-312v-94h105v-569h100v569zM631 -60h89v494h-89v-378q-30 -42 -57 -42q-18 0 -21 21q-1 3 -1 35v364h-89v-391q0 -49 8 -73 +q12 -37 58 -37q48 0 102 61v-54zM1060 88v197q0 73 -9 99q-17 56 -71 56q-50 0 -93 -54v217h-89v-663h89v48q45 -55 93 -55q54 0 71 55q9 27 9 100zM1398 98v13h-91q0 -51 -2 -61q-7 -36 -40 -36q-46 0 -46 69v87h179v103q0 79 -27 116q-39 51 -106 51q-68 0 -107 -51 +q-28 -37 -28 -116v-173q0 -79 29 -116q39 -51 108 -51q72 0 108 53q18 27 21 54q2 9 2 58zM790 1011v210q0 69 -43 69t-43 -69v-210q0 -70 43 -70t43 70zM1509 260q0 -234 -26 -350q-14 -59 -58 -99t-102 -46q-184 -21 -555 -21t-555 21q-58 6 -102.5 46t-57.5 99 +q-26 112 -26 350q0 234 26 350q14 59 58 99t103 47q183 20 554 20t555 -20q58 -7 102.5 -47t57.5 -99q26 -112 26 -350zM511 1536h102l-121 -399v-271h-100v271q-14 74 -61 212q-37 103 -65 187h106l71 -263zM881 1203v-175q0 -81 -28 -118q-38 -51 -106 -51q-67 0 -105 51 +q-28 38 -28 118v175q0 80 28 117q38 51 105 51q68 0 106 -51q28 -37 28 -117zM1216 1365v-499h-91v55q-53 -62 -103 -62q-46 0 -59 37q-8 24 -8 75v394h91v-367q0 -33 1 -35q3 -22 21 -22q27 0 57 43v381h91z" /> + <glyph glyph-name="xing" unicode="" horiz-adv-x="1408" +d="M597 869q-10 -18 -257 -456q-27 -46 -65 -46h-239q-21 0 -31 17t0 36l253 448q1 0 0 1l-161 279q-12 22 -1 37q9 15 32 15h239q40 0 66 -45zM1403 1511q11 -16 0 -37l-528 -934v-1l336 -615q11 -20 1 -37q-10 -15 -32 -15h-239q-42 0 -66 45l-339 622q18 32 531 942 +q25 45 64 45h241q22 0 31 -15z" /> + <glyph glyph-name="xing_sign" unicode="" +d="M685 771q0 1 -126 222q-21 34 -52 34h-184q-18 0 -26 -11q-7 -12 1 -29l125 -216v-1l-196 -346q-9 -14 0 -28q8 -13 24 -13h185q31 0 50 36zM1309 1268q-7 12 -24 12h-187q-30 0 -49 -35l-411 -729q1 -2 262 -481q20 -35 52 -35h184q18 0 25 12q8 13 -1 28l-260 476v1 +l409 723q8 16 0 28zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="youtube_play" unicode="" horiz-adv-x="1792" +d="M711 408l484 250l-484 253v-503zM896 1270q168 0 324.5 -4.5t229.5 -9.5l73 -4q1 0 17 -1.5t23 -3t23.5 -4.5t28.5 -8t28 -13t31 -19.5t29 -26.5q6 -6 15.5 -18.5t29 -58.5t26.5 -101q8 -64 12.5 -136.5t5.5 -113.5v-40v-136q1 -145 -18 -290q-7 -55 -25 -99.5t-32 -61.5 +l-14 -17q-14 -15 -29 -26.5t-31 -19t-28 -12.5t-28.5 -8t-24 -4.5t-23 -3t-16.5 -1.5q-251 -19 -627 -19q-207 2 -359.5 6.5t-200.5 7.5l-49 4l-36 4q-36 5 -54.5 10t-51 21t-56.5 41q-6 6 -15.5 18.5t-29 58.5t-26.5 101q-8 64 -12.5 136.5t-5.5 113.5v40v136 +q-1 145 18 290q7 55 25 99.5t32 61.5l14 17q14 15 29 26.5t31 19.5t28 13t28.5 8t23.5 4.5t23 3t17 1.5q251 18 627 18z" /> + <glyph glyph-name="dropbox" unicode="" horiz-adv-x="1792" +d="M402 829l494 -305l-342 -285l-490 319zM1388 274v-108l-490 -293v-1l-1 1l-1 -1v1l-489 293v108l147 -96l342 284v2l1 -1l1 1v-2l343 -284zM554 1418l342 -285l-494 -304l-338 270zM1390 829l338 -271l-489 -319l-343 285zM1239 1418l489 -319l-338 -270l-494 304z" /> + <glyph glyph-name="stackexchange" unicode="" +d="M1289 -96h-1118v480h-160v-640h1438v640h-160v-480zM347 428l33 157l783 -165l-33 -156zM450 802l67 146l725 -339l-67 -145zM651 1158l102 123l614 -513l-102 -123zM1048 1536l477 -641l-128 -96l-477 641zM330 65v159h800v-159h-800z" /> + <glyph glyph-name="instagram" unicode="" +d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1162 640q0 -164 -115 -279t-279 -115t-279 115t-115 279t115 279t279 115t279 -115t115 -279zM1270 1050q0 -38 -27 -65t-65 -27t-65 27t-27 65t27 65t65 27t65 -27t27 -65zM768 1270 +q-7 0 -76.5 0.5t-105.5 0t-96.5 -3t-103 -10t-71.5 -18.5q-50 -20 -88 -58t-58 -88q-11 -29 -18.5 -71.5t-10 -103t-3 -96.5t0 -105.5t0.5 -76.5t-0.5 -76.5t0 -105.5t3 -96.5t10 -103t18.5 -71.5q20 -50 58 -88t88 -58q29 -11 71.5 -18.5t103 -10t96.5 -3t105.5 0t76.5 0.5 +t76.5 -0.5t105.5 0t96.5 3t103 10t71.5 18.5q50 20 88 58t58 88q11 29 18.5 71.5t10 103t3 96.5t0 105.5t-0.5 76.5t0.5 76.5t0 105.5t-3 96.5t-10 103t-18.5 71.5q-20 50 -58 88t-88 58q-29 11 -71.5 18.5t-103 10t-96.5 3t-105.5 0t-76.5 -0.5zM1536 640q0 -229 -5 -317 +q-10 -208 -124 -322t-322 -124q-88 -5 -317 -5t-317 5q-208 10 -322 124t-124 322q-5 88 -5 317t5 317q10 208 124 322t322 124q88 5 317 5t317 -5q208 -10 322 -124t124 -322q5 -88 5 -317z" /> + <glyph glyph-name="flickr" unicode="" +d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM698 640q0 88 -62 150t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150zM1262 640q0 88 -62 150 +t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150z" /> + <glyph glyph-name="adn" unicode="" +d="M768 914l201 -306h-402zM1133 384h94l-459 691l-459 -691h94l104 160h522zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="f171" unicode="" horiz-adv-x="1408" +d="M815 677q8 -63 -50.5 -101t-111.5 -6q-39 17 -53.5 58t-0.5 82t52 58q36 18 72.5 12t64 -35.5t27.5 -67.5zM926 698q-14 107 -113 164t-197 13q-63 -28 -100.5 -88.5t-34.5 -129.5q4 -91 77.5 -155t165.5 -56q91 8 152 84t50 168zM1165 1240q-20 27 -56 44.5t-58 22 +t-71 12.5q-291 47 -566 -2q-43 -7 -66 -12t-55 -22t-50 -43q30 -28 76 -45.5t73.5 -22t87.5 -11.5q228 -29 448 -1q63 8 89.5 12t72.5 21.5t75 46.5zM1222 205q-8 -26 -15.5 -76.5t-14 -84t-28.5 -70t-58 -56.5q-86 -48 -189.5 -71.5t-202 -22t-201.5 18.5q-46 8 -81.5 18 +t-76.5 27t-73 43.5t-52 61.5q-25 96 -57 292l6 16l18 9q223 -148 506.5 -148t507.5 148q21 -6 24 -23t-5 -45t-8 -37zM1403 1166q-26 -167 -111 -655q-5 -30 -27 -56t-43.5 -40t-54.5 -31q-252 -126 -610 -88q-248 27 -394 139q-15 12 -25.5 26.5t-17 35t-9 34t-6 39.5 +t-5.5 35q-9 50 -26.5 150t-28 161.5t-23.5 147.5t-22 158q3 26 17.5 48.5t31.5 37.5t45 30t46 22.5t48 18.5q125 46 313 64q379 37 676 -50q155 -46 215 -122q16 -20 16.5 -51t-5.5 -54z" /> + <glyph glyph-name="bitbucket_sign" unicode="" +d="M848 666q0 43 -41 66t-77 1q-43 -20 -42.5 -72.5t43.5 -70.5q39 -23 81 4t36 72zM928 682q8 -66 -36 -121t-110 -61t-119 40t-56 113q-2 49 25.5 93t72.5 64q70 31 141.5 -10t81.5 -118zM1100 1073q-20 -21 -53.5 -34t-53 -16t-63.5 -8q-155 -20 -324 0q-44 6 -63 9.5 +t-52.5 16t-54.5 32.5q13 19 36 31t40 15.5t47 8.5q198 35 408 1q33 -5 51 -8.5t43 -16t39 -31.5zM1142 327q0 7 5.5 26.5t3 32t-17.5 16.5q-161 -106 -365 -106t-366 106l-12 -6l-5 -12q26 -154 41 -210q47 -81 204 -108q249 -46 428 53q34 19 49 51.5t22.5 85.5t12.5 71z +M1272 1020q9 53 -8 75q-43 55 -155 88q-216 63 -487 36q-132 -12 -226 -46q-38 -15 -59.5 -25t-47 -34t-29.5 -54q8 -68 19 -138t29 -171t24 -137q1 -5 5 -31t7 -36t12 -27t22 -28q105 -80 284 -100q259 -28 440 63q24 13 39.5 23t31 29t19.5 40q48 267 80 473zM1536 1120 +v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="tumblr" unicode="" horiz-adv-x="1024" +d="M944 207l80 -237q-23 -35 -111 -66t-177 -32q-104 -2 -190.5 26t-142.5 74t-95 106t-55.5 120t-16.5 118v544h-168v215q72 26 129 69.5t91 90t58 102t34 99t15 88.5q1 5 4.5 8.5t7.5 3.5h244v-424h333v-252h-334v-518q0 -30 6.5 -56t22.5 -52.5t49.5 -41.5t81.5 -14 +q78 2 134 29z" /> + <glyph glyph-name="tumblr_sign" unicode="" +d="M1136 75l-62 183q-44 -22 -103 -22q-36 -1 -62 10.5t-38.5 31.5t-17.5 40.5t-5 43.5v398h257v194h-256v326h-188q-8 0 -9 -10q-5 -44 -17.5 -87t-39 -95t-77 -95t-118.5 -68v-165h130v-418q0 -57 21.5 -115t65 -111t121 -85.5t176.5 -30.5q69 1 136.5 25t85.5 50z +M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="long_arrow_down" unicode="" horiz-adv-x="768" +d="M765 237q8 -19 -5 -35l-350 -384q-10 -10 -23 -10q-14 0 -24 10l-355 384q-13 16 -5 35q9 19 29 19h224v1248q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1248h224q21 0 29 -19z" /> + <glyph glyph-name="long_arrow_up" unicode="" horiz-adv-x="768" +d="M765 1043q-9 -19 -29 -19h-224v-1248q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1248h-224q-21 0 -29 19t5 35l350 384q10 10 23 10q14 0 24 -10l355 -384q13 -16 5 -35z" /> + <glyph glyph-name="long_arrow_left" unicode="" horiz-adv-x="1792" +d="M1792 736v-192q0 -14 -9 -23t-23 -9h-1248v-224q0 -21 -19 -29t-35 5l-384 350q-10 10 -10 23q0 14 10 24l384 354q16 14 35 6q19 -9 19 -29v-224h1248q14 0 23 -9t9 -23z" /> + <glyph glyph-name="long_arrow_right" unicode="" horiz-adv-x="1792" +d="M1728 643q0 -14 -10 -24l-384 -354q-16 -14 -35 -6q-19 9 -19 29v224h-1248q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h1248v224q0 21 19 29t35 -5l384 -350q10 -10 10 -23z" /> + <glyph glyph-name="apple" unicode="" horiz-adv-x="1408" +d="M1393 321q-39 -125 -123 -250q-129 -196 -257 -196q-49 0 -140 32q-86 32 -151 32q-61 0 -142 -33q-81 -34 -132 -34q-152 0 -301 259q-147 261 -147 503q0 228 113 374q113 144 284 144q72 0 177 -30q104 -30 138 -30q45 0 143 34q102 34 173 34q119 0 213 -65 +q52 -36 104 -100q-79 -67 -114 -118q-65 -94 -65 -207q0 -124 69 -223t158 -126zM1017 1494q0 -61 -29 -136q-30 -75 -93 -138q-54 -54 -108 -72q-37 -11 -104 -17q3 149 78 257q74 107 250 148q1 -3 2.5 -11t2.5 -11q0 -4 0.5 -10t0.5 -10z" /> + <glyph glyph-name="windows" unicode="" horiz-adv-x="1664" +d="M682 530v-651l-682 94v557h682zM682 1273v-659h-682v565zM1664 530v-786l-907 125v661h907zM1664 1408v-794h-907v669z" /> + <glyph glyph-name="android" unicode="" horiz-adv-x="1408" +d="M493 1053q16 0 27.5 11.5t11.5 27.5t-11.5 27.5t-27.5 11.5t-27 -11.5t-11 -27.5t11 -27.5t27 -11.5zM915 1053q16 0 27 11.5t11 27.5t-11 27.5t-27 11.5t-27.5 -11.5t-11.5 -27.5t11.5 -27.5t27.5 -11.5zM103 869q42 0 72 -30t30 -72v-430q0 -43 -29.5 -73t-72.5 -30 +t-73 30t-30 73v430q0 42 30 72t73 30zM1163 850v-666q0 -46 -32 -78t-77 -32h-75v-227q0 -43 -30 -73t-73 -30t-73 30t-30 73v227h-138v-227q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73l-1 227h-74q-46 0 -78 32t-32 78v666h918zM931 1255q107 -55 171 -153.5t64 -215.5 +h-925q0 117 64 215.5t172 153.5l-71 131q-7 13 5 20q13 6 20 -6l72 -132q95 42 201 42t201 -42l72 132q7 12 20 6q12 -7 5 -20zM1408 767v-430q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73v430q0 43 30 72.5t72 29.5q43 0 73 -29.5t30 -72.5z" /> + <glyph glyph-name="linux" unicode="" +d="M663 1125q-11 -1 -15.5 -10.5t-8.5 -9.5q-5 -1 -5 5q0 12 19 15h10zM750 1111q-4 -1 -11.5 6.5t-17.5 4.5q24 11 32 -2q3 -6 -3 -9zM399 684q-4 1 -6 -3t-4.5 -12.5t-5.5 -13.5t-10 -13q-10 -11 -1 -12q4 -1 12.5 7t12.5 18q1 3 2 7t2 6t1.5 4.5t0.5 4v3t-1 2.5t-3 2z +M1254 325q0 18 -55 42q4 15 7.5 27.5t5 26t3 21.5t0.5 22.5t-1 19.5t-3.5 22t-4 20.5t-5 25t-5.5 26.5q-10 48 -47 103t-72 75q24 -20 57 -83q87 -162 54 -278q-11 -40 -50 -42q-31 -4 -38.5 18.5t-8 83.5t-11.5 107q-9 39 -19.5 69t-19.5 45.5t-15.5 24.5t-13 15t-7.5 7 +q-14 62 -31 103t-29.5 56t-23.5 33t-15 40q-4 21 6 53.5t4.5 49.5t-44.5 25q-15 3 -44.5 18t-35.5 16q-8 1 -11 26t8 51t36 27q37 3 51 -30t4 -58q-11 -19 -2 -26.5t30 -0.5q13 4 13 36v37q-5 30 -13.5 50t-21 30.5t-23.5 15t-27 7.5q-107 -8 -89 -134q0 -15 -1 -15 +q-9 9 -29.5 10.5t-33 -0.5t-15.5 5q1 57 -16 90t-45 34q-27 1 -41.5 -27.5t-16.5 -59.5q-1 -15 3.5 -37t13 -37.5t15.5 -13.5q10 3 16 14q4 9 -7 8q-7 0 -15.5 14.5t-9.5 33.5q-1 22 9 37t34 14q17 0 27 -21t9.5 -39t-1.5 -22q-22 -15 -31 -29q-8 -12 -27.5 -23.5 +t-20.5 -12.5q-13 -14 -15.5 -27t7.5 -18q14 -8 25 -19.5t16 -19t18.5 -13t35.5 -6.5q47 -2 102 15q2 1 23 7t34.5 10.5t29.5 13t21 17.5q9 14 20 8q5 -3 6.5 -8.5t-3 -12t-16.5 -9.5q-20 -6 -56.5 -21.5t-45.5 -19.5q-44 -19 -70 -23q-25 -5 -79 2q-10 2 -9 -2t17 -19 +q25 -23 67 -22q17 1 36 7t36 14t33.5 17.5t30 17t24.5 12t17.5 2.5t8.5 -11q0 -2 -1 -4.5t-4 -5t-6 -4.5t-8.5 -5t-9 -4.5t-10 -5t-9.5 -4.5q-28 -14 -67.5 -44t-66.5 -43t-49 -1q-21 11 -63 73q-22 31 -25 22q-1 -3 -1 -10q0 -25 -15 -56.5t-29.5 -55.5t-21 -58t11.5 -63 +q-23 -6 -62.5 -90t-47.5 -141q-2 -18 -1.5 -69t-5.5 -59q-8 -24 -29 -3q-32 31 -36 94q-2 28 4 56q4 19 -1 18q-2 -1 -4 -5q-36 -65 10 -166q5 -12 25 -28t24 -20q20 -23 104 -90.5t93 -76.5q16 -15 17.5 -38t-14 -43t-45.5 -23q8 -15 29 -44.5t28 -54t7 -70.5q46 24 7 92 +q-4 8 -10.5 16t-9.5 12t-2 6q3 5 13 9.5t20 -2.5q46 -52 166 -36q133 15 177 87q23 38 34 30q12 -6 10 -52q-1 -25 -23 -92q-9 -23 -6 -37.5t24 -15.5q3 19 14.5 77t13.5 90q2 21 -6.5 73.5t-7.5 97t23 70.5q15 18 51 18q1 37 34.5 53t72.5 10.5t60 -22.5zM626 1152 +q3 17 -2.5 30t-11.5 15q-9 2 -9 -7q2 -5 5 -6q10 0 7 -15q-3 -20 8 -20q3 0 3 3zM1045 955q-2 8 -6.5 11.5t-13 5t-14.5 5.5q-5 3 -9.5 8t-7 8t-5.5 6.5t-4 4t-4 -1.5q-14 -16 7 -43.5t39 -31.5q9 -1 14.5 8t3.5 20zM867 1168q0 11 -5 19.5t-11 12.5t-9 3q-6 0 -8 -2t0 -4 +t5 -3q14 -4 18 -31q0 -3 8 2q2 2 2 3zM921 1401q0 2 -2.5 5t-9 7t-9.5 6q-15 15 -24 15q-9 -1 -11.5 -7.5t-1 -13t-0.5 -12.5q-1 -4 -6 -10.5t-6 -9t3 -8.5q4 -3 8 0t11 9t15 9q1 1 9 1t15 2t9 7zM1486 60q20 -12 31 -24.5t12 -24t-2.5 -22.5t-15.5 -22t-23.5 -19.5 +t-30 -18.5t-31.5 -16.5t-32 -15.5t-27 -13q-38 -19 -85.5 -56t-75.5 -64q-17 -16 -68 -19.5t-89 14.5q-18 9 -29.5 23.5t-16.5 25.5t-22 19.5t-47 9.5q-44 1 -130 1q-19 0 -57 -1.5t-58 -2.5q-44 -1 -79.5 -15t-53.5 -30t-43.5 -28.5t-53.5 -11.5q-29 1 -111 31t-146 43 +q-19 4 -51 9.5t-50 9t-39.5 9.5t-33.5 14.5t-17 19.5q-10 23 7 66.5t18 54.5q1 16 -4 40t-10 42.5t-4.5 36.5t10.5 27q14 12 57 14t60 12q30 18 42 35t12 51q21 -73 -32 -106q-32 -20 -83 -15q-34 3 -43 -10q-13 -15 5 -57q2 -6 8 -18t8.5 -18t4.5 -17t1 -22q0 -15 -17 -49 +t-14 -48q3 -17 37 -26q20 -6 84.5 -18.5t99.5 -20.5q24 -6 74 -22t82.5 -23t55.5 -4q43 6 64.5 28t23 48t-7.5 58.5t-19 52t-20 36.5q-121 190 -169 242q-68 74 -113 40q-11 -9 -15 15q-3 16 -2 38q1 29 10 52t24 47t22 42q8 21 26.5 72t29.5 78t30 61t39 54 +q110 143 124 195q-12 112 -16 310q-2 90 24 151.5t106 104.5q39 21 104 21q53 1 106 -13.5t89 -41.5q57 -42 91.5 -121.5t29.5 -147.5q-5 -95 30 -214q34 -113 133 -218q55 -59 99.5 -163t59.5 -191q8 -49 5 -84.5t-12 -55.5t-20 -22q-10 -2 -23.5 -19t-27 -35.5 +t-40.5 -33.5t-61 -14q-18 1 -31.5 5t-22.5 13.5t-13.5 15.5t-11.5 20.5t-9 19.5q-22 37 -41 30t-28 -49t7 -97q20 -70 1 -195q-10 -65 18 -100.5t73 -33t85 35.5q59 49 89.5 66.5t103.5 42.5q53 18 77 36.5t18.5 34.5t-25 28.5t-51.5 23.5q-33 11 -49.5 48t-15 72.5 +t15.5 47.5q1 -31 8 -56.5t14.5 -40.5t20.5 -28.5t21 -19t21.5 -13t16.5 -9.5z" /> + <glyph glyph-name="dribble" unicode="" +d="M1024 36q-42 241 -140 498h-2l-2 -1q-16 -6 -43 -16.5t-101 -49t-137 -82t-131 -114.5t-103 -148l-15 11q184 -150 418 -150q132 0 256 52zM839 643q-21 49 -53 111q-311 -93 -673 -93q-1 -7 -1 -21q0 -124 44 -236.5t124 -201.5q50 89 123.5 166.5t142.5 124.5t130.5 81 +t99.5 48l37 13q4 1 13 3.5t13 4.5zM732 855q-120 213 -244 378q-138 -65 -234 -186t-128 -272q302 0 606 80zM1416 536q-210 60 -409 29q87 -239 128 -469q111 75 185 189.5t96 250.5zM611 1277q-1 0 -2 -1q1 1 2 1zM1201 1132q-185 164 -433 164q-76 0 -155 -19 +q131 -170 246 -382q69 26 130 60.5t96.5 61.5t65.5 57t37.5 40.5zM1424 647q-3 232 -149 410l-1 -1q-9 -12 -19 -24.5t-43.5 -44.5t-71 -60.5t-100 -65t-131.5 -64.5q25 -53 44 -95q2 -5 6.5 -17t7.5 -17q36 5 74.5 7t73.5 2t69 -1.5t64 -4t56.5 -5.5t48 -6.5t36.5 -6 +t25 -4.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="skype" unicode="" +d="M1173 473q0 50 -19.5 91.5t-48.5 68.5t-73 49t-82.5 34t-87.5 23l-104 24q-30 7 -44 10.5t-35 11.5t-30 16t-16.5 21t-7.5 30q0 77 144 77q43 0 77 -12t54 -28.5t38 -33.5t40 -29t48 -12q47 0 75.5 32t28.5 77q0 55 -56 99.5t-142 67.5t-182 23q-68 0 -132 -15.5 +t-119.5 -47t-89 -87t-33.5 -128.5q0 -61 19 -106.5t56 -75.5t80 -48.5t103 -32.5l146 -36q90 -22 112 -36q32 -20 32 -60q0 -39 -40 -64.5t-105 -25.5q-51 0 -91.5 16t-65 38.5t-45.5 45t-46 38.5t-54 16q-50 0 -75.5 -30t-25.5 -75q0 -92 122 -157.5t291 -65.5 +q73 0 140 18.5t122.5 53.5t88.5 93.5t33 131.5zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5q-130 0 -234 80q-77 -16 -150 -16q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5q0 73 16 150q-80 104 -80 234q0 159 112.5 271.5t271.5 112.5q130 0 234 -80 +q77 16 150 16q143 0 273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -73 -16 -150q80 -104 80 -234z" /> + <glyph glyph-name="foursquare" unicode="" horiz-adv-x="1280" +d="M1000 1102l37 194q5 23 -9 40t-35 17h-712q-23 0 -38.5 -17t-15.5 -37v-1101q0 -7 6 -1l291 352q23 26 38 33.5t48 7.5h239q22 0 37 14.5t18 29.5q24 130 37 191q4 21 -11.5 40t-36.5 19h-294q-29 0 -48 19t-19 48v42q0 29 19 47.5t48 18.5h346q18 0 35 13.5t20 29.5z +M1227 1324q-15 -73 -53.5 -266.5t-69.5 -350t-35 -173.5q-6 -22 -9 -32.5t-14 -32.5t-24.5 -33t-38.5 -21t-58 -10h-271q-13 0 -22 -10q-8 -9 -426 -494q-22 -25 -58.5 -28.5t-48.5 5.5q-55 22 -55 98v1410q0 55 38 102.5t120 47.5h888q95 0 127 -53t10 -159zM1227 1324 +l-158 -790q4 17 35 173.5t69.5 350t53.5 266.5z" /> + <glyph glyph-name="trello" unicode="" +d="M704 192v1024q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-1024q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1376 576v640q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-640q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408 +q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" /> + <glyph glyph-name="female" unicode="" horiz-adv-x="1280" +d="M1280 480q0 -40 -28 -68t-68 -28q-51 0 -80 43l-227 341h-45v-132l247 -411q9 -15 9 -33q0 -26 -19 -45t-45 -19h-192v-272q0 -46 -33 -79t-79 -33h-160q-46 0 -79 33t-33 79v272h-192q-26 0 -45 19t-19 45q0 18 9 33l247 411v132h-45l-227 -341q-29 -43 -80 -43 +q-40 0 -68 28t-28 68q0 29 16 53l256 384q73 107 176 107h384q103 0 176 -107l256 -384q16 -24 16 -53zM864 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" /> + <glyph glyph-name="male" unicode="" horiz-adv-x="1024" +d="M1024 832v-416q0 -40 -28 -68t-68 -28t-68 28t-28 68v352h-64v-912q0 -46 -33 -79t-79 -33t-79 33t-33 79v464h-64v-464q0 -46 -33 -79t-79 -33t-79 33t-33 79v912h-64v-352q0 -40 -28 -68t-68 -28t-68 28t-28 68v416q0 80 56 136t136 56h640q80 0 136 -56t56 -136z +M736 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" /> + <glyph glyph-name="gittip" unicode="" +d="M773 234l350 473q16 22 24.5 59t-6 85t-61.5 79q-40 26 -83 25.5t-73.5 -17.5t-54.5 -45q-36 -40 -96 -40q-59 0 -95 40q-24 28 -54.5 45t-73.5 17.5t-84 -25.5q-46 -31 -60.5 -79t-6 -85t24.5 -59zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 +t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="sun" unicode="" horiz-adv-x="1792" +d="M1472 640q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123t223.5 -45.5t223.5 45.5t184 123t123 184t45.5 223.5zM1748 363q-4 -15 -20 -20l-292 -96v-306q0 -16 -13 -26q-15 -10 -29 -4 +l-292 94l-180 -248q-10 -13 -26 -13t-26 13l-180 248l-292 -94q-14 -6 -29 4q-13 10 -13 26v306l-292 96q-16 5 -20 20q-5 17 4 29l180 248l-180 248q-9 13 -4 29q4 15 20 20l292 96v306q0 16 13 26q15 10 29 4l292 -94l180 248q9 12 26 12t26 -12l180 -248l292 94 +q14 6 29 -4q13 -10 13 -26v-306l292 -96q16 -5 20 -20q5 -16 -4 -29l-180 -248l180 -248q9 -12 4 -29z" /> + <glyph glyph-name="_366" unicode="" +d="M1262 233q-54 -9 -110 -9q-182 0 -337 90t-245 245t-90 337q0 192 104 357q-201 -60 -328.5 -229t-127.5 -384q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51q144 0 273.5 61.5t220.5 171.5zM1465 318q-94 -203 -283.5 -324.5t-413.5 -121.5q-156 0 -298 61 +t-245 164t-164 245t-61 298q0 153 57.5 292.5t156 241.5t235.5 164.5t290 68.5q44 2 61 -39q18 -41 -15 -72q-86 -78 -131.5 -181.5t-45.5 -218.5q0 -148 73 -273t198 -198t273 -73q118 0 228 51q41 18 72 -13q14 -14 17.5 -34t-4.5 -38z" /> + <glyph glyph-name="archive" unicode="" horiz-adv-x="1792" +d="M1088 704q0 26 -19 45t-45 19h-256q-26 0 -45 -19t-19 -45t19 -45t45 -19h256q26 0 45 19t19 45zM1664 896v-960q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v960q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1728 1344v-256q0 -26 -19 -45t-45 -19h-1536 +q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1536q26 0 45 -19t19 -45z" /> + <glyph glyph-name="bug" unicode="" horiz-adv-x="1664" +d="M1632 576q0 -26 -19 -45t-45 -19h-224q0 -171 -67 -290l208 -209q19 -19 19 -45t-19 -45q-18 -19 -45 -19t-45 19l-198 197q-5 -5 -15 -13t-42 -28.5t-65 -36.5t-82 -29t-97 -13v896h-128v-896q-51 0 -101.5 13.5t-87 33t-66 39t-43.5 32.5l-15 14l-183 -207 +q-20 -21 -48 -21q-24 0 -43 16q-19 18 -20.5 44.5t15.5 46.5l202 227q-58 114 -58 274h-224q-26 0 -45 19t-19 45t19 45t45 19h224v294l-173 173q-19 19 -19 45t19 45t45 19t45 -19l173 -173h844l173 173q19 19 45 19t45 -19t19 -45t-19 -45l-173 -173v-294h224q26 0 45 -19 +t19 -45zM1152 1152h-640q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5z" /> + <glyph glyph-name="vk" unicode="" horiz-adv-x="1920" +d="M1917 1016q23 -64 -150 -294q-24 -32 -65 -85q-40 -51 -55 -72t-30.5 -49.5t-12 -42t13 -34.5t32.5 -43t57 -53q4 -2 5 -4q141 -131 191 -221q3 -5 6.5 -12.5t7 -26.5t-0.5 -34t-25 -27.5t-59 -12.5l-256 -4q-24 -5 -56 5t-52 22l-20 12q-30 21 -70 64t-68.5 77.5t-61 58 +t-56.5 15.5q-3 -1 -8 -3.5t-17 -14.5t-21.5 -29.5t-17 -52t-6.5 -77.5q0 -15 -3.5 -27.5t-7.5 -18.5l-4 -5q-18 -19 -53 -22h-115q-71 -4 -146 16.5t-131.5 53t-103 66t-70.5 57.5l-25 24q-10 10 -27.5 30t-71.5 91t-106 151t-122.5 211t-130.5 272q-6 16 -6 27t3 16l4 6 +q15 19 57 19l274 2q12 -2 23 -6.5t16 -8.5l5 -3q16 -11 24 -32q20 -50 46 -103.5t41 -81.5l16 -29q29 -60 56 -104t48.5 -68.5t41.5 -38.5t34 -14t27 5q2 1 5 5t12 22t13.5 47t9.5 81t0 125q-2 40 -9 73t-14 46l-6 12q-25 34 -85 43q-13 2 5 24q16 19 38 30q53 26 239 24 +q82 -1 135 -13q20 -5 33.5 -13.5t20.5 -24t10.5 -32t3.5 -45.5t-1 -55t-2.5 -70.5t-1.5 -82.5q0 -11 -1 -42t-0.5 -48t3.5 -40.5t11.5 -39t22.5 -24.5q8 -2 17 -4t26 11t38 34.5t52 67t68 107.5q60 104 107 225q4 10 10 17.5t11 10.5l4 3l5 2.5t13 3t20 0.5l288 2 +q39 5 64 -2.5t31 -16.5z" /> + <glyph glyph-name="weibo" unicode="" horiz-adv-x="1792" +d="M675 252q21 34 11 69t-45 50q-34 14 -73 1t-60 -46q-22 -34 -13 -68.5t43 -50.5t74.5 -2.5t62.5 47.5zM769 373q8 13 3.5 26.5t-17.5 18.5q-14 5 -28.5 -0.5t-21.5 -18.5q-17 -31 13 -45q14 -5 29 0.5t22 18.5zM943 266q-45 -102 -158 -150t-224 -12 +q-107 34 -147.5 126.5t6.5 187.5q47 93 151.5 139t210.5 19q111 -29 158.5 -119.5t2.5 -190.5zM1255 426q-9 96 -89 170t-208.5 109t-274.5 21q-223 -23 -369.5 -141.5t-132.5 -264.5q9 -96 89 -170t208.5 -109t274.5 -21q223 23 369.5 141.5t132.5 264.5zM1563 422 +q0 -68 -37 -139.5t-109 -137t-168.5 -117.5t-226 -83t-270.5 -31t-275 33.5t-240.5 93t-171.5 151t-65 199.5q0 115 69.5 245t197.5 258q169 169 341.5 236t246.5 -7q65 -64 20 -209q-4 -14 -1 -20t10 -7t14.5 0.5t13.5 3.5l6 2q139 59 246 59t153 -61q45 -63 0 -178 +q-2 -13 -4.5 -20t4.5 -12.5t12 -7.5t17 -6q57 -18 103 -47t80 -81.5t34 -116.5zM1489 1046q42 -47 54.5 -108.5t-6.5 -117.5q-8 -23 -29.5 -34t-44.5 -4q-23 8 -34 29.5t-4 44.5q20 63 -24 111t-107 35q-24 -5 -45 8t-25 37q-5 24 8 44.5t37 25.5q60 13 119 -5.5t101 -65.5z +M1670 1209q87 -96 112.5 -222.5t-13.5 -241.5q-9 -27 -34 -40t-52 -4t-40 34t-5 52q28 82 10 172t-80 158q-62 69 -148 95.5t-173 8.5q-28 -6 -52 9.5t-30 43.5t9.5 51.5t43.5 29.5q123 26 244 -11.5t208 -134.5z" /> + <glyph glyph-name="renren" unicode="" +d="M1133 -34q-171 -94 -368 -94q-196 0 -367 94q138 87 235.5 211t131.5 268q35 -144 132.5 -268t235.5 -211zM638 1394v-485q0 -252 -126.5 -459.5t-330.5 -306.5q-181 215 -181 495q0 187 83.5 349.5t229.5 269.5t325 137zM1536 638q0 -280 -181 -495 +q-204 99 -330.5 306.5t-126.5 459.5v485q179 -30 325 -137t229.5 -269.5t83.5 -349.5z" /> + <glyph glyph-name="_372" unicode="" horiz-adv-x="1408" +d="M1402 433q-32 -80 -76 -138t-91 -88.5t-99 -46.5t-101.5 -14.5t-96.5 8.5t-86.5 22t-69.5 27.5t-46 22.5l-17 10q-113 -228 -289.5 -359.5t-384.5 -132.5q-19 0 -32 13t-13 32t13 31.5t32 12.5q173 1 322.5 107.5t251.5 294.5q-36 -14 -72 -23t-83 -13t-91 2.5t-93 28.5 +t-92 59t-84.5 100t-74.5 146q114 47 214 57t167.5 -7.5t124.5 -56.5t88.5 -77t56.5 -82q53 131 79 291q-7 -1 -18 -2.5t-46.5 -2.5t-69.5 0.5t-81.5 10t-88.5 23t-84 42.5t-75 65t-54.5 94.5t-28.5 127.5q70 28 133.5 36.5t112.5 -1t92 -30t73.5 -50t56 -61t42 -63t27.5 -56 +t16 -39.5l4 -16q12 122 12 195q-8 6 -21.5 16t-49 44.5t-63.5 71.5t-54 93t-33 112.5t12 127t70 138.5q73 -25 127.5 -61.5t84.5 -76.5t48 -85t20.5 -89t-0.5 -85.5t-13 -76.5t-19 -62t-17 -42l-7 -15q1 -4 1 -50t-1 -72q3 7 10 18.5t30.5 43t50.5 58t71 55.5t91.5 44.5 +t112 14.5t132.5 -24q-2 -78 -21.5 -141.5t-50 -104.5t-69.5 -71.5t-81.5 -45.5t-84.5 -24t-80 -9.5t-67.5 1t-46.5 4.5l-17 3q-23 -147 -73 -283q6 7 18 18.5t49.5 41t77.5 52.5t99.5 42t117.5 20t129 -23.5t137 -77.5z" /> + <glyph glyph-name="stack_exchange" unicode="" horiz-adv-x="1280" +d="M1259 283v-66q0 -85 -57.5 -144.5t-138.5 -59.5h-57l-260 -269v269h-529q-81 0 -138.5 59.5t-57.5 144.5v66h1238zM1259 609v-255h-1238v255h1238zM1259 937v-255h-1238v255h1238zM1259 1077v-67h-1238v67q0 84 57.5 143.5t138.5 59.5h846q81 0 138.5 -59.5t57.5 -143.5z +" /> + <glyph glyph-name="_374" unicode="" +d="M1152 640q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 +t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="arrow_circle_alt_left" unicode="" +d="M1152 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-192q0 -14 -9 -23t-23 -9q-12 0 -24 10l-319 319q-9 9 -9 23t9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h352q13 0 22.5 -9.5t9.5 -22.5zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 +t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="_376" unicode="" +d="M1024 960v-640q0 -26 -19 -45t-45 -19q-20 0 -37 12l-448 320q-27 19 -27 52t27 52l448 320q17 12 37 12q26 0 45 -19t19 -45zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5z +M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="dot_circle_alt" unicode="" +d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5 +t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="_378" unicode="" horiz-adv-x="1664" +d="M1023 349l102 -204q-58 -179 -210 -290t-339 -111q-156 0 -288.5 77.5t-210 210t-77.5 288.5q0 181 104.5 330t274.5 211l17 -131q-122 -54 -195 -165.5t-73 -244.5q0 -185 131.5 -316.5t316.5 -131.5q126 0 232.5 65t165 175.5t49.5 236.5zM1571 249l58 -114l-256 -128 +q-13 -7 -29 -7q-40 0 -57 35l-239 477h-472q-24 0 -42.5 16.5t-21.5 40.5l-96 779q-2 17 6 42q14 51 57 82.5t97 31.5q66 0 113 -47t47 -113q0 -69 -52 -117.5t-120 -41.5l37 -289h423v-128h-407l16 -128h455q40 0 57 -35l228 -455z" /> + <glyph glyph-name="vimeo_square" unicode="" +d="M1292 898q10 216 -161 222q-231 8 -312 -261q44 19 82 19q85 0 74 -96q-4 -57 -74 -167t-105 -110q-43 0 -82 169q-13 54 -45 255q-30 189 -160 177q-59 -7 -164 -100l-81 -72l-81 -72l52 -67q76 52 87 52q57 0 107 -179q15 -55 45 -164.5t45 -164.5q68 -179 164 -179 +q157 0 383 294q220 283 226 444zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_380" unicode="" horiz-adv-x="1152" +d="M1152 704q0 -191 -94.5 -353t-256.5 -256.5t-353 -94.5h-160q-14 0 -23 9t-9 23v611l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v93l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v250q0 14 9 23t23 9h160 +q14 0 23 -9t9 -23v-181l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-93l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-487q188 13 318 151t130 328q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" /> + <glyph glyph-name="plus_square_o" unicode="" horiz-adv-x="1408" +d="M1152 736v-64q0 -14 -9 -23t-23 -9h-352v-352q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v352h-352q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h352v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-352h352q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832 +q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_382" unicode="" horiz-adv-x="2176" +d="M620 416q-110 -64 -268 -64h-128v64h-64q-13 0 -22.5 23.5t-9.5 56.5q0 24 7 49q-58 2 -96.5 10.5t-38.5 20.5t38.5 20.5t96.5 10.5q-7 25 -7 49q0 33 9.5 56.5t22.5 23.5h64v64h128q158 0 268 -64h1113q42 -7 106.5 -18t80.5 -14q89 -15 150 -40.5t83.5 -47.5t22.5 -40 +t-22.5 -40t-83.5 -47.5t-150 -40.5q-16 -3 -80.5 -14t-106.5 -18h-1113zM1739 668q53 -36 53 -92t-53 -92l81 -30q68 48 68 122t-68 122zM625 400h1015q-217 -38 -456 -80q-57 0 -113 -24t-83 -48l-28 -24l-288 -288q-26 -26 -70.5 -45t-89.5 -19h-96l-93 464h29 +q157 0 273 64zM352 816h-29l93 464h96q46 0 90 -19t70 -45l288 -288q4 -4 11 -10.5t30.5 -23t48.5 -29t61.5 -23t72.5 -10.5l456 -80h-1015q-116 64 -273 64z" /> + <glyph glyph-name="_383" unicode="" horiz-adv-x="1664" +d="M1519 760q62 0 103.5 -40.5t41.5 -101.5q0 -97 -93 -130l-172 -59l56 -167q7 -21 7 -47q0 -59 -42 -102t-101 -43q-47 0 -85.5 27t-53.5 72l-55 165l-310 -106l55 -164q8 -24 8 -47q0 -59 -42 -102t-102 -43q-47 0 -85 27t-53 72l-55 163l-153 -53q-29 -9 -50 -9 +q-61 0 -101.5 40t-40.5 101q0 47 27.5 85t71.5 53l156 53l-105 313l-156 -54q-26 -8 -48 -8q-60 0 -101 40.5t-41 100.5q0 47 27.5 85t71.5 53l157 53l-53 159q-8 24 -8 47q0 60 42 102.5t102 42.5q47 0 85 -27t53 -72l54 -160l310 105l-54 160q-8 24 -8 47q0 59 42.5 102 +t101.5 43q47 0 85.5 -27.5t53.5 -71.5l53 -161l162 55q21 6 43 6q60 0 102.5 -39.5t42.5 -98.5q0 -45 -30 -81.5t-74 -51.5l-157 -54l105 -316l164 56q24 8 46 8zM725 498l310 105l-105 315l-310 -107z" /> + <glyph glyph-name="_384" unicode="" +d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM1280 352v436q-31 -35 -64 -55q-34 -22 -132.5 -85t-151.5 -99q-98 -69 -164 -69v0v0q-66 0 -164 69 +q-47 32 -142 92.5t-142 92.5q-12 8 -33 27t-31 27v-436q0 -40 28 -68t68 -28h832q40 0 68 28t28 68zM1280 925q0 41 -27.5 70t-68.5 29h-832q-40 0 -68 -28t-28 -68q0 -37 30.5 -76.5t67.5 -64.5q47 -32 137.5 -89t129.5 -83q3 -2 17 -11.5t21 -14t21 -13t23.5 -13 +t21.5 -9.5t22.5 -7.5t20.5 -2.5t20.5 2.5t22.5 7.5t21.5 9.5t23.5 13t21 13t21 14t17 11.5l267 174q35 23 66.5 62.5t31.5 73.5z" /> + <glyph glyph-name="_385" unicode="" horiz-adv-x="1792" +d="M127 640q0 163 67 313l367 -1005q-196 95 -315 281t-119 411zM1415 679q0 -19 -2.5 -38.5t-10 -49.5t-11.5 -44t-17.5 -59t-17.5 -58l-76 -256l-278 826q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-75 1 -202 10q-12 1 -20.5 -5t-11.5 -15t-1.5 -18.5t9 -16.5 +t19.5 -8l80 -8l120 -328l-168 -504l-280 832q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-7 0 -23 0.5t-26 0.5q105 160 274.5 253.5t367.5 93.5q147 0 280.5 -53t238.5 -149h-10q-55 0 -92 -40.5t-37 -95.5q0 -12 2 -24t4 -21.5t8 -23t9 -21t12 -22.5t12.5 -21 +t14.5 -24t14 -23q63 -107 63 -212zM909 573l237 -647q1 -6 5 -11q-126 -44 -255 -44q-112 0 -217 32zM1570 1009q95 -174 95 -369q0 -209 -104 -385.5t-279 -278.5l235 678q59 169 59 276q0 42 -6 79zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286 +t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 -215q173 0 331.5 68t273 182.5t182.5 273t68 331.5t-68 331.5t-182.5 273t-273 182.5t-331.5 68t-331.5 -68t-273 -182.5t-182.5 -273t-68 -331.5t68 -331.5t182.5 -273 +t273 -182.5t331.5 -68z" /> + <glyph glyph-name="_386" unicode="" horiz-adv-x="1792" +d="M1086 1536v-1536l-272 -128q-228 20 -414 102t-293 208.5t-107 272.5q0 140 100.5 263.5t275 205.5t391.5 108v-172q-217 -38 -356.5 -150t-139.5 -255q0 -152 154.5 -267t388.5 -145v1360zM1755 954l37 -390l-525 114l147 83q-119 70 -280 99v172q277 -33 481 -157z" /> + <glyph glyph-name="_387" unicode="" horiz-adv-x="2048" +d="M960 1536l960 -384v-128h-128q0 -26 -20.5 -45t-48.5 -19h-1526q-28 0 -48.5 19t-20.5 45h-128v128zM256 896h256v-768h128v768h256v-768h128v768h256v-768h128v768h256v-768h59q28 0 48.5 -19t20.5 -45v-64h-1664v64q0 26 20.5 45t48.5 19h59v768zM1851 -64 +q28 0 48.5 -19t20.5 -45v-128h-1920v128q0 26 20.5 45t48.5 19h1782z" /> + <glyph glyph-name="_388" unicode="" horiz-adv-x="2304" +d="M1774 700l18 -316q4 -69 -82 -128t-235 -93.5t-323 -34.5t-323 34.5t-235 93.5t-82 128l18 316l574 -181q22 -7 48 -7t48 7zM2304 1024q0 -23 -22 -31l-1120 -352q-4 -1 -10 -1t-10 1l-652 206q-43 -34 -71 -111.5t-34 -178.5q63 -36 63 -109q0 -69 -58 -107l58 -433 +q2 -14 -8 -25q-9 -11 -24 -11h-192q-15 0 -24 11q-10 11 -8 25l58 433q-58 38 -58 107q0 73 65 111q11 207 98 330l-333 104q-22 8 -22 31t22 31l1120 352q4 1 10 1t10 -1l1120 -352q22 -8 22 -31z" /> + <glyph glyph-name="_389" unicode="" +d="M859 579l13 -707q-62 11 -105 11q-41 0 -105 -11l13 707q-40 69 -168.5 295.5t-216.5 374.5t-181 287q58 -15 108 -15q44 0 111 15q63 -111 133.5 -229.5t167 -276.5t138.5 -227q37 61 109.5 177.5t117.5 190t105 176t107 189.5q54 -14 107 -14q56 0 114 14v0 +q-28 -39 -60 -88.5t-49.5 -78.5t-56.5 -96t-49 -84q-146 -248 -353 -610z" /> + <glyph glyph-name="uniF1A0" unicode="" +d="M768 750h725q12 -67 12 -128q0 -217 -91 -387.5t-259.5 -266.5t-386.5 -96q-157 0 -299 60.5t-245 163.5t-163.5 245t-60.5 299t60.5 299t163.5 245t245 163.5t299 60.5q300 0 515 -201l-209 -201q-123 119 -306 119q-129 0 -238.5 -65t-173.5 -176.5t-64 -243.5 +t64 -243.5t173.5 -176.5t238.5 -65q87 0 160 24t120 60t82 82t51.5 87t22.5 78h-436v264z" /> + <glyph glyph-name="f1a1" unicode="" horiz-adv-x="1792" +d="M1095 369q16 -16 0 -31q-62 -62 -199 -62t-199 62q-16 15 0 31q6 6 15 6t15 -6q48 -49 169 -49q120 0 169 49q6 6 15 6t15 -6zM788 550q0 -37 -26 -63t-63 -26t-63.5 26t-26.5 63q0 38 26.5 64t63.5 26t63 -26.5t26 -63.5zM1183 550q0 -37 -26.5 -63t-63.5 -26t-63 26 +t-26 63t26 63.5t63 26.5t63.5 -26t26.5 -64zM1434 670q0 49 -35 84t-85 35t-86 -36q-130 90 -311 96l63 283l200 -45q0 -37 26 -63t63 -26t63.5 26.5t26.5 63.5t-26.5 63.5t-63.5 26.5q-54 0 -80 -50l-221 49q-19 5 -25 -16l-69 -312q-180 -7 -309 -97q-35 37 -87 37 +q-50 0 -85 -35t-35 -84q0 -35 18.5 -64t49.5 -44q-6 -27 -6 -56q0 -142 140 -243t337 -101q198 0 338 101t140 243q0 32 -7 57q30 15 48 43.5t18 63.5zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191 +t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="_392" unicode="" +d="M939 407q13 -13 0 -26q-53 -53 -171 -53t-171 53q-13 13 0 26q5 6 13 6t13 -6q42 -42 145 -42t145 42q5 6 13 6t13 -6zM676 563q0 -31 -23 -54t-54 -23t-54 23t-23 54q0 32 22.5 54.5t54.5 22.5t54.5 -22.5t22.5 -54.5zM1014 563q0 -31 -23 -54t-54 -23t-54 23t-23 54 +q0 32 22.5 54.5t54.5 22.5t54.5 -22.5t22.5 -54.5zM1229 666q0 42 -30 72t-73 30q-42 0 -73 -31q-113 78 -267 82l54 243l171 -39q1 -32 23.5 -54t53.5 -22q32 0 54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5q-48 0 -69 -43l-189 42q-17 5 -21 -13l-60 -268q-154 -6 -265 -83 +q-30 32 -74 32q-43 0 -73 -30t-30 -72q0 -30 16 -55t42 -38q-5 -25 -5 -48q0 -122 120 -208.5t289 -86.5q170 0 290 86.5t120 208.5q0 25 -6 49q25 13 40.5 37.5t15.5 54.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 +q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_393" unicode="" +d="M866 697l90 27v62q0 79 -58 135t-138 56t-138 -55.5t-58 -134.5v-283q0 -20 -14 -33.5t-33 -13.5t-32.5 13.5t-13.5 33.5v120h-151v-122q0 -82 57.5 -139t139.5 -57q81 0 138.5 56.5t57.5 136.5v280q0 19 13.5 33t33.5 14q19 0 32.5 -14t13.5 -33v-54zM1199 502v122h-150 +v-126q0 -20 -13.5 -33.5t-33.5 -13.5q-19 0 -32.5 14t-13.5 33v123l-90 -26l-60 28v-123q0 -80 58 -137t139 -57t138.5 57t57.5 139zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103 +t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="f1a4" unicode="" horiz-adv-x="1920" +d="M1062 824v118q0 42 -30 72t-72 30t-72 -30t-30 -72v-612q0 -175 -126 -299t-303 -124q-178 0 -303.5 125.5t-125.5 303.5v266h328v-262q0 -43 30 -72.5t72 -29.5t72 29.5t30 72.5v620q0 171 126.5 292t301.5 121q176 0 302 -122t126 -294v-136l-195 -58zM1592 602h328 +v-266q0 -178 -125.5 -303.5t-303.5 -125.5q-177 0 -303 124.5t-126 300.5v268l131 -61l195 58v-270q0 -42 30 -71.5t72 -29.5t72 29.5t30 71.5v275z" /> + <glyph glyph-name="_395" unicode="" +d="M1472 160v480h-704v704h-480q-93 0 -158.5 -65.5t-65.5 -158.5v-480h704v-704h480q93 0 158.5 65.5t65.5 158.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 +t84.5 -203.5z" /> + <glyph glyph-name="_396" unicode="" horiz-adv-x="2048" +d="M328 1254h204v-983h-532v697h328v286zM328 435v369h-123v-369h123zM614 968v-697h205v697h-205zM614 1254v-204h205v204h-205zM901 968h533v-942h-533v163h328v82h-328v697zM1229 435v369h-123v-369h123zM1516 968h532v-942h-532v163h327v82h-327v697zM1843 435v369h-123 +v-369h123z" /> + <glyph glyph-name="_397" unicode="" +d="M1046 516q0 -64 -38 -109t-91 -45q-43 0 -70 15v277q28 17 70 17q53 0 91 -45.5t38 -109.5zM703 944q0 -64 -38 -109.5t-91 -45.5q-43 0 -70 15v277q28 17 70 17q53 0 91 -45t38 -109zM1265 513q0 134 -88 229t-213 95q-20 0 -39 -3q-23 -78 -78 -136q-87 -95 -211 -101 +v-636l211 41v206q51 -19 117 -19q125 0 213 95t88 229zM922 940q0 134 -88.5 229t-213.5 95q-74 0 -141 -36h-186v-840l211 41v206q55 -19 116 -19q125 0 213.5 95t88.5 229zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 +q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_398" unicode="" horiz-adv-x="2038" +d="M1222 607q75 3 143.5 -20.5t118 -58.5t101 -94.5t84 -108t75.5 -120.5q33 -56 78.5 -109t75.5 -80.5t99 -88.5q-48 -30 -108.5 -57.5t-138.5 -59t-114 -47.5q-44 37 -74 115t-43.5 164.5t-33 180.5t-42.5 168.5t-72.5 123t-122.5 48.5l-10 -2l-6 -4q4 -5 13 -14 +q6 -5 28 -23.5t25.5 -22t19 -18t18 -20.5t11.5 -21t10.5 -27.5t4.5 -31t4 -40.5l1 -33q1 -26 -2.5 -57.5t-7.5 -52t-12.5 -58.5t-11.5 -53q-35 1 -101 -9.5t-98 -10.5q-39 0 -72 10q-2 16 -2 47q0 74 3 96q2 13 31.5 41.5t57 59t26.5 51.5q-24 2 -43 -24 +q-36 -53 -111.5 -99.5t-136.5 -46.5q-25 0 -75.5 63t-106.5 139.5t-84 96.5q-6 4 -27 30q-482 -112 -513 -112q-16 0 -28 11t-12 27q0 15 8.5 26.5t22.5 14.5l486 106q-8 14 -8 25t5.5 17.5t16 11.5t20 7t23 4.5t18.5 4.5q4 1 15.5 7.5t17.5 6.5q15 0 28 -16t20 -33 +q163 37 172 37q17 0 29.5 -11t12.5 -28q0 -15 -8.5 -26t-23.5 -14l-182 -40l-1 -16q-1 -26 81.5 -117.5t104.5 -91.5q47 0 119 80t72 129q0 36 -23.5 53t-51 18.5t-51 11.5t-23.5 34q0 16 10 34l-68 19q43 44 43 117q0 26 -5 58q82 16 144 16q44 0 71.5 -1.5t48.5 -8.5 +t31 -13.5t20.5 -24.5t15.5 -33.5t17 -47.5t24 -60l50 25q-3 -40 -23 -60t-42.5 -21t-40 -6.5t-16.5 -20.5zM1282 842q-5 5 -13.5 15.5t-12 14.5t-10.5 11.5t-10 10.5l-8 8t-8.5 7.5t-8 5t-8.5 4.5q-7 3 -14.5 5t-20.5 2.5t-22 0.5h-32.5h-37.5q-126 0 -217 -43 +q16 30 36 46.5t54 29.5t65.5 36t46 36.5t50 55t43.5 50.5q12 -9 28 -31.5t32 -36.5t38 -13l12 1v-76l22 -1q247 95 371 190q28 21 50 39t42.5 37.5t33 31t29.5 34t24 31t24.5 37t23 38t27 47.5t29.5 53l7 9q-2 -53 -43 -139q-79 -165 -205 -264t-306 -142q-14 -3 -42 -7.5 +t-50 -9.5t-39 -14q3 -19 24.5 -46t21.5 -34q0 -11 -26 -30zM1061 -79q39 26 131.5 47.5t146.5 21.5q9 0 22.5 -15.5t28 -42.5t26 -50t24 -51t14.5 -33q-121 -45 -244 -45q-61 0 -125 11zM822 568l48 12l109 -177l-73 -48zM1323 51q3 -15 3 -16q0 -7 -17.5 -14.5t-46 -13 +t-54 -9.5t-53.5 -7.5t-32 -4.5l-7 43q21 2 60.5 8.5t72 10t60.5 3.5h14zM866 679l-96 -20l-6 17q10 1 32.5 7t34.5 6q19 0 35 -10zM1061 45h31l10 -83l-41 -12v95zM1950 1535v1v-1zM1950 1535l-1 -5l-2 -2l1 3zM1950 1535l1 1z" /> + <glyph glyph-name="_399" unicode="" +d="M1167 -50q-5 19 -24 5q-30 -22 -87 -39t-131 -17q-129 0 -193 49q-5 4 -13 4q-11 0 -26 -12q-7 -6 -7.5 -16t7.5 -20q34 -32 87.5 -46t102.5 -12.5t99 4.5q41 4 84.5 20.5t65 30t28.5 20.5q12 12 7 29zM1128 65q-19 47 -39 61q-23 15 -76 15q-47 0 -71 -10 +q-29 -12 -78 -56q-26 -24 -12 -44q9 -8 17.5 -4.5t31.5 23.5q3 2 10.5 8.5t10.5 8.5t10 7t11.5 7t12.5 5t15 4.5t16.5 2.5t20.5 1q27 0 44.5 -7.5t23 -14.5t13.5 -22q10 -17 12.5 -20t12.5 1q23 12 14 34zM1483 346q0 22 -5 44.5t-16.5 45t-34 36.5t-52.5 14 +q-33 0 -97 -41.5t-129 -83.5t-101 -42q-27 -1 -63.5 19t-76 49t-83.5 58t-100 49t-111 19q-115 -1 -197 -78.5t-84 -178.5q-2 -112 74 -164q29 -20 62.5 -28.5t103.5 -8.5q57 0 132 32.5t134 71t120 70.5t93 31q26 -1 65 -31.5t71.5 -67t68 -67.5t55.5 -32q35 -3 58.5 14 +t55.5 63q28 41 42.5 101t14.5 106zM1536 506q0 -164 -62 -304.5t-166 -236t-242.5 -149.5t-290.5 -54t-293 57.5t-247.5 157t-170.5 241.5t-64 302q0 89 19.5 172.5t49 145.5t70.5 118.5t78.5 94t78.5 69.5t64.5 46.5t42.5 24.5q14 8 51 26.5t54.5 28.5t48 30t60.5 44 +q36 28 58 72.5t30 125.5q129 -155 186 -193q44 -29 130 -68t129 -66q21 -13 39 -25t60.5 -46.5t76 -70.5t75 -95t69 -122t47 -148.5t19.5 -177.5z" /> + <glyph glyph-name="_400" unicode="" +d="M1070 463l-160 -160l-151 -152l-30 -30q-65 -64 -151.5 -87t-171.5 -2q-16 -70 -72 -115t-129 -45q-85 0 -145 60.5t-60 145.5q0 72 44.5 128t113.5 72q-22 86 1 173t88 152l12 12l151 -152l-11 -11q-37 -37 -37 -89t37 -90q37 -37 89 -37t89 37l30 30l151 152l161 160z +M729 1145l12 -12l-152 -152l-12 12q-37 37 -89 37t-89 -37t-37 -89.5t37 -89.5l29 -29l152 -152l160 -160l-151 -152l-161 160l-151 152l-30 30q-68 67 -90 159.5t5 179.5q-70 15 -115 71t-45 129q0 85 60 145.5t145 60.5q76 0 133.5 -49t69.5 -123q84 20 169.5 -3.5 +t149.5 -87.5zM1536 78q0 -85 -60 -145.5t-145 -60.5q-74 0 -131 47t-71 118q-86 -28 -179.5 -6t-161.5 90l-11 12l151 152l12 -12q37 -37 89 -37t89 37t37 89t-37 89l-30 30l-152 152l-160 160l152 152l160 -160l152 -152l29 -30q64 -64 87.5 -150.5t2.5 -171.5 +q76 -11 126.5 -68.5t50.5 -134.5zM1534 1202q0 -77 -51 -135t-127 -69q26 -85 3 -176.5t-90 -158.5l-12 -12l-151 152l12 12q37 37 37 89t-37 89t-89 37t-89 -37l-30 -30l-152 -152l-160 -160l-152 152l161 160l152 152l29 30q67 67 159 89.5t178 -3.5q11 75 68.5 126 +t135.5 51q85 0 145 -60.5t60 -145.5z" /> + <glyph glyph-name="f1ab" unicode="" +d="M654 458q-1 -3 -12.5 0.5t-31.5 11.5l-20 9q-44 20 -87 49q-7 5 -41 31.5t-38 28.5q-67 -103 -134 -181q-81 -95 -105 -110q-4 -2 -19.5 -4t-18.5 0q6 4 82 92q21 24 85.5 115t78.5 118q17 30 51 98.5t36 77.5q-8 1 -110 -33q-8 -2 -27.5 -7.5t-34.5 -9.5t-17 -5 +q-2 -2 -2 -10.5t-1 -9.5q-5 -10 -31 -15q-23 -7 -47 0q-18 4 -28 21q-4 6 -5 23q6 2 24.5 5t29.5 6q58 16 105 32q100 35 102 35q10 2 43 19.5t44 21.5q9 3 21.5 8t14.5 5.5t6 -0.5q2 -12 -1 -33q0 -2 -12.5 -27t-26.5 -53.5t-17 -33.5q-25 -50 -77 -131l64 -28 +q12 -6 74.5 -32t67.5 -28q4 -1 10.5 -25.5t4.5 -30.5zM449 944q3 -15 -4 -28q-12 -23 -50 -38q-30 -12 -60 -12q-26 3 -49 26q-14 15 -18 41l1 3q3 -3 19.5 -5t26.5 0t58 16q36 12 55 14q17 0 21 -17zM1147 815l63 -227l-139 42zM39 15l694 232v1032l-694 -233v-1031z +M1280 332l102 -31l-181 657l-100 31l-216 -536l102 -31l45 110l211 -65zM777 1294l573 -184v380zM1088 -29l158 -13l-54 -160l-40 66q-130 -83 -276 -108q-58 -12 -91 -12h-84q-79 0 -199.5 39t-183.5 85q-8 7 -8 16q0 8 5 13.5t13 5.5q4 0 18 -7.5t30.5 -16.5t20.5 -11 +q73 -37 159.5 -61.5t157.5 -24.5q95 0 167 14.5t157 50.5q15 7 30.5 15.5t34 19t28.5 16.5zM1536 1050v-1079l-774 246q-14 -6 -375 -127.5t-368 -121.5q-13 0 -18 13q0 1 -1 3v1078q3 9 4 10q5 6 20 11q107 36 149 50v384l558 -198q2 0 160.5 55t316 108.5t161.5 53.5 +q20 0 20 -21v-418z" /> + <glyph glyph-name="_402" unicode="" horiz-adv-x="1792" +d="M288 1152q66 0 113 -47t47 -113v-1088q0 -66 -47 -113t-113 -47h-128q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h128zM1664 989q58 -34 93 -93t35 -128v-768q0 -106 -75 -181t-181 -75h-864q-66 0 -113 47t-47 113v1536q0 40 28 68t68 28h672q40 0 88 -20t76 -48 +l152 -152q28 -28 48 -76t20 -88v-163zM928 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 512v128q0 14 -9 23 +t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128 +q14 0 23 9t9 23zM1184 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 256v128q0 14 -9 23t-23 9h-128 +q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1536 896v256h-160q-40 0 -68 28t-28 68v160h-640v-512h896z" /> + <glyph glyph-name="_403" unicode="" +d="M1344 1536q26 0 45 -19t19 -45v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280zM512 1248v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 992v-64q0 -14 9 -23t23 -9h64q14 0 23 9 +t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 736v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 480v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM384 160v64 +q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 +q14 0 23 9t9 23zM384 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 -96v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9 +t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM896 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 928v64 +q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 160v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 +q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9 +t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23z" /> + <glyph glyph-name="_404" unicode="" horiz-adv-x="1280" +d="M1188 988l-292 -292v-824q0 -46 -33 -79t-79 -33t-79 33t-33 79v384h-64v-384q0 -46 -33 -79t-79 -33t-79 33t-33 79v824l-292 292q-28 28 -28 68t28 68q29 28 68.5 28t67.5 -28l228 -228h368l228 228q28 28 68 28t68 -28q28 -29 28 -68.5t-28 -67.5zM864 1152 +q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" /> + <glyph glyph-name="uniF1B1" unicode="" horiz-adv-x="1664" +d="M780 1064q0 -60 -19 -113.5t-63 -92.5t-105 -39q-76 0 -138 57.5t-92 135.5t-30 151q0 60 19 113.5t63 92.5t105 39q77 0 138.5 -57.5t91.5 -135t30 -151.5zM438 581q0 -80 -42 -139t-119 -59q-76 0 -141.5 55.5t-100.5 133.5t-35 152q0 80 42 139.5t119 59.5 +q76 0 141.5 -55.5t100.5 -134t35 -152.5zM832 608q118 0 255 -97.5t229 -237t92 -254.5q0 -46 -17 -76.5t-48.5 -45t-64.5 -20t-76 -5.5q-68 0 -187.5 45t-182.5 45q-66 0 -192.5 -44.5t-200.5 -44.5q-183 0 -183 146q0 86 56 191.5t139.5 192.5t187.5 146t193 59zM1071 819 +q-61 0 -105 39t-63 92.5t-19 113.5q0 74 30 151.5t91.5 135t138.5 57.5q61 0 105 -39t63 -92.5t19 -113.5q0 -73 -30 -151t-92 -135.5t-138 -57.5zM1503 923q77 0 119 -59.5t42 -139.5q0 -74 -35 -152t-100.5 -133.5t-141.5 -55.5q-77 0 -119 59t-42 139q0 74 35 152.5 +t100.5 134t141.5 55.5z" /> + <glyph glyph-name="_406" unicode="" horiz-adv-x="768" +d="M704 1008q0 -145 -57 -243.5t-152 -135.5l45 -821q2 -26 -16 -45t-44 -19h-192q-26 0 -44 19t-16 45l45 821q-95 37 -152 135.5t-57 243.5q0 128 42.5 249.5t117.5 200t160 78.5t160 -78.5t117.5 -200t42.5 -249.5z" /> + <glyph glyph-name="_407" unicode="" horiz-adv-x="1792" +d="M896 -93l640 349v636l-640 -233v-752zM832 772l698 254l-698 254l-698 -254zM1664 1024v-768q0 -35 -18 -65t-49 -47l-704 -384q-28 -16 -61 -16t-61 16l-704 384q-31 17 -49 47t-18 65v768q0 40 23 73t61 47l704 256q22 8 44 8t44 -8l704 -256q38 -14 61 -47t23 -73z +" /> + <glyph glyph-name="_408" unicode="" horiz-adv-x="2304" +d="M640 -96l384 192v314l-384 -164v-342zM576 358l404 173l-404 173l-404 -173zM1664 -96l384 192v314l-384 -164v-342zM1600 358l404 173l-404 173l-404 -173zM1152 651l384 165v266l-384 -164v-267zM1088 1030l441 189l-441 189l-441 -189zM2176 512v-416q0 -36 -19 -67 +t-52 -47l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-4 2 -7 4q-2 -2 -7 -4l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-33 16 -52 47t-19 67v416q0 38 21.5 70t56.5 48l434 186v400q0 38 21.5 70t56.5 48l448 192q23 10 50 10t50 -10l448 -192q35 -16 56.5 -48t21.5 -70 +v-400l434 -186q36 -16 57 -48t21 -70z" /> + <glyph glyph-name="_409" unicode="" horiz-adv-x="2048" +d="M1848 1197h-511v-124h511v124zM1596 771q-90 0 -146 -52.5t-62 -142.5h408q-18 195 -200 195zM1612 186q63 0 122 32t76 87h221q-100 -307 -427 -307q-214 0 -340.5 132t-126.5 347q0 208 130.5 345.5t336.5 137.5q138 0 240.5 -68t153 -179t50.5 -248q0 -17 -2 -47h-658 +q0 -111 57.5 -171.5t166.5 -60.5zM277 236h296q205 0 205 167q0 180 -199 180h-302v-347zM277 773h281q78 0 123.5 36.5t45.5 113.5q0 144 -190 144h-260v-294zM0 1282h594q87 0 155 -14t126.5 -47.5t90 -96.5t31.5 -154q0 -181 -172 -263q114 -32 172 -115t58 -204 +q0 -75 -24.5 -136.5t-66 -103.5t-98.5 -71t-121 -42t-134 -13h-611v1260z" /> + <glyph glyph-name="_410" unicode="" +d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM499 1041h-371v-787h382q117 0 197 57.5t80 170.5q0 158 -143 200q107 52 107 164q0 57 -19.5 96.5 +t-56.5 60.5t-79 29.5t-97 8.5zM477 723h-176v184h163q119 0 119 -90q0 -94 -106 -94zM486 388h-185v217h189q124 0 124 -113q0 -104 -128 -104zM1136 356q-68 0 -104 38t-36 107h411q1 10 1 30q0 132 -74.5 220.5t-203.5 88.5q-128 0 -210 -86t-82 -216q0 -135 79 -217 +t213 -82q205 0 267 191h-138q-11 -34 -47.5 -54t-75.5 -20zM1126 722q113 0 124 -122h-254q4 56 39 89t91 33zM964 988h319v-77h-319v77z" /> + <glyph glyph-name="_411" unicode="" horiz-adv-x="1792" +d="M1582 954q0 -101 -71.5 -172.5t-172.5 -71.5t-172.5 71.5t-71.5 172.5t71.5 172.5t172.5 71.5t172.5 -71.5t71.5 -172.5zM812 212q0 104 -73 177t-177 73q-27 0 -54 -6l104 -42q77 -31 109.5 -106.5t1.5 -151.5q-31 -77 -107 -109t-152 -1q-21 8 -62 24.5t-61 24.5 +q32 -60 91 -96.5t130 -36.5q104 0 177 73t73 177zM1642 953q0 126 -89.5 215.5t-215.5 89.5q-127 0 -216.5 -89.5t-89.5 -215.5q0 -127 89.5 -216t216.5 -89q126 0 215.5 89t89.5 216zM1792 953q0 -189 -133.5 -322t-321.5 -133l-437 -319q-12 -129 -109 -218t-229 -89 +q-121 0 -214 76t-118 192l-230 92v429l389 -157q79 48 173 48q13 0 35 -2l284 407q2 187 135.5 319t320.5 132q188 0 321.5 -133.5t133.5 -321.5z" /> + <glyph glyph-name="_412" unicode="" +d="M1242 889q0 80 -57 136.5t-137 56.5t-136.5 -57t-56.5 -136q0 -80 56.5 -136.5t136.5 -56.5t137 56.5t57 136.5zM632 301q0 -83 -58 -140.5t-140 -57.5q-56 0 -103 29t-72 77q52 -20 98 -40q60 -24 120 1.5t85 86.5q24 60 -1.5 120t-86.5 84l-82 33q22 5 42 5 +q82 0 140 -57.5t58 -140.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v153l172 -69q20 -92 93.5 -152t168.5 -60q104 0 181 70t87 173l345 252q150 0 255.5 105.5t105.5 254.5q0 150 -105.5 255.5t-255.5 105.5 +q-148 0 -253 -104.5t-107 -252.5l-225 -322q-9 1 -28 1q-75 0 -137 -37l-297 119v468q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5zM1289 887q0 -100 -71 -170.5t-171 -70.5t-170.5 70.5t-70.5 170.5t70.5 171t170.5 71q101 0 171.5 -70.5t70.5 -171.5z +" /> + <glyph glyph-name="_413" unicode="" horiz-adv-x="1792" +d="M836 367l-15 -368l-2 -22l-420 29q-36 3 -67 31.5t-47 65.5q-11 27 -14.5 55t4 65t12 55t21.5 64t19 53q78 -12 509 -28zM449 953l180 -379l-147 92q-63 -72 -111.5 -144.5t-72.5 -125t-39.5 -94.5t-18.5 -63l-4 -21l-190 357q-17 26 -18 56t6 47l8 18q35 63 114 188 +l-140 86zM1680 436l-188 -359q-12 -29 -36.5 -46.5t-43.5 -20.5l-18 -4q-71 -7 -219 -12l8 -164l-230 367l211 362l7 -173q170 -16 283 -5t170 33zM895 1360q-47 -63 -265 -435l-317 187l-19 12l225 356q20 31 60 45t80 10q24 -2 48.5 -12t42 -21t41.5 -33t36 -34.5 +t36 -39.5t32 -35zM1550 1053l212 -363q18 -37 12.5 -76t-27.5 -74q-13 -20 -33 -37t-38 -28t-48.5 -22t-47 -16t-51.5 -14t-46 -12q-34 72 -265 436l313 195zM1407 1279l142 83l-220 -373l-419 20l151 86q-34 89 -75 166t-75.5 123.5t-64.5 80t-47 46.5l-17 13l405 -1 +q31 3 58 -10.5t39 -28.5l11 -15q39 -61 112 -190z" /> + <glyph glyph-name="_414" unicode="" horiz-adv-x="2048" +d="M480 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM516 768h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5zM1888 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM2048 544v-384 +q0 -14 -9 -23t-23 -9h-96v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-1024v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5t179 63.5h768q98 0 179 -63.5t104 -157.5 +l105 -419h28q93 0 158.5 -65.5t65.5 -158.5z" /> + <glyph glyph-name="_415" unicode="" horiz-adv-x="2048" +d="M1824 640q93 0 158.5 -65.5t65.5 -158.5v-384q0 -14 -9 -23t-23 -9h-96v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-1024v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5 +t179 63.5h128v224q0 14 9 23t23 9h448q14 0 23 -9t9 -23v-224h128q98 0 179 -63.5t104 -157.5l105 -419h28zM320 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM516 640h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5z +M1728 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47z" /> + <glyph glyph-name="_416" unicode="" +d="M1504 64q0 -26 -19 -45t-45 -19h-462q1 -17 6 -87.5t5 -108.5q0 -25 -18 -42.5t-43 -17.5h-320q-25 0 -43 17.5t-18 42.5q0 38 5 108.5t6 87.5h-462q-26 0 -45 19t-19 45t19 45l402 403h-229q-26 0 -45 19t-19 45t19 45l402 403h-197q-26 0 -45 19t-19 45t19 45l384 384 +q19 19 45 19t45 -19l384 -384q19 -19 19 -45t-19 -45t-45 -19h-197l402 -403q19 -19 19 -45t-19 -45t-45 -19h-229l402 -403q19 -19 19 -45z" /> + <glyph glyph-name="_417" unicode="" +d="M1127 326q0 32 -30 51q-193 115 -447 115q-133 0 -287 -34q-42 -9 -42 -52q0 -20 13.5 -34.5t35.5 -14.5q5 0 37 8q132 27 243 27q226 0 397 -103q19 -11 33 -11q19 0 33 13.5t14 34.5zM1223 541q0 40 -35 61q-237 141 -548 141q-153 0 -303 -42q-48 -13 -48 -64 +q0 -25 17.5 -42.5t42.5 -17.5q7 0 37 8q122 33 251 33q279 0 488 -124q24 -13 38 -13q25 0 42.5 17.5t17.5 42.5zM1331 789q0 47 -40 70q-126 73 -293 110.5t-343 37.5q-204 0 -364 -47q-23 -7 -38.5 -25.5t-15.5 -48.5q0 -31 20.5 -52t51.5 -21q11 0 40 8q133 37 307 37 +q159 0 309.5 -34t253.5 -95q21 -12 40 -12q29 0 50.5 20.5t21.5 51.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="_418" unicode="" horiz-adv-x="1024" +d="M1024 1233l-303 -582l24 -31h279v-415h-507l-44 -30l-142 -273l-30 -30h-301v303l303 583l-24 30h-279v415h507l44 30l142 273l30 30h301v-303z" /> + <glyph glyph-name="_419" unicode="" horiz-adv-x="2304" +d="M784 164l16 241l-16 523q-1 10 -7.5 17t-16.5 7q-9 0 -16 -7t-7 -17l-14 -523l14 -241q1 -10 7.5 -16.5t15.5 -6.5q22 0 24 23zM1080 193l11 211l-12 586q0 16 -13 24q-8 5 -16 5t-16 -5q-13 -8 -13 -24l-1 -6l-10 -579q0 -1 11 -236v-1q0 -10 6 -17q9 -11 23 -11 +q11 0 20 9q9 7 9 20zM35 533l20 -128l-20 -126q-2 -9 -9 -9t-9 9l-17 126l17 128q2 9 9 9t9 -9zM121 612l26 -207l-26 -203q-2 -9 -10 -9q-9 0 -9 10l-23 202l23 207q0 9 9 9q8 0 10 -9zM401 159zM213 650l25 -245l-25 -237q0 -11 -11 -11q-10 0 -12 11l-21 237l21 245 +q2 12 12 12q11 0 11 -12zM307 657l23 -252l-23 -244q-2 -13 -14 -13q-13 0 -13 13l-21 244l21 252q0 13 13 13q12 0 14 -13zM401 639l21 -234l-21 -246q-2 -16 -16 -16q-6 0 -10.5 4.5t-4.5 11.5l-20 246l20 234q0 6 4.5 10.5t10.5 4.5q14 0 16 -15zM784 164zM495 785 +l21 -380l-21 -246q0 -7 -5 -12.5t-12 -5.5q-16 0 -18 18l-18 246l18 380q2 18 18 18q7 0 12 -5.5t5 -12.5zM589 871l19 -468l-19 -244q0 -8 -5.5 -13.5t-13.5 -5.5q-18 0 -20 19l-16 244l16 468q2 19 20 19q8 0 13.5 -5.5t5.5 -13.5zM687 911l18 -506l-18 -242 +q-2 -21 -22 -21q-19 0 -21 21l-16 242l16 506q0 9 6.5 15.5t14.5 6.5q9 0 15 -6.5t7 -15.5zM1079 169v0v0v0zM881 915l15 -510l-15 -239q0 -10 -7.5 -17.5t-17.5 -7.5t-17 7t-8 18l-14 239l14 510q0 11 7.5 18t17.5 7t17.5 -7t7.5 -18zM980 896l14 -492l-14 -236 +q0 -11 -8 -19t-19 -8t-19 8t-9 19l-12 236l12 492q1 12 9 20t19 8t18.5 -8t8.5 -20zM1192 404l-14 -231v0q0 -13 -9 -22t-22 -9t-22 9t-10 22l-6 114l-6 117l12 636v3q2 15 12 24q9 7 20 7q8 0 15 -5q14 -8 16 -26zM2304 423q0 -117 -83 -199.5t-200 -82.5h-786 +q-13 2 -22 11t-9 22v899q0 23 28 33q85 34 181 34q195 0 338 -131.5t160 -323.5q53 22 110 22q117 0 200 -83t83 -201z" /> + <glyph glyph-name="uniF1C0" unicode="" +d="M768 768q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 0q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127 +t443 -43zM768 384q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 1536q208 0 385 -34.5t280 -93.5t103 -128v-128q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5 +t-103 128v128q0 69 103 128t280 93.5t385 34.5z" /> + <glyph glyph-name="uniF1C1" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +M894 465q33 -26 84 -56q59 7 117 7q147 0 177 -49q16 -22 2 -52q0 -1 -1 -2l-2 -2v-1q-6 -38 -71 -38q-48 0 -115 20t-130 53q-221 -24 -392 -83q-153 -262 -242 -262q-15 0 -28 7l-24 12q-1 1 -6 5q-10 10 -6 36q9 40 56 91.5t132 96.5q14 9 23 -6q2 -2 2 -4q52 85 107 197 +q68 136 104 262q-24 82 -30.5 159.5t6.5 127.5q11 40 42 40h21h1q23 0 35 -15q18 -21 9 -68q-2 -6 -4 -8q1 -3 1 -8v-30q-2 -123 -14 -192q55 -164 146 -238zM318 54q52 24 137 158q-51 -40 -87.5 -84t-49.5 -74zM716 974q-15 -42 -2 -132q1 7 7 44q0 3 7 43q1 4 4 8 +q-1 1 -1 2q-1 2 -1 3q-1 22 -13 36q0 -1 -1 -2v-2zM592 313q135 54 284 81q-2 1 -13 9.5t-16 13.5q-76 67 -127 176q-27 -86 -83 -197q-30 -56 -45 -83zM1238 329q-24 24 -140 24q76 -28 124 -28q14 0 18 1q0 1 -2 3z" /> + <glyph glyph-name="_422" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +M233 768v-107h70l164 -661h159l128 485q7 20 10 46q2 16 2 24h4l3 -24q1 -3 3.5 -20t5.5 -26l128 -485h159l164 661h70v107h-300v-107h90l-99 -438q-5 -20 -7 -46l-2 -21h-4q0 3 -0.5 6.5t-1.5 8t-1 6.5q-1 5 -4 21t-5 25l-144 545h-114l-144 -545q-2 -9 -4.5 -24.5 +t-3.5 -21.5l-4 -21h-4l-2 21q-2 26 -7 46l-99 438h90v107h-300z" /> + <glyph glyph-name="_423" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +M429 106v-106h281v106h-75l103 161q5 7 10 16.5t7.5 13.5t3.5 4h2q1 -4 5 -10q2 -4 4.5 -7.5t6 -8t6.5 -8.5l107 -161h-76v-106h291v106h-68l-192 273l195 282h67v107h-279v-107h74l-103 -159q-4 -7 -10 -16.5t-9 -13.5l-2 -3h-2q-1 4 -5 10q-6 11 -17 23l-106 159h76v107 +h-290v-107h68l189 -272l-194 -283h-68z" /> + <glyph glyph-name="_424" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +M416 106v-106h327v106h-93v167h137q76 0 118 15q67 23 106.5 87t39.5 146q0 81 -37 141t-100 87q-48 19 -130 19h-368v-107h92v-555h-92zM769 386h-119v268h120q52 0 83 -18q56 -33 56 -115q0 -89 -62 -120q-31 -15 -78 -15z" /> + <glyph glyph-name="_425" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +M1280 320v-320h-1024v192l192 192l128 -128l384 384zM448 512q-80 0 -136 56t-56 136t56 136t136 56t136 -56t56 -136t-56 -136t-136 -56z" /> + <glyph glyph-name="_426" unicode="" +d="M640 1152v128h-128v-128h128zM768 1024v128h-128v-128h128zM640 896v128h-128v-128h128zM768 768v128h-128v-128h128zM1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400 +v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-128v-128h-128v128h-512v-1536h1280zM781 593l107 -349q8 -27 8 -52q0 -83 -72.5 -137.5t-183.5 -54.5t-183.5 54.5t-72.5 137.5q0 25 8 52q21 63 120 396v128h128v-128h79 +q22 0 39 -13t23 -34zM640 128q53 0 90.5 19t37.5 45t-37.5 45t-90.5 19t-90.5 -19t-37.5 -45t37.5 -45t90.5 -19z" /> + <glyph glyph-name="_427" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +M620 686q20 -8 20 -30v-544q0 -22 -20 -30q-8 -2 -12 -2q-12 0 -23 9l-166 167h-131q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h131l166 167q16 15 35 7zM1037 -3q31 0 50 24q129 159 129 363t-129 363q-16 21 -43 24t-47 -14q-21 -17 -23.5 -43.5t14.5 -47.5 +q100 -123 100 -282t-100 -282q-17 -21 -14.5 -47.5t23.5 -42.5q18 -15 40 -15zM826 145q27 0 47 20q87 93 87 219t-87 219q-18 19 -45 20t-46 -17t-20 -44.5t18 -46.5q52 -57 52 -131t-52 -131q-19 -20 -18 -46.5t20 -44.5q20 -17 44 -17z" /> + <glyph glyph-name="_428" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +M768 768q52 0 90 -38t38 -90v-384q0 -52 -38 -90t-90 -38h-384q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h384zM1260 766q20 -8 20 -30v-576q0 -22 -20 -30q-8 -2 -12 -2q-14 0 -23 9l-265 266v90l265 266q9 9 23 9q4 0 12 -2z" /> + <glyph glyph-name="_429" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +M480 768q8 11 21 12.5t24 -6.5l51 -38q11 -8 12.5 -21t-6.5 -24l-182 -243l182 -243q8 -11 6.5 -24t-12.5 -21l-51 -38q-11 -8 -24 -6.5t-21 12.5l-226 301q-14 19 0 38zM1282 467q14 -19 0 -38l-226 -301q-8 -11 -21 -12.5t-24 6.5l-51 38q-11 8 -12.5 21t6.5 24l182 243 +l-182 243q-8 11 -6.5 24t12.5 21l51 38q11 8 24 6.5t21 -12.5zM662 6q-13 2 -20.5 13t-5.5 24l138 831q2 13 13 20.5t24 5.5l63 -10q13 -2 20.5 -13t5.5 -24l-138 -831q-2 -13 -13 -20.5t-24 -5.5z" /> + <glyph glyph-name="_430" unicode="" +d="M1497 709v-198q-101 -23 -198 -23q-65 -136 -165.5 -271t-181.5 -215.5t-128 -106.5q-80 -45 -162 3q-28 17 -60.5 43.5t-85 83.5t-102.5 128.5t-107.5 184t-105.5 244t-91.5 314.5t-70.5 390h283q26 -218 70 -398.5t104.5 -317t121.5 -235.5t140 -195q169 169 287 406 +q-142 72 -223 220t-81 333q0 192 104 314.5t284 122.5q178 0 273 -105.5t95 -297.5q0 -159 -58 -286q-7 -1 -19.5 -3t-46 -2t-63 6t-62 25.5t-50.5 51.5q31 103 31 184q0 87 -29 132t-79 45q-53 0 -85 -49.5t-32 -140.5q0 -186 105 -293.5t267 -107.5q62 0 121 14z" /> + <glyph glyph-name="_431" unicode="" horiz-adv-x="1792" +d="M216 367l603 -402v359l-334 223zM154 511l193 129l-193 129v-258zM973 -35l603 402l-269 180l-334 -223v-359zM896 458l272 182l-272 182l-272 -182zM485 733l334 223v359l-603 -402zM1445 640l193 -129v258zM1307 733l269 180l-603 402v-359zM1792 913v-546 +q0 -41 -34 -64l-819 -546q-21 -13 -43 -13t-43 13l-819 546q-34 23 -34 64v546q0 41 34 64l819 546q21 13 43 13t43 -13l819 -546q34 -23 34 -64z" /> + <glyph glyph-name="_432" unicode="" horiz-adv-x="2048" +d="M1800 764q111 -46 179.5 -145.5t68.5 -221.5q0 -164 -118 -280.5t-285 -116.5q-4 0 -11.5 0.5t-10.5 0.5h-1209h-1h-2h-5q-170 10 -288 125.5t-118 280.5q0 110 55 203t147 147q-12 39 -12 82q0 115 82 196t199 81q95 0 172 -58q75 154 222.5 248t326.5 94 +q166 0 306 -80.5t221.5 -218.5t81.5 -301q0 -6 -0.5 -18t-0.5 -18zM468 498q0 -122 84 -193t208 -71q137 0 240 99q-16 20 -47.5 56.5t-43.5 50.5q-67 -65 -144 -65q-55 0 -93.5 33.5t-38.5 87.5q0 53 38.5 87t91.5 34q44 0 84.5 -21t73 -55t65 -75t69 -82t77 -75t97 -55 +t121.5 -21q121 0 204.5 71.5t83.5 190.5q0 121 -84 192t-207 71q-143 0 -241 -97l93 -108q66 64 142 64q52 0 92 -33t40 -84q0 -57 -37 -91.5t-94 -34.5q-43 0 -82.5 21t-72 55t-65.5 75t-69.5 82t-77.5 75t-96.5 55t-118.5 21q-122 0 -207 -70.5t-85 -189.5z" /> + <glyph glyph-name="_433" unicode="" horiz-adv-x="1792" +d="M896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 1408q-190 0 -361 -90l194 -194q82 28 167 28t167 -28l194 194q-171 90 -361 90zM218 279l194 194 +q-28 82 -28 167t28 167l-194 194q-90 -171 -90 -361t90 -361zM896 -128q190 0 361 90l-194 194q-82 -28 -167 -28t-167 28l-194 -194q171 -90 361 -90zM896 256q159 0 271.5 112.5t112.5 271.5t-112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5 +t271.5 -112.5zM1380 473l194 -194q90 171 90 361t-90 361l-194 -194q28 -82 28 -167t-28 -167z" /> + <glyph glyph-name="_434" unicode="" horiz-adv-x="1792" +d="M1760 640q0 -176 -68.5 -336t-184 -275.5t-275.5 -184t-336 -68.5t-336 68.5t-275.5 184t-184 275.5t-68.5 336q0 213 97 398.5t265 305.5t374 151v-228q-221 -45 -366.5 -221t-145.5 -406q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5 +t136.5 204t51 248.5q0 230 -145.5 406t-366.5 221v228q206 -31 374 -151t265 -305.5t97 -398.5z" /> + <glyph glyph-name="uniF1D0" unicode="" horiz-adv-x="1792" +d="M19 662q8 217 116 406t305 318h5q0 -1 -1 -3q-8 -8 -28 -33.5t-52 -76.5t-60 -110.5t-44.5 -135.5t-14 -150.5t39 -157.5t108.5 -154q50 -50 102 -69.5t90.5 -11.5t69.5 23.5t47 32.5l16 16q39 51 53 116.5t6.5 122.5t-21 107t-26.5 80l-14 29q-10 25 -30.5 49.5t-43 41 +t-43.5 29.5t-35 19l-13 6l104 115q39 -17 78 -52t59 -61l19 -27q1 48 -18.5 103.5t-40.5 87.5l-20 31l161 183l160 -181q-33 -46 -52.5 -102.5t-22.5 -90.5l-4 -33q22 37 61.5 72.5t67.5 52.5l28 17l103 -115q-44 -14 -85 -50t-60 -65l-19 -29q-31 -56 -48 -133.5t-7 -170 +t57 -156.5q33 -45 77.5 -60.5t85 -5.5t76 26.5t57.5 33.5l21 16q60 53 96.5 115t48.5 121.5t10 121.5t-18 118t-37 107.5t-45.5 93t-45 72t-34.5 47.5l-13 17q-14 13 -7 13l10 -3q40 -29 62.5 -46t62 -50t64 -58t58.5 -65t55.5 -77t45.5 -88t38 -103t23.5 -117t10.5 -136 +q3 -259 -108 -465t-312 -321t-456 -115q-185 0 -351 74t-283.5 198t-184 293t-60.5 353z" /> + <glyph glyph-name="uniF1D1" unicode="" horiz-adv-x="1792" +d="M874 -102v-66q-208 6 -385 109.5t-283 275.5l58 34q29 -49 73 -99l65 57q148 -168 368 -212l-17 -86q65 -12 121 -13zM276 428l-83 -28q22 -60 49 -112l-57 -33q-98 180 -98 385t98 385l57 -33q-30 -56 -49 -112l82 -28q-35 -100 -35 -212q0 -109 36 -212zM1528 251 +l58 -34q-106 -172 -283 -275.5t-385 -109.5v66q56 1 121 13l-17 86q220 44 368 212l65 -57q44 50 73 99zM1377 805l-233 -80q14 -42 14 -85t-14 -85l232 -80q-31 -92 -98 -169l-185 162q-57 -67 -147 -85l48 -241q-52 -10 -98 -10t-98 10l48 241q-90 18 -147 85l-185 -162 +q-67 77 -98 169l232 80q-14 42 -14 85t14 85l-233 80q33 93 99 169l185 -162q59 68 147 86l-48 240q44 10 98 10t98 -10l-48 -240q88 -18 147 -86l185 162q66 -76 99 -169zM874 1448v-66q-65 -2 -121 -13l17 -86q-220 -42 -368 -211l-65 56q-38 -42 -73 -98l-57 33 +q106 172 282 275.5t385 109.5zM1705 640q0 -205 -98 -385l-57 33q27 52 49 112l-83 28q36 103 36 212q0 112 -35 212l82 28q-19 56 -49 112l57 33q98 -180 98 -385zM1585 1063l-57 -33q-35 56 -73 98l-65 -56q-148 169 -368 211l17 86q-56 11 -121 13v66q209 -6 385 -109.5 +t282 -275.5zM1748 640q0 173 -67.5 331t-181.5 272t-272 181.5t-331 67.5t-331 -67.5t-272 -181.5t-181.5 -272t-67.5 -331t67.5 -331t181.5 -272t272 -181.5t331 -67.5t331 67.5t272 181.5t181.5 272t67.5 331zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71 +t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="uniF1D2" unicode="" +d="M582 228q0 -66 -93 -66q-107 0 -107 63q0 64 98 64q102 0 102 -61zM546 694q0 -85 -74 -85q-77 0 -77 84q0 90 77 90q36 0 55 -25.5t19 -63.5zM712 769v125q-78 -29 -135 -29q-50 29 -110 29q-86 0 -145 -57t-59 -143q0 -50 29.5 -102t73.5 -67v-3q-38 -17 -38 -85 +q0 -53 41 -77v-3q-113 -37 -113 -139q0 -45 20 -78.5t54 -51t72 -25.5t81 -8q224 0 224 188q0 67 -48 99t-126 46q-27 5 -51.5 20.5t-24.5 39.5q0 44 49 52q77 15 122 70t45 134q0 24 -10 52q37 9 49 13zM771 350h137q-2 27 -2 82v387q0 46 2 69h-137q3 -23 3 -71v-392 +q0 -50 -3 -75zM1280 366v121q-30 -21 -68 -21q-53 0 -53 82v225h52q9 0 26.5 -1t26.5 -1v117h-105q0 82 3 102h-140q4 -24 4 -55v-47h-60v-117q36 3 37 3q3 0 11 -0.5t12 -0.5v-2h-2v-217q0 -37 2.5 -64t11.5 -56.5t24.5 -48.5t43.5 -31t66 -12q64 0 108 24zM924 1072 +q0 36 -24 63.5t-60 27.5t-60.5 -27t-24.5 -64q0 -36 25 -62.5t60 -26.5t59.5 27t24.5 62zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_438" unicode="" horiz-adv-x="1792" +d="M595 22q0 100 -165 100q-158 0 -158 -104q0 -101 172 -101q151 0 151 105zM536 777q0 61 -30 102t-89 41q-124 0 -124 -145q0 -135 124 -135q119 0 119 137zM805 1101v-202q-36 -12 -79 -22q16 -43 16 -84q0 -127 -73 -216.5t-197 -112.5q-40 -8 -59.5 -27t-19.5 -58 +q0 -31 22.5 -51.5t58 -32t78.5 -22t86 -25.5t78.5 -37.5t58 -64t22.5 -98.5q0 -304 -363 -304q-69 0 -130 12.5t-116 41t-87.5 82t-32.5 127.5q0 165 182 225v4q-67 41 -67 126q0 109 63 137v4q-72 24 -119.5 108.5t-47.5 165.5q0 139 95 231.5t235 92.5q96 0 178 -47 +q98 0 218 47zM1123 220h-222q4 45 4 134v609q0 94 -4 128h222q-4 -33 -4 -124v-613q0 -89 4 -134zM1724 442v-196q-71 -39 -174 -39q-62 0 -107 20t-70 50t-39.5 78t-18.5 92t-4 103v351h2v4q-7 0 -19 1t-18 1q-21 0 -59 -6v190h96v76q0 54 -6 89h227q-6 -41 -6 -165h171 +v-190q-15 0 -43.5 2t-42.5 2h-85v-365q0 -131 87 -131q61 0 109 33zM1148 1389q0 -58 -39 -101.5t-96 -43.5q-58 0 -98 43.5t-40 101.5q0 59 39.5 103t98.5 44q58 0 96.5 -44.5t38.5 -102.5z" /> + <glyph glyph-name="_439" unicode="" +d="M809 532l266 499h-112l-157 -312q-24 -48 -44 -92l-42 92l-155 312h-120l263 -493v-324h101v318zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="uniF1D5" unicode="" horiz-adv-x="1280" +d="M842 964q0 -80 -57 -136.5t-136 -56.5q-60 0 -111 35q-62 -67 -115 -146q-247 -371 -202 -859q1 -22 -12.5 -38.5t-34.5 -18.5h-5q-20 0 -35 13.5t-17 33.5q-14 126 -3.5 247.5t29.5 217t54 186t69 155.5t74 125q61 90 132 165q-16 35 -16 77q0 80 56.5 136.5t136.5 56.5 +t136.5 -56.5t56.5 -136.5zM1223 953q0 -158 -78 -292t-212.5 -212t-292.5 -78q-64 0 -131 14q-21 5 -32.5 23.5t-6.5 39.5q5 20 23 31.5t39 7.5q51 -13 108 -13q97 0 186 38t153 102t102 153t38 186t-38 186t-102 153t-153 102t-186 38t-186 -38t-153 -102t-102 -153 +t-38 -186q0 -114 52 -218q10 -20 3.5 -40t-25.5 -30t-39.5 -3t-30.5 26q-64 123 -64 265q0 119 46.5 227t124.5 186t186 124t226 46q158 0 292.5 -78t212.5 -212.5t78 -292.5z" /> + <glyph glyph-name="uniF1D6" unicode="" horiz-adv-x="1792" +d="M270 730q-8 19 -8 52q0 20 11 49t24 45q-1 22 7.5 53t22.5 43q0 139 92.5 288.5t217.5 209.5q139 66 324 66q133 0 266 -55q49 -21 90 -48t71 -56t55 -68t42 -74t32.5 -84.5t25.5 -89.5t22 -98l1 -5q55 -83 55 -150q0 -14 -9 -40t-9 -38q0 -1 1.5 -3.5t3.5 -5t2 -3.5 +q77 -114 120.5 -214.5t43.5 -208.5q0 -43 -19.5 -100t-55.5 -57q-9 0 -19.5 7.5t-19 17.5t-19 26t-16 26.5t-13.5 26t-9 17.5q-1 1 -3 1l-5 -4q-59 -154 -132 -223q20 -20 61.5 -38.5t69 -41.5t35.5 -65q-2 -4 -4 -16t-7 -18q-64 -97 -302 -97q-53 0 -110.5 9t-98 20 +t-104.5 30q-15 5 -23 7q-14 4 -46 4.5t-40 1.5q-41 -45 -127.5 -65t-168.5 -20q-35 0 -69 1.5t-93 9t-101 20.5t-74.5 40t-32.5 64q0 40 10 59.5t41 48.5q11 2 40.5 13t49.5 12q4 0 14 2q2 2 2 4l-2 3q-48 11 -108 105.5t-73 156.5l-5 3q-4 0 -12 -20q-18 -41 -54.5 -74.5 +t-77.5 -37.5h-1q-4 0 -6 4.5t-5 5.5q-23 54 -23 100q0 275 252 466z" /> + <glyph glyph-name="uniF1D7" unicode="" horiz-adv-x="2048" +d="M580 1075q0 41 -25 66t-66 25q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 66 24.5t25 65.5zM1323 568q0 28 -25.5 50t-65.5 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q40 0 65.5 22t25.5 51zM1087 1075q0 41 -24.5 66t-65.5 25 +q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 65.5 24.5t24.5 65.5zM1722 568q0 28 -26 50t-65 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q39 0 65 22t26 51zM1456 965q-31 4 -70 4q-169 0 -311 -77t-223.5 -208.5t-81.5 -287.5 +q0 -78 23 -152q-35 -3 -68 -3q-26 0 -50 1.5t-55 6.5t-44.5 7t-54.5 10.5t-50 10.5l-253 -127l72 218q-290 203 -290 490q0 169 97.5 311t264 223.5t363.5 81.5q176 0 332.5 -66t262 -182.5t136.5 -260.5zM2048 404q0 -117 -68.5 -223.5t-185.5 -193.5l55 -181l-199 109 +q-150 -37 -218 -37q-169 0 -311 70.5t-223.5 191.5t-81.5 264t81.5 264t223.5 191.5t311 70.5q161 0 303 -70.5t227.5 -192t85.5 -263.5z" /> + <glyph glyph-name="_443" unicode="" horiz-adv-x="1792" +d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-453 185l-242 -295q-18 -23 -49 -23q-13 0 -22 4q-19 7 -30.5 23.5t-11.5 36.5v349l864 1059l-1069 -925l-395 162q-37 14 -40 55q-2 40 32 59l1664 960q15 9 32 9q20 0 36 -11z" /> + <glyph glyph-name="_444" unicode="" horiz-adv-x="1792" +d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-527 215l-298 -327q-18 -21 -47 -21q-14 0 -23 4q-19 7 -30 23.5t-11 36.5v452l-472 193q-37 14 -40 55q-3 39 32 59l1664 960q35 21 68 -2zM1422 26l221 1323l-1434 -827l336 -137 +l863 639l-478 -797z" /> + <glyph glyph-name="_445" unicode="" +d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 +t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298zM896 928v-448q0 -14 -9 -23 +t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23z" /> + <glyph glyph-name="_446" unicode="" +d="M768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 +t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="_447" unicode="" horiz-adv-x="1792" +d="M1682 -128q-44 0 -132.5 3.5t-133.5 3.5q-44 0 -132 -3.5t-132 -3.5q-24 0 -37 20.5t-13 45.5q0 31 17 46t39 17t51 7t45 15q33 21 33 140l-1 391q0 21 -1 31q-13 4 -50 4h-675q-38 0 -51 -4q-1 -10 -1 -31l-1 -371q0 -142 37 -164q16 -10 48 -13t57 -3.5t45 -15 +t20 -45.5q0 -26 -12.5 -48t-36.5 -22q-47 0 -139.5 3.5t-138.5 3.5q-43 0 -128 -3.5t-127 -3.5q-23 0 -35.5 21t-12.5 45q0 30 15.5 45t36 17.5t47.5 7.5t42 15q33 23 33 143l-1 57v813q0 3 0.5 26t0 36.5t-1.5 38.5t-3.5 42t-6.5 36.5t-11 31.5t-16 18q-15 10 -45 12t-53 2 +t-41 14t-18 45q0 26 12 48t36 22q46 0 138.5 -3.5t138.5 -3.5q42 0 126.5 3.5t126.5 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17 -43.5t-38.5 -14.5t-49.5 -4t-43 -13q-35 -21 -35 -160l1 -320q0 -21 1 -32q13 -3 39 -3h699q25 0 38 3q1 11 1 32l1 320q0 139 -35 160 +q-18 11 -58.5 12.5t-66 13t-25.5 49.5q0 26 12.5 48t37.5 22q44 0 132 -3.5t132 -3.5q43 0 129 3.5t129 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17.5 -44t-40 -14.5t-51.5 -3t-44 -12.5q-35 -23 -35 -161l1 -943q0 -119 34 -140q16 -10 46 -13.5t53.5 -4.5t41.5 -15.5t18 -44.5 +q0 -26 -12 -48t-36 -22z" /> + <glyph glyph-name="_448" unicode="" horiz-adv-x="1280" +d="M1278 1347v-73q0 -29 -18.5 -61t-42.5 -32q-50 0 -54 -1q-26 -6 -32 -31q-3 -11 -3 -64v-1152q0 -25 -18 -43t-43 -18h-108q-25 0 -43 18t-18 43v1218h-143v-1218q0 -25 -17.5 -43t-43.5 -18h-108q-26 0 -43.5 18t-17.5 43v496q-147 12 -245 59q-126 58 -192 179 +q-64 117 -64 259q0 166 88 286q88 118 209 159q111 37 417 37h479q25 0 43 -18t18 -43z" /> + <glyph glyph-name="_449" unicode="" +d="M352 128v-128h-352v128h352zM704 256q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM864 640v-128h-864v128h864zM224 1152v-128h-224v128h224zM1536 128v-128h-736v128h736zM576 1280q26 0 45 -19t19 -45v-256 +q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1216 768q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1536 640v-128h-224v128h224zM1536 1152v-128h-864v128h864z" /> + <glyph glyph-name="uniF1E0" unicode="" +d="M1216 512q133 0 226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5t-226.5 93.5t-93.5 226.5q0 12 2 34l-360 180q-92 -86 -218 -86q-133 0 -226.5 93.5t-93.5 226.5t93.5 226.5t226.5 93.5q126 0 218 -86l360 180q-2 22 -2 34q0 133 93.5 226.5t226.5 93.5 +t226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5q-126 0 -218 86l-360 -180q2 -22 2 -34t-2 -34l360 -180q92 86 218 86z" /> + <glyph glyph-name="_451" unicode="" +d="M1280 341q0 88 -62.5 151t-150.5 63q-84 0 -145 -58l-241 120q2 16 2 23t-2 23l241 120q61 -58 145 -58q88 0 150.5 63t62.5 151t-62.5 150.5t-150.5 62.5t-151 -62.5t-63 -150.5q0 -7 2 -23l-241 -120q-62 57 -145 57q-88 0 -150.5 -62.5t-62.5 -150.5t62.5 -150.5 +t150.5 -62.5q83 0 145 57l241 -120q-2 -16 -2 -23q0 -88 63 -150.5t151 -62.5t150.5 62.5t62.5 150.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_452" unicode="" horiz-adv-x="1792" +d="M571 947q-10 25 -34 35t-49 0q-108 -44 -191 -127t-127 -191q-10 -25 0 -49t35 -34q13 -5 24 -5q42 0 60 40q34 84 98.5 148.5t148.5 98.5q25 11 35 35t0 49zM1513 1303l46 -46l-244 -243l68 -68q19 -19 19 -45.5t-19 -45.5l-64 -64q89 -161 89 -343q0 -143 -55.5 -273.5 +t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5q182 0 343 -89l64 64q19 19 45.5 19t45.5 -19l68 -68zM1521 1359q-10 -10 -22 -10q-13 0 -23 10l-91 90q-9 10 -9 23t9 23q10 9 23 9t23 -9l90 -91 +q10 -9 10 -22.5t-10 -22.5zM1751 1129q-11 -9 -23 -9t-23 9l-90 91q-10 9 -10 22.5t10 22.5q9 10 22.5 10t22.5 -10l91 -90q9 -10 9 -23t-9 -23zM1792 1312q0 -14 -9 -23t-23 -9h-96q-14 0 -23 9t-9 23t9 23t23 9h96q14 0 23 -9t9 -23zM1600 1504v-96q0 -14 -9 -23t-23 -9 +t-23 9t-9 23v96q0 14 9 23t23 9t23 -9t9 -23zM1751 1449l-91 -90q-10 -10 -22 -10q-13 0 -23 10q-10 9 -10 22.5t10 22.5l90 91q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" /> + <glyph glyph-name="_453" unicode="" horiz-adv-x="1792" +d="M609 720l287 208l287 -208l-109 -336h-355zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM1515 186q149 203 149 454v3l-102 -89l-240 224l63 323 +l134 -12q-150 206 -389 282l53 -124l-287 -159l-287 159l53 124q-239 -76 -389 -282l135 12l62 -323l-240 -224l-102 89v-3q0 -251 149 -454l30 132l326 -40l139 -298l-116 -69q117 -39 240 -39t240 39l-116 69l139 298l326 40z" /> + <glyph glyph-name="_454" unicode="" horiz-adv-x="1792" +d="M448 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM256 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM832 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 +v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM66 768q-28 0 -47 19t-19 46v129h514v-129q0 -27 -19 -46t-46 -19h-383zM1216 224v-192q0 -14 -9 -23t-23 -9h-192 +q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1600 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23 +zM1408 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1016v-13h-514v10q0 104 -382 102q-382 -1 -382 -102v-10h-514v13q0 17 8.5 43t34 64t65.5 75.5t110.5 76t160 67.5t224 47.5t293.5 18.5t293 -18.5t224 -47.5 +t160.5 -67.5t110.5 -76t65.5 -75.5t34 -64t8.5 -43zM1792 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 962v-129q0 -27 -19 -46t-46 -19h-384q-27 0 -46 19t-19 46v129h514z" /> + <glyph glyph-name="_455" unicode="" horiz-adv-x="1792" +d="M704 1216v-768q0 -26 -19 -45t-45 -19v-576q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v512l249 873q7 23 31 23h424zM1024 1216v-704h-256v704h256zM1792 320v-512q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v576q-26 0 -45 19t-19 45v768h424q24 0 31 -23z +M736 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23zM1408 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23z" /> + <glyph glyph-name="_456" unicode="" horiz-adv-x="1792" +d="M1755 1083q37 -38 37 -90.5t-37 -90.5l-401 -400l150 -150l-160 -160q-163 -163 -389.5 -186.5t-411.5 100.5l-362 -362h-181v181l362 362q-124 185 -100.5 411.5t186.5 389.5l160 160l150 -150l400 401q38 37 91 37t90 -37t37 -90.5t-37 -90.5l-400 -401l234 -234 +l401 400q38 37 91 37t90 -37z" /> + <glyph glyph-name="_457" unicode="" horiz-adv-x="1792" +d="M873 796q0 -83 -63.5 -142.5t-152.5 -59.5t-152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59t152.5 -59t63.5 -143zM1375 796q0 -83 -63 -142.5t-153 -59.5q-89 0 -152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59q90 0 153 -59t63 -143zM1600 616v667q0 87 -32 123.5 +t-111 36.5h-1112q-83 0 -112.5 -34t-29.5 -126v-673q43 -23 88.5 -40t81 -28t81 -18.5t71 -11t70 -4t58.5 -0.5t56.5 2t44.5 2q68 1 95 -27q6 -6 10 -9q26 -25 61 -51q7 91 118 87q5 0 36.5 -1.5t43 -2t45.5 -1t53 1t54.5 4.5t61 8.5t62 13.5t67 19.5t67.5 27t72 34.5z +M1763 621q-121 -149 -372 -252q84 -285 -23 -465q-66 -113 -183 -148q-104 -32 -182 15q-86 51 -82 164l-1 326v1q-8 2 -24.5 6t-23.5 5l-1 -338q4 -114 -83 -164q-79 -47 -183 -15q-117 36 -182 150q-105 180 -22 463q-251 103 -372 252q-25 37 -4 63t60 -1q4 -2 11.5 -7 +t10.5 -8v694q0 72 47 123t114 51h1257q67 0 114 -51t47 -123v-694l21 15q39 27 60 1t-4 -63z" /> + <glyph glyph-name="_458" unicode="" horiz-adv-x="1792" +d="M896 1102v-434h-145v434h145zM1294 1102v-434h-145v434h145zM1294 342l253 254v795h-1194v-1049h326v-217l217 217h398zM1692 1536v-1013l-434 -434h-326l-217 -217h-217v217h-398v1158l109 289h1483z" /> + <glyph glyph-name="_459" unicode="" +d="M773 217v-127q-1 -292 -6 -305q-12 -32 -51 -40q-54 -9 -181.5 38t-162.5 89q-13 15 -17 36q-1 12 4 26q4 10 34 47t181 216q1 0 60 70q15 19 39.5 24.5t49.5 -3.5q24 -10 37.5 -29t12.5 -42zM624 468q-3 -55 -52 -70l-120 -39q-275 -88 -292 -88q-35 2 -54 36 +q-12 25 -17 75q-8 76 1 166.5t30 124.5t56 32q13 0 202 -77q71 -29 115 -47l84 -34q23 -9 35.5 -30.5t11.5 -48.5zM1450 171q-7 -54 -91.5 -161t-135.5 -127q-37 -14 -63 7q-14 10 -184 287l-47 77q-14 21 -11.5 46t19.5 46q35 43 83 26q1 -1 119 -40q203 -66 242 -79.5 +t47 -20.5q28 -22 22 -61zM778 803q5 -102 -54 -122q-58 -17 -114 71l-378 598q-8 35 19 62q41 43 207.5 89.5t224.5 31.5q40 -10 49 -45q3 -18 22 -305.5t24 -379.5zM1440 695q3 -39 -26 -59q-15 -10 -329 -86q-67 -15 -91 -23l1 2q-23 -6 -46 4t-37 32q-30 47 0 87 +q1 1 75 102q125 171 150 204t34 39q28 19 65 2q48 -23 123 -133.5t81 -167.5v-3z" /> + <glyph glyph-name="_460" unicode="" horiz-adv-x="2048" +d="M1024 1024h-384v-384h384v384zM1152 384v-128h-640v128h640zM1152 1152v-640h-640v640h640zM1792 384v-128h-512v128h512zM1792 640v-128h-512v128h512zM1792 896v-128h-512v128h512zM1792 1152v-128h-512v128h512zM256 192v960h-128v-960q0 -26 19 -45t45 -19t45 19 +t19 45zM1920 192v1088h-1536v-1088q0 -33 -11 -64h1483q26 0 45 19t19 45zM2048 1408v-1216q0 -80 -56 -136t-136 -56h-1664q-80 0 -136 56t-56 136v1088h256v128h1792z" /> + <glyph glyph-name="_461" unicode="" horiz-adv-x="2048" +d="M1024 13q-20 0 -93 73.5t-73 93.5q0 32 62.5 54t103.5 22t103.5 -22t62.5 -54q0 -20 -73 -93.5t-93 -73.5zM1294 284q-2 0 -40 25t-101.5 50t-128.5 25t-128.5 -25t-101 -50t-40.5 -25q-18 0 -93.5 75t-75.5 93q0 13 10 23q78 77 196 121t233 44t233 -44t196 -121 +q10 -10 10 -23q0 -18 -75.5 -93t-93.5 -75zM1567 556q-11 0 -23 8q-136 105 -252 154.5t-268 49.5q-85 0 -170.5 -22t-149 -53t-113.5 -62t-79 -53t-31 -22q-17 0 -92 75t-75 93q0 12 10 22q132 132 320 205t380 73t380 -73t320 -205q10 -10 10 -22q0 -18 -75 -93t-92 -75z +M1838 827q-11 0 -22 9q-179 157 -371.5 236.5t-420.5 79.5t-420.5 -79.5t-371.5 -236.5q-11 -9 -22 -9q-17 0 -92.5 75t-75.5 93q0 13 10 23q187 186 445 288t527 102t527 -102t445 -288q10 -10 10 -23q0 -18 -75.5 -93t-92.5 -75z" /> + <glyph glyph-name="_462" unicode="" horiz-adv-x="1792" +d="M384 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 +t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5 +t37.5 90.5zM384 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 768q0 53 -37.5 90.5t-90.5 37.5 +t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1536 0v384q0 52 -38 90t-90 38t-90 -38t-38 -90v-384q0 -52 38 -90t90 -38t90 38t38 90zM1152 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z +M1536 1088v256q0 26 -19 45t-45 19h-1280q-26 0 -45 -19t-19 -45v-256q0 -26 19 -45t45 -19h1280q26 0 45 19t19 45zM1536 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1408v-1536q0 -52 -38 -90t-90 -38 +h-1408q-52 0 -90 38t-38 90v1536q0 52 38 90t90 38h1408q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_463" unicode="" +d="M1519 890q18 -84 -4 -204q-87 -444 -565 -444h-44q-25 0 -44 -16.5t-24 -42.5l-4 -19l-55 -346l-2 -15q-5 -26 -24.5 -42.5t-44.5 -16.5h-251q-21 0 -33 15t-9 36q9 56 26.5 168t26.5 168t27 167.5t27 167.5q5 37 43 37h131q133 -2 236 21q175 39 287 144q102 95 155 246 +q24 70 35 133q1 6 2.5 7.5t3.5 1t6 -3.5q79 -59 98 -162zM1347 1172q0 -107 -46 -236q-80 -233 -302 -315q-113 -40 -252 -42q0 -1 -90 -1l-90 1q-100 0 -118 -96q-2 -8 -85 -530q-1 -10 -12 -10h-295q-22 0 -36.5 16.5t-11.5 38.5l232 1471q5 29 27.5 48t51.5 19h598 +q34 0 97.5 -13t111.5 -32q107 -41 163.5 -123t56.5 -196z" /> + <glyph glyph-name="_464" unicode="" horiz-adv-x="1792" +d="M441 864q33 0 52 -26q266 -364 362 -774h-446q-127 441 -367 749q-12 16 -3 33.5t29 17.5h373zM1000 507q-49 -199 -125 -393q-79 310 -256 594q40 221 44 449q211 -340 337 -650zM1099 1216q235 -324 384.5 -698.5t184.5 -773.5h-451q-41 665 -553 1472h435zM1792 640 +q0 -424 -101 -812q-67 560 -359 1083q-25 301 -106 584q-4 16 5.5 28.5t25.5 12.5h359q21 0 38.5 -13t22.5 -33q115 -409 115 -850z" /> + <glyph glyph-name="uniF1F0" unicode="" horiz-adv-x="2304" +d="M1975 546h-138q14 37 66 179l3 9q4 10 10 26t9 26l12 -55zM531 611l-58 295q-11 54 -75 54h-268l-2 -13q311 -79 403 -336zM710 960l-162 -438l-17 89q-26 70 -85 129.5t-131 88.5l135 -510h175l261 641h-176zM849 318h166l104 642h-166zM1617 944q-69 27 -149 27 +q-123 0 -201 -59t-79 -153q-1 -102 145 -174q48 -23 67 -41t19 -39q0 -30 -30 -46t-69 -16q-86 0 -156 33l-22 11l-23 -144q74 -34 185 -34q130 -1 208.5 59t80.5 160q0 106 -140 174q-49 25 -71 42t-22 38q0 22 24.5 38.5t70.5 16.5q70 1 124 -24l15 -8zM2042 960h-128 +q-65 0 -87 -54l-246 -588h174l35 96h212q5 -22 20 -96h154zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_466" unicode="" horiz-adv-x="2304" +d="M1119 1195q-128 85 -281 85q-103 0 -197.5 -40.5t-162.5 -108.5t-108.5 -162t-40.5 -197q0 -104 40.5 -198t108.5 -162t162 -108.5t198 -40.5q153 0 281 85q-131 107 -178 265.5t0.5 316.5t177.5 265zM1152 1171q-126 -99 -172 -249.5t-0.5 -300.5t172.5 -249 +q127 99 172.5 249t-0.5 300.5t-172 249.5zM1185 1195q130 -107 177.5 -265.5t0.5 -317t-178 -264.5q128 -85 281 -85q104 0 198 40.5t162 108.5t108.5 162t40.5 198q0 103 -40.5 197t-108.5 162t-162.5 108.5t-197.5 40.5q-153 0 -281 -85zM1926 473h7v3h-17v-3h7v-17h3v17z +M1955 456h4v20h-5l-6 -13l-6 13h-5v-20h3v15l6 -13h4l5 13v-15zM1947 16v-2h-2h-3v3h3h2v-1zM1947 7h3l-4 5h2l1 1q1 1 1 3t-1 3l-1 1h-3h-6v-13h3v5h1zM685 75q0 19 11 31t30 12q18 0 29 -12.5t11 -30.5q0 -19 -11 -31t-29 -12q-19 0 -30 12t-11 31zM1158 119q30 0 35 -32 +h-70q5 32 35 32zM1514 75q0 19 11 31t29 12t29.5 -12.5t11.5 -30.5q0 -19 -11 -31t-30 -12q-18 0 -29 12t-11 31zM1786 75q0 18 11.5 30.5t29.5 12.5t29.5 -12.5t11.5 -30.5q0 -19 -11.5 -31t-29.5 -12t-29.5 12.5t-11.5 30.5zM1944 3q-2 0 -4 1q-1 0 -3 2t-2 3q-1 2 -1 4 +q0 3 1 4q0 2 2 4l1 1q2 0 2 1q2 1 4 1q3 0 4 -1l4 -2l2 -4v-1q1 -2 1 -3l-1 -1v-3t-1 -1l-1 -2q-2 -2 -4 -2q-1 -1 -4 -1zM599 7h30v85q0 24 -14.5 38.5t-39.5 15.5q-32 0 -47 -24q-14 24 -45 24q-24 0 -39 -20v16h-30v-135h30v75q0 36 33 36q30 0 30 -36v-75h29v75 +q0 36 33 36q30 0 30 -36v-75zM765 7h29v68v67h-29v-16q-17 20 -43 20q-29 0 -48 -20t-19 -51t19 -51t48 -20q28 0 43 20v-17zM943 48q0 34 -47 40l-14 2q-23 4 -23 14q0 15 25 15q23 0 43 -11l12 24q-22 14 -55 14q-26 0 -41 -12t-15 -32q0 -33 47 -39l13 -2q24 -4 24 -14 +q0 -17 -31 -17q-25 0 -45 14l-13 -23q25 -17 58 -17q29 0 45.5 12t16.5 32zM1073 14l-8 25q-13 -7 -26 -7q-19 0 -19 22v61h48v27h-48v41h-30v-41h-28v-27h28v-61q0 -50 47 -50q21 0 36 10zM1159 146q-29 0 -48 -20t-19 -51q0 -32 19.5 -51.5t49.5 -19.5q33 0 55 19l-14 22 +q-18 -15 -39 -15q-34 0 -41 33h101v12q0 32 -18 51.5t-46 19.5zM1318 146q-23 0 -35 -20v16h-30v-135h30v76q0 35 29 35q10 0 18 -4l9 28q-9 4 -21 4zM1348 75q0 -31 19.5 -51t52.5 -20q29 0 48 16l-14 24q-18 -13 -35 -12q-18 0 -29.5 12t-11.5 31t11.5 31t29.5 12 +q19 0 35 -12l14 24q-20 16 -48 16q-33 0 -52.5 -20t-19.5 -51zM1593 7h30v68v67h-30v-16q-15 20 -42 20q-29 0 -48.5 -20t-19.5 -51t19.5 -51t48.5 -20q28 0 42 20v-17zM1726 146q-23 0 -35 -20v16h-29v-135h29v76q0 35 29 35q10 0 18 -4l9 28q-8 4 -21 4zM1866 7h29v68v122 +h-29v-71q-15 20 -43 20t-47.5 -20.5t-19.5 -50.5t19.5 -50.5t47.5 -20.5q29 0 43 20v-17zM1944 27l-2 -1h-3q-2 -1 -4 -3q-3 -1 -3 -4q-1 -2 -1 -6q0 -3 1 -5q0 -2 3 -4q2 -2 4 -3t5 -1q4 0 6 1q0 1 2 2l2 1q1 1 3 4q1 2 1 5q0 4 -1 6q-1 1 -3 4q0 1 -2 2l-2 1q-1 0 -3 0.5 +t-3 0.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_467" unicode="" horiz-adv-x="2304" +d="M313 759q0 -51 -36 -84q-29 -26 -89 -26h-17v220h17q61 0 89 -27q36 -31 36 -83zM2089 824q0 -52 -64 -52h-19v101h20q63 0 63 -49zM380 759q0 74 -50 120.5t-129 46.5h-95v-333h95q74 0 119 38q60 51 60 128zM410 593h65v333h-65v-333zM730 694q0 40 -20.5 62t-75.5 42 +q-29 10 -39.5 19t-10.5 23q0 16 13.5 26.5t34.5 10.5q29 0 53 -27l34 44q-41 37 -98 37q-44 0 -74 -27.5t-30 -67.5q0 -35 18 -55.5t64 -36.5q37 -13 45 -19q19 -12 19 -34q0 -20 -14 -33.5t-36 -13.5q-48 0 -71 44l-42 -40q44 -64 115 -64q51 0 83 30.5t32 79.5zM1008 604 +v77q-37 -37 -78 -37q-49 0 -80.5 32.5t-31.5 82.5q0 48 31.5 81.5t77.5 33.5q43 0 81 -38v77q-40 20 -80 20q-74 0 -125.5 -50.5t-51.5 -123.5t51 -123.5t125 -50.5q42 0 81 19zM2240 0v527q-65 -40 -144.5 -84t-237.5 -117t-329.5 -137.5t-417.5 -134.5t-504 -118h1569 +q26 0 45 19t19 45zM1389 757q0 75 -53 128t-128 53t-128 -53t-53 -128t53 -128t128 -53t128 53t53 128zM1541 584l144 342h-71l-90 -224l-89 224h-71l142 -342h35zM1714 593h184v56h-119v90h115v56h-115v74h119v57h-184v-333zM2105 593h80l-105 140q76 16 76 94q0 47 -31 73 +t-87 26h-97v-333h65v133h9zM2304 1274v-1268q0 -56 -38.5 -95t-93.5 -39h-2040q-55 0 -93.5 39t-38.5 95v1268q0 56 38.5 95t93.5 39h2040q55 0 93.5 -39t38.5 -95z" /> + <glyph glyph-name="f1f3" unicode="" horiz-adv-x="2304" +d="M119 854h89l-45 108zM740 328l74 79l-70 79h-163v-49h142v-55h-142v-54h159zM898 406l99 -110v217zM1186 453q0 33 -40 33h-84v-69h83q41 0 41 36zM1475 457q0 29 -42 29h-82v-61h81q43 0 43 32zM1197 923q0 29 -42 29h-82v-60h81q43 0 43 31zM1656 854h89l-44 108z +M699 1009v-271h-66v212l-94 -212h-57l-94 212v-212h-132l-25 60h-135l-25 -60h-70l116 271h96l110 -257v257h106l85 -184l77 184h108zM1255 453q0 -20 -5.5 -35t-14 -25t-22.5 -16.5t-26 -10t-31.5 -4.5t-31.5 -1t-32.5 0.5t-29.5 0.5v-91h-126l-80 90l-83 -90h-256v271h260 +l80 -89l82 89h207q109 0 109 -89zM964 794v-56h-217v271h217v-57h-152v-49h148v-55h-148v-54h152zM2304 235v-229q0 -55 -38.5 -94.5t-93.5 -39.5h-2040q-55 0 -93.5 39.5t-38.5 94.5v678h111l25 61h55l25 -61h218v46l19 -46h113l20 47v-47h541v99l10 1q10 0 10 -14v-86h279 +v23q23 -12 55 -18t52.5 -6.5t63 0.5t51.5 1l25 61h56l25 -61h227v58l34 -58h182v378h-180v-44l-25 44h-185v-44l-23 44h-249q-69 0 -109 -22v22h-172v-22q-24 22 -73 22h-628l-43 -97l-43 97h-198v-44l-22 44h-169l-78 -179v391q0 55 38.5 94.5t93.5 39.5h2040 +q55 0 93.5 -39.5t38.5 -94.5v-678h-120q-51 0 -81 -22v22h-177q-55 0 -78 -22v22h-316v-22q-31 22 -87 22h-209v-22q-23 22 -91 22h-234l-54 -58l-50 58h-349v-378h343l55 59l52 -59h211v89h21q59 0 90 13v-102h174v99h8q8 0 10 -2t2 -10v-87h529q57 0 88 24v-24h168 +q60 0 95 17zM1546 469q0 -23 -12 -43t-34 -29q25 -9 34 -26t9 -46v-54h-65v45q0 33 -12 43.5t-46 10.5h-69v-99h-65v271h154q48 0 77 -15t29 -58zM1269 936q0 -24 -12.5 -44t-33.5 -29q26 -9 34.5 -25.5t8.5 -46.5v-53h-65q0 9 0.5 26.5t0 25t-3 18.5t-8.5 16t-17.5 8.5 +t-29.5 3.5h-70v-98h-64v271l153 -1q49 0 78 -14.5t29 -57.5zM1798 327v-56h-216v271h216v-56h-151v-49h148v-55h-148v-54zM1372 1009v-271h-66v271h66zM2065 357q0 -86 -102 -86h-126v58h126q34 0 34 25q0 16 -17 21t-41.5 5t-49.5 3.5t-42 22.5t-17 55q0 39 26 60t66 21 +h130v-57h-119q-36 0 -36 -25q0 -16 17.5 -20.5t42 -4t49 -2.5t42 -21.5t17.5 -54.5zM2304 407v-101q-24 -35 -88 -35h-125v58h125q33 0 33 25q0 13 -12.5 19t-31 5.5t-40 2t-40 8t-31 24t-12.5 48.5q0 39 26.5 60t66.5 21h129v-57h-118q-36 0 -36 -25q0 -20 29 -22t68.5 -5 +t56.5 -26zM2139 1008v-270h-92l-122 203v-203h-132l-26 60h-134l-25 -60h-75q-129 0 -129 133q0 138 133 138h63v-59q-7 0 -28 1t-28.5 0.5t-23 -2t-21.5 -6.5t-14.5 -13.5t-11.5 -23t-3 -33.5q0 -38 13.5 -58t49.5 -20h29l92 213h97l109 -256v256h99l114 -188v188h66z" /> + <glyph glyph-name="_469" unicode="" horiz-adv-x="2304" +d="M745 630q0 -37 -25.5 -61.5t-62.5 -24.5q-29 0 -46.5 16t-17.5 44q0 37 25 62.5t62 25.5q28 0 46.5 -16.5t18.5 -45.5zM1530 779q0 -42 -22 -57t-66 -15l-32 -1l17 107q2 11 13 11h18q22 0 35 -2t25 -12.5t12 -30.5zM1881 630q0 -36 -25.5 -61t-61.5 -25q-29 0 -47 16 +t-18 44q0 37 25 62.5t62 25.5q28 0 46.5 -16.5t18.5 -45.5zM513 801q0 59 -38.5 85.5t-100.5 26.5h-160q-19 0 -21 -19l-65 -408q-1 -6 3 -11t10 -5h76q20 0 22 19l18 110q1 8 7 13t15 6.5t17 1.5t19 -1t14 -1q86 0 135 48.5t49 134.5zM822 489l41 261q1 6 -3 11t-10 5h-76 +q-14 0 -17 -33q-27 40 -95 40q-72 0 -122.5 -54t-50.5 -127q0 -59 34.5 -94t92.5 -35q28 0 58 12t48 32q-4 -12 -4 -21q0 -16 13 -16h69q19 0 22 19zM1269 752q0 5 -4 9.5t-9 4.5h-77q-11 0 -18 -10l-106 -156l-44 150q-5 16 -22 16h-75q-5 0 -9 -4.5t-4 -9.5q0 -2 19.5 -59 +t42 -123t23.5 -70q-82 -112 -82 -120q0 -13 13 -13h77q11 0 18 10l255 368q2 2 2 7zM1649 801q0 59 -38.5 85.5t-100.5 26.5h-159q-20 0 -22 -19l-65 -408q-1 -6 3 -11t10 -5h82q12 0 16 13l18 116q1 8 7 13t15 6.5t17 1.5t19 -1t14 -1q86 0 135 48.5t49 134.5zM1958 489 +l41 261q1 6 -3 11t-10 5h-76q-14 0 -17 -33q-26 40 -95 40q-72 0 -122.5 -54t-50.5 -127q0 -59 34.5 -94t92.5 -35q29 0 59 12t47 32q0 -1 -2 -9t-2 -12q0 -16 13 -16h69q19 0 22 19zM2176 898v1q0 14 -13 14h-74q-11 0 -13 -11l-65 -416l-1 -2q0 -5 4 -9.5t10 -4.5h66 +q19 0 21 19zM392 764q-5 -35 -26 -46t-60 -11l-33 -1l17 107q2 11 13 11h19q40 0 58 -11.5t12 -48.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_470" unicode="" horiz-adv-x="2304" +d="M1597 633q0 -69 -21 -106q-19 -35 -52 -35q-23 0 -41 9v224q29 30 57 30q57 0 57 -122zM2035 669h-110q6 98 56 98q51 0 54 -98zM476 534q0 59 -33 91.5t-101 57.5q-36 13 -52 24t-16 25q0 26 38 26q58 0 124 -33l18 112q-67 32 -149 32q-77 0 -123 -38q-48 -39 -48 -109 +q0 -58 32.5 -90.5t99.5 -56.5q39 -14 54.5 -25.5t15.5 -27.5q0 -31 -48 -31q-29 0 -70 12.5t-72 30.5l-18 -113q72 -41 168 -41q81 0 129 37q51 41 51 117zM771 749l19 111h-96v135l-129 -21l-18 -114l-46 -8l-17 -103h62v-219q0 -84 44 -120q38 -30 111 -30q32 0 79 11v118 +q-32 -7 -44 -7q-42 0 -42 50v197h77zM1087 724v139q-15 3 -28 3q-32 0 -55.5 -16t-33.5 -46l-10 56h-131v-471h150v306q26 31 82 31q16 0 26 -2zM1124 389h150v471h-150v-471zM1746 638q0 122 -45 179q-40 52 -111 52q-64 0 -117 -56l-8 47h-132v-645l150 25v151 +q36 -11 68 -11q83 0 134 56q61 65 61 202zM1278 986q0 33 -23 56t-56 23t-56 -23t-23 -56t23 -56.5t56 -23.5t56 23.5t23 56.5zM2176 629q0 113 -48 176q-50 64 -144 64q-96 0 -151.5 -66t-55.5 -180q0 -128 63 -188q55 -55 161 -55q101 0 160 40l-16 103q-57 -31 -128 -31 +q-43 0 -63 19q-23 19 -28 66h248q2 14 2 52zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_471" unicode="" horiz-adv-x="2048" +d="M1558 684q61 -356 298 -556q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5zM1024 -176q16 0 16 16t-16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5zM2026 1424q8 -10 7.5 -23.5t-10.5 -22.5 +l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5 +l418 363q10 8 23.5 7t21.5 -11z" /> + <glyph glyph-name="_472" unicode="" horiz-adv-x="2048" +d="M1040 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM503 315l877 760q-42 88 -132.5 146.5t-223.5 58.5q-93 0 -169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -384 -137 -645zM1856 128 +q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5l149 129h757q-166 187 -227 459l111 97q61 -356 298 -556zM1942 1520l84 -96q8 -10 7.5 -23.5t-10.5 -22.5l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161 +q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5l418 363q10 8 23.5 7t21.5 -11z" /> + <glyph glyph-name="_473" unicode="" horiz-adv-x="1408" +d="M512 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM768 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1024 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704 +q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167 +q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" /> + <glyph glyph-name="_474" unicode="" +d="M1150 462v-109q0 -50 -36.5 -89t-94 -60.5t-118 -32.5t-117.5 -11q-205 0 -342.5 139t-137.5 346q0 203 136 339t339 136q34 0 75.5 -4.5t93 -18t92.5 -34t69 -56.5t28 -81v-109q0 -16 -16 -16h-118q-16 0 -16 16v70q0 43 -65.5 67.5t-137.5 24.5q-140 0 -228.5 -91.5 +t-88.5 -237.5q0 -151 91.5 -249.5t233.5 -98.5q68 0 138 24t70 66v70q0 7 4.5 11.5t10.5 4.5h119q6 0 11 -4.5t5 -11.5zM768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5 +t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="_475" unicode="" +d="M972 761q0 108 -53.5 169t-147.5 61q-63 0 -124 -30.5t-110 -84.5t-79.5 -137t-30.5 -180q0 -112 53.5 -173t150.5 -61q96 0 176 66.5t122.5 166t42.5 203.5zM1536 640q0 -111 -37 -197t-98.5 -135t-131.5 -74.5t-145 -27.5q-6 0 -15.5 -0.5t-16.5 -0.5q-95 0 -142 53 +q-28 33 -33 83q-52 -66 -131.5 -110t-173.5 -44q-161 0 -249.5 95.5t-88.5 269.5q0 157 66 290t179 210.5t246 77.5q87 0 155 -35.5t106 -99.5l2 19l11 56q1 6 5.5 12t9.5 6h118q5 0 13 -11q5 -5 3 -16l-120 -614q-5 -24 -5 -48q0 -39 12.5 -52t44.5 -13q28 1 57 5.5t73 24 +t77 50t57 89.5t24 137q0 292 -174 466t-466 174q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51q228 0 405 144q11 9 24 8t21 -12l41 -49q8 -12 7 -24q-2 -13 -12 -22q-102 -83 -227.5 -128t-258.5 -45q-156 0 -298 61 +t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q344 0 556 -212t212 -556z" /> + <glyph glyph-name="_476" unicode="" horiz-adv-x="1792" +d="M1698 1442q94 -94 94 -226.5t-94 -225.5l-225 -223l104 -104q10 -10 10 -23t-10 -23l-210 -210q-10 -10 -23 -10t-23 10l-105 105l-603 -603q-37 -37 -90 -37h-203l-256 -128l-64 64l128 256v203q0 53 37 90l603 603l-105 105q-10 10 -10 23t10 23l210 210q10 10 23 10 +t23 -10l104 -104l223 225q93 94 225.5 94t226.5 -94zM512 64l576 576l-192 192l-576 -576v-192h192z" /> + <glyph glyph-name="f1fc" unicode="" horiz-adv-x="1792" +d="M1615 1536q70 0 122.5 -46.5t52.5 -116.5q0 -63 -45 -151q-332 -629 -465 -752q-97 -91 -218 -91q-126 0 -216.5 92.5t-90.5 219.5q0 128 92 212l638 579q59 54 130 54zM706 502q39 -76 106.5 -130t150.5 -76l1 -71q4 -213 -129.5 -347t-348.5 -134q-123 0 -218 46.5 +t-152.5 127.5t-86.5 183t-29 220q7 -5 41 -30t62 -44.5t59 -36.5t46 -17q41 0 55 37q25 66 57.5 112.5t69.5 76t88 47.5t103 25.5t125 10.5z" /> + <glyph glyph-name="_478" unicode="" horiz-adv-x="1792" +d="M1792 128v-384h-1792v384q45 0 85 14t59 27.5t47 37.5q30 27 51.5 38t56.5 11q24 0 44 -7t31 -15t33 -27q29 -25 47 -38t58 -27t86 -14q45 0 85 14.5t58 27t48 37.5q21 19 32.5 27t31 15t43.5 7q35 0 56.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14t85 14t59 27.5 +t47 37.5q30 27 51.5 38t56.5 11q34 0 55.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14zM1792 448v-192q-24 0 -44 7t-31 15t-33 27q-29 25 -47 38t-58 27t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-22 -19 -33 -27t-31 -15t-44 -7q-35 0 -56.5 11t-51.5 38q-29 25 -47 38 +t-58 27t-86 14q-45 0 -85 -14.5t-58 -27t-48 -37.5q-21 -19 -32.5 -27t-31 -15t-43.5 -7q-35 0 -56.5 11t-51.5 38q-28 24 -47 37.5t-59 27.5t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-30 -27 -51.5 -38t-56.5 -11v192q0 80 56 136t136 56h64v448h256v-448h256v448h256v-448 +h256v448h256v-448h64q80 0 136 -56t56 -136zM512 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1024 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5 +q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1536 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150z" /> + <glyph glyph-name="_479" unicode="" horiz-adv-x="2048" +d="M2048 0v-128h-2048v1536h128v-1408h1920zM1664 1024l256 -896h-1664v576l448 576l576 -576z" /> + <glyph glyph-name="_480" unicode="" horiz-adv-x="1792" +d="M768 646l546 -546q-106 -108 -247.5 -168t-298.5 -60q-209 0 -385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103v-762zM955 640h773q0 -157 -60 -298.5t-168 -247.5zM1664 768h-768v768q209 0 385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="_481" unicode="" horiz-adv-x="2048" +d="M2048 0v-128h-2048v1536h128v-1408h1920zM1920 1248v-435q0 -21 -19.5 -29.5t-35.5 7.5l-121 121l-633 -633q-10 -10 -23 -10t-23 10l-233 233l-416 -416l-192 192l585 585q10 10 23 10t23 -10l233 -233l464 464l-121 121q-16 16 -7.5 35.5t29.5 19.5h435q14 0 23 -9 +t9 -23z" /> + <glyph glyph-name="_482" unicode="" horiz-adv-x="1792" +d="M1292 832q0 -6 10 -41q10 -29 25 -49.5t41 -34t44 -20t55 -16.5q325 -91 325 -332q0 -146 -105.5 -242.5t-254.5 -96.5q-59 0 -111.5 18.5t-91.5 45.5t-77 74.5t-63 87.5t-53.5 103.5t-43.5 103t-39.5 106.5t-35.5 95q-32 81 -61.5 133.5t-73.5 96.5t-104 64t-142 20 +q-96 0 -183 -55.5t-138 -144.5t-51 -185q0 -160 106.5 -279.5t263.5 -119.5q177 0 258 95q56 63 83 116l84 -152q-15 -34 -44 -70l1 -1q-131 -152 -388 -152q-147 0 -269.5 79t-190.5 207.5t-68 274.5q0 105 43.5 206t116 176.5t172 121.5t204.5 46q87 0 159 -19t123.5 -50 +t95 -80t72.5 -99t58.5 -117t50.5 -124.5t50 -130.5t55 -127q96 -200 233 -200q81 0 138.5 48.5t57.5 128.5q0 42 -19 72t-50.5 46t-72.5 31.5t-84.5 27t-87.5 34t-81 52t-65 82t-39 122.5q-3 16 -3 33q0 110 87.5 192t198.5 78q78 -3 120.5 -14.5t90.5 -53.5h-1 +q12 -11 23 -24.5t26 -36t19 -27.5l-129 -99q-26 49 -54 70v1q-23 21 -97 21q-49 0 -84 -33t-35 -83z" /> + <glyph glyph-name="_483" unicode="" +d="M1432 484q0 173 -234 239q-35 10 -53 16.5t-38 25t-29 46.5q0 2 -2 8.5t-3 12t-1 7.5q0 36 24.5 59.5t60.5 23.5q54 0 71 -15h-1q20 -15 39 -51l93 71q-39 54 -49 64q-33 29 -67.5 39t-85.5 10q-80 0 -142 -57.5t-62 -137.5q0 -7 2 -23q16 -96 64.5 -140t148.5 -73 +q29 -8 49 -15.5t45 -21.5t38.5 -34.5t13.5 -46.5v-5q1 -58 -40.5 -93t-100.5 -35q-97 0 -167 144q-23 47 -51.5 121.5t-48 125.5t-54 110.5t-74 95.5t-103.5 60.5t-147 24.5q-101 0 -192 -56t-144 -148t-50 -192v-1q4 -108 50.5 -199t133.5 -147.5t196 -56.5q186 0 279 110 +q20 27 31 51l-60 109q-42 -80 -99 -116t-146 -36q-115 0 -191 87t-76 204q0 105 82 189t186 84q112 0 170 -53.5t104 -172.5q8 -21 25.5 -68.5t28.5 -76.5t31.5 -74.5t38.5 -74t45.5 -62.5t55.5 -53.5t66 -33t80 -13.5q107 0 183 69.5t76 174.5zM1536 1120v-960 +q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_484" unicode="" horiz-adv-x="2048" +d="M1152 640q0 104 -40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM1920 640q0 104 -40.5 198.5 +t-109.5 163.5t-163.5 109.5t-198.5 40.5h-386q119 -90 188.5 -224t69.5 -288t-69.5 -288t-188.5 -224h386q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM2048 640q0 -130 -51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5 +t-136.5 204t-51 248.5t51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5z" /> + <glyph glyph-name="_485" unicode="" horiz-adv-x="2048" +d="M0 640q0 130 51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5t-51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5t-136.5 204t-51 248.5zM1408 128q104 0 198.5 40.5t163.5 109.5 +t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5z" /> + <glyph glyph-name="_486" unicode="" horiz-adv-x="2304" +d="M762 384h-314q-40 0 -57.5 35t6.5 67l188 251q-65 31 -137 31q-132 0 -226 -94t-94 -226t94 -226t226 -94q115 0 203 72.5t111 183.5zM576 512h186q-18 85 -75 148zM1056 512l288 384h-480l-99 -132q105 -103 126 -252h165zM2176 448q0 132 -94 226t-226 94 +q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94t226 94t94 226zM2304 448q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 97 39.5 183.5t109.5 149.5l-65 98l-353 -469 +q-18 -26 -51 -26h-197q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q114 0 215 -55l137 183h-224q-26 0 -45 19t-19 45t19 45t45 19h384v-128h435l-85 128h-222q-26 0 -45 19t-19 45t19 45t45 19h256q33 0 53 -28l267 -400 +q91 44 192 44q185 0 316.5 -131.5t131.5 -316.5z" /> + <glyph glyph-name="_487" unicode="" +d="M384 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1408 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1362 716l-72 384q-5 23 -22.5 37.5t-40.5 14.5 +h-918q-23 0 -40.5 -14.5t-22.5 -37.5l-72 -384q-5 -30 14 -53t49 -23h1062q30 0 49 23t14 53zM1136 1328q0 20 -14 34t-34 14h-640q-20 0 -34 -14t-14 -34t14 -34t34 -14h640q20 0 34 14t14 34zM1536 603v-603h-128v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 +t-37.5 90.5v128h-768v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5v128h-128v603q0 112 25 223l103 454q9 78 97.5 137t230 89t312.5 30t312.5 -30t230 -89t97.5 -137l105 -454q23 -102 23 -223z" /> + <glyph glyph-name="_488" unicode="" horiz-adv-x="2048" +d="M1463 704q0 -35 -25 -60.5t-61 -25.5h-702q-36 0 -61 25.5t-25 60.5t25 60.5t61 25.5h702q36 0 61 -25.5t25 -60.5zM1677 704q0 86 -23 170h-982q-36 0 -61 25t-25 60q0 36 25 61t61 25h908q-88 143 -235 227t-320 84q-177 0 -327.5 -87.5t-238 -237.5t-87.5 -327 +q0 -86 23 -170h982q36 0 61 -25t25 -60q0 -36 -25 -61t-61 -25h-908q88 -143 235.5 -227t320.5 -84q132 0 253 51.5t208 139t139 208t52 253.5zM2048 959q0 -35 -25 -60t-61 -25h-131q17 -85 17 -170q0 -167 -65.5 -319.5t-175.5 -263t-262.5 -176t-319.5 -65.5 +q-246 0 -448.5 133t-301.5 350h-189q-36 0 -61 25t-25 61q0 35 25 60t61 25h132q-17 85 -17 170q0 167 65.5 319.5t175.5 263t262.5 176t320.5 65.5q245 0 447.5 -133t301.5 -350h188q36 0 61 -25t25 -61z" /> + <glyph glyph-name="_489" unicode="" horiz-adv-x="1280" +d="M953 1158l-114 -328l117 -21q165 451 165 518q0 56 -38 56q-57 0 -130 -225zM654 471l33 -88q37 42 71 67l-33 5.5t-38.5 7t-32.5 8.5zM362 1367q0 -98 159 -521q17 10 49 10q15 0 75 -5l-121 351q-75 220 -123 220q-19 0 -29 -17.5t-10 -37.5zM283 608q0 -36 51.5 -119 +t117.5 -153t100 -70q14 0 25.5 13t11.5 27q0 24 -32 102q-13 32 -32 72t-47.5 89t-61.5 81t-62 32q-20 0 -45.5 -27t-25.5 -47zM125 273q0 -41 25 -104q59 -145 183.5 -227t281.5 -82q227 0 382 170q152 169 152 427q0 43 -1 67t-11.5 62t-30.5 56q-56 49 -211.5 75.5 +t-270.5 26.5q-37 0 -49 -11q-12 -5 -12 -35q0 -34 21.5 -60t55.5 -40t77.5 -23.5t87.5 -11.5t85 -4t70 0h23q24 0 40 -19q15 -19 19 -55q-28 -28 -96 -54q-61 -22 -93 -46q-64 -46 -108.5 -114t-44.5 -137q0 -31 18.5 -88.5t18.5 -87.5l-3 -12q-4 -12 -4 -14 +q-137 10 -146 216q-8 -2 -41 -2q2 -7 2 -21q0 -53 -40.5 -89.5t-94.5 -36.5q-82 0 -166.5 78t-84.5 159q0 34 33 67q52 -64 60 -76q77 -104 133 -104q12 0 26.5 8.5t14.5 20.5q0 34 -87.5 145t-116.5 111q-43 0 -70 -44.5t-27 -90.5zM11 264q0 101 42.5 163t136.5 88 +q-28 74 -28 104q0 62 61 123t122 61q29 0 70 -15q-163 462 -163 567q0 80 41 130.5t119 50.5q131 0 325 -581q6 -17 8 -23q6 16 29 79.5t43.5 118.5t54 127.5t64.5 123t70.5 86.5t76.5 36q71 0 112 -49t41 -122q0 -108 -159 -550q61 -15 100.5 -46t58.5 -78t26 -93.5 +t7 -110.5q0 -150 -47 -280t-132 -225t-211 -150t-278 -55q-111 0 -223 42q-149 57 -258 191.5t-109 286.5z" /> + <glyph glyph-name="_490" unicode="" horiz-adv-x="2048" +d="M785 528h207q-14 -158 -98.5 -248.5t-214.5 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-203q-5 64 -35.5 99t-81.5 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t40 -51.5t66 -18q95 0 109 139zM1497 528h206 +q-14 -158 -98 -248.5t-214 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-204q-4 64 -35 99t-81 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t39.5 -51.5t65.5 -18q49 0 76.5 38t33.5 101zM1856 647q0 207 -15.5 307 +t-60.5 161q-6 8 -13.5 14t-21.5 15t-16 11q-86 63 -697 63q-625 0 -710 -63q-5 -4 -17.5 -11.5t-21 -14t-14.5 -14.5q-45 -60 -60 -159.5t-15 -308.5q0 -208 15 -307.5t60 -160.5q6 -8 15 -15t20.5 -14t17.5 -12q44 -33 239.5 -49t470.5 -16q610 0 697 65q5 4 17 11t20.5 14 +t13.5 16q46 60 61 159t15 309zM2048 1408v-1536h-2048v1536h2048z" /> + <glyph glyph-name="_491" unicode="" +d="M992 912v-496q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v496q0 112 -80 192t-192 80h-272v-1152q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v1344q0 14 9 23t23 9h464q135 0 249 -66.5t180.5 -180.5t66.5 -249zM1376 1376v-880q0 -135 -66.5 -249t-180.5 -180.5 +t-249 -66.5h-464q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h160q14 0 23 -9t9 -23v-768h272q112 0 192 80t80 192v880q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" /> + <glyph glyph-name="_492" unicode="" +d="M1311 694v-114q0 -24 -13.5 -38t-37.5 -14h-202q-24 0 -38 14t-14 38v114q0 24 14 38t38 14h202q24 0 37.5 -14t13.5 -38zM821 464v250q0 53 -32.5 85.5t-85.5 32.5h-133q-68 0 -96 -52q-28 52 -96 52h-130q-53 0 -85.5 -32.5t-32.5 -85.5v-250q0 -22 21 -22h55 +q22 0 22 22v230q0 24 13.5 38t38.5 14h94q24 0 38 -14t14 -38v-230q0 -22 21 -22h54q22 0 22 22v230q0 24 14 38t38 14h97q24 0 37.5 -14t13.5 -38v-230q0 -22 22 -22h55q21 0 21 22zM1410 560v154q0 53 -33 85.5t-86 32.5h-264q-53 0 -86 -32.5t-33 -85.5v-410 +q0 -21 22 -21h55q21 0 21 21v180q31 -42 94 -42h191q53 0 86 32.5t33 85.5zM1536 1176v-1072q0 -96 -68 -164t-164 -68h-1072q-96 0 -164 68t-68 164v1072q0 96 68 164t164 68h1072q96 0 164 -68t68 -164z" /> + <glyph glyph-name="_493" unicode="" +d="M915 450h-294l147 551zM1001 128h311l-324 1024h-440l-324 -1024h311l383 314zM1536 1120v-960q0 -118 -85 -203t-203 -85h-960q-118 0 -203 85t-85 203v960q0 118 85 203t203 85h960q118 0 203 -85t85 -203z" /> + <glyph glyph-name="_494" unicode="" horiz-adv-x="2048" +d="M2048 641q0 -21 -13 -36.5t-33 -19.5l-205 -356q3 -9 3 -18q0 -20 -12.5 -35.5t-32.5 -19.5l-193 -337q3 -8 3 -16q0 -23 -16.5 -40t-40.5 -17q-25 0 -41 18h-400q-17 -20 -43 -20t-43 20h-399q-17 -20 -43 -20q-23 0 -40 16.5t-17 40.5q0 8 4 20l-193 335 +q-20 4 -32.5 19.5t-12.5 35.5q0 9 3 18l-206 356q-20 5 -32.5 20.5t-12.5 35.5q0 21 13.5 36.5t33.5 19.5l199 344q0 1 -0.5 3t-0.5 3q0 36 34 51l209 363q-4 10 -4 18q0 24 17 40.5t40 16.5q26 0 44 -21h396q16 21 43 21t43 -21h398q18 21 44 21q23 0 40 -16.5t17 -40.5 +q0 -6 -4 -18l207 -358q23 -1 39 -17.5t16 -38.5q0 -13 -7 -27l187 -324q19 -4 31.5 -19.5t12.5 -35.5zM1063 -158h389l-342 354h-143l-342 -354h360q18 16 39 16t39 -16zM112 654q1 -4 1 -13q0 -10 -2 -15l208 -360l15 -6l188 199v347l-187 194q-13 -8 -29 -10zM986 1438 +h-388l190 -200l554 200h-280q-16 -16 -38 -16t-38 16zM1689 226q1 6 5 11l-64 68l-17 -79h76zM1583 226l22 105l-252 266l-296 -307l63 -64h463zM1495 -142l16 28l65 310h-427l333 -343q8 4 13 5zM578 -158h5l342 354h-373v-335l4 -6q14 -5 22 -13zM552 226h402l64 66 +l-309 321l-157 -166v-221zM359 226h163v189l-168 -177q4 -8 5 -12zM358 1051q0 -1 0.5 -2t0.5 -2q0 -16 -8 -29l171 -177v269zM552 1121v-311l153 -157l297 314l-223 236zM556 1425l-4 -8v-264l205 74l-191 201q-6 -2 -10 -3zM1447 1438h-16l-621 -224l213 -225zM1023 946 +l-297 -315l311 -319l296 307zM688 634l-136 141v-284zM1038 270l-42 -44h85zM1374 618l238 -251l132 624l-3 5l-1 1zM1718 1018q-8 13 -8 29v2l-216 376q-5 1 -13 5l-437 -463l310 -327zM522 1142v223l-163 -282zM522 196h-163l163 -283v283zM1607 196l-48 -227l130 227h-82 +zM1729 266l207 361q-2 10 -2 14q0 1 3 16l-171 296l-129 -612l77 -82q5 3 15 7z" /> + <glyph glyph-name="f210" unicode="" +d="M0 856q0 131 91.5 226.5t222.5 95.5h742l352 358v-1470q0 -132 -91.5 -227t-222.5 -95h-780q-131 0 -222.5 95t-91.5 227v790zM1232 102l-176 180v425q0 46 -32 79t-78 33h-484q-46 0 -78 -33t-32 -79v-492q0 -46 32.5 -79.5t77.5 -33.5h770z" /> + <glyph glyph-name="_496" unicode="" +d="M934 1386q-317 -121 -556 -362.5t-358 -560.5q-20 89 -20 176q0 208 102.5 384.5t278.5 279t384 102.5q82 0 169 -19zM1203 1267q93 -65 164 -155q-389 -113 -674.5 -400.5t-396.5 -676.5q-93 72 -155 162q112 386 395 671t667 399zM470 -67q115 356 379.5 622t619.5 384 +q40 -92 54 -195q-292 -120 -516 -345t-343 -518q-103 14 -194 52zM1536 -125q-193 50 -367 115q-135 -84 -290 -107q109 205 274 370.5t369 275.5q-21 -152 -101 -284q65 -175 115 -370z" /> + <glyph glyph-name="f212" unicode="" horiz-adv-x="2048" +d="M1893 1144l155 -1272q-131 0 -257 57q-200 91 -393 91q-226 0 -374 -148q-148 148 -374 148q-193 0 -393 -91q-128 -57 -252 -57h-5l155 1272q224 127 482 127q233 0 387 -106q154 106 387 106q258 0 482 -127zM1398 157q129 0 232 -28.5t260 -93.5l-124 1021 +q-171 78 -368 78q-224 0 -374 -141q-150 141 -374 141q-197 0 -368 -78l-124 -1021q105 43 165.5 65t148.5 39.5t178 17.5q202 0 374 -108q172 108 374 108zM1438 191l-55 907q-211 -4 -359 -155q-152 155 -374 155q-176 0 -336 -66l-114 -941q124 51 228.5 76t221.5 25 +q209 0 374 -102q172 107 374 102z" /> + <glyph glyph-name="_498" unicode="" horiz-adv-x="2048" +d="M1500 165v733q0 21 -15 36t-35 15h-93q-20 0 -35 -15t-15 -36v-733q0 -20 15 -35t35 -15h93q20 0 35 15t15 35zM1216 165v531q0 20 -15 35t-35 15h-101q-20 0 -35 -15t-15 -35v-531q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM924 165v429q0 20 -15 35t-35 15h-101 +q-20 0 -35 -15t-15 -35v-429q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM632 165v362q0 20 -15 35t-35 15h-101q-20 0 -35 -15t-15 -35v-362q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM2048 311q0 -166 -118 -284t-284 -118h-1244q-166 0 -284 118t-118 284 +q0 116 63 214.5t168 148.5q-10 34 -10 73q0 113 80.5 193.5t193.5 80.5q102 0 180 -67q45 183 194 300t338 117q149 0 275 -73.5t199.5 -199.5t73.5 -275q0 -66 -14 -122q135 -33 221 -142.5t86 -247.5z" /> + <glyph glyph-name="_499" unicode="" +d="M0 1536h1536v-1392l-776 -338l-760 338v1392zM1436 209v926h-1336v-926l661 -294zM1436 1235v201h-1336v-201h1336zM181 937v-115h-37v115h37zM181 789v-115h-37v115h37zM181 641v-115h-37v115h37zM181 493v-115h-37v115h37zM181 345v-115h-37v115h37zM207 202l15 34 +l105 -47l-15 -33zM343 142l15 34l105 -46l-15 -34zM478 82l15 34l105 -46l-15 -34zM614 23l15 33l104 -46l-15 -34zM797 10l105 46l15 -33l-105 -47zM932 70l105 46l15 -34l-105 -46zM1068 130l105 46l15 -34l-105 -46zM1203 189l105 47l15 -34l-105 -46zM259 1389v-36h-114 +v36h114zM421 1389v-36h-115v36h115zM583 1389v-36h-115v36h115zM744 1389v-36h-114v36h114zM906 1389v-36h-114v36h114zM1068 1389v-36h-115v36h115zM1230 1389v-36h-115v36h115zM1391 1389v-36h-114v36h114zM181 1049v-79h-37v115h115v-36h-78zM421 1085v-36h-115v36h115z +M583 1085v-36h-115v36h115zM744 1085v-36h-114v36h114zM906 1085v-36h-114v36h114zM1068 1085v-36h-115v36h115zM1230 1085v-36h-115v36h115zM1355 970v79h-78v36h115v-115h-37zM1355 822v115h37v-115h-37zM1355 674v115h37v-115h-37zM1355 526v115h37v-115h-37zM1355 378 +v115h37v-115h-37zM1355 230v115h37v-115h-37zM760 265q-129 0 -221 91.5t-92 221.5q0 129 92 221t221 92q130 0 221.5 -92t91.5 -221q0 -130 -91.5 -221.5t-221.5 -91.5zM595 646q0 -36 19.5 -56.5t49.5 -25t64 -7t64 -2t49.5 -9t19.5 -30.5q0 -49 -112 -49q-97 0 -123 51 +h-3l-31 -63q67 -42 162 -42q29 0 56.5 5t55.5 16t45.5 33t17.5 53q0 46 -27.5 69.5t-67.5 27t-79.5 3t-67 5t-27.5 25.5q0 21 20.5 33t40.5 15t41 3q34 0 70.5 -11t51.5 -34h3l30 58q-3 1 -21 8.5t-22.5 9t-19.5 7t-22 7t-20 4.5t-24 4t-23 1q-29 0 -56.5 -5t-54 -16.5 +t-43 -34t-16.5 -53.5z" /> + <glyph glyph-name="_500" unicode="" horiz-adv-x="2048" +d="M863 504q0 112 -79.5 191.5t-191.5 79.5t-191 -79.5t-79 -191.5t79 -191t191 -79t191.5 79t79.5 191zM1726 505q0 112 -79 191t-191 79t-191.5 -79t-79.5 -191q0 -113 79.5 -192t191.5 -79t191 79.5t79 191.5zM2048 1314v-1348q0 -44 -31.5 -75.5t-76.5 -31.5h-1832 +q-45 0 -76.5 31.5t-31.5 75.5v1348q0 44 31.5 75.5t76.5 31.5h431q44 0 76 -31.5t32 -75.5v-161h754v161q0 44 32 75.5t76 31.5h431q45 0 76.5 -31.5t31.5 -75.5z" /> + <glyph glyph-name="_501" unicode="" horiz-adv-x="2048" +d="M1430 953zM1690 749q148 0 253 -98.5t105 -244.5q0 -157 -109 -261.5t-267 -104.5q-85 0 -162 27.5t-138 73.5t-118 106t-109 126t-103.5 132.5t-108.5 126.5t-117 106t-136 73.5t-159 27.5q-154 0 -251.5 -91.5t-97.5 -244.5q0 -157 104 -250t263 -93q100 0 208 37.5 +t193 98.5q5 4 21 18.5t30 24t22 9.5q14 0 24.5 -10.5t10.5 -24.5q0 -24 -60 -77q-101 -88 -234.5 -142t-260.5 -54q-133 0 -245.5 58t-180 165t-67.5 241q0 205 141.5 341t347.5 136q120 0 226.5 -43.5t185.5 -113t151.5 -153t139 -167.5t133.5 -153.5t149.5 -113 +t172.5 -43.5q102 0 168.5 61.5t66.5 162.5q0 95 -64.5 159t-159.5 64q-30 0 -81.5 -18.5t-68.5 -18.5q-20 0 -35.5 15t-15.5 35q0 18 8.5 57t8.5 59q0 159 -107.5 263t-266.5 104q-58 0 -111.5 -18.5t-84 -40.5t-55.5 -40.5t-33 -18.5q-15 0 -25.5 10.5t-10.5 25.5 +q0 19 25 46q59 67 147 103.5t182 36.5q191 0 318 -125.5t127 -315.5q0 -37 -4 -66q57 15 115 15z" /> + <glyph glyph-name="_502" unicode="" horiz-adv-x="1664" +d="M1216 832q0 26 -19 45t-45 19h-128v128q0 26 -19 45t-45 19t-45 -19t-19 -45v-128h-128q-26 0 -45 -19t-19 -45t19 -45t45 -19h128v-128q0 -26 19 -45t45 -19t45 19t19 45v128h128q26 0 45 19t19 45zM640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 +t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920 +q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" /> + <glyph glyph-name="_503" unicode="" horiz-adv-x="1664" +d="M1280 832q0 26 -19 45t-45 19t-45 -19l-147 -146v293q0 26 -19 45t-45 19t-45 -19t-19 -45v-293l-147 146q-19 19 -45 19t-45 -19t-19 -45t19 -45l256 -256q19 -19 45 -19t45 19l256 256q19 19 19 45zM640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 +t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920 +q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" /> + <glyph glyph-name="_504" unicode="" horiz-adv-x="2048" +d="M212 768l623 -665l-300 665h-323zM1024 -4l349 772h-698zM538 896l204 384h-262l-288 -384h346zM1213 103l623 665h-323zM683 896h682l-204 384h-274zM1510 896h346l-288 384h-262zM1651 1382l384 -512q14 -18 13 -41.5t-17 -40.5l-960 -1024q-18 -20 -47 -20t-47 20 +l-960 1024q-16 17 -17 40.5t13 41.5l384 512q18 26 51 26h1152q33 0 51 -26z" /> + <glyph glyph-name="_505" unicode="" horiz-adv-x="2048" +d="M1811 -19q19 19 45 19t45 -19l128 -128l-90 -90l-83 83l-83 -83q-18 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83 +q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-128 128l90 90l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83 +q19 19 45 19t45 -19l83 -83zM237 19q-19 -19 -45 -19t-45 19l-128 128l90 90l83 -82l83 82q19 19 45 19t45 -19l83 -82l64 64v293l-210 314q-17 26 -7 56.5t40 40.5l177 58v299h128v128h256v128h256v-128h256v-128h128v-299l177 -58q30 -10 40 -40.5t-7 -56.5l-210 -314 +v-293l19 18q19 19 45 19t45 -19l83 -82l83 82q19 19 45 19t45 -19l128 -128l-90 -90l-83 83l-83 -83q-18 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83 +q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83zM640 1152v-128l384 128l384 -128v128h-128v128h-512v-128h-128z" /> + <glyph glyph-name="_506" unicode="" +d="M576 0l96 448l-96 128l-128 64zM832 0l128 640l-128 -64l-96 -128zM992 1010q-2 4 -4 6q-10 8 -96 8q-70 0 -167 -19q-7 -2 -21 -2t-21 2q-97 19 -167 19q-86 0 -96 -8q-2 -2 -4 -6q2 -18 4 -27q2 -3 7.5 -6.5t7.5 -10.5q2 -4 7.5 -20.5t7 -20.5t7.5 -17t8.5 -17t9 -14 +t12 -13.5t14 -9.5t17.5 -8t20.5 -4t24.5 -2q36 0 59 12.5t32.5 30t14.5 34.5t11.5 29.5t17.5 12.5h12q11 0 17.5 -12.5t11.5 -29.5t14.5 -34.5t32.5 -30t59 -12.5q13 0 24.5 2t20.5 4t17.5 8t14 9.5t12 13.5t9 14t8.5 17t7.5 17t7 20.5t7.5 20.5q2 7 7.5 10.5t7.5 6.5 +q2 9 4 27zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 61 4.5 118t19 125.5t37.5 123.5t63.5 103.5t93.5 74.5l-90 220h214q-22 64 -22 128q0 12 2 32q-194 40 -194 96q0 57 210 99q17 62 51.5 134t70.5 114q32 37 76 37q30 0 84 -31t84 -31t84 31 +t84 31q44 0 76 -37q36 -42 70.5 -114t51.5 -134q210 -42 210 -99q0 -56 -194 -96q7 -81 -20 -160h214l-82 -225q63 -33 107.5 -96.5t65.5 -143.5t29 -151.5t8 -148.5z" /> + <glyph glyph-name="_507" unicode="" horiz-adv-x="2304" +d="M2301 500q12 -103 -22 -198.5t-99 -163.5t-158.5 -106t-196.5 -31q-161 11 -279.5 125t-134.5 274q-12 111 27.5 210.5t118.5 170.5l-71 107q-96 -80 -151 -194t-55 -244q0 -27 -18.5 -46.5t-45.5 -19.5h-256h-69q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5 +t-131.5 316.5t131.5 316.5t316.5 131.5q76 0 152 -27l24 45q-123 110 -304 110h-64q-26 0 -45 19t-19 45t19 45t45 19h128q78 0 145 -13.5t116.5 -38.5t71.5 -39.5t51 -36.5h512h115l-85 128h-222q-30 0 -49 22.5t-14 52.5q4 23 23 38t43 15h253q33 0 53 -28l70 -105 +l114 114q19 19 46 19h101q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-179l115 -172q131 63 275 36q143 -26 244 -134.5t118 -253.5zM448 128q115 0 203 72.5t111 183.5h-314q-35 0 -55 31q-18 32 -1 63l147 277q-47 13 -91 13q-132 0 -226 -94t-94 -226t94 -226 +t226 -94zM1856 128q132 0 226 94t94 226t-94 226t-226 94q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94z" /> + <glyph glyph-name="_508" unicode="" +d="M1408 0q0 -63 -61.5 -113.5t-164 -81t-225 -46t-253.5 -15.5t-253.5 15.5t-225 46t-164 81t-61.5 113.5q0 49 33 88.5t91 66.5t118 44.5t131 29.5q26 5 48 -10.5t26 -41.5q5 -26 -10.5 -48t-41.5 -26q-58 -10 -106 -23.5t-76.5 -25.5t-48.5 -23.5t-27.5 -19.5t-8.5 -12 +q3 -11 27 -26.5t73 -33t114 -32.5t160.5 -25t201.5 -10t201.5 10t160.5 25t114 33t73 33.5t27 27.5q-1 4 -8.5 11t-27.5 19t-48.5 23.5t-76.5 25t-106 23.5q-26 4 -41.5 26t-10.5 48q4 26 26 41.5t48 10.5q71 -12 131 -29.5t118 -44.5t91 -66.5t33 -88.5zM1024 896v-384 +q0 -26 -19 -45t-45 -19h-64v-384q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v384h-64q-26 0 -45 19t-19 45v384q0 53 37.5 90.5t90.5 37.5h384q53 0 90.5 -37.5t37.5 -90.5zM928 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5 +t158.5 -65.5t65.5 -158.5z" /> + <glyph glyph-name="_509" unicode="" horiz-adv-x="1792" +d="M1280 512h305q-5 -6 -10 -10.5t-9 -7.5l-3 -4l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-5 2 -21 20h369q22 0 39.5 13.5t22.5 34.5l70 281l190 -667q6 -20 23 -33t39 -13q21 0 38 13t23 33l146 485l56 -112q18 -35 57 -35zM1792 940q0 -145 -103 -300h-369l-111 221 +q-8 17 -25.5 27t-36.5 8q-45 -5 -56 -46l-129 -430l-196 686q-6 20 -23.5 33t-39.5 13t-39 -13.5t-22 -34.5l-116 -464h-423q-103 155 -103 300q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124 +t127 -344z" /> + <glyph glyph-name="venus" unicode="" horiz-adv-x="1280" +d="M1152 960q0 -221 -147.5 -384.5t-364.5 -187.5v-260h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v260q-150 16 -271.5 103t-186 224t-52.5 292 +q11 134 80.5 249t182 188t245.5 88q170 19 319 -54t236 -212t87 -306zM128 960q0 -185 131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5z" /> + <glyph glyph-name="_511" unicode="" +d="M1472 1408q26 0 45 -19t19 -45v-416q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v262l-382 -383q126 -156 126 -359q0 -117 -45.5 -223.5t-123 -184t-184 -123t-223.5 -45.5t-223.5 45.5t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123t223.5 45.5 +q203 0 359 -126l382 382h-261q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h416zM576 0q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> + <glyph glyph-name="_512" unicode="" horiz-adv-x="1280" +d="M830 1220q145 -72 233.5 -210.5t88.5 -305.5q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-217 24 -364.5 187.5 +t-147.5 384.5q0 167 88.5 305.5t233.5 210.5q-165 96 -228 273q-6 16 3.5 29.5t26.5 13.5h69q21 0 29 -20q44 -106 140 -171t214 -65t214 65t140 171q8 20 37 20h61q17 0 26.5 -13.5t3.5 -29.5q-63 -177 -228 -273zM576 256q185 0 316.5 131.5t131.5 316.5t-131.5 316.5 +t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> + <glyph glyph-name="_513" unicode="" +d="M1024 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q126 -158 126 -359q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64 +q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-149 16 -270.5 103t-186.5 223.5t-53 291.5q16 204 160 353.5t347 172.5q118 14 228 -19t198 -103l255 254h-134q-14 0 -23 9t-9 23v64zM576 256q185 0 316.5 131.5t131.5 316.5t-131.5 316.5 +t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> + <glyph glyph-name="_514" unicode="" horiz-adv-x="1792" +d="M1280 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q126 -158 126 -359q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64 +q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-217 24 -364.5 187.5t-147.5 384.5q0 201 126 359l-52 53l-101 -111q-9 -10 -22 -10.5t-23 7.5l-48 44q-10 8 -10.5 21.5t8.5 23.5l105 115l-111 112v-134q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9 +t-9 23v288q0 26 19 45t45 19h288q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-133l106 -107l86 94q9 10 22 10.5t23 -7.5l48 -44q10 -8 10.5 -21.5t-8.5 -23.5l-90 -99l57 -56q158 126 359 126t359 -126l255 254h-134q-14 0 -23 9t-9 23v64zM832 256q185 0 316.5 131.5 +t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> + <glyph glyph-name="_515" unicode="" horiz-adv-x="1792" +d="M1790 1007q12 -155 -52.5 -292t-186 -224t-271.5 -103v-260h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-512v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23 +t23 9h224v260q-150 16 -271.5 103t-186 224t-52.5 292q17 206 164.5 356.5t352.5 169.5q206 21 377 -94q171 115 377 94q205 -19 352.5 -169.5t164.5 -356.5zM896 647q128 131 128 313t-128 313q-128 -131 -128 -313t128 -313zM576 512q115 0 218 57q-154 165 -154 391 +q0 224 154 391q-103 57 -218 57q-185 0 -316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5zM1152 128v260q-137 15 -256 94q-119 -79 -256 -94v-260h512zM1216 512q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5q-115 0 -218 -57q154 -167 154 -391 +q0 -226 -154 -391q103 -57 218 -57z" /> + <glyph glyph-name="_516" unicode="" horiz-adv-x="1920" +d="M1536 1120q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q76 -95 107.5 -214t9.5 -247q-31 -182 -166 -312t-318 -156q-210 -29 -384.5 80t-241.5 300q-117 6 -221 57.5t-177.5 133t-113.5 192.5t-32 230 +q9 135 78 252t182 191.5t248 89.5q118 14 227.5 -19t198.5 -103l255 254h-134q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q59 -74 93 -169q182 -9 328 -124l255 254h-134q-14 0 -23 9 +t-9 23v64zM1024 704q0 20 -4 58q-162 -25 -271 -150t-109 -292q0 -20 4 -58q162 25 271 150t109 292zM128 704q0 -168 111 -294t276 -149q-3 29 -3 59q0 210 135 369.5t338 196.5q-53 120 -163.5 193t-245.5 73q-185 0 -316.5 -131.5t-131.5 -316.5zM1088 -128 +q185 0 316.5 131.5t131.5 316.5q0 168 -111 294t-276 149q3 -28 3 -59q0 -210 -135 -369.5t-338 -196.5q53 -120 163.5 -193t245.5 -73z" /> + <glyph glyph-name="_517" unicode="" horiz-adv-x="2048" +d="M1664 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q76 -95 107.5 -214t9.5 -247q-32 -180 -164.5 -310t-313.5 -157q-223 -34 -409 90q-117 -78 -256 -93v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23 +t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-155 17 -279.5 109.5t-187 237.5t-39.5 307q25 187 159.5 322.5t320.5 164.5q224 34 410 -90q146 97 320 97q201 0 359 -126l255 254h-134q-14 0 -23 9 +t-9 23v64zM896 391q128 131 128 313t-128 313q-128 -131 -128 -313t128 -313zM128 704q0 -185 131.5 -316.5t316.5 -131.5q117 0 218 57q-154 167 -154 391t154 391q-101 57 -218 57q-185 0 -316.5 -131.5t-131.5 -316.5zM1216 256q185 0 316.5 131.5t131.5 316.5 +t-131.5 316.5t-316.5 131.5q-117 0 -218 -57q154 -167 154 -391t-154 -391q101 -57 218 -57z" /> + <glyph glyph-name="_518" unicode="" +d="M1472 1408q26 0 45 -19t19 -45v-416q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v262l-213 -214l140 -140q9 -10 9 -23t-9 -22l-46 -46q-9 -9 -22 -9t-23 9l-140 141l-78 -79q126 -156 126 -359q0 -117 -45.5 -223.5t-123 -184t-184 -123t-223.5 -45.5t-223.5 45.5 +t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123t223.5 45.5q203 0 359 -126l78 78l-172 172q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l172 -172l213 213h-261q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h416zM576 0q185 0 316.5 131.5t131.5 316.5t-131.5 316.5 +t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> + <glyph glyph-name="_519" unicode="" horiz-adv-x="1280" +d="M640 892q217 -24 364.5 -187.5t147.5 -384.5q0 -167 -87 -306t-236 -212t-319 -54q-133 15 -245.5 88t-182 188t-80.5 249q-12 155 52.5 292t186 224t271.5 103v132h-160q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h160v165l-92 -92q-10 -9 -23 -9t-22 9l-46 46q-9 9 -9 22 +t9 23l202 201q19 19 45 19t45 -19l202 -201q9 -10 9 -23t-9 -22l-46 -46q-9 -9 -22 -9t-23 9l-92 92v-165h160q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-160v-132zM576 -128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5 +t131.5 -316.5t316.5 -131.5z" /> + <glyph glyph-name="_520" unicode="" horiz-adv-x="2048" +d="M1901 621q19 -19 19 -45t-19 -45l-294 -294q-9 -10 -22.5 -10t-22.5 10l-45 45q-10 9 -10 22.5t10 22.5l185 185h-294v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-132q-24 -217 -187.5 -364.5t-384.5 -147.5q-167 0 -306 87t-212 236t-54 319q15 133 88 245.5 +t188 182t249 80.5q155 12 292 -52.5t224 -186t103 -271.5h132v224q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-224h294l-185 185q-10 9 -10 22.5t10 22.5l45 45q9 10 22.5 10t22.5 -10zM576 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5 +t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> + <glyph glyph-name="_521" unicode="" horiz-adv-x="1280" +d="M1152 960q0 -221 -147.5 -384.5t-364.5 -187.5v-612q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v612q-217 24 -364.5 187.5t-147.5 384.5q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5zM576 512q185 0 316.5 131.5 +t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> + <glyph glyph-name="_522" unicode="" horiz-adv-x="1280" +d="M1024 576q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1152 576q0 -117 -45.5 -223.5t-123 -184t-184 -123t-223.5 -45.5t-223.5 45.5t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123 +t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5z" /> + <glyph glyph-name="_523" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="_524" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="_525" unicode="" +d="M1451 1408q35 0 60 -25t25 -60v-1366q0 -35 -25 -60t-60 -25h-391v595h199l30 232h-229v148q0 56 23.5 84t91.5 28l122 1v207q-63 9 -178 9q-136 0 -217.5 -80t-81.5 -226v-171h-200v-232h200v-595h-735q-35 0 -60 25t-25 60v1366q0 35 25 60t60 25h1366z" /> + <glyph glyph-name="_526" unicode="" horiz-adv-x="1280" +d="M0 939q0 108 37.5 203.5t103.5 166.5t152 123t185 78t202 26q158 0 294 -66.5t221 -193.5t85 -287q0 -96 -19 -188t-60 -177t-100 -149.5t-145 -103t-189 -38.5q-68 0 -135 32t-96 88q-10 -39 -28 -112.5t-23.5 -95t-20.5 -71t-26 -71t-32 -62.5t-46 -77.5t-62 -86.5 +l-14 -5l-9 10q-15 157 -15 188q0 92 21.5 206.5t66.5 287.5t52 203q-32 65 -32 169q0 83 52 156t132 73q61 0 95 -40.5t34 -102.5q0 -66 -44 -191t-44 -187q0 -63 45 -104.5t109 -41.5q55 0 102 25t78.5 68t56 95t38 110.5t20 111t6.5 99.5q0 173 -109.5 269.5t-285.5 96.5 +q-200 0 -334 -129.5t-134 -328.5q0 -44 12.5 -85t27 -65t27 -45.5t12.5 -30.5q0 -28 -15 -73t-37 -45q-2 0 -17 3q-51 15 -90.5 56t-61 94.5t-32.5 108t-11 106.5z" /> + <glyph glyph-name="_527" unicode="" +d="M985 562q13 0 97.5 -44t89.5 -53q2 -5 2 -15q0 -33 -17 -76q-16 -39 -71 -65.5t-102 -26.5q-57 0 -190 62q-98 45 -170 118t-148 185q-72 107 -71 194v8q3 91 74 158q24 22 52 22q6 0 18 -1.5t19 -1.5q19 0 26.5 -6.5t15.5 -27.5q8 -20 33 -88t25 -75q0 -21 -34.5 -57.5 +t-34.5 -46.5q0 -7 5 -15q34 -73 102 -137q56 -53 151 -101q12 -7 22 -7q15 0 54 48.5t52 48.5zM782 32q127 0 243.5 50t200.5 134t134 200.5t50 243.5t-50 243.5t-134 200.5t-200.5 134t-243.5 50t-243.5 -50t-200.5 -134t-134 -200.5t-50 -243.5q0 -203 120 -368l-79 -233 +l242 77q158 -104 345 -104zM782 1414q153 0 292.5 -60t240.5 -161t161 -240.5t60 -292.5t-60 -292.5t-161 -240.5t-240.5 -161t-292.5 -60q-195 0 -365 94l-417 -134l136 405q-108 178 -108 389q0 153 60 292.5t161 240.5t240.5 161t292.5 60z" /> + <glyph glyph-name="_528" unicode="" horiz-adv-x="1792" +d="M128 128h1024v128h-1024v-128zM128 640h1024v128h-1024v-128zM1696 192q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM128 1152h1024v128h-1024v-128zM1696 704q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1696 1216 +q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1792 384v-384h-1792v384h1792zM1792 896v-384h-1792v384h1792zM1792 1408v-384h-1792v384h1792z" /> + <glyph glyph-name="_529" unicode="" horiz-adv-x="2048" +d="M704 640q-159 0 -271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5zM1664 512h352q13 0 22.5 -9.5t9.5 -22.5v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-352q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5 +t-9.5 22.5v352h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v352q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5v-352zM928 288q0 -52 38 -90t90 -38h256v-238q-68 -50 -171 -50h-874q-121 0 -194 69t-73 190q0 53 3.5 103.5t14 109t26.5 108.5 +t43 97.5t62 81t85.5 53.5t111.5 20q19 0 39 -17q79 -61 154.5 -91.5t164.5 -30.5t164.5 30.5t154.5 91.5q20 17 39 17q132 0 217 -96h-223q-52 0 -90 -38t-38 -90v-192z" /> + <glyph glyph-name="_530" unicode="" horiz-adv-x="2048" +d="M704 640q-159 0 -271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5zM1781 320l249 -249q9 -9 9 -23q0 -13 -9 -22l-136 -136q-9 -9 -22 -9q-14 0 -23 9l-249 249l-249 -249q-9 -9 -23 -9q-13 0 -22 9l-136 136 +q-9 9 -9 22q0 14 9 23l249 249l-249 249q-9 9 -9 23q0 13 9 22l136 136q9 9 22 9q14 0 23 -9l249 -249l249 249q9 9 23 9q13 0 22 -9l136 -136q9 -9 9 -22q0 -14 -9 -23zM1283 320l-181 -181q-37 -37 -37 -91q0 -53 37 -90l83 -83q-21 -3 -44 -3h-874q-121 0 -194 69 +t-73 190q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q19 0 39 -17q154 -122 319 -122t319 122q20 17 39 17q28 0 57 -6q-28 -27 -41 -50t-13 -56q0 -54 37 -91z" /> + <glyph glyph-name="_531" unicode="" horiz-adv-x="2048" +d="M256 512h1728q26 0 45 -19t19 -45v-448h-256v256h-1536v-256h-256v1216q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-704zM832 832q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM2048 576v64q0 159 -112.5 271.5t-271.5 112.5h-704 +q-26 0 -45 -19t-19 -45v-384h1152z" /> + <glyph glyph-name="_532" unicode="" +d="M1536 1536l-192 -448h192v-192h-274l-55 -128h329v-192h-411l-357 -832l-357 832h-411v192h329l-55 128h-274v192h192l-192 448h256l323 -768h378l323 768h256zM768 320l108 256h-216z" /> + <glyph glyph-name="_533" unicode="" +d="M1088 1536q185 0 316.5 -93.5t131.5 -226.5v-896q0 -130 -125.5 -222t-305.5 -97l213 -202q16 -15 8 -35t-30 -20h-1056q-22 0 -30 20t8 35l213 202q-180 5 -305.5 97t-125.5 222v896q0 133 131.5 226.5t316.5 93.5h640zM768 192q80 0 136 56t56 136t-56 136t-136 56 +t-136 -56t-56 -136t56 -136t136 -56zM1344 768v512h-1152v-512h1152z" /> + <glyph glyph-name="_534" unicode="" +d="M1088 1536q185 0 316.5 -93.5t131.5 -226.5v-896q0 -130 -125.5 -222t-305.5 -97l213 -202q16 -15 8 -35t-30 -20h-1056q-22 0 -30 20t8 35l213 202q-180 5 -305.5 97t-125.5 222v896q0 133 131.5 226.5t316.5 93.5h640zM288 224q66 0 113 47t47 113t-47 113t-113 47 +t-113 -47t-47 -113t47 -113t113 -47zM704 768v512h-544v-512h544zM1248 224q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM1408 768v512h-576v-512h576z" /> + <glyph glyph-name="_535" unicode="" horiz-adv-x="1792" +d="M597 1115v-1173q0 -25 -12.5 -42.5t-36.5 -17.5q-17 0 -33 8l-465 233q-21 10 -35.5 33.5t-14.5 46.5v1140q0 20 10 34t29 14q14 0 44 -15l511 -256q3 -3 3 -5zM661 1014l534 -866l-534 266v600zM1792 996v-1054q0 -25 -14 -40.5t-38 -15.5t-47 13l-441 220zM1789 1116 +q0 -3 -256.5 -419.5t-300.5 -487.5l-390 634l324 527q17 28 52 28q14 0 26 -6l541 -270q4 -2 4 -6z" /> + <glyph glyph-name="_536" unicode="" +d="M809 532l266 499h-112l-157 -312q-24 -48 -44 -92l-42 92l-155 312h-120l263 -493v-324h101v318zM1536 1408v-1536h-1536v1536h1536z" /> + <glyph glyph-name="_537" unicode="" horiz-adv-x="2296" +d="M478 -139q-8 -16 -27 -34.5t-37 -25.5q-25 -9 -51.5 3.5t-28.5 31.5q-1 22 40 55t68 38q23 4 34 -21.5t2 -46.5zM1819 -139q7 -16 26 -34.5t38 -25.5q25 -9 51.5 3.5t27.5 31.5q2 22 -39.5 55t-68.5 38q-22 4 -33 -21.5t-2 -46.5zM1867 -30q13 -27 56.5 -59.5t77.5 -41.5 +q45 -13 82 4.5t37 50.5q0 46 -67.5 100.5t-115.5 59.5q-40 5 -63.5 -37.5t-6.5 -76.5zM428 -30q-13 -27 -56 -59.5t-77 -41.5q-45 -13 -82 4.5t-37 50.5q0 46 67.5 100.5t115.5 59.5q40 5 63 -37.5t6 -76.5zM1158 1094h1q-41 0 -76 -15q27 -8 44 -30.5t17 -49.5 +q0 -35 -27 -60t-65 -25q-52 0 -80 43q-5 -23 -5 -42q0 -74 56 -126.5t135 -52.5q80 0 136 52.5t56 126.5t-56 126.5t-136 52.5zM1462 1312q-99 109 -220.5 131.5t-245.5 -44.5q27 60 82.5 96.5t118 39.5t121.5 -17t99.5 -74.5t44.5 -131.5zM2212 73q8 -11 -11 -42 +q7 -23 7 -40q1 -56 -44.5 -112.5t-109.5 -91.5t-118 -37q-48 -2 -92 21.5t-66 65.5q-687 -25 -1259 0q-23 -41 -66.5 -65t-92.5 -22q-86 3 -179.5 80.5t-92.5 160.5q2 22 7 40q-19 31 -11 42q6 10 31 1q14 22 41 51q-7 29 2 38q11 10 39 -4q29 20 59 34q0 29 13 37 +q23 12 51 -16q35 5 61 -2q18 -4 38 -19v73q-11 0 -18 2q-53 10 -97 44.5t-55 87.5q-9 38 0 81q15 62 93 95q2 17 19 35.5t36 23.5t33 -7.5t19 -30.5h13q46 -5 60 -23q3 -3 5 -7q10 1 30.5 3.5t30.5 3.5q-15 11 -30 17q-23 40 -91 43q0 6 1 10q-62 2 -118.5 18.5t-84.5 47.5 +q-32 36 -42.5 92t-2.5 112q16 126 90 179q23 16 52 4.5t32 -40.5q0 -1 1.5 -14t2.5 -21t3 -20t5.5 -19t8.5 -10q27 -14 76 -12q48 46 98 74q-40 4 -162 -14l47 46q61 58 163 111q145 73 282 86q-20 8 -41 15.5t-47 14t-42.5 10.5t-47.5 11t-43 10q595 126 904 -139 +q98 -84 158 -222q85 -10 121 9h1q5 3 8.5 10t5.5 19t3 19.5t3 21.5l1 14q3 28 32 40t52 -5q73 -52 91 -178q7 -57 -3.5 -113t-42.5 -91q-28 -32 -83.5 -48.5t-115.5 -18.5v-10q-71 -2 -95 -43q-14 -5 -31 -17q11 -1 32 -3.5t30 -3.5q1 5 5 8q16 18 60 23h13q5 18 19 30t33 8 +t36 -23t19 -36q79 -32 93 -95q9 -40 1 -81q-12 -53 -56 -88t-97 -44q-10 -2 -17 -2q0 -49 -1 -73q20 15 38 19q26 7 61 2q28 28 51 16q14 -9 14 -37q33 -16 59 -34q27 13 38 4q10 -10 2 -38q28 -30 41 -51q23 8 31 -1zM1937 1025q0 -29 -9 -54q82 -32 112 -132 +q4 37 -9.5 98.5t-41.5 90.5q-20 19 -36 17t-16 -20zM1859 925q35 -42 47.5 -108.5t-0.5 -124.5q67 13 97 45q13 14 18 28q-3 64 -31 114.5t-79 66.5q-15 -15 -52 -21zM1822 921q-30 0 -44 1q42 -115 53 -239q21 0 43 3q16 68 1 135t-53 100zM258 839q30 100 112 132 +q-9 25 -9 54q0 18 -16.5 20t-35.5 -17q-28 -29 -41.5 -90.5t-9.5 -98.5zM294 737q29 -31 97 -45q-13 58 -0.5 124.5t47.5 108.5v0q-37 6 -52 21q-51 -16 -78.5 -66t-31.5 -115q9 -17 18 -28zM471 683q14 124 73 235q-19 -4 -55 -18l-45 -19v1q-46 -89 -20 -196q25 -3 47 -3z +M1434 644q8 -38 16.5 -108.5t11.5 -89.5q3 -18 9.5 -21.5t23.5 4.5q40 20 62 85.5t23 125.5q-24 2 -146 4zM1152 1285q-116 0 -199 -82.5t-83 -198.5q0 -117 83 -199.5t199 -82.5t199 82.5t83 199.5q0 116 -83 198.5t-199 82.5zM1380 646q-105 2 -211 0v1q-1 -27 2.5 -86 +t13.5 -66q29 -14 93.5 -14.5t95.5 10.5q9 3 11 39t-0.5 69.5t-4.5 46.5zM1112 447q8 4 9.5 48t-0.5 88t-4 63v1q-212 -3 -214 -3q-4 -20 -7 -62t0 -83t14 -46q34 -15 101 -16t101 10zM718 636q-16 -59 4.5 -118.5t77.5 -84.5q15 -8 24 -5t12 21q3 16 8 90t10 103 +q-69 -2 -136 -6zM591 510q3 -23 -34 -36q132 -141 271.5 -240t305.5 -154q172 49 310.5 146t293.5 250q-33 13 -30 34q0 2 0.5 3.5t1.5 3t1 2.5v1v-1q-17 2 -50 5.5t-48 4.5q-26 -90 -82 -132q-51 -38 -82 1q-5 6 -9 14q-7 13 -17 62q-2 -5 -5 -9t-7.5 -7t-8 -5.5t-9.5 -4 +l-10 -2.5t-12 -2l-12 -1.5t-13.5 -1t-13.5 -0.5q-106 -9 -163 11q-4 -17 -10 -26.5t-21 -15t-23 -7t-36 -3.5q-6 -1 -9 -1q-179 -17 -203 40q-2 -63 -56 -54q-47 8 -91 54q-12 13 -20 26q-17 29 -26 65q-58 -6 -87 -10q1 -2 4 -10zM507 -118q3 14 3 30q-17 71 -51 130 +t-73 70q-41 12 -101.5 -14.5t-104.5 -80t-39 -107.5q35 -53 100 -93t119 -42q51 -2 94 28t53 79zM510 53q23 -63 27 -119q195 113 392 174q-98 52 -180.5 120t-179.5 165q-6 -4 -29 -13q0 -1 -1 -4t-1 -5q31 -18 22 -37q-12 -23 -56 -34q-10 -13 -29 -24h-1q-2 -83 1 -150 +q19 -34 35 -73zM579 -113q532 -21 1145 0q-254 147 -428 196q-76 -35 -156 -57q-8 -3 -16 0q-65 21 -129 49q-208 -60 -416 -188h-1v-1q1 0 1 1zM1763 -67q4 54 28 120q14 38 33 71l-1 -1q3 77 3 153q-15 8 -30 25q-42 9 -56 33q-9 20 22 38q-2 4 -2 9q-16 4 -28 12 +q-204 -190 -383 -284q198 -59 414 -176zM2155 -90q5 54 -39 107.5t-104 80t-102 14.5q-38 -11 -72.5 -70.5t-51.5 -129.5q0 -16 3 -30q10 -49 53 -79t94 -28q54 2 119 42t100 93z" /> + <glyph glyph-name="_538" unicode="" horiz-adv-x="2304" +d="M1524 -25q0 -68 -48 -116t-116 -48t-116.5 48t-48.5 116t48.5 116.5t116.5 48.5t116 -48.5t48 -116.5zM775 -25q0 -68 -48.5 -116t-116.5 -48t-116 48t-48 116t48 116.5t116 48.5t116.5 -48.5t48.5 -116.5zM0 1469q57 -60 110.5 -104.5t121 -82t136 -63t166 -45.5 +t200 -31.5t250 -18.5t304 -9.5t372.5 -2.5q139 0 244.5 -5t181 -16.5t124 -27.5t71 -39.5t24 -51.5t-19.5 -64t-56.5 -76.5t-89.5 -91t-116 -104.5t-139 -119q-185 -157 -286 -247q29 51 76.5 109t94 105.5t94.5 98.5t83 91.5t54 80.5t13 70t-45.5 55.5t-116.5 41t-204 23.5 +t-304 5q-168 -2 -314 6t-256 23t-204.5 41t-159.5 51.5t-122.5 62.5t-91.5 66.5t-68 71.5t-50.5 69.5t-40 68t-36.5 59.5z" /> + <glyph glyph-name="_539" unicode="" horiz-adv-x="1792" +d="M896 1472q-169 0 -323 -66t-265.5 -177.5t-177.5 -265.5t-66 -323t66 -323t177.5 -265.5t265.5 -177.5t323 -66t323 66t265.5 177.5t177.5 265.5t66 323t-66 323t-177.5 265.5t-265.5 177.5t-323 66zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348 +t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM496 704q16 0 16 -16v-480q0 -16 -16 -16h-32q-16 0 -16 16v480q0 16 16 16h32zM896 640q53 0 90.5 -37.5t37.5 -90.5q0 -35 -17.5 -64t-46.5 -46v-114q0 -14 -9 -23 +t-23 -9h-64q-14 0 -23 9t-9 23v114q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5zM896 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM544 928v-96 +q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v96q0 93 65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5v-96q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v96q0 146 -103 249t-249 103t-249 -103t-103 -249zM1408 192v512q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-512 +q0 -26 19 -45t45 -19h896q26 0 45 19t19 45z" /> + <glyph glyph-name="_540" unicode="" horiz-adv-x="2304" +d="M1920 1024v-768h-1664v768h1664zM2048 448h128v384h-128v288q0 14 -9 23t-23 9h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288zM2304 832v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113 +v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160q53 0 90.5 -37.5t37.5 -90.5z" /> + <glyph glyph-name="_541" unicode="" horiz-adv-x="2304" +d="M256 256v768h1280v-768h-1280zM2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9 +h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" /> + <glyph glyph-name="_542" unicode="" horiz-adv-x="2304" +d="M256 256v768h896v-768h-896zM2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9 +h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" /> + <glyph glyph-name="_543" unicode="" horiz-adv-x="2304" +d="M256 256v768h512v-768h-512zM2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9 +h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" /> + <glyph glyph-name="_544" unicode="" horiz-adv-x="2304" +d="M2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9h-1856q-14 0 -23 -9t-9 -23 +v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" /> + <glyph glyph-name="_545" unicode="" horiz-adv-x="1280" +d="M1133 493q31 -30 14 -69q-17 -40 -59 -40h-382l201 -476q10 -25 0 -49t-34 -35l-177 -75q-25 -10 -49 0t-35 34l-191 452l-312 -312q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v1504q0 42 40 59q12 5 24 5q27 0 45 -19z" /> + <glyph glyph-name="_546" unicode="" horiz-adv-x="1024" +d="M832 1408q-320 0 -320 -224v-416h128v-128h-128v-544q0 -224 320 -224h64v-128h-64q-272 0 -384 146q-112 -146 -384 -146h-64v128h64q320 0 320 224v544h-128v128h128v416q0 224 -320 224h-64v128h64q272 0 384 -146q112 146 384 146h64v-128h-64z" /> + <glyph glyph-name="_547" unicode="" horiz-adv-x="2048" +d="M2048 1152h-128v-1024h128v-384h-384v128h-1280v-128h-384v384h128v1024h-128v384h384v-128h1280v128h384v-384zM1792 1408v-128h128v128h-128zM128 1408v-128h128v128h-128zM256 -128v128h-128v-128h128zM1664 0v128h128v1024h-128v128h-1280v-128h-128v-1024h128v-128 +h1280zM1920 -128v128h-128v-128h128zM1280 896h384v-768h-896v256h-384v768h896v-256zM512 512h640v512h-640v-512zM1536 256v512h-256v-384h-384v-128h640z" /> + <glyph glyph-name="_548" unicode="" horiz-adv-x="2304" +d="M2304 768h-128v-640h128v-384h-384v128h-896v-128h-384v384h128v128h-384v-128h-384v384h128v640h-128v384h384v-128h896v128h384v-384h-128v-128h384v128h384v-384zM2048 1024v-128h128v128h-128zM1408 1408v-128h128v128h-128zM128 1408v-128h128v128h-128zM256 256 +v128h-128v-128h128zM1536 384h-128v-128h128v128zM384 384h896v128h128v640h-128v128h-896v-128h-128v-640h128v-128zM896 -128v128h-128v-128h128zM2176 -128v128h-128v-128h128zM2048 128v640h-128v128h-384v-384h128v-384h-384v128h-384v-128h128v-128h896v128h128z" /> + <glyph glyph-name="_549" unicode="" +d="M1024 288v-416h-928q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1344q40 0 68 -28t28 -68v-928h-416q-40 0 -68 -28t-28 -68zM1152 256h381q-15 -82 -65 -132l-184 -184q-50 -50 -132 -65v381z" /> + <glyph glyph-name="_550" unicode="" +d="M1400 256h-248v-248q29 10 41 22l185 185q12 12 22 41zM1120 384h288v896h-1280v-1280h896v288q0 40 28 68t68 28zM1536 1312v-1024q0 -40 -20 -88t-48 -76l-184 -184q-28 -28 -76 -48t-88 -20h-1024q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1344q40 0 68 -28t28 -68 +z" /> + <glyph glyph-name="_551" unicode="" horiz-adv-x="2304" +d="M1951 538q0 -26 -15.5 -44.5t-38.5 -23.5q-8 -2 -18 -2h-153v140h153q10 0 18 -2q23 -5 38.5 -23.5t15.5 -44.5zM1933 751q0 -25 -15 -42t-38 -21q-3 -1 -15 -1h-139v129h139q3 0 8.5 -0.5t6.5 -0.5q23 -4 38 -21.5t15 -42.5zM728 587v308h-228v-308q0 -58 -38 -94.5 +t-105 -36.5q-108 0 -229 59v-112q53 -15 121 -23t109 -9l42 -1q328 0 328 217zM1442 403v113q-99 -52 -200 -59q-108 -8 -169 41t-61 142t61 142t169 41q101 -7 200 -58v112q-48 12 -100 19.5t-80 9.5l-28 2q-127 6 -218.5 -14t-140.5 -60t-71 -88t-22 -106t22 -106t71 -88 +t140.5 -60t218.5 -14q101 4 208 31zM2176 518q0 54 -43 88.5t-109 39.5v3q57 8 89 41.5t32 79.5q0 55 -41 88t-107 36q-3 0 -12 0.5t-14 0.5h-455v-510h491q74 0 121.5 36.5t47.5 96.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90 +t90 38h2048q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_552" unicode="" horiz-adv-x="2304" +d="M858 295v693q-106 -41 -172 -135.5t-66 -211.5t66 -211.5t172 -134.5zM1362 641q0 117 -66 211.5t-172 135.5v-694q106 41 172 135.5t66 211.5zM1577 641q0 -159 -78.5 -294t-213.5 -213.5t-294 -78.5q-119 0 -227.5 46.5t-187 125t-125 187t-46.5 227.5q0 159 78.5 294 +t213.5 213.5t294 78.5t294 -78.5t213.5 -213.5t78.5 -294zM1960 634q0 139 -55.5 261.5t-147.5 205.5t-213.5 131t-252.5 48h-301q-176 0 -323.5 -81t-235 -230t-87.5 -335q0 -171 87 -317.5t236 -231.5t323 -85h301q129 0 251.5 50.5t214.5 135t147.5 202.5t55.5 246z +M2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_553" unicode="" horiz-adv-x="1792" +d="M1664 -96v1088q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5v-1088q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5zM1792 992v-1088q0 -66 -47 -113t-113 -47h-1088q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1088q66 0 113 -47t47 -113 +zM1408 1376v-160h-128v160q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5v-1088q0 -13 9.5 -22.5t22.5 -9.5h160v-128h-160q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1088q66 0 113 -47t47 -113z" /> + <glyph glyph-name="_554" unicode="" horiz-adv-x="2304" +d="M1728 1088l-384 -704h768zM448 1088l-384 -704h768zM1269 1280q-14 -40 -45.5 -71.5t-71.5 -45.5v-1291h608q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1344q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h608v1291q-40 14 -71.5 45.5t-45.5 71.5h-491q-14 0 -23 9t-9 23v64 +q0 14 9 23t23 9h491q21 57 70 92.5t111 35.5t111 -35.5t70 -92.5h491q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-491zM1088 1264q33 0 56.5 23.5t23.5 56.5t-23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5zM2176 384q0 -73 -46.5 -131t-117.5 -91 +t-144.5 -49.5t-139.5 -16.5t-139.5 16.5t-144.5 49.5t-117.5 91t-46.5 131q0 11 35 81t92 174.5t107 195.5t102 184t56 100q18 33 56 33t56 -33q4 -7 56 -100t102 -184t107 -195.5t92 -174.5t35 -81zM896 384q0 -73 -46.5 -131t-117.5 -91t-144.5 -49.5t-139.5 -16.5 +t-139.5 16.5t-144.5 49.5t-117.5 91t-46.5 131q0 11 35 81t92 174.5t107 195.5t102 184t56 100q18 33 56 33t56 -33q4 -7 56 -100t102 -184t107 -195.5t92 -174.5t35 -81z" /> + <glyph glyph-name="_555" unicode="" +d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 +t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM874 700q77 29 149 92.5t129.5 152.5t92.5 210t35 253h-1024q0 -132 35 -253t92.5 -210t129.5 -152.5t149 -92.5q19 -7 30.5 -23.5t11.5 -36.5t-11.5 -36.5t-30.5 -23.5q-77 -29 -149 -92.5 +t-129.5 -152.5t-92.5 -210t-35 -253h1024q0 132 -35 253t-92.5 210t-129.5 152.5t-149 92.5q-19 7 -30.5 23.5t-11.5 36.5t11.5 36.5t30.5 23.5z" /> + <glyph glyph-name="_556" unicode="" +d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 +t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM1280 1408h-1024q0 -66 9 -128h1006q9 61 9 128zM1280 -128q0 130 -34 249.5t-90.5 208t-126.5 152t-146 94.5h-230q-76 -31 -146 -94.5t-126.5 -152t-90.5 -208t-34 -249.5h1024z" /> + <glyph glyph-name="_557" unicode="" +d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 +t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM1280 1408h-1024q0 -206 85 -384h854q85 178 85 384zM1223 192q-54 141 -145.5 241.5t-194.5 142.5h-230q-103 -42 -194.5 -142.5t-145.5 -241.5h910z" /> + <glyph glyph-name="_558" unicode="" +d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 +t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM874 700q77 29 149 92.5t129.5 152.5t92.5 210t35 253h-1024q0 -132 35 -253t92.5 -210t129.5 -152.5t149 -92.5q19 -7 30.5 -23.5t11.5 -36.5t-11.5 -36.5t-30.5 -23.5q-137 -51 -244 -196 +h700q-107 145 -244 196q-19 7 -30.5 23.5t-11.5 36.5t11.5 36.5t30.5 23.5z" /> + <glyph glyph-name="_559" unicode="" +d="M1504 -64q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v128q0 14 9 23t23 9h1472zM130 0q3 55 16 107t30 95t46 87t53.5 76t64.5 69.5t66 60t70.5 55t66.5 47.5t65 43q-43 28 -65 43t-66.5 47.5t-70.5 55t-66 60t-64.5 69.5t-53.5 76t-46 87 +t-30 95t-16 107h1276q-3 -55 -16 -107t-30 -95t-46 -87t-53.5 -76t-64.5 -69.5t-66 -60t-70.5 -55t-66.5 -47.5t-65 -43q43 -28 65 -43t66.5 -47.5t70.5 -55t66 -60t64.5 -69.5t53.5 -76t46 -87t30 -95t16 -107h-1276zM1504 1536q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9 +h-1472q-14 0 -23 9t-9 23v128q0 14 9 23t23 9h1472z" /> + <glyph glyph-name="_560" unicode="" +d="M768 1152q-53 0 -90.5 -37.5t-37.5 -90.5v-128h-32v93q0 48 -32 81.5t-80 33.5q-46 0 -79 -33t-33 -79v-429l-32 30v172q0 48 -32 81.5t-80 33.5q-46 0 -79 -33t-33 -79v-224q0 -47 35 -82l310 -296q39 -39 39 -102q0 -26 19 -45t45 -19h640q26 0 45 19t19 45v25 +q0 41 10 77l108 436q10 36 10 77v246q0 48 -32 81.5t-80 33.5q-46 0 -79 -33t-33 -79v-32h-32v125q0 40 -25 72.5t-64 40.5q-14 2 -23 2q-46 0 -79 -33t-33 -79v-128h-32v122q0 51 -32.5 89.5t-82.5 43.5q-5 1 -13 1zM768 1280q84 0 149 -50q57 34 123 34q59 0 111 -27 +t86 -76q27 7 59 7q100 0 170 -71.5t70 -171.5v-246q0 -51 -13 -108l-109 -436q-6 -24 -6 -71q0 -80 -56 -136t-136 -56h-640q-84 0 -138 58.5t-54 142.5l-308 296q-76 73 -76 175v224q0 99 70.5 169.5t169.5 70.5q11 0 16 -1q6 95 75.5 160t164.5 65q52 0 98 -21 +q72 69 174 69z" /> + <glyph glyph-name="_561" unicode="" horiz-adv-x="1792" +d="M880 1408q-46 0 -79 -33t-33 -79v-656h-32v528q0 46 -33 79t-79 33t-79 -33t-33 -79v-528v-256l-154 205q-38 51 -102 51q-53 0 -90.5 -37.5t-37.5 -90.5q0 -43 26 -77l384 -512q38 -51 102 -51h688q34 0 61 22t34 56l76 405q5 32 5 59v498q0 46 -33 79t-79 33t-79 -33 +t-33 -79v-272h-32v528q0 46 -33 79t-79 33t-79 -33t-33 -79v-528h-32v656q0 46 -33 79t-79 33zM880 1536q68 0 125.5 -35.5t88.5 -96.5q19 4 42 4q99 0 169.5 -70.5t70.5 -169.5v-17q105 6 180.5 -64t75.5 -175v-498q0 -40 -8 -83l-76 -404q-14 -79 -76.5 -131t-143.5 -52 +h-688q-60 0 -114.5 27.5t-90.5 74.5l-384 512q-51 68 -51 154q0 106 75 181t181 75q78 0 128 -34v434q0 99 70.5 169.5t169.5 70.5q23 0 42 -4q31 61 88.5 96.5t125.5 35.5z" /> + <glyph glyph-name="_562" unicode="" horiz-adv-x="1792" +d="M1073 -128h-177q-163 0 -226 141q-23 49 -23 102v5q-62 30 -98.5 88.5t-36.5 127.5q0 38 5 48h-261q-106 0 -181 75t-75 181t75 181t181 75h113l-44 17q-74 28 -119.5 93.5t-45.5 145.5q0 106 75 181t181 75q46 0 91 -17l628 -239h401q106 0 181 -75t75 -181v-668 +q0 -88 -54 -157.5t-140 -90.5l-339 -85q-92 -23 -186 -23zM1024 583l-155 -71l-163 -74q-30 -14 -48 -41.5t-18 -60.5q0 -46 33 -79t79 -33q26 0 46 10l338 154q-49 10 -80.5 50t-31.5 90v55zM1344 272q0 46 -33 79t-79 33q-26 0 -46 -10l-290 -132q-28 -13 -37 -17 +t-30.5 -17t-29.5 -23.5t-16 -29t-8 -40.5q0 -50 31.5 -82t81.5 -32q20 0 38 9l352 160q30 14 48 41.5t18 60.5zM1112 1024l-650 248q-24 8 -46 8q-53 0 -90.5 -37.5t-37.5 -90.5q0 -40 22.5 -73t59.5 -47l526 -200v-64h-640q-53 0 -90.5 -37.5t-37.5 -90.5t37.5 -90.5 +t90.5 -37.5h535l233 106v198q0 63 46 106l111 102h-69zM1073 0q82 0 155 19l339 85q43 11 70 45.5t27 78.5v668q0 53 -37.5 90.5t-90.5 37.5h-308l-136 -126q-36 -33 -36 -82v-296q0 -46 33 -77t79 -31t79 35t33 81v208h32v-208q0 -70 -57 -114q52 -8 86.5 -48.5t34.5 -93.5 +q0 -42 -23 -78t-61 -53l-310 -141h91z" /> + <glyph glyph-name="_563" unicode="" horiz-adv-x="2048" +d="M1151 1536q61 0 116 -28t91 -77l572 -781q118 -159 118 -359v-355q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v177l-286 143h-546q-80 0 -136 56t-56 136v32q0 119 84.5 203.5t203.5 84.5h420l42 128h-686q-100 0 -173.5 67.5t-81.5 166.5q-65 79 -65 182v32 +q0 80 56 136t136 56h959zM1920 -64v355q0 157 -93 284l-573 781q-39 52 -103 52h-959q-26 0 -45 -19t-19 -45q0 -32 1.5 -49.5t9.5 -40.5t25 -43q10 31 35.5 50t56.5 19h832v-32h-832q-26 0 -45 -19t-19 -45q0 -44 3 -58q8 -44 44 -73t81 -29h640h91q40 0 68 -28t28 -68 +q0 -15 -5 -30l-64 -192q-10 -29 -35 -47.5t-56 -18.5h-443q-66 0 -113 -47t-47 -113v-32q0 -26 19 -45t45 -19h561q16 0 29 -7l317 -158q24 -13 38.5 -36t14.5 -50v-197q0 -26 19 -45t45 -19h384q26 0 45 19t19 45z" /> + <glyph glyph-name="_564" unicode="" horiz-adv-x="2048" +d="M459 -256q-77 0 -137.5 47.5t-79.5 122.5l-101 401q-13 57 -13 108q0 45 -5 67l-116 477q-7 27 -7 57q0 93 62 161t155 78q17 85 82.5 139t152.5 54q83 0 148 -51.5t85 -132.5l83 -348l103 428q20 81 85 132.5t148 51.5q89 0 155.5 -57.5t80.5 -144.5q92 -10 152 -79 +t60 -162q0 -24 -7 -59l-123 -512q10 7 37.5 28.5t38.5 29.5t35 23t41 20.5t41.5 11t49.5 5.5q105 0 180 -74t75 -179q0 -62 -28.5 -118t-78.5 -94l-507 -380q-68 -51 -153 -51h-694zM1104 1408q-38 0 -68.5 -24t-39.5 -62l-164 -682h-127l-145 602q-9 38 -39.5 62t-68.5 24 +q-48 0 -80 -33t-32 -80q0 -15 3 -28l132 -547h-26l-99 408q-9 37 -40 62.5t-69 25.5q-47 0 -80 -33t-33 -79q0 -14 3 -26l116 -478q7 -28 9 -86t10 -88l100 -401q8 -32 34 -52.5t59 -20.5h694q42 0 76 26l507 379q56 43 56 110q0 52 -37.5 88.5t-89.5 36.5q-43 0 -77 -26 +l-307 -230v227q0 4 32 138t68 282t39 161q4 18 4 29q0 47 -32 81t-79 34q-39 0 -69.5 -24t-39.5 -62l-116 -482h-26l150 624q3 14 3 28q0 48 -31.5 82t-79.5 34z" /> + <glyph glyph-name="_565" unicode="" horiz-adv-x="1792" +d="M640 1408q-53 0 -90.5 -37.5t-37.5 -90.5v-512v-384l-151 202q-41 54 -107 54q-52 0 -89 -38t-37 -90q0 -43 26 -77l384 -512q38 -51 102 -51h718q22 0 39.5 13.5t22.5 34.5l92 368q24 96 24 194v217q0 41 -28 71t-68 30t-68 -28t-28 -68h-32v61q0 48 -32 81.5t-80 33.5 +q-46 0 -79 -33t-33 -79v-64h-32v90q0 55 -37 94.5t-91 39.5q-53 0 -90.5 -37.5t-37.5 -90.5v-96h-32v570q0 55 -37 94.5t-91 39.5zM640 1536q107 0 181.5 -77.5t74.5 -184.5v-220q22 2 32 2q99 0 173 -69q47 21 99 21q113 0 184 -87q27 7 56 7q94 0 159 -67.5t65 -161.5 +v-217q0 -116 -28 -225l-92 -368q-16 -64 -68 -104.5t-118 -40.5h-718q-60 0 -114.5 27.5t-90.5 74.5l-384 512q-51 68 -51 154q0 105 74.5 180.5t179.5 75.5q71 0 130 -35v547q0 106 75 181t181 75zM768 128v384h-32v-384h32zM1024 128v384h-32v-384h32zM1280 128v384h-32 +v-384h32z" /> + <glyph glyph-name="_566" unicode="" +d="M1288 889q60 0 107 -23q141 -63 141 -226v-177q0 -94 -23 -186l-85 -339q-21 -86 -90.5 -140t-157.5 -54h-668q-106 0 -181 75t-75 181v401l-239 628q-17 45 -17 91q0 106 75 181t181 75q80 0 145.5 -45.5t93.5 -119.5l17 -44v113q0 106 75 181t181 75t181 -75t75 -181 +v-261q27 5 48 5q69 0 127.5 -36.5t88.5 -98.5zM1072 896q-33 0 -60.5 -18t-41.5 -48l-74 -163l-71 -155h55q50 0 90 -31.5t50 -80.5l154 338q10 20 10 46q0 46 -33 79t-79 33zM1293 761q-22 0 -40.5 -8t-29 -16t-23.5 -29.5t-17 -30.5t-17 -37l-132 -290q-10 -20 -10 -46 +q0 -46 33 -79t79 -33q33 0 60.5 18t41.5 48l160 352q9 18 9 38q0 50 -32 81.5t-82 31.5zM128 1120q0 -22 8 -46l248 -650v-69l102 111q43 46 106 46h198l106 233v535q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5v-640h-64l-200 526q-14 37 -47 59.5t-73 22.5 +q-53 0 -90.5 -37.5t-37.5 -90.5zM1180 -128q44 0 78.5 27t45.5 70l85 339q19 73 19 155v91l-141 -310q-17 -38 -53 -61t-78 -23q-53 0 -93.5 34.5t-48.5 86.5q-44 -57 -114 -57h-208v32h208q46 0 81 33t35 79t-31 79t-77 33h-296q-49 0 -82 -36l-126 -136v-308 +q0 -53 37.5 -90.5t90.5 -37.5h668z" /> + <glyph glyph-name="_567" unicode="" horiz-adv-x="1973" +d="M857 992v-117q0 -13 -9.5 -22t-22.5 -9h-298v-812q0 -13 -9 -22.5t-22 -9.5h-135q-13 0 -22.5 9t-9.5 23v812h-297q-13 0 -22.5 9t-9.5 22v117q0 14 9 23t23 9h793q13 0 22.5 -9.5t9.5 -22.5zM1895 995l77 -961q1 -13 -8 -24q-10 -10 -23 -10h-134q-12 0 -21 8.5 +t-10 20.5l-46 588l-189 -425q-8 -19 -29 -19h-120q-20 0 -29 19l-188 427l-45 -590q-1 -12 -10 -20.5t-21 -8.5h-135q-13 0 -23 10q-9 10 -9 24l78 961q1 12 10 20.5t21 8.5h142q20 0 29 -19l220 -520q10 -24 20 -51q3 7 9.5 24.5t10.5 26.5l221 520q9 19 29 19h141 +q13 0 22 -8.5t10 -20.5z" /> + <glyph glyph-name="_568" unicode="" horiz-adv-x="1792" +d="M1042 833q0 88 -60 121q-33 18 -117 18h-123v-281h162q66 0 102 37t36 105zM1094 548l205 -373q8 -17 -1 -31q-8 -16 -27 -16h-152q-20 0 -28 17l-194 365h-155v-350q0 -14 -9 -23t-23 -9h-134q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h294q128 0 190 -24q85 -31 134 -109 +t49 -180q0 -92 -42.5 -165.5t-115.5 -109.5q6 -10 9 -16zM896 1376q-150 0 -286 -58.5t-234.5 -157t-157 -234.5t-58.5 -286t58.5 -286t157 -234.5t234.5 -157t286 -58.5t286 58.5t234.5 157t157 234.5t58.5 286t-58.5 286t-157 234.5t-234.5 157t-286 58.5zM1792 640 +q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="_569" unicode="" horiz-adv-x="1792" +d="M605 303q153 0 257 104q14 18 3 36l-45 82q-6 13 -24 17q-16 2 -27 -11l-4 -3q-4 -4 -11.5 -10t-17.5 -13.5t-23.5 -14.5t-28.5 -13t-33.5 -9.5t-37.5 -3.5q-76 0 -125 50t-49 127q0 76 48 125.5t122 49.5q37 0 71.5 -14t50.5 -28l16 -14q11 -11 26 -10q16 2 24 14l53 78 +q13 20 -2 39q-3 4 -11 12t-30 23.5t-48.5 28t-67.5 22.5t-86 10q-148 0 -246 -96.5t-98 -240.5q0 -146 97 -241.5t247 -95.5zM1235 303q153 0 257 104q14 18 4 36l-45 82q-8 14 -25 17q-16 2 -27 -11l-4 -3q-4 -4 -11.5 -10t-17.5 -13.5t-23.5 -14.5t-28.5 -13t-33.5 -9.5 +t-37.5 -3.5q-76 0 -125 50t-49 127q0 76 48 125.5t122 49.5q37 0 71.5 -14t50.5 -28l16 -14q11 -11 26 -10q16 2 24 14l53 78q13 20 -2 39q-3 4 -11 12t-30 23.5t-48.5 28t-67.5 22.5t-86 10q-147 0 -245.5 -96.5t-98.5 -240.5q0 -146 97 -241.5t247 -95.5zM896 1376 +q-150 0 -286 -58.5t-234.5 -157t-157 -234.5t-58.5 -286t58.5 -286t157 -234.5t234.5 -157t286 -58.5t286 58.5t234.5 157t157 234.5t58.5 286t-58.5 286t-157 234.5t-234.5 157t-286 58.5zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191 +t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71z" /> + <glyph glyph-name="f260" unicode="" horiz-adv-x="2048" +d="M736 736l384 -384l-384 -384l-672 672l672 672l168 -168l-96 -96l-72 72l-480 -480l480 -480l193 193l-289 287zM1312 1312l672 -672l-672 -672l-168 168l96 96l72 -72l480 480l-480 480l-193 -193l289 -287l-96 -96l-384 384z" /> + <glyph glyph-name="f261" unicode="" horiz-adv-x="1792" +d="M717 182l271 271l-279 279l-88 -88l192 -191l-96 -96l-279 279l279 279l40 -40l87 87l-127 128l-454 -454zM1075 190l454 454l-454 454l-271 -271l279 -279l88 88l-192 191l96 96l279 -279l-279 -279l-40 40l-87 -88zM1792 640q0 -182 -71 -348t-191 -286t-286 -191 +t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="_572" unicode="" horiz-adv-x="2304" +d="M651 539q0 -39 -27.5 -66.5t-65.5 -27.5q-39 0 -66.5 27.5t-27.5 66.5q0 38 27.5 65.5t66.5 27.5q38 0 65.5 -27.5t27.5 -65.5zM1805 540q0 -39 -27.5 -66.5t-66.5 -27.5t-66.5 27.5t-27.5 66.5t27.5 66t66.5 27t66.5 -27t27.5 -66zM765 539q0 79 -56.5 136t-136.5 57 +t-136.5 -56.5t-56.5 -136.5t56.5 -136.5t136.5 -56.5t136.5 56.5t56.5 136.5zM1918 540q0 80 -56.5 136.5t-136.5 56.5q-79 0 -136 -56.5t-57 -136.5t56.5 -136.5t136.5 -56.5t136.5 56.5t56.5 136.5zM850 539q0 -116 -81.5 -197.5t-196.5 -81.5q-116 0 -197.5 82t-81.5 197 +t82 196.5t197 81.5t196.5 -81.5t81.5 -196.5zM2004 540q0 -115 -81.5 -196.5t-197.5 -81.5q-115 0 -196.5 81.5t-81.5 196.5t81.5 196.5t196.5 81.5q116 0 197.5 -81.5t81.5 -196.5zM1040 537q0 191 -135.5 326.5t-326.5 135.5q-125 0 -231 -62t-168 -168.5t-62 -231.5 +t62 -231.5t168 -168.5t231 -62q191 0 326.5 135.5t135.5 326.5zM1708 1110q-254 111 -556 111q-319 0 -573 -110q117 0 223 -45.5t182.5 -122.5t122 -183t45.5 -223q0 115 43.5 219.5t118 180.5t177.5 123t217 50zM2187 537q0 191 -135 326.5t-326 135.5t-326.5 -135.5 +t-135.5 -326.5t135.5 -326.5t326.5 -135.5t326 135.5t135 326.5zM1921 1103h383q-44 -51 -75 -114.5t-40 -114.5q110 -151 110 -337q0 -156 -77 -288t-209 -208.5t-287 -76.5q-133 0 -249 56t-196 155q-47 -56 -129 -179q-11 22 -53.5 82.5t-74.5 97.5 +q-80 -99 -196.5 -155.5t-249.5 -56.5q-155 0 -287 76.5t-209 208.5t-77 288q0 186 110 337q-9 51 -40 114.5t-75 114.5h365q149 100 355 156.5t432 56.5q224 0 421 -56t348 -157z" /> + <glyph glyph-name="f263" unicode="" horiz-adv-x="1280" +d="M640 629q-188 0 -321 133t-133 320q0 188 133 321t321 133t321 -133t133 -321q0 -187 -133 -320t-321 -133zM640 1306q-92 0 -157.5 -65.5t-65.5 -158.5q0 -92 65.5 -157.5t157.5 -65.5t157.5 65.5t65.5 157.5q0 93 -65.5 158.5t-157.5 65.5zM1163 574q13 -27 15 -49.5 +t-4.5 -40.5t-26.5 -38.5t-42.5 -37t-61.5 -41.5q-115 -73 -315 -94l73 -72l267 -267q30 -31 30 -74t-30 -73l-12 -13q-31 -30 -74 -30t-74 30q-67 68 -267 268l-267 -268q-31 -30 -74 -30t-73 30l-12 13q-31 30 -31 73t31 74l267 267l72 72q-203 21 -317 94 +q-39 25 -61.5 41.5t-42.5 37t-26.5 38.5t-4.5 40.5t15 49.5q10 20 28 35t42 22t56 -2t65 -35q5 -4 15 -11t43 -24.5t69 -30.5t92 -24t113 -11q91 0 174 25.5t120 50.5l38 25q33 26 65 35t56 2t42 -22t28 -35z" /> + <glyph glyph-name="_574" unicode="" +d="M927 956q0 -66 -46.5 -112.5t-112.5 -46.5t-112.5 46.5t-46.5 112.5t46.5 112.5t112.5 46.5t112.5 -46.5t46.5 -112.5zM1141 593q-10 20 -28 32t-47.5 9.5t-60.5 -27.5q-10 -8 -29 -20t-81 -32t-127 -20t-124 18t-86 36l-27 18q-31 25 -60.5 27.5t-47.5 -9.5t-28 -32 +q-22 -45 -2 -74.5t87 -73.5q83 -53 226 -67l-51 -52q-142 -142 -191 -190q-22 -22 -22 -52.5t22 -52.5l9 -9q22 -22 52.5 -22t52.5 22l191 191q114 -115 191 -191q22 -22 52.5 -22t52.5 22l9 9q22 22 22 52.5t-22 52.5l-191 190l-52 52q141 14 225 67q67 44 87 73.5t-2 74.5 +zM1092 956q0 134 -95 229t-229 95t-229 -95t-95 -229t95 -229t229 -95t229 95t95 229zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_575" unicode="" horiz-adv-x="1720" +d="M1565 1408q65 0 110 -45.5t45 -110.5v-519q0 -176 -68 -336t-182.5 -275t-274 -182.5t-334.5 -67.5q-176 0 -335.5 67.5t-274.5 182.5t-183 275t-68 336v519q0 64 46 110t110 46h1409zM861 344q47 0 82 33l404 388q37 35 37 85q0 49 -34.5 83.5t-83.5 34.5q-47 0 -82 -33 +l-323 -310l-323 310q-35 33 -81 33q-49 0 -83.5 -34.5t-34.5 -83.5q0 -51 36 -85l405 -388q33 -33 81 -33z" /> + <glyph glyph-name="_576" unicode="" horiz-adv-x="2304" +d="M1494 -103l-295 695q-25 -49 -158.5 -305.5t-198.5 -389.5q-1 -1 -27.5 -0.5t-26.5 1.5q-82 193 -255.5 587t-259.5 596q-21 50 -66.5 107.5t-103.5 100.5t-102 43q0 5 -0.5 24t-0.5 27h583v-50q-39 -2 -79.5 -16t-66.5 -43t-10 -64q26 -59 216.5 -499t235.5 -540 +q31 61 140 266.5t131 247.5q-19 39 -126 281t-136 295q-38 69 -201 71v50l513 -1v-47q-60 -2 -93.5 -25t-12.5 -69q33 -70 87 -189.5t86 -187.5q110 214 173 363q24 55 -10 79.5t-129 26.5q1 7 1 25v24q64 0 170.5 0.5t180 1t92.5 0.5v-49q-62 -2 -119 -33t-90 -81 +l-213 -442q13 -33 127.5 -290t121.5 -274l441 1017q-14 38 -49.5 62.5t-65 31.5t-55.5 8v50l460 -4l1 -2l-1 -44q-139 -4 -201 -145q-526 -1216 -559 -1291h-49z" /> + <glyph glyph-name="_577" unicode="" horiz-adv-x="1792" +d="M949 643q0 -26 -16.5 -45t-41.5 -19q-26 0 -45 16.5t-19 41.5q0 26 17 45t42 19t44 -16.5t19 -41.5zM964 585l350 581q-9 -8 -67.5 -62.5t-125.5 -116.5t-136.5 -127t-117 -110.5t-50.5 -51.5l-349 -580q7 7 67 62t126 116.5t136 127t117 111t50 50.5zM1611 640 +q0 -201 -104 -371q-3 2 -17 11t-26.5 16.5t-16.5 7.5q-13 0 -13 -13q0 -10 59 -44q-74 -112 -184.5 -190.5t-241.5 -110.5l-16 67q-1 10 -15 10q-5 0 -8 -5.5t-2 -9.5l16 -68q-72 -15 -146 -15q-199 0 -372 105q1 2 13 20.5t21.5 33.5t9.5 19q0 13 -13 13q-6 0 -17 -14.5 +t-22.5 -34.5t-13.5 -23q-113 75 -192 187.5t-110 244.5l69 15q10 3 10 15q0 5 -5.5 8t-10.5 2l-68 -15q-14 72 -14 139q0 206 109 379q2 -1 18.5 -12t30 -19t17.5 -8q13 0 13 12q0 6 -12.5 15.5t-32.5 21.5l-20 12q77 112 189 189t244 107l15 -67q2 -10 15 -10q5 0 8 5.5 +t2 10.5l-15 66q71 13 134 13q204 0 379 -109q-39 -56 -39 -65q0 -13 12 -13q11 0 48 64q111 -75 187.5 -186t107.5 -241l-56 -12q-10 -2 -10 -16q0 -5 5.5 -8t9.5 -2l57 13q14 -72 14 -140zM1696 640q0 163 -63.5 311t-170.5 255t-255 170.5t-311 63.5t-311 -63.5 +t-255 -170.5t-170.5 -255t-63.5 -311t63.5 -311t170.5 -255t255 -170.5t311 -63.5t311 63.5t255 170.5t170.5 255t63.5 311zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191 +t191 -286t71 -348z" /> + <glyph glyph-name="_578" unicode="" horiz-adv-x="1792" +d="M893 1536q240 2 451 -120q232 -134 352 -372l-742 39q-160 9 -294 -74.5t-185 -229.5l-276 424q128 159 311 245.5t383 87.5zM146 1131l337 -663q72 -143 211 -217t293 -45l-230 -451q-212 33 -385 157.5t-272.5 316t-99.5 411.5q0 267 146 491zM1732 962 +q58 -150 59.5 -310.5t-48.5 -306t-153 -272t-246 -209.5q-230 -133 -498 -119l405 623q88 131 82.5 290.5t-106.5 277.5zM896 942q125 0 213.5 -88.5t88.5 -213.5t-88.5 -213.5t-213.5 -88.5t-213.5 88.5t-88.5 213.5t88.5 213.5t213.5 88.5z" /> + <glyph glyph-name="_579" unicode="" horiz-adv-x="1792" +d="M903 -256q-283 0 -504.5 150.5t-329.5 398.5q-58 131 -67 301t26 332.5t111 312t179 242.5l-11 -281q11 14 68 15.5t70 -15.5q42 81 160.5 138t234.5 59q-54 -45 -119.5 -148.5t-58.5 -163.5q25 -8 62.5 -13.5t63 -7.5t68 -4t50.5 -3q15 -5 9.5 -45.5t-30.5 -75.5 +q-5 -7 -16.5 -18.5t-56.5 -35.5t-101 -34l15 -189l-139 67q-18 -43 -7.5 -81.5t36 -66.5t65.5 -41.5t81 -6.5q51 9 98 34.5t83.5 45t73.5 17.5q61 -4 89.5 -33t19.5 -65q-1 -2 -2.5 -5.5t-8.5 -12.5t-18 -15.5t-31.5 -10.5t-46.5 -1q-60 -95 -144.5 -135.5t-209.5 -29.5 +q74 -61 162.5 -82.5t168.5 -6t154.5 52t128 87.5t80.5 104q43 91 39 192.5t-37.5 188.5t-78.5 125q87 -38 137 -79.5t77 -112.5q15 170 -57.5 343t-209.5 284q265 -77 412 -279.5t151 -517.5q2 -127 -40.5 -255t-123.5 -238t-189 -196t-247.5 -135.5t-288.5 -49.5z" /> + <glyph glyph-name="_580" unicode="" horiz-adv-x="1792" +d="M1493 1308q-165 110 -359 110q-155 0 -293 -73t-240 -200q-75 -93 -119.5 -218t-48.5 -266v-42q4 -141 48.5 -266t119.5 -218q102 -127 240 -200t293 -73q194 0 359 110q-121 -108 -274.5 -168t-322.5 -60q-29 0 -43 1q-175 8 -333 82t-272 193t-181 281t-67 339 +q0 182 71 348t191 286t286 191t348 71h3q168 -1 320.5 -60.5t273.5 -167.5zM1792 640q0 -192 -77 -362.5t-213 -296.5q-104 -63 -222 -63q-137 0 -255 84q154 56 253.5 233t99.5 405q0 227 -99 404t-253 234q119 83 254 83q119 0 226 -65q135 -125 210.5 -295t75.5 -361z +" /> + <glyph glyph-name="_581" unicode="" horiz-adv-x="1792" +d="M1792 599q0 -56 -7 -104h-1151q0 -146 109.5 -244.5t257.5 -98.5q99 0 185.5 46.5t136.5 130.5h423q-56 -159 -170.5 -281t-267.5 -188.5t-321 -66.5q-187 0 -356 83q-228 -116 -394 -116q-237 0 -237 263q0 115 45 275q17 60 109 229q199 360 475 606 +q-184 -79 -427 -354q63 274 283.5 449.5t501.5 175.5q30 0 45 -1q255 117 433 117q64 0 116 -13t94.5 -40.5t66.5 -76.5t24 -115q0 -116 -75 -286q101 -182 101 -390zM1722 1239q0 83 -53 132t-137 49q-108 0 -254 -70q121 -47 222.5 -131.5t170.5 -195.5q51 135 51 216z +M128 2q0 -86 48.5 -132.5t134.5 -46.5q115 0 266 83q-122 72 -213.5 183t-137.5 245q-98 -205 -98 -332zM632 715h728q-5 142 -113 237t-251 95q-144 0 -251.5 -95t-112.5 -237z" /> + <glyph glyph-name="_582" unicode="" horiz-adv-x="2048" +d="M1792 288v960q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1248v-960q0 -66 -47 -113t-113 -47h-736v-128h352q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23 +v64q0 14 9 23t23 9h352v128h-736q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" /> + <glyph glyph-name="_583" unicode="" horiz-adv-x="1792" +d="M138 1408h197q-70 -64 -126 -149q-36 -56 -59 -115t-30 -125.5t-8.5 -120t10.5 -132t21 -126t28 -136.5q4 -19 6 -28q51 -238 81 -329q57 -171 152 -275h-272q-48 0 -82 34t-34 82v1304q0 48 34 82t82 34zM1346 1408h308q48 0 82 -34t34 -82v-1304q0 -48 -34 -82t-82 -34 +h-178q212 210 196 565l-469 -101q-2 -45 -12 -82t-31 -72t-59.5 -59.5t-93.5 -36.5q-123 -26 -199 40q-32 27 -53 61t-51.5 129t-64.5 258q-35 163 -45.5 263t-5.5 139t23 77q20 41 62.5 73t102.5 45q45 12 83.5 6.5t67 -17t54 -35t43 -48t34.5 -56.5l468 100 +q-68 175 -180 287z" /> + <glyph glyph-name="_584" unicode="" +d="M1401 -11l-6 -6q-113 -113 -259 -175q-154 -64 -317 -64q-165 0 -317 64q-148 63 -259 175q-113 112 -175 258q-42 103 -54 189q-4 28 48 36q51 8 56 -20q1 -1 1 -4q18 -90 46 -159q50 -124 152 -226q98 -98 226 -152q132 -56 276 -56q143 0 276 56q128 55 225 152l6 6 +q10 10 25 6q12 -3 33 -22q36 -37 17 -58zM929 604l-66 -66l63 -63q21 -21 -7 -49q-17 -17 -32 -17q-10 0 -19 10l-62 61l-66 -66q-5 -5 -15 -5q-15 0 -31 16l-2 2q-18 15 -18 29q0 7 8 17l66 65l-66 66q-16 16 14 45q18 18 31 18q6 0 13 -5l65 -66l65 65q18 17 48 -13 +q27 -27 11 -44zM1400 547q0 -118 -46 -228q-45 -105 -126 -186q-80 -80 -187 -126t-228 -46t-228 46t-187 126q-82 82 -125 186q-15 33 -15 40h-1q-9 27 43 44q50 16 60 -12q37 -99 97 -167h1v339v2q3 136 102 232q105 103 253 103q147 0 251 -103t104 -249 +q0 -147 -104.5 -251t-250.5 -104q-58 0 -112 16q-28 11 -13 61q16 51 44 43l14 -3q14 -3 33 -6t30 -3q104 0 176 71.5t72 174.5q0 101 -72 171q-71 71 -175 71q-107 0 -178 -80q-64 -72 -64 -160v-413q110 -67 242 -67q96 0 185 36.5t156 103.5t103.5 155t36.5 183 +q0 198 -141 339q-140 140 -339 140q-200 0 -340 -140q-53 -53 -77 -87l-2 -2q-8 -11 -13 -15.5t-21.5 -9.5t-38.5 3q-21 5 -36.5 16.5t-15.5 26.5v680q0 15 10.5 26.5t27.5 11.5h877q30 0 30 -55t-30 -55h-811v-483h1q40 42 102 84t108 61q109 46 231 46q121 0 228 -46 +t187 -126q81 -81 126 -186q46 -112 46 -229zM1369 1128q9 -8 9 -18t-5.5 -18t-16.5 -21q-26 -26 -39 -26q-9 0 -16 7q-106 91 -207 133q-128 56 -276 56q-133 0 -262 -49q-27 -10 -45 37q-9 25 -8 38q3 16 16 20q130 57 299 57q164 0 316 -64q137 -58 235 -152z" /> + <glyph glyph-name="_585" unicode="" horiz-adv-x="1792" +d="M1551 60q15 6 26 3t11 -17.5t-15 -33.5q-13 -16 -44 -43.5t-95.5 -68t-141 -74t-188 -58t-229.5 -24.5q-119 0 -238 31t-209 76.5t-172.5 104t-132.5 105t-84 87.5q-8 9 -10 16.5t1 12t8 7t11.5 2t11.5 -4.5q192 -117 300 -166q389 -176 799 -90q190 40 391 135z +M1758 175q11 -16 2.5 -69.5t-28.5 -102.5q-34 -83 -85 -124q-17 -14 -26 -9t0 24q21 45 44.5 121.5t6.5 98.5q-5 7 -15.5 11.5t-27 6t-29.5 2.5t-35 0t-31.5 -2t-31 -3t-22.5 -2q-6 -1 -13 -1.5t-11 -1t-8.5 -1t-7 -0.5h-5.5h-4.5t-3 0.5t-2 1.5l-1.5 3q-6 16 47 40t103 30 +q46 7 108 1t76 -24zM1364 618q0 -31 13.5 -64t32 -58t37.5 -46t33 -32l13 -11l-227 -224q-40 37 -79 75.5t-58 58.5l-19 20q-11 11 -25 33q-38 -59 -97.5 -102.5t-127.5 -63.5t-140 -23t-137.5 21t-117.5 65.5t-83 113t-31 162.5q0 84 28 154t72 116.5t106.5 83t122.5 57 +t130 34.5t119.5 18.5t99.5 6.5v127q0 65 -21 97q-34 53 -121 53q-6 0 -16.5 -1t-40.5 -12t-56 -29.5t-56 -59.5t-48 -96l-294 27q0 60 22 119t67 113t108 95t151.5 65.5t190.5 24.5q100 0 181 -25t129.5 -61.5t81 -83t45 -86t12.5 -73.5v-589zM692 597q0 -86 70 -133 +q66 -44 139 -22q84 25 114 123q14 45 14 101v162q-59 -2 -111 -12t-106.5 -33.5t-87 -71t-32.5 -114.5z" /> + <glyph glyph-name="_586" unicode="" horiz-adv-x="1792" +d="M1536 1280q52 0 90 -38t38 -90v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128zM1152 1376v-288q0 -14 9 -23t23 -9 +h64q14 0 23 9t9 23v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM384 1376v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM1536 -128v1024h-1408v-1024h1408zM896 448h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224 +v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v224q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-224z" /> + <glyph glyph-name="_587" unicode="" horiz-adv-x="1792" +d="M1152 416v-64q0 -14 -9 -23t-23 -9h-576q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h576q14 0 23 -9t9 -23zM128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23 +t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47 +t47 -113v-96h128q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_588" unicode="" horiz-adv-x="1792" +d="M1111 151l-46 -46q-9 -9 -22 -9t-23 9l-188 189l-188 -189q-10 -9 -23 -9t-22 9l-46 46q-9 9 -9 22t9 23l189 188l-189 188q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l188 -188l188 188q10 9 23 9t22 -9l46 -46q9 -9 9 -22t-9 -23l-188 -188l188 -188q9 -10 9 -23t-9 -22z +M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 +q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_589" unicode="" horiz-adv-x="1792" +d="M1303 572l-512 -512q-10 -9 -23 -9t-23 9l-288 288q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l220 -220l444 444q10 9 23 9t22 -9l46 -46q9 -9 9 -22t-9 -23zM128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23 +t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47 +t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_590" unicode="" horiz-adv-x="1792" +d="M448 1536q26 0 45 -19t19 -45v-891l536 429q17 14 40 14q26 0 45 -19t19 -45v-379l536 429q17 14 40 14q26 0 45 -19t19 -45v-1152q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h384z" /> + <glyph glyph-name="_591" unicode="" horiz-adv-x="1024" +d="M512 448q66 0 128 15v-655q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v655q62 -15 128 -15zM512 1536q212 0 362 -150t150 -362t-150 -362t-362 -150t-362 150t-150 362t150 362t362 150zM512 1312q14 0 23 9t9 23t-9 23t-23 9q-146 0 -249 -103t-103 -249 +q0 -14 9 -23t23 -9t23 9t9 23q0 119 84.5 203.5t203.5 84.5z" /> + <glyph glyph-name="_592" unicode="" horiz-adv-x="1792" +d="M1745 1239q10 -10 10 -23t-10 -23l-141 -141q-28 -28 -68 -28h-1344q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h576v64q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-64h512q40 0 68 -28zM768 320h256v-512q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v512zM1600 768 +q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-1344q-40 0 -68 28l-141 141q-10 10 -10 23t10 23l141 141q28 28 68 28h512v192h256v-192h576z" /> + <glyph glyph-name="_593" unicode="" horiz-adv-x="2048" +d="M2020 1525q28 -20 28 -53v-1408q0 -20 -11 -36t-29 -23l-640 -256q-24 -11 -48 0l-616 246l-616 -246q-10 -5 -24 -5q-19 0 -36 11q-28 20 -28 53v1408q0 20 11 36t29 23l640 256q24 11 48 0l616 -246l616 246q32 13 60 -6zM736 1390v-1270l576 -230v1270zM128 1173 +v-1270l544 217v1270zM1920 107v1270l-544 -217v-1270z" /> + <glyph glyph-name="_594" unicode="" horiz-adv-x="1792" +d="M512 1536q13 0 22.5 -9.5t9.5 -22.5v-1472q0 -20 -17 -28l-480 -256q-7 -4 -15 -4q-13 0 -22.5 9.5t-9.5 22.5v1472q0 20 17 28l480 256q7 4 15 4zM1760 1536q13 0 22.5 -9.5t9.5 -22.5v-1472q0 -20 -17 -28l-480 -256q-7 -4 -15 -4q-13 0 -22.5 9.5t-9.5 22.5v1472 +q0 20 17 28l480 256q7 4 15 4zM640 1536q8 0 14 -3l512 -256q18 -10 18 -29v-1472q0 -13 -9.5 -22.5t-22.5 -9.5q-8 0 -14 3l-512 256q-18 10 -18 29v1472q0 13 9.5 22.5t22.5 9.5z" /> + <glyph glyph-name="_595" unicode="" horiz-adv-x="1792" +d="M640 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1408 640q0 53 -37.5 90.5t-90.5 37.5 +t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-110 0 -211 18q-173 -173 -435 -229q-52 -10 -86 -13q-12 -1 -22 6t-13 18q-4 15 20 37q5 5 23.5 21.5t25.5 23.5t23.5 25.5t24 31.5t20.5 37 +t20 48t14.5 57.5t12.5 72.5q-146 90 -229.5 216.5t-83.5 269.5q0 174 120 321.5t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" /> + <glyph glyph-name="_596" unicode="" horiz-adv-x="1792" +d="M640 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1024 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 -53 -37.5 -90.5t-90.5 -37.5 +t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5 +t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51 +t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 130 71 248.5t191 204.5t286 136.5t348 50.5t348 -50.5t286 -136.5t191 -204.5t71 -248.5z" /> + <glyph glyph-name="_597" unicode="" horiz-adv-x="1024" +d="M512 345l512 295v-591l-512 -296v592zM0 640v-591l512 296zM512 1527v-591l-512 -296v591zM512 936l512 295v-591z" /> + <glyph glyph-name="_598" unicode="" horiz-adv-x="1792" +d="M1709 1018q-10 -236 -332 -651q-333 -431 -562 -431q-142 0 -240 263q-44 160 -132 482q-72 262 -157 262q-18 0 -127 -76l-77 98q24 21 108 96.5t130 115.5q156 138 241 146q95 9 153 -55.5t81 -203.5q44 -287 66 -373q55 -249 120 -249q51 0 154 161q101 161 109 246 +q13 139 -109 139q-57 0 -121 -26q120 393 459 382q251 -8 236 -326z" /> + <glyph glyph-name="f27e" unicode="" +d="M0 1408h1536v-1536h-1536v1536zM1085 293l-221 631l221 297h-634l221 -297l-221 -631l317 -304z" /> + <glyph glyph-name="uniF280" unicode="" +d="M0 1408h1536v-1536h-1536v1536zM908 1088l-12 -33l75 -83l-31 -114l25 -25l107 57l107 -57l25 25l-31 114l75 83l-12 33h-95l-53 96h-32l-53 -96h-95zM641 925q32 0 44.5 -16t11.5 -63l174 21q0 55 -17.5 92.5t-50.5 56t-69 25.5t-85 7q-133 0 -199 -57.5t-66 -182.5v-72 +h-96v-128h76q20 0 20 -8v-382q0 -14 -5 -20t-18 -7l-73 -7v-88h448v86l-149 14q-6 1 -8.5 1.5t-3.5 2.5t-0.5 4t1 7t0.5 10v387h191l38 128h-231q-6 0 -2 6t4 9v80q0 27 1.5 40.5t7.5 28t19.5 20t36.5 5.5zM1248 96v86l-54 9q-7 1 -9.5 2.5t-2.5 3t1 7.5t1 12v520h-275 +l-23 -101l83 -22q23 -7 23 -27v-370q0 -14 -6 -18.5t-20 -6.5l-70 -9v-86h352z" /> + <glyph glyph-name="uniF281" unicode="" horiz-adv-x="1792" +d="M1792 690q0 -58 -29.5 -105.5t-79.5 -72.5q12 -46 12 -96q0 -155 -106.5 -287t-290.5 -208.5t-400 -76.5t-399.5 76.5t-290 208.5t-106.5 287q0 47 11 94q-51 25 -82 73.5t-31 106.5q0 82 58 140.5t141 58.5q85 0 145 -63q218 152 515 162l116 521q3 13 15 21t26 5 +l369 -81q18 37 54 59.5t79 22.5q62 0 106 -43.5t44 -105.5t-44 -106t-106 -44t-105.5 43.5t-43.5 105.5l-334 74l-104 -472q300 -9 519 -160q58 61 143 61q83 0 141 -58.5t58 -140.5zM418 491q0 -62 43.5 -106t105.5 -44t106 44t44 106t-44 105.5t-106 43.5q-61 0 -105 -44 +t-44 -105zM1228 136q11 11 11 26t-11 26q-10 10 -25 10t-26 -10q-41 -42 -121 -62t-160 -20t-160 20t-121 62q-11 10 -26 10t-25 -10q-11 -10 -11 -25.5t11 -26.5q43 -43 118.5 -68t122.5 -29.5t91 -4.5t91 4.5t122.5 29.5t118.5 68zM1225 341q62 0 105.5 44t43.5 106 +q0 61 -44 105t-105 44q-62 0 -106 -43.5t-44 -105.5t44 -106t106 -44z" /> + <glyph glyph-name="_602" unicode="" horiz-adv-x="1792" +d="M69 741h1q16 126 58.5 241.5t115 217t167.5 176t223.5 117.5t276.5 43q231 0 414 -105.5t294 -303.5q104 -187 104 -442v-188h-1125q1 -111 53.5 -192.5t136.5 -122.5t189.5 -57t213 -3t208 46.5t173.5 84.5v-377q-92 -55 -229.5 -92t-312.5 -38t-316 53 +q-189 73 -311.5 249t-124.5 372q-3 242 111 412t325 268q-48 -60 -78 -125.5t-46 -159.5h635q8 77 -8 140t-47 101.5t-70.5 66.5t-80.5 41t-75 20.5t-56 8.5l-22 1q-135 -5 -259.5 -44.5t-223.5 -104.5t-176 -140.5t-138 -163.5z" /> + <glyph glyph-name="_603" unicode="" horiz-adv-x="2304" +d="M0 32v608h2304v-608q0 -66 -47 -113t-113 -47h-1984q-66 0 -113 47t-47 113zM640 256v-128h384v128h-384zM256 256v-128h256v128h-256zM2144 1408q66 0 113 -47t47 -113v-224h-2304v224q0 66 47 113t113 47h1984z" /> + <glyph glyph-name="_604" unicode="" horiz-adv-x="1792" +d="M1584 246l-218 111q-74 -120 -196.5 -189t-263.5 -69q-147 0 -271 72t-196 196t-72 270q0 110 42.5 209.5t115 172t172 115t209.5 42.5q131 0 247.5 -60.5t192.5 -168.5l215 125q-110 169 -286.5 265t-378.5 96q-161 0 -308 -63t-253 -169t-169 -253t-63 -308t63 -308 +t169 -253t253 -169t308 -63q213 0 397.5 107t290.5 292zM1030 643l693 -352q-116 -253 -334.5 -400t-492.5 -147q-182 0 -348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71q260 0 470.5 -133.5t335.5 -366.5zM1543 640h-39v-160h-96v352h136q32 0 54.5 -20 +t28.5 -48t1 -56t-27.5 -48t-57.5 -20z" /> + <glyph glyph-name="uniF285" unicode="" horiz-adv-x="1792" +d="M1427 827l-614 386l92 151h855zM405 562l-184 116v858l1183 -743zM1424 697l147 -95v-858l-532 335zM1387 718l-500 -802h-855l356 571z" /> + <glyph glyph-name="uniF286" unicode="" horiz-adv-x="1792" +d="M640 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1152 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1664 496v-752h-640v320q0 80 -56 136t-136 56t-136 -56t-56 -136v-320h-640v752q0 16 16 16h96 +q16 0 16 -16v-112h128v624q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 6 2.5 9.5t8.5 5t9.5 2t11.5 0t9 -0.5v391q-32 15 -32 50q0 23 16.5 39t38.5 16t38.5 -16t16.5 -39q0 -35 -32 -50v-17q45 10 83 10q21 0 59.5 -7.5t54.5 -7.5 +q17 0 47 7.5t37 7.5q16 0 16 -16v-210q0 -15 -35 -21.5t-62 -6.5q-18 0 -54.5 7.5t-55.5 7.5q-40 0 -90 -12v-133q1 0 9 0.5t11.5 0t9.5 -2t8.5 -5t2.5 -9.5v-112h128v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-624h128v112q0 16 16 16h96 +q16 0 16 -16z" /> + <glyph glyph-name="_607" unicode="" horiz-adv-x="2304" +d="M2288 731q16 -8 16 -27t-16 -27l-320 -192q-8 -5 -16 -5q-9 0 -16 4q-16 10 -16 28v128h-858q37 -58 83 -165q16 -37 24.5 -55t24 -49t27 -47t27 -34t31.5 -26t33 -8h96v96q0 14 9 23t23 9h320q14 0 23 -9t9 -23v-320q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v96h-96 +q-32 0 -61 10t-51 23.5t-45 40.5t-37 46t-33.5 57t-28.5 57.5t-28 60.5q-23 53 -37 81.5t-36 65t-44.5 53.5t-46.5 17h-360q-22 -84 -91 -138t-157 -54q-106 0 -181 75t-75 181t75 181t181 75q88 0 157 -54t91 -138h104q24 0 46.5 17t44.5 53.5t36 65t37 81.5q19 41 28 60.5 +t28.5 57.5t33.5 57t37 46t45 40.5t51 23.5t61 10h107q21 57 70 92.5t111 35.5q80 0 136 -56t56 -136t-56 -136t-136 -56q-62 0 -111 35.5t-70 92.5h-107q-17 0 -33 -8t-31.5 -26t-27 -34t-27 -47t-24 -49t-24.5 -55q-46 -107 -83 -165h1114v128q0 18 16 28t32 -1z" /> + <glyph glyph-name="_608" unicode="" horiz-adv-x="1792" +d="M1150 774q0 -56 -39.5 -95t-95.5 -39h-253v269h253q56 0 95.5 -39.5t39.5 -95.5zM1329 774q0 130 -91.5 222t-222.5 92h-433v-896h180v269h253q130 0 222 91.5t92 221.5zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348 +t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="_609" unicode="" horiz-adv-x="2304" +d="M1645 438q0 59 -34 106.5t-87 68.5q-7 -45 -23 -92q-7 -24 -27.5 -38t-44.5 -14q-12 0 -24 3q-31 10 -45 38.5t-4 58.5q23 71 23 143q0 123 -61 227.5t-166 165.5t-228 61q-134 0 -247 -73t-167 -194q108 -28 188 -106q22 -23 22 -55t-22 -54t-54 -22t-55 22 +q-75 75 -180 75q-106 0 -181 -74.5t-75 -180.5t75 -180.5t181 -74.5h1046q79 0 134.5 55.5t55.5 133.5zM1798 438q0 -142 -100.5 -242t-242.5 -100h-1046q-169 0 -289 119.5t-120 288.5q0 153 100 267t249 136q62 184 221 298t354 114q235 0 408.5 -158.5t196.5 -389.5 +q116 -25 192.5 -118.5t76.5 -214.5zM2048 438q0 -175 -97 -319q-23 -33 -64 -33q-24 0 -43 13q-26 17 -32 48.5t12 57.5q71 104 71 233t-71 233q-18 26 -12 57t32 49t57.5 11.5t49.5 -32.5q97 -142 97 -318zM2304 438q0 -244 -134 -443q-23 -34 -64 -34q-23 0 -42 13 +q-26 18 -32.5 49t11.5 57q108 164 108 358q0 195 -108 357q-18 26 -11.5 57.5t32.5 48.5q26 18 57 12t49 -33q134 -198 134 -442z" /> + <glyph glyph-name="_610" unicode="" +d="M1500 -13q0 -89 -63 -152.5t-153 -63.5t-153.5 63.5t-63.5 152.5q0 90 63.5 153.5t153.5 63.5t153 -63.5t63 -153.5zM1267 268q-115 -15 -192.5 -102.5t-77.5 -205.5q0 -74 33 -138q-146 -78 -379 -78q-109 0 -201 21t-153.5 54.5t-110.5 76.5t-76 85t-44.5 83 +t-23.5 66.5t-6 39.5q0 19 4.5 42.5t18.5 56t36.5 58t64 43.5t94.5 18t94 -17.5t63 -41t35.5 -53t17.5 -49t4 -33.5q0 -34 -23 -81q28 -27 82 -42t93 -17l40 -1q115 0 190 51t75 133q0 26 -9 48.5t-31.5 44.5t-49.5 41t-74 44t-93.5 47.5t-119.5 56.5q-28 13 -43 20 +q-116 55 -187 100t-122.5 102t-72 125.5t-20.5 162.5q0 78 20.5 150t66 137.5t112.5 114t166.5 77t221.5 28.5q120 0 220 -26t164.5 -67t109.5 -94t64 -105.5t19 -103.5q0 -46 -15 -82.5t-36.5 -58t-48.5 -36t-49 -19.5t-39 -5h-8h-32t-39 5t-44 14t-41 28t-37 46t-24 70.5 +t-10 97.5q-15 16 -59 25.5t-81 10.5l-37 1q-68 0 -117.5 -31t-70.5 -70t-21 -76q0 -24 5 -43t24 -46t53 -51t97 -53.5t150 -58.5q76 -25 138.5 -53.5t109 -55.5t83 -59t60.5 -59.5t41 -62.5t26.5 -62t14.5 -63.5t6 -62t1 -62.5z" /> + <glyph glyph-name="_611" unicode="" +d="M704 352v576q0 14 -9 23t-23 9h-256q-14 0 -23 -9t-9 -23v-576q0 -14 9 -23t23 -9h256q14 0 23 9t9 23zM1152 352v576q0 14 -9 23t-23 9h-256q-14 0 -23 -9t-9 -23v-576q0 -14 9 -23t23 -9h256q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103 +t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="_612" unicode="" +d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM768 96q148 0 273 73t198 198t73 273t-73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273 +t73 -273t198 -198t273 -73zM864 320q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-192zM480 320q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-192z" /> + <glyph glyph-name="_613" unicode="" +d="M1088 352v576q0 14 -9 23t-23 9h-576q-14 0 -23 -9t-9 -23v-576q0 -14 9 -23t23 -9h576q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 +t103 -385.5z" /> + <glyph glyph-name="_614" unicode="" +d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM768 96q148 0 273 73t198 198t73 273t-73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273 +t73 -273t198 -198t273 -73zM480 320q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h576q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-576z" /> + <glyph glyph-name="_615" unicode="" horiz-adv-x="1792" +d="M1757 128l35 -313q3 -28 -16 -50q-19 -21 -48 -21h-1664q-29 0 -48 21q-19 22 -16 50l35 313h1722zM1664 967l86 -775h-1708l86 775q3 24 21 40.5t43 16.5h256v-128q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5v128h384v-128q0 -53 37.5 -90.5t90.5 -37.5 +t90.5 37.5t37.5 90.5v128h256q25 0 43 -16.5t21 -40.5zM1280 1152v-256q0 -26 -19 -45t-45 -19t-45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-256q0 -26 -19 -45t-45 -19t-45 19t-19 45v256q0 159 112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" /> + <glyph glyph-name="_616" unicode="" horiz-adv-x="2048" +d="M1920 768q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5h-15l-115 -662q-8 -46 -44 -76t-82 -30h-1280q-46 0 -82 30t-44 76l-115 662h-15q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5h1792zM485 -32q26 2 43.5 22.5t15.5 46.5l-32 416q-2 26 -22.5 43.5 +t-46.5 15.5t-43.5 -22.5t-15.5 -46.5l32 -416q2 -25 20.5 -42t43.5 -17h5zM896 32v416q0 26 -19 45t-45 19t-45 -19t-19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45zM1280 32v416q0 26 -19 45t-45 19t-45 -19t-19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45zM1632 27l32 416 +q2 26 -15.5 46.5t-43.5 22.5t-46.5 -15.5t-22.5 -43.5l-32 -416q-2 -26 15.5 -46.5t43.5 -22.5h5q25 0 43.5 17t20.5 42zM476 1244l-93 -412h-132l101 441q19 88 89 143.5t160 55.5h167q0 26 19 45t45 19h384q26 0 45 -19t19 -45h167q90 0 160 -55.5t89 -143.5l101 -441 +h-132l-93 412q-11 44 -45.5 72t-79.5 28h-167q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45h-167q-45 0 -79.5 -28t-45.5 -72z" /> + <glyph glyph-name="_617" unicode="" horiz-adv-x="1792" +d="M991 512l64 256h-254l-64 -256h254zM1759 1016l-56 -224q-7 -24 -31 -24h-327l-64 -256h311q15 0 25 -12q10 -14 6 -28l-56 -224q-5 -24 -31 -24h-327l-81 -328q-7 -24 -31 -24h-224q-16 0 -26 12q-9 12 -6 28l78 312h-254l-81 -328q-7 -24 -31 -24h-225q-15 0 -25 12 +q-9 12 -6 28l78 312h-311q-15 0 -25 12q-9 12 -6 28l56 224q7 24 31 24h327l64 256h-311q-15 0 -25 12q-10 14 -6 28l56 224q5 24 31 24h327l81 328q7 24 32 24h224q15 0 25 -12q9 -12 6 -28l-78 -312h254l81 328q7 24 32 24h224q15 0 25 -12q9 -12 6 -28l-78 -312h311 +q15 0 25 -12q9 -12 6 -28z" /> + <glyph glyph-name="_618" unicode="" +d="M841 483l148 -148l-149 -149zM840 1094l149 -149l-148 -148zM710 -130l464 464l-306 306l306 306l-464 464v-611l-255 255l-93 -93l320 -321l-320 -321l93 -93l255 255v-611zM1429 640q0 -209 -32 -365.5t-87.5 -257t-140.5 -162.5t-181.5 -86.5t-219.5 -24.5 +t-219.5 24.5t-181.5 86.5t-140.5 162.5t-87.5 257t-32 365.5t32 365.5t87.5 257t140.5 162.5t181.5 86.5t219.5 24.5t219.5 -24.5t181.5 -86.5t140.5 -162.5t87.5 -257t32 -365.5z" /> + <glyph glyph-name="_619" unicode="" horiz-adv-x="1024" +d="M596 113l173 172l-173 172v-344zM596 823l173 172l-173 172v-344zM628 640l356 -356l-539 -540v711l-297 -296l-108 108l372 373l-372 373l108 108l297 -296v711l539 -540z" /> + <glyph glyph-name="_620" unicode="" +d="M1280 256q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM512 1024q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5 +t112.5 -271.5zM1440 1344q0 -20 -13 -38l-1056 -1408q-19 -26 -51 -26h-160q-26 0 -45 19t-19 45q0 20 13 38l1056 1408q19 26 51 26h160q26 0 45 -19t19 -45zM768 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 +t271.5 -112.5t112.5 -271.5z" /> + <glyph glyph-name="_621" unicode="" horiz-adv-x="1792" +d="M104 830l792 -1015l-868 630q-18 13 -25 34.5t0 42.5l101 308v0zM566 830h660l-330 -1015v0zM368 1442l198 -612h-462l198 612q8 23 33 23t33 -23zM1688 830l101 -308q7 -21 0 -42.5t-25 -34.5l-868 -630l792 1015v0zM1688 830h-462l198 612q8 23 33 23t33 -23z" /> + <glyph glyph-name="_622" unicode="" horiz-adv-x="1792" +d="M384 704h160v224h-160v-224zM1221 372v92q-104 -36 -243 -38q-135 -1 -259.5 46.5t-220.5 122.5l1 -96q88 -80 212 -128.5t272 -47.5q129 0 238 49zM640 704h640v224h-640v-224zM1792 736q0 -187 -99 -352q89 -102 89 -229q0 -157 -129.5 -268t-313.5 -111 +q-122 0 -225 52.5t-161 140.5q-19 -1 -57 -1t-57 1q-58 -88 -161 -140.5t-225 -52.5q-184 0 -313.5 111t-129.5 268q0 127 89 229q-99 165 -99 352q0 209 120 385.5t326.5 279.5t449.5 103t449.5 -103t326.5 -279.5t120 -385.5z" /> + <glyph glyph-name="_623" unicode="" +d="M515 625v-128h-252v128h252zM515 880v-127h-252v127h252zM1273 369v-128h-341v128h341zM1273 625v-128h-672v128h672zM1273 880v-127h-672v127h672zM1408 20v1240q0 8 -6 14t-14 6h-32l-378 -256l-210 171l-210 -171l-378 256h-32q-8 0 -14 -6t-6 -14v-1240q0 -8 6 -14 +t14 -6h1240q8 0 14 6t6 14zM553 1130l185 150h-406zM983 1130l221 150h-406zM1536 1260v-1240q0 -62 -43 -105t-105 -43h-1240q-62 0 -105 43t-43 105v1240q0 62 43 105t105 43h1240q62 0 105 -43t43 -105z" /> + <glyph glyph-name="_624" unicode="" horiz-adv-x="1792" +d="M896 720q-104 196 -160 278q-139 202 -347 318q-34 19 -70 36q-89 40 -94 32t34 -38l39 -31q62 -43 112.5 -93.5t94.5 -116.5t70.5 -113t70.5 -131q9 -17 13 -25q44 -84 84 -153t98 -154t115.5 -150t131 -123.5t148.5 -90.5q153 -66 154 -60q1 3 -49 37q-53 36 -81 57 +q-77 58 -179 211t-185 310zM549 177q-76 60 -132.5 125t-98 143.5t-71 154.5t-58.5 186t-52 209t-60.5 252t-76.5 289q273 0 497.5 -36t379 -92t271 -144.5t185.5 -172.5t110 -198.5t56 -199.5t12.5 -198.5t-9.5 -173t-20 -143.5t-13 -107l323 -327h-104l-281 285 +q-22 -2 -91.5 -14t-121.5 -19t-138 -6t-160.5 17t-167.5 59t-179 111z" /> + <glyph glyph-name="_625" unicode="" horiz-adv-x="1792" +d="M1374 879q-6 26 -28.5 39.5t-48.5 7.5q-261 -62 -401 -62t-401 62q-26 6 -48.5 -7.5t-28.5 -39.5t7.5 -48.5t39.5 -28.5q194 -46 303 -58q-2 -158 -15.5 -269t-26.5 -155.5t-41 -115.5l-9 -21q-10 -25 1 -49t36 -34q9 -4 23 -4q44 0 60 41l8 20q54 139 71 259h42 +q17 -120 71 -259l8 -20q16 -41 60 -41q14 0 23 4q25 10 36 34t1 49l-9 21q-28 71 -41 115.5t-26.5 155.5t-15.5 269q109 12 303 58q26 6 39.5 28.5t7.5 48.5zM1024 1024q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z +M1600 640q0 -143 -55.5 -273.5t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5zM896 1408q-156 0 -298 -61t-245 -164t-164 -245t-61 -298t61 -298 +t164 -245t245 -164t298 -61t298 61t245 164t164 245t61 298t-61 298t-164 245t-245 164t-298 61zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="_626" unicode="" +d="M1438 723q34 -35 29 -82l-44 -551q-4 -42 -34.5 -70t-71.5 -28q-6 0 -9 1q-44 3 -72.5 36.5t-25.5 77.5l35 429l-143 -8q55 -113 55 -240q0 -216 -148 -372l-137 137q91 101 91 235q0 145 -102.5 248t-247.5 103q-134 0 -236 -92l-137 138q120 114 284 141l264 300 +l-149 87l-181 -161q-33 -30 -77 -27.5t-73 35.5t-26.5 77t34.5 73l239 213q26 23 60 26.5t64 -14.5l488 -283q36 -21 48 -68q17 -67 -26 -117l-205 -232l371 20q49 3 83 -32zM1240 1180q-74 0 -126 52t-52 126t52 126t126 52t126.5 -52t52.5 -126t-52.5 -126t-126.5 -52z +M613 -62q106 0 196 61l139 -139q-146 -116 -335 -116q-148 0 -273.5 73t-198.5 198t-73 273q0 188 116 336l139 -139q-60 -88 -60 -197q0 -145 102.5 -247.5t247.5 -102.5z" /> + <glyph glyph-name="_627" unicode="" +d="M880 336v-160q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v160q0 14 9 23t23 9h160q14 0 23 -9t9 -23zM1136 832q0 -50 -15 -90t-45.5 -69t-52 -44t-59.5 -36q-32 -18 -46.5 -28t-26 -24t-11.5 -29v-32q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v68q0 35 10.5 64.5 +t24 47.5t39 35.5t41 25.5t44.5 21q53 25 75 43t22 49q0 42 -43.5 71.5t-95.5 29.5q-56 0 -95 -27q-29 -20 -80 -83q-9 -12 -25 -12q-11 0 -19 6l-108 82q-10 7 -12 20t5 23q122 192 349 192q129 0 238.5 -89.5t109.5 -214.5zM768 1280q-130 0 -248.5 -51t-204 -136.5 +t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5 +t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="_628" unicode="" horiz-adv-x="1408" +d="M366 1225q-64 0 -110 45.5t-46 110.5q0 64 46 109.5t110 45.5t109.5 -45.5t45.5 -109.5q0 -65 -45.5 -110.5t-109.5 -45.5zM917 583q0 -50 -30 -67.5t-63.5 -6.5t-47.5 34l-367 438q-7 12 -14 15.5t-11 1.5l-3 -3q-7 -8 4 -21l122 -139l1 -354l-161 -457 +q-67 -192 -92 -234q-15 -26 -28 -32q-50 -26 -103 -1q-29 13 -41.5 43t-9.5 57q2 17 197 618l5 416l-85 -164l35 -222q4 -24 -1 -42t-14 -27.5t-19 -16t-17 -7.5l-7 -2q-19 -3 -34.5 3t-24 16t-14 22t-7.5 19.5t-2 9.5l-46 299l211 381q23 34 113 34q75 0 107 -40l424 -521 +q7 -5 14 -17l3 -3l-1 -1q7 -13 7 -29zM514 433q43 -113 88.5 -225t69.5 -168l24 -55q36 -93 42 -125q11 -70 -36 -97q-35 -22 -66 -16t-51 22t-29 35h-1q-6 16 -8 25l-124 351zM1338 -159q31 -49 31 -57q0 -5 -3 -7q-9 -5 -14.5 0.5t-15.5 26t-16 30.5q-114 172 -423 661 +q3 -1 7 1t7 4l3 2q11 9 11 17z" /> + <glyph glyph-name="_629" unicode="" horiz-adv-x="2304" +d="M504 542h171l-1 265zM1530 641q0 87 -50.5 140t-146.5 53h-54v-388h52q91 0 145 57t54 138zM956 1018l1 -756q0 -14 -9.5 -24t-23.5 -10h-216q-14 0 -23.5 10t-9.5 24v62h-291l-55 -81q-10 -15 -28 -15h-267q-21 0 -30.5 18t3.5 35l556 757q9 14 27 14h332q14 0 24 -10 +t10 -24zM1783 641q0 -193 -125.5 -303t-324.5 -110h-270q-14 0 -24 10t-10 24v756q0 14 10 24t24 10h268q200 0 326 -109t126 -302zM1939 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-44.5 -108t-73.5 -102.5h-51q38 45 66.5 104.5t41.5 112t21 98t9 72.5l1 27q0 8 -0.5 22.5 +t-7.5 60t-20 91.5t-41 111.5t-66 124.5h43q41 -47 72 -107t45.5 -111.5t23 -96t10.5 -70.5zM2123 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-45 -108t-74 -102.5h-51q38 45 66.5 104.5t41.5 112t21 98t9 72.5l1 27q0 8 -0.5 22.5t-7.5 60t-19.5 91.5t-40.5 111.5t-66 124.5 +h43q41 -47 72 -107t45.5 -111.5t23 -96t10.5 -70.5zM2304 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-44.5 -108t-73.5 -102.5h-51q38 45 66 104.5t41 112t21 98t9 72.5l1 27q0 8 -0.5 22.5t-7.5 60t-19.5 91.5t-40.5 111.5t-66 124.5h43q41 -47 72 -107t45.5 -111.5t23 -96 +t9.5 -70.5z" /> + <glyph glyph-name="uniF2A0" unicode="" horiz-adv-x="1408" +d="M617 -153q0 11 -13 58t-31 107t-20 69q-1 4 -5 26.5t-8.5 36t-13.5 21.5q-15 14 -51 14q-23 0 -70 -5.5t-71 -5.5q-34 0 -47 11q-6 5 -11 15.5t-7.5 20t-6.5 24t-5 18.5q-37 128 -37 255t37 255q1 4 5 18.5t6.5 24t7.5 20t11 15.5q13 11 47 11q24 0 71 -5.5t70 -5.5 +q36 0 51 14q9 8 13.5 21.5t8.5 36t5 26.5q2 9 20 69t31 107t13 58q0 22 -43.5 52.5t-75.5 42.5q-20 8 -45 8q-34 0 -98 -18q-57 -17 -96.5 -40.5t-71 -66t-46 -70t-45.5 -94.5q-6 -12 -9 -19q-49 -107 -68 -216t-19 -244t19 -244t68 -216q56 -122 83 -161q63 -91 179 -127 +l6 -2q64 -18 98 -18q25 0 45 8q32 12 75.5 42.5t43.5 52.5zM776 760q-26 0 -45 19t-19 45.5t19 45.5q37 37 37 90q0 52 -37 91q-19 19 -19 45t19 45t45 19t45 -19q75 -75 75 -181t-75 -181q-21 -19 -45 -19zM957 579q-27 0 -45 19q-19 19 -19 45t19 45q112 114 112 272 +t-112 272q-19 19 -19 45t19 45t45 19t45 -19q150 -150 150 -362t-150 -362q-18 -19 -45 -19zM1138 398q-27 0 -45 19q-19 19 -19 45t19 45q90 91 138.5 208t48.5 245t-48.5 245t-138.5 208q-19 19 -19 45t19 45t45 19t45 -19q109 -109 167 -249t58 -294t-58 -294t-167 -249 +q-18 -19 -45 -19z" /> + <glyph glyph-name="uniF2A1" unicode="" horiz-adv-x="2176" +d="M192 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM704 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM704 864q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1472 352 +q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1472 864q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 864 +q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 1376q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 192q0 -80 -56 -136 +t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 1216q0 -80 -56 -136t-136 -56 +t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM2176 192q0 -80 -56 -136t-136 -56t-136 56 +t-56 136t56 136t136 56t136 -56t56 -136zM1664 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM2176 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136 +t56 136t136 56t136 -56t56 -136zM2176 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136z" /> + <glyph glyph-name="uniF2A2" unicode="" horiz-adv-x="1792" +d="M128 -192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM320 0q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM365 365l256 -256l-90 -90l-256 256zM704 384q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45z +M1411 704q0 -59 -11.5 -108.5t-37.5 -93.5t-44 -67.5t-53 -64.5q-31 -35 -45.5 -54t-33.5 -50t-26.5 -64t-7.5 -74q0 -159 -112.5 -271.5t-271.5 -112.5q-26 0 -45 19t-19 45t19 45t45 19q106 0 181 75t75 181q0 57 11.5 105.5t37 91t43.5 66.5t52 63q40 46 59.5 72 +t37.5 74.5t18 103.5q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5zM896 576q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45 +t45 19t45 -19t19 -45zM1184 704q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 93 -65.5 158.5t-158.5 65.5q-92 0 -158 -65.5t-66 -158.5q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 146 103 249t249 103t249 -103t103 -249zM1578 993q10 -25 -1 -49t-36 -34q-9 -4 -23 -4 +q-19 0 -35.5 11t-23.5 30q-68 178 -224 295q-21 16 -25 42t12 47q17 21 43 25t47 -12q183 -137 266 -351zM1788 1074q9 -25 -1.5 -49t-35.5 -34q-11 -4 -23 -4q-44 0 -60 41q-92 238 -297 393q-22 16 -25.5 42t12.5 47q16 22 42 25.5t47 -12.5q235 -175 341 -449z" /> + <glyph glyph-name="uniF2A3" unicode="" horiz-adv-x="2304" +d="M1032 576q-59 2 -84 55q-17 34 -48 53.5t-68 19.5q-53 0 -90.5 -37.5t-37.5 -90.5q0 -56 36 -89l10 -8q34 -31 82 -31q37 0 68 19.5t48 53.5q25 53 84 55zM1600 704q0 56 -36 89l-10 8q-34 31 -82 31q-37 0 -68 -19.5t-48 -53.5q-25 -53 -84 -55q59 -2 84 -55 +q17 -34 48 -53.5t68 -19.5q53 0 90.5 37.5t37.5 90.5zM1174 925q-17 -35 -55 -48t-73 4q-62 31 -134 31q-51 0 -99 -17q3 0 9.5 0.5t9.5 0.5q92 0 170.5 -50t118.5 -133q17 -36 3.5 -73.5t-49.5 -54.5q-18 -9 -39 -9q21 0 39 -9q36 -17 49.5 -54.5t-3.5 -73.5 +q-40 -83 -118.5 -133t-170.5 -50h-6q-16 2 -44 4l-290 27l-239 -120q-14 -7 -29 -7q-40 0 -57 35l-160 320q-11 23 -4 47.5t29 37.5l209 119l148 267q17 155 91.5 291.5t195.5 236.5q31 25 70.5 21.5t64.5 -34.5t21.5 -70t-34.5 -65q-70 -59 -117 -128q123 84 267 101 +q40 5 71.5 -19t35.5 -64q5 -40 -19 -71.5t-64 -35.5q-84 -10 -159 -55q46 10 99 10q115 0 218 -50q36 -18 49 -55.5t-5 -73.5zM2137 1085l160 -320q11 -23 4 -47.5t-29 -37.5l-209 -119l-148 -267q-17 -155 -91.5 -291.5t-195.5 -236.5q-26 -22 -61 -22q-45 0 -74 35 +q-25 31 -21.5 70t34.5 65q70 59 117 128q-123 -84 -267 -101q-4 -1 -12 -1q-36 0 -63.5 24t-31.5 60q-5 40 19 71.5t64 35.5q84 10 159 55q-46 -10 -99 -10q-115 0 -218 50q-36 18 -49 55.5t5 73.5q17 35 55 48t73 -4q62 -31 134 -31q51 0 99 17q-3 0 -9.5 -0.5t-9.5 -0.5 +q-92 0 -170.5 50t-118.5 133q-17 36 -3.5 73.5t49.5 54.5q18 9 39 9q-21 0 -39 9q-36 17 -49.5 54.5t3.5 73.5q40 83 118.5 133t170.5 50h6h1q14 -2 42 -4l291 -27l239 120q14 7 29 7q40 0 57 -35z" /> + <glyph glyph-name="uniF2A4" unicode="" horiz-adv-x="1792" +d="M1056 704q0 -26 19 -45t45 -19t45 19t19 45q0 146 -103 249t-249 103t-249 -103t-103 -249q0 -26 19 -45t45 -19t45 19t19 45q0 93 66 158.5t158 65.5t158 -65.5t66 -158.5zM835 1280q-117 0 -223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5q0 -26 19 -45t45 -19t45 19 +t19 45q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -55 -18 -103.5t-37.5 -74.5t-59.5 -72q-34 -39 -52 -63t-43.5 -66.5t-37 -91t-11.5 -105.5q0 -106 -75 -181t-181 -75q-26 0 -45 -19t-19 -45t19 -45t45 -19q159 0 271.5 112.5t112.5 271.5q0 41 7.5 74 +t26.5 64t33.5 50t45.5 54q35 41 53 64.5t44 67.5t37.5 93.5t11.5 108.5q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5zM591 561l226 -226l-579 -579q-12 -12 -29 -12t-29 12l-168 168q-12 12 -12 29t12 29zM1612 1524l168 -168q12 -12 12 -29t-12 -30l-233 -233 +l-26 -25l-71 -71q-66 153 -195 258l91 91l207 207q13 12 30 12t29 -12z" /> + <glyph glyph-name="uniF2A5" unicode="" +d="M866 1021q0 -27 -13 -94q-11 -50 -31.5 -150t-30.5 -150q-2 -11 -4.5 -12.5t-13.5 -2.5q-20 -2 -31 -2q-58 0 -84 49.5t-26 113.5q0 88 35 174t103 124q28 14 51 14q28 0 36.5 -16.5t8.5 -47.5zM1352 597q0 14 -39 75.5t-52 66.5q-21 8 -34 8q-91 0 -226 -77l-2 2 +q3 22 27.5 135t24.5 178q0 233 -242 233q-24 0 -68 -6q-94 -17 -168.5 -89.5t-111.5 -166.5t-37 -189q0 -146 80.5 -225t227.5 -79q25 0 25 -3t-1 -5q-4 -34 -26 -117q-14 -52 -51.5 -101t-82.5 -49q-42 0 -42 47q0 24 10.5 47.5t25 39.5t29.5 28.5t26 20t11 8.5q0 3 -7 10 +q-24 22 -58.5 36.5t-65.5 14.5q-35 0 -63.5 -34t-41 -75t-12.5 -75q0 -88 51.5 -142t138.5 -54q82 0 155 53t117.5 126t65.5 153q6 22 15.5 66.5t14.5 66.5q3 12 14 18q118 60 227 60q48 0 127 -18q1 -1 4 -1q5 0 9.5 4.5t4.5 8.5zM1536 1120v-960q0 -119 -84.5 -203.5 +t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="uniF2A6" unicode="" horiz-adv-x="1535" +d="M744 1231q0 24 -2 38.5t-8.5 30t-21 23t-37.5 7.5q-39 0 -78 -23q-105 -58 -159 -190.5t-54 -269.5q0 -44 8.5 -85.5t26.5 -80.5t52.5 -62.5t81.5 -23.5q4 0 18 -0.5t20 0t16 3t15 8.5t7 16q16 77 48 231.5t48 231.5q19 91 19 146zM1498 575q0 -7 -7.5 -13.5t-15.5 -6.5 +l-6 1q-22 3 -62 11t-72 12.5t-63 4.5q-167 0 -351 -93q-15 -8 -21 -27q-10 -36 -24.5 -105.5t-22.5 -100.5q-23 -91 -70 -179.5t-112.5 -164.5t-154.5 -123t-185 -47q-135 0 -214.5 83.5t-79.5 219.5q0 53 19.5 117t63 116.5t97.5 52.5q38 0 120 -33.5t83 -61.5 +q0 -1 -16.5 -12.5t-39.5 -31t-46 -44.5t-39 -61t-16 -74q0 -33 16.5 -53t48.5 -20q45 0 85 31.5t66.5 78t48 105.5t32.5 107t16 90v9q0 2 -3.5 3.5t-8.5 1.5h-10t-10 -0.5t-6 -0.5q-227 0 -352 122.5t-125 348.5q0 108 34.5 221t96 210t156 167.5t204.5 89.5q52 9 106 9 +q374 0 374 -360q0 -98 -38 -273t-43 -211l3 -3q101 57 182.5 88t167.5 31q22 0 53 -13q19 -7 80 -102.5t61 -116.5z" /> + <glyph glyph-name="uniF2A7" unicode="" horiz-adv-x="1664" +d="M831 863q32 0 59 -18l222 -148q61 -40 110 -97l146 -170q40 -46 29 -106l-72 -413q-6 -32 -29.5 -53.5t-55.5 -25.5l-527 -56l-352 -32h-9q-39 0 -67.5 28t-28.5 68q0 37 27 64t65 32l260 32h-448q-41 0 -69.5 30t-26.5 71q2 39 32 65t69 26l442 1l-521 64q-41 5 -66 37 +t-19 73q6 35 34.5 57.5t65.5 22.5h10l481 -60l-351 94q-38 10 -62 41.5t-18 68.5q6 36 33 58.5t62 22.5q6 0 20 -2l448 -96l217 -37q1 0 3 -0.5t3 -0.5q23 0 30.5 23t-12.5 36l-186 125q-35 23 -42 63.5t18 73.5q27 38 76 38zM761 661l186 -125l-218 37l-5 2l-36 38 +l-238 262q-1 1 -2.5 3.5t-2.5 3.5q-24 31 -18.5 70t37.5 64q31 23 68 17.5t64 -33.5l142 -147q-2 -1 -5 -3.5t-4 -4.5q-32 -45 -23 -99t55 -85zM1648 1115l15 -266q4 -73 -11 -147l-48 -219q-12 -59 -67 -87l-106 -54q2 62 -39 109l-146 170q-53 61 -117 103l-222 148 +q-34 23 -76 23q-51 0 -88 -37l-235 312q-25 33 -18 73.5t41 63.5q33 22 71.5 14t62.5 -40l266 -352l-262 455q-21 35 -10.5 75t47.5 59q35 18 72.5 6t57.5 -46l241 -420l-136 337q-15 35 -4.5 74t44.5 56q37 19 76 6t56 -51l193 -415l101 -196q8 -15 23 -17.5t27 7.5t11 26 +l-12 224q-2 41 26 71t69 31q39 0 67 -28.5t30 -67.5z" /> + <glyph glyph-name="uniF2A8" unicode="" horiz-adv-x="1792" +d="M335 180q-2 0 -6 2q-86 57 -168.5 145t-139.5 180q-21 30 -21 69q0 9 2 19t4 18t7 18t8.5 16t10.5 17t10 15t12 15.5t11 14.5q184 251 452 365q-110 198 -110 211q0 19 17 29q116 64 128 64q18 0 28 -16l124 -229q92 19 192 19q266 0 497.5 -137.5t378.5 -369.5 +q20 -31 20 -69t-20 -69q-91 -142 -218.5 -253.5t-278.5 -175.5q110 -198 110 -211q0 -20 -17 -29q-116 -64 -127 -64q-19 0 -29 16l-124 229l-64 119l-444 820l7 7q-58 -24 -99 -47q3 -5 127 -234t243 -449t119 -223q0 -7 -9 -9q-13 -3 -72 -3q-57 0 -60 7l-456 841 +q-39 -28 -82 -68q24 -43 214 -393.5t190 -354.5q0 -10 -11 -10q-14 0 -82.5 22t-72.5 28l-106 197l-224 413q-44 -53 -78 -106q2 -3 18 -25t23 -34l176 -327q0 -10 -10 -10zM1165 282l49 -91q273 111 450 385q-180 277 -459 389q67 -64 103 -148.5t36 -176.5 +q0 -106 -47 -200.5t-132 -157.5zM848 896q0 -20 14 -34t34 -14q86 0 147 -61t61 -147q0 -20 14 -34t34 -14t34 14t14 34q0 126 -89 215t-215 89q-20 0 -34 -14t-14 -34zM1214 961l-9 4l7 -7z" /> + <glyph glyph-name="uniF2A9" unicode="" horiz-adv-x="1280" +d="M1050 430q0 -215 -147 -374q-148 -161 -378 -161q-232 0 -378 161q-147 159 -147 374q0 147 68 270.5t189 196.5t268 73q96 0 182 -31q-32 -62 -39 -126q-66 28 -143 28q-167 0 -280.5 -123t-113.5 -291q0 -170 112.5 -288.5t281.5 -118.5t281 118.5t112 288.5 +q0 89 -32 166q66 13 123 49q41 -98 41 -212zM846 619q0 -192 -79.5 -345t-238.5 -253l-14 -1q-29 0 -62 5q83 32 146.5 102.5t99.5 154.5t58.5 189t30 192.5t7.5 178.5q0 69 -3 103q55 -160 55 -326zM791 947v-2q-73 214 -206 440q88 -59 142.5 -186.5t63.5 -251.5z +M1035 744q-83 0 -160 75q218 120 290 247q19 37 21 56q-42 -94 -139.5 -166.5t-204.5 -97.5q-35 54 -35 113q0 37 17 79t43 68q46 44 157 74q59 16 106 58.5t74 100.5q74 -105 74 -253q0 -109 -24 -170q-32 -77 -88.5 -130.5t-130.5 -53.5z" /> + <glyph glyph-name="uniF2AA" unicode="" +d="M1050 495q0 78 -28 147q-41 -25 -85 -34q22 -50 22 -114q0 -117 -77 -198.5t-193 -81.5t-193.5 81.5t-77.5 198.5q0 115 78 199.5t193 84.5q53 0 98 -19q4 43 27 87q-60 21 -125 21q-154 0 -257.5 -108.5t-103.5 -263.5t103.5 -261t257.5 -106t257.5 106.5t103.5 260.5z +M872 850q2 -24 2 -71q0 -63 -5 -123t-20.5 -132.5t-40.5 -130t-68.5 -106t-100.5 -70.5q21 -3 42 -3h10q219 139 219 411q0 116 -38 225zM872 850q-4 80 -44 171.5t-98 130.5q92 -156 142 -302zM1207 955q0 102 -51 174q-41 -86 -124 -109q-69 -19 -109 -53.5t-40 -99.5 +q0 -40 24 -77q74 17 140.5 67t95.5 115q-4 -52 -74.5 -111.5t-138.5 -97.5q52 -52 110 -52q51 0 90 37t60 90q17 42 17 117zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 +t84.5 -203.5z" /> + <glyph glyph-name="uniF2AB" unicode="" +d="M1279 388q0 22 -22 27q-67 15 -118 59t-80 108q-7 19 -7 25q0 15 19.5 26t43 17t43 20.5t19.5 36.5q0 19 -18.5 31.5t-38.5 12.5q-12 0 -32 -8t-31 -8q-4 0 -12 2q5 95 5 114q0 79 -17 114q-36 78 -103 121.5t-152 43.5q-199 0 -275 -165q-17 -35 -17 -114q0 -19 5 -114 +q-4 -2 -14 -2q-12 0 -32 7.5t-30 7.5q-21 0 -38.5 -12t-17.5 -32q0 -21 19.5 -35.5t43 -20.5t43 -17t19.5 -26q0 -6 -7 -25q-64 -138 -198 -167q-22 -5 -22 -27q0 -46 137 -68q2 -5 6 -26t11.5 -30.5t23.5 -9.5q12 0 37.5 4.5t39.5 4.5q35 0 67 -15t54 -32.5t57.5 -32.5 +t76.5 -15q43 0 79 15t57.5 32.5t53.5 32.5t67 15q14 0 39.5 -4t38.5 -4q16 0 23 10t11 30t6 25q137 22 137 68zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 +t103 -385.5z" /> + <glyph glyph-name="uniF2AC" unicode="" horiz-adv-x="1664" +d="M848 1408q134 1 240.5 -68.5t163.5 -192.5q27 -58 27 -179q0 -47 -9 -191q14 -7 28 -7q18 0 51 13.5t51 13.5q29 0 56 -18t27 -46q0 -32 -31.5 -54t-69 -31.5t-69 -29t-31.5 -47.5q0 -15 12 -43q37 -82 102.5 -150t144.5 -101q28 -12 80 -23q28 -6 28 -35 +q0 -70 -219 -103q-7 -11 -11 -39t-14 -46.5t-33 -18.5q-20 0 -62 6.5t-64 6.5q-37 0 -62 -5q-32 -5 -63 -22.5t-58 -38t-58 -40.5t-76 -33.5t-99 -13.5q-52 0 -96.5 13.5t-75 33.5t-57.5 40.5t-58 38t-62 22.5q-26 5 -63 5q-24 0 -65.5 -7.5t-58.5 -7.5q-25 0 -35 18.5 +t-14 47.5t-11 40q-219 33 -219 103q0 29 28 35q52 11 80 23q78 32 144.5 101t102.5 150q12 28 12 43q0 28 -31.5 47.5t-69.5 29.5t-69.5 31.5t-31.5 52.5q0 27 26 45.5t55 18.5q15 0 48 -13t53 -13q18 0 32 7q-9 142 -9 190q0 122 27 180q64 137 172 198t264 63z" /> + <glyph glyph-name="uniF2AD" unicode="" +d="M1280 388q0 22 -22 27q-67 14 -118 58t-80 109q-7 14 -7 25q0 15 19.5 26t42.5 17t42.5 20.5t19.5 36.5q0 19 -18.5 31.5t-38.5 12.5q-11 0 -31 -8t-32 -8q-4 0 -12 2q5 63 5 115q0 78 -17 114q-36 78 -102.5 121.5t-152.5 43.5q-198 0 -275 -165q-18 -38 -18 -115 +q0 -38 6 -114q-10 -2 -15 -2q-11 0 -31.5 8t-30.5 8q-20 0 -37.5 -12.5t-17.5 -32.5q0 -21 19.5 -35.5t42.5 -20.5t42.5 -17t19.5 -26q0 -11 -7 -25q-64 -138 -198 -167q-22 -5 -22 -27q0 -47 138 -69q2 -5 6 -26t11 -30.5t23 -9.5q13 0 38.5 5t38.5 5q35 0 67.5 -15 +t54.5 -32.5t57.5 -32.5t76.5 -15q43 0 79 15t57.5 32.5t54 32.5t67.5 15q13 0 39 -4.5t39 -4.5q15 0 22.5 9.5t11.5 31t5 24.5q138 22 138 69zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960 +q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="uniF2AE" unicode="" horiz-adv-x="2304" +d="M2304 1536q-69 -46 -125 -92t-89 -81t-59.5 -71.5t-37.5 -57.5t-22 -44.5t-14 -29.5q-10 -18 -35.5 -136.5t-48.5 -164.5q-15 -29 -50 -60.5t-67.5 -50.5t-72.5 -41t-48 -28q-47 -31 -151 -231q-341 14 -630 -158q-92 -53 -303 -179q47 16 86 31t55 22l15 7 +q71 27 163 64.5t133.5 53.5t108 34.5t142.5 31.5q186 31 465 -7q1 0 10 -3q11 -6 14 -17t-3 -22l-194 -345q-15 -29 -47 -22q-128 24 -354 24q-146 0 -402 -44.5t-392 -46.5q-82 -1 -149 13t-107 37t-61 40t-33 34l-1 1v2q0 6 6 6q138 0 371 55q192 366 374.5 524t383.5 158 +q5 0 14.5 -0.5t38 -5t55 -12t61.5 -24.5t63 -39.5t54 -59t40 -82.5l102 177q2 4 21 42.5t44.5 86.5t61 109.5t84 133.5t100.5 137q66 82 128 141.5t121.5 96.5t92.5 53.5t88 39.5z" /> + <glyph glyph-name="uniF2B0" unicode="" +d="M1322 640q0 -45 -5 -76l-236 14l224 -78q-19 -73 -58 -141l-214 103l177 -158q-44 -61 -107 -108l-157 178l103 -215q-61 -37 -140 -59l-79 228l14 -240q-38 -6 -76 -6t-76 6l14 238l-78 -226q-74 19 -140 59l103 215l-157 -178q-59 43 -108 108l178 158l-214 -104 +q-39 69 -58 141l224 79l-237 -14q-5 42 -5 76q0 35 5 77l238 -14l-225 79q19 73 58 140l214 -104l-177 159q46 61 107 108l158 -178l-103 215q67 39 140 58l77 -224l-13 236q36 6 75 6q38 0 76 -6l-14 -237l78 225q74 -19 140 -59l-103 -214l158 178q61 -47 107 -108 +l-177 -159l213 104q37 -62 58 -141l-224 -78l237 14q5 -31 5 -77zM1352 640q0 160 -78.5 295.5t-213 214t-292.5 78.5q-119 0 -227 -46.5t-186.5 -125t-124.5 -187.5t-46 -229q0 -119 46 -228t124.5 -187.5t186.5 -125t227 -46.5q158 0 292.5 78.5t213 214t78.5 294.5z +M1425 1023v-766l-657 -383l-657 383v766l657 383zM768 -183l708 412v823l-708 411l-708 -411v-823zM1536 1088v-896l-768 -448l-768 448v896l768 448z" /> + <glyph glyph-name="uniF2B1" unicode="" horiz-adv-x="1664" +d="M339 1318h691l-26 -72h-665q-110 0 -188.5 -79t-78.5 -189v-771q0 -95 60.5 -169.5t153.5 -93.5q23 -5 98 -5v-72h-45q-140 0 -239.5 100t-99.5 240v771q0 140 99.5 240t239.5 100zM1190 1536h247l-482 -1294q-23 -61 -40.5 -103.5t-45 -98t-54 -93.5t-64.5 -78.5 +t-79.5 -65t-95.5 -41t-116 -18.5v195q163 26 220 182q20 52 20 105q0 54 -20 106l-285 733h228l187 -585zM1664 978v-1111h-795q37 55 45 73h678v1038q0 85 -49.5 155t-129.5 99l25 67q101 -34 163.5 -123.5t62.5 -197.5z" /> + <glyph glyph-name="uniF2B2" unicode="" horiz-adv-x="1792" +d="M852 1227q0 -29 -17 -52.5t-45 -23.5t-45 23.5t-17 52.5t17 52.5t45 23.5t45 -23.5t17 -52.5zM688 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50 -21.5t-20 -51.5v-114q0 -30 20.5 -52t49.5 -22q30 0 50.5 22t20.5 52zM860 -149v114q0 30 -20 51.5t-50 21.5t-50.5 -21.5 +t-20.5 -51.5v-114q0 -30 20.5 -52t50.5 -22q29 0 49.5 22t20.5 52zM1034 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50.5 -21.5t-20.5 -51.5v-114q0 -30 20.5 -52t50.5 -22t50.5 22t20.5 52zM1208 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50.5 -21.5t-20.5 -51.5v-114 +q0 -30 20.5 -52t50.5 -22t50.5 22t20.5 52zM1476 535q-84 -160 -232 -259.5t-323 -99.5q-123 0 -229.5 51.5t-178.5 137t-113 197.5t-41 232q0 88 21 174q-104 -175 -104 -390q0 -162 65 -312t185 -251q30 57 91 57q56 0 86 -50q32 50 87 50q56 0 86 -50q32 50 87 50t87 -50 +q30 50 86 50q28 0 52.5 -15.5t37.5 -40.5q112 94 177 231.5t73 287.5zM1326 564q0 75 -72 75q-17 0 -47 -6q-95 -19 -149 -19q-226 0 -226 243q0 86 30 204q-83 -127 -83 -275q0 -150 89 -260.5t235 -110.5q111 0 210 70q13 48 13 79zM884 1223q0 50 -32 89.5t-81 39.5 +t-81 -39.5t-32 -89.5q0 -51 31.5 -90.5t81.5 -39.5t81.5 39.5t31.5 90.5zM1513 884q0 96 -37.5 179t-113 137t-173.5 54q-77 0 -149 -35t-127 -94q-48 -159 -48 -268q0 -104 45.5 -157t147.5 -53q53 0 142 19q36 6 53 6q51 0 77.5 -28t26.5 -80q0 -26 -4 -46 +q75 68 117.5 165.5t42.5 200.5zM1792 667q0 -111 -33.5 -249.5t-93.5 -204.5q-58 -64 -195 -142.5t-228 -104.5l-4 -1v-114q0 -43 -29.5 -75t-72.5 -32q-56 0 -86 50q-32 -50 -87 -50t-87 50q-30 -50 -86 -50q-55 0 -87 50q-30 -50 -86 -50q-47 0 -75 33.5t-28 81.5 +q-90 -68 -198 -68q-118 0 -211 80q54 1 106 20q-113 31 -182 127q32 -7 71 -7q89 0 164 46q-192 192 -240 306q-24 56 -24 160q0 57 9 125.5t31.5 146.5t55 141t86.5 105t120 42q59 0 81 -52q19 29 42 54q2 3 12 13t13 16q10 15 23 38t25 42t28 39q87 111 211.5 177 +t260.5 66q35 0 62 -4q59 64 146 64q83 0 140 -57q5 -5 5 -12q0 -5 -6 -13.5t-12.5 -16t-16 -17l-10.5 -10.5q17 -6 36 -18t19 -24q0 -6 -16 -25q157 -138 197 -378q25 30 60 30q45 0 100 -49q90 -80 90 -279z" /> + <glyph glyph-name="uniF2B3" unicode="" +d="M917 631q0 33 -6 64h-362v-132h217q-12 -76 -74.5 -120.5t-142.5 -44.5q-99 0 -169 71.5t-70 170.5t70 170.5t169 71.5q93 0 153 -59l104 101q-108 100 -257 100q-160 0 -272 -112.5t-112 -271.5t112 -271.5t272 -112.5q165 0 266.5 105t101.5 270zM1262 585h109v110 +h-109v110h-110v-110h-110v-110h110v-110h110v110zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="uniF2B4" unicode="" +d="M1536 1024v-839q0 -48 -49 -62q-174 -52 -338 -52q-73 0 -215.5 29.5t-227.5 29.5q-164 0 -370 -48v-338h-160v1368q-63 25 -101 81t-38 124q0 91 64 155t155 64t155 -64t64 -155q0 -68 -38 -124t-101 -81v-68q190 44 343 44q99 0 198 -15q14 -2 111.5 -22.5t149.5 -20.5 +q77 0 165 18q11 2 80 21t89 19q26 0 45 -19t19 -45z" /> + <glyph glyph-name="uniF2B5" unicode="" horiz-adv-x="2304" +d="M192 384q40 0 56 32t0 64t-56 32t-56 -32t0 -64t56 -32zM1665 442q-10 13 -38.5 50t-41.5 54t-38 49t-42.5 53t-40.5 47t-45 49l-125 -140q-83 -94 -208.5 -92t-205.5 98q-57 69 -56.5 158t58.5 157l177 206q-22 11 -51 16.5t-47.5 6t-56.5 -0.5t-49 -1q-92 0 -158 -66 +l-158 -158h-155v-544q5 0 21 0.5t22 0t19.5 -2t20.5 -4.5t17.5 -8.5t18.5 -13.5l297 -292q115 -111 227 -111q78 0 125 47q57 -20 112.5 8t72.5 85q74 -6 127 44q20 18 36 45.5t14 50.5q10 -10 43 -10q43 0 77 21t49.5 53t12 71.5t-30.5 73.5zM1824 384h96v512h-93l-157 180 +q-66 76 -169 76h-167q-89 0 -146 -67l-209 -243q-28 -33 -28 -75t27 -75q43 -51 110 -52t111 49l193 218q25 23 53.5 21.5t47 -27t8.5 -56.5q16 -19 56 -63t60 -68q29 -36 82.5 -105.5t64.5 -84.5q52 -66 60 -140zM2112 384q40 0 56 32t0 64t-56 32t-56 -32t0 -64t56 -32z +M2304 960v-640q0 -26 -19 -45t-45 -19h-434q-27 -65 -82 -106.5t-125 -51.5q-33 -48 -80.5 -81.5t-102.5 -45.5q-42 -53 -104.5 -81.5t-128.5 -24.5q-60 -34 -126 -39.5t-127.5 14t-117 53.5t-103.5 81l-287 282h-358q-26 0 -45 19t-19 45v672q0 26 19 45t45 19h421 +q14 14 47 48t47.5 48t44 40t50.5 37.5t51 25.5t62 19.5t68 5.5h117q99 0 181 -56q82 56 181 56h167q35 0 67 -6t56.5 -14.5t51.5 -26.5t44.5 -31t43 -39.5t39 -42t41 -48t41.5 -48.5h355q26 0 45 -19t19 -45z" /> + <glyph glyph-name="uniF2B6" unicode="" horiz-adv-x="1792" +d="M1792 882v-978q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v978q0 15 11 24q8 7 39 34.5t41.5 36t45.5 37.5t70 55.5t96 73t143.5 107t192.5 140.5q5 4 52.5 40t71.5 52.5t64 35t69 18.5t69 -18.5t65 -35.5t71 -52t52 -40q110 -80 192.5 -140.5t143.5 -107 +t96 -73t70 -55.5t45.5 -37.5t41.5 -36t39 -34.5q11 -9 11 -24zM1228 297q263 191 345 252q11 8 12.5 20.5t-6.5 23.5l-38 52q-8 11 -21 12.5t-24 -6.5q-231 -169 -343 -250q-5 -3 -52 -39t-71.5 -52.5t-64.5 -35t-69 -18.5t-69 18.5t-64.5 35t-71.5 52.5t-52 39 +q-186 134 -343 250q-11 8 -24 6.5t-21 -12.5l-38 -52q-8 -11 -6.5 -23.5t12.5 -20.5q82 -61 345 -252q10 -8 50 -38t65 -47t64 -39.5t77.5 -33.5t75.5 -11t75.5 11t79 34.5t64.5 39.5t65 47.5t48 36.5z" /> + <glyph glyph-name="uniF2B7" unicode="" horiz-adv-x="1792" +d="M1474 623l39 -51q8 -11 6.5 -23.5t-11.5 -20.5q-43 -34 -126.5 -98.5t-146.5 -113t-67 -51.5q-39 -32 -60 -48t-60.5 -41t-76.5 -36.5t-74 -11.5h-1h-1q-37 0 -74 11.5t-76 36.5t-61 41.5t-60 47.5q-5 4 -65 50.5t-143.5 111t-122.5 94.5q-11 8 -12.5 20.5t6.5 23.5 +l37 52q8 11 21.5 13t24.5 -7q94 -73 306 -236q5 -4 43.5 -35t60.5 -46.5t56.5 -32.5t58.5 -17h1h1q24 0 58.5 17t56.5 32.5t60.5 46.5t43.5 35q258 198 313 242q11 8 24 6.5t21 -12.5zM1664 -96v928q-90 83 -159 139q-91 74 -389 304q-3 2 -43 35t-61 48t-56 32.5t-59 17.5 +h-1h-1q-24 0 -59 -17.5t-56 -32.5t-61 -48t-43 -35q-215 -166 -315.5 -245.5t-129.5 -104t-82 -74.5q-14 -12 -21 -19v-928q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 832v-928q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v928q0 56 41 94 +q123 114 350 290.5t233 181.5q36 30 59 47.5t61.5 42t76 36.5t74.5 12h1h1q37 0 74.5 -12t76 -36.5t61.5 -42t59 -47.5q43 -36 156 -122t226 -177t201 -173q41 -38 41 -94z" /> + <glyph glyph-name="uniF2B8" unicode="" +d="M330 1l202 -214l-34 236l-216 213zM556 -225l274 218l-11 245l-300 -215zM245 413l227 -213l-48 327l-245 204zM495 189l317 214l-14 324l-352 -200zM843 178l95 -80l-2 239l-103 79q0 -1 1 -8.5t0 -12t-5 -7.5l-78 -52l85 -70q7 -6 7 -88zM138 930l256 -200l-68 465 +l-279 173zM1173 267l15 234l-230 -164l2 -240zM417 722l373 194l-19 441l-423 -163zM1270 357l20 233l-226 142l-2 -105l144 -95q6 -4 4 -9l-7 -119zM1461 496l30 222l-179 -128l-20 -228zM1273 329l-71 49l-8 -117q0 -5 -4 -8l-234 -187q-7 -5 -14 0l-98 83l7 -161 +q0 -5 -4 -8l-293 -234q-4 -2 -6 -2q-8 2 -8 3l-228 242q-4 4 -59 277q-2 7 5 11l61 37q-94 86 -95 92l-72 351q-2 7 6 12l94 45q-133 100 -135 108l-96 466q-2 10 7 13l433 135q5 0 8 -1l317 -153q6 -4 6 -9l20 -463q0 -7 -6 -10l-118 -61l126 -85q5 -2 5 -8l5 -123l121 74 +q5 4 11 0l84 -56l3 110q0 6 5 9l206 126q6 3 11 0l245 -135q4 -4 5 -7t-6.5 -60t-17.5 -124.5t-10 -70.5q0 -5 -4 -7l-191 -153q-6 -5 -13 0z" /> + <glyph glyph-name="uniF2B9" unicode="" horiz-adv-x="1664" +d="M1201 298q0 57 -5.5 107t-21 100.5t-39.5 86t-64 58t-91 22.5q-6 -4 -33.5 -20.5t-42.5 -24.5t-40.5 -20t-49 -17t-46.5 -5t-46.5 5t-49 17t-40.5 20t-42.5 24.5t-33.5 20.5q-51 0 -91 -22.5t-64 -58t-39.5 -86t-21 -100.5t-5.5 -107q0 -73 42 -121.5t103 -48.5h576 +q61 0 103 48.5t42 121.5zM1028 892q0 108 -76.5 184t-183.5 76t-183.5 -76t-76.5 -184q0 -107 76.5 -183t183.5 -76t183.5 76t76.5 183zM1664 352v-192q0 -14 -9 -23t-23 -9h-96v-224q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v1472q0 66 47 113t113 47h1216 +q66 0 113 -47t47 -113v-224h96q14 0 23 -9t9 -23v-192q0 -14 -9 -23t-23 -9h-96v-128h96q14 0 23 -9t9 -23v-192q0 -14 -9 -23t-23 -9h-96v-128h96q14 0 23 -9t9 -23z" /> + <glyph glyph-name="uniF2BA" unicode="" horiz-adv-x="1664" +d="M1028 892q0 -107 -76.5 -183t-183.5 -76t-183.5 76t-76.5 183q0 108 76.5 184t183.5 76t183.5 -76t76.5 -184zM980 672q46 0 82.5 -17t60 -47.5t39.5 -67t24 -81t11.5 -82.5t3.5 -79q0 -67 -39.5 -118.5t-105.5 -51.5h-576q-66 0 -105.5 51.5t-39.5 118.5q0 48 4.5 93.5 +t18.5 98.5t36.5 91.5t63 64.5t93.5 26h5q7 -4 32 -19.5t35.5 -21t33 -17t37 -16t35 -9t39.5 -4.5t39.5 4.5t35 9t37 16t33 17t35.5 21t32 19.5zM1664 928q0 -13 -9.5 -22.5t-22.5 -9.5h-96v-128h96q13 0 22.5 -9.5t9.5 -22.5v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-96v-128h96 +q13 0 22.5 -9.5t9.5 -22.5v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-96v-224q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v1472q0 66 47 113t113 47h1216q66 0 113 -47t47 -113v-224h96q13 0 22.5 -9.5t9.5 -22.5v-192zM1408 -96v1472q0 13 -9.5 22.5t-22.5 9.5h-1216 +q-13 0 -22.5 -9.5t-9.5 -22.5v-1472q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5z" /> + <glyph glyph-name="uniF2BB" unicode="" horiz-adv-x="2048" +d="M1024 405q0 64 -9 117.5t-29.5 103t-60.5 78t-97 28.5q-6 -4 -30 -18t-37.5 -21.5t-35.5 -17.5t-43 -14.5t-42 -4.5t-42 4.5t-43 14.5t-35.5 17.5t-37.5 21.5t-30 18q-57 0 -97 -28.5t-60.5 -78t-29.5 -103t-9 -117.5t37 -106.5t91 -42.5h512q54 0 91 42.5t37 106.5z +M867 925q0 94 -66.5 160.5t-160.5 66.5t-160.5 -66.5t-66.5 -160.5t66.5 -160.5t160.5 -66.5t160.5 66.5t66.5 160.5zM1792 416v64q0 14 -9 23t-23 9h-576q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h576q14 0 23 9t9 23zM1792 676v56q0 15 -10.5 25.5t-25.5 10.5h-568 +q-15 0 -25.5 -10.5t-10.5 -25.5v-56q0 -15 10.5 -25.5t25.5 -10.5h568q15 0 25.5 10.5t10.5 25.5zM1792 928v64q0 14 -9 23t-23 9h-576q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h576q14 0 23 9t9 23zM2048 1248v-1216q0 -66 -47 -113t-113 -47h-352v96q0 14 -9 23t-23 9 +h-64q-14 0 -23 -9t-9 -23v-96h-768v96q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-96h-352q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1728q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2BC" unicode="" horiz-adv-x="2048" +d="M1024 405q0 -64 -37 -106.5t-91 -42.5h-512q-54 0 -91 42.5t-37 106.5t9 117.5t29.5 103t60.5 78t97 28.5q6 -4 30 -18t37.5 -21.5t35.5 -17.5t43 -14.5t42 -4.5t42 4.5t43 14.5t35.5 17.5t37.5 21.5t30 18q57 0 97 -28.5t60.5 -78t29.5 -103t9 -117.5zM867 925 +q0 -94 -66.5 -160.5t-160.5 -66.5t-160.5 66.5t-66.5 160.5t66.5 160.5t160.5 66.5t160.5 -66.5t66.5 -160.5zM1792 480v-64q0 -14 -9 -23t-23 -9h-576q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h576q14 0 23 -9t9 -23zM1792 732v-56q0 -15 -10.5 -25.5t-25.5 -10.5h-568 +q-15 0 -25.5 10.5t-10.5 25.5v56q0 15 10.5 25.5t25.5 10.5h568q15 0 25.5 -10.5t10.5 -25.5zM1792 992v-64q0 -14 -9 -23t-23 -9h-576q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h576q14 0 23 -9t9 -23zM1920 32v1216q0 13 -9.5 22.5t-22.5 9.5h-1728q-13 0 -22.5 -9.5 +t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h352v96q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-96h768v96q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-96h352q13 0 22.5 9.5t9.5 22.5zM2048 1248v-1216q0 -66 -47 -113t-113 -47h-1728q-66 0 -113 47t-47 113v1216q0 66 47 113 +t113 47h1728q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2BD" unicode="" horiz-adv-x="1792" +d="M1523 197q-22 155 -87.5 257.5t-184.5 118.5q-67 -74 -159.5 -115.5t-195.5 -41.5t-195.5 41.5t-159.5 115.5q-119 -16 -184.5 -118.5t-87.5 -257.5q106 -150 271 -237.5t356 -87.5t356 87.5t271 237.5zM1280 896q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5 +t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1792 640q0 -182 -71 -347.5t-190.5 -286t-285.5 -191.5t-349 -71q-182 0 -348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="uniF2BE" unicode="" horiz-adv-x="1792" +d="M896 1536q182 0 348 -71t286 -191t191 -286t71 -348q0 -181 -70.5 -347t-190.5 -286t-286 -191.5t-349 -71.5t-349 71t-285.5 191.5t-190.5 286t-71 347.5t71 348t191 286t286 191t348 71zM1515 185q149 205 149 455q0 156 -61 298t-164 245t-245 164t-298 61t-298 -61 +t-245 -164t-164 -245t-61 -298q0 -250 149 -455q66 327 306 327q131 -128 313 -128t313 128q240 0 306 -327zM1280 832q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5z" /> + <glyph glyph-name="uniF2C0" unicode="" +d="M1201 752q47 -14 89.5 -38t89 -73t79.5 -115.5t55 -172t22 -236.5q0 -154 -100 -263.5t-241 -109.5h-854q-141 0 -241 109.5t-100 263.5q0 131 22 236.5t55 172t79.5 115.5t89 73t89.5 38q-79 125 -79 272q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5 +t198.5 -40.5t163.5 -109.5t109.5 -163.5t40.5 -198.5q0 -147 -79 -272zM768 1408q-159 0 -271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5t-112.5 271.5t-271.5 112.5zM1195 -128q88 0 150.5 71.5t62.5 173.5q0 239 -78.5 377t-225.5 145 +q-145 -127 -336 -127t-336 127q-147 -7 -225.5 -145t-78.5 -377q0 -102 62.5 -173.5t150.5 -71.5h854z" /> + <glyph glyph-name="uniF2C1" unicode="" horiz-adv-x="1280" +d="M1024 278q0 -64 -37 -107t-91 -43h-512q-54 0 -91 43t-37 107t9 118t29.5 104t61 78.5t96.5 28.5q80 -75 188 -75t188 75q56 0 96.5 -28.5t61 -78.5t29.5 -104t9 -118zM870 797q0 -94 -67.5 -160.5t-162.5 -66.5t-162.5 66.5t-67.5 160.5t67.5 160.5t162.5 66.5 +t162.5 -66.5t67.5 -160.5zM1152 -96v1376h-1024v-1376q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1280 1376v-1472q0 -66 -47 -113t-113 -47h-960q-66 0 -113 47t-47 113v1472q0 66 47 113t113 47h352v-96q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v96h352 +q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2C2" unicode="" horiz-adv-x="2048" +d="M896 324q0 54 -7.5 100.5t-24.5 90t-51 68.5t-81 25q-64 -64 -156 -64t-156 64q-47 0 -81 -25t-51 -68.5t-24.5 -90t-7.5 -100.5q0 -55 31.5 -93.5t75.5 -38.5h426q44 0 75.5 38.5t31.5 93.5zM768 768q0 80 -56 136t-136 56t-136 -56t-56 -136t56 -136t136 -56t136 56 +t56 136zM1792 288v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1408 544v64q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1792 544v64q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23 +v-64q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1792 800v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM128 1152h1792v96q0 14 -9 23t-23 9h-1728q-14 0 -23 -9t-9 -23v-96zM2048 1248v-1216q0 -66 -47 -113t-113 -47h-1728 +q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1728q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2C3" unicode="" horiz-adv-x="2048" +d="M896 324q0 -55 -31.5 -93.5t-75.5 -38.5h-426q-44 0 -75.5 38.5t-31.5 93.5q0 54 7.5 100.5t24.5 90t51 68.5t81 25q64 -64 156 -64t156 64q47 0 81 -25t51 -68.5t24.5 -90t7.5 -100.5zM768 768q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136z +M1792 352v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704q14 0 23 -9t9 -23zM1408 608v-64q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h320q14 0 23 -9t9 -23zM1792 608v-64q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v64 +q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 864v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704q14 0 23 -9t9 -23zM1920 32v1120h-1792v-1120q0 -13 9.5 -22.5t22.5 -9.5h1728q13 0 22.5 9.5t9.5 22.5zM2048 1248v-1216q0 -66 -47 -113t-113 -47 +h-1728q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1728q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2C4" unicode="" horiz-adv-x="1792" +d="M1255 749q0 318 -105 474.5t-330 156.5q-222 0 -326 -157t-104 -474q0 -316 104 -471.5t326 -155.5q74 0 131 17q-22 43 -39 73t-44 65t-53.5 56.5t-63 36t-77.5 14.5q-46 0 -79 -16l-49 97q105 91 276 91q132 0 215.5 -54t150.5 -155q67 149 67 402zM1645 117h117 +q3 -27 -2 -67t-26.5 -95t-58 -100.5t-107 -78t-162.5 -32.5q-71 0 -130.5 19t-105.5 56t-79 78t-66 96q-97 -27 -205 -27q-150 0 -292.5 58t-253 158.5t-178 249t-67.5 317.5q0 170 67.5 319.5t178.5 250.5t253.5 159t291.5 58q121 0 238.5 -36t217 -106t176 -164.5 +t119.5 -219t43 -261.5q0 -190 -80.5 -347.5t-218.5 -264.5q47 -70 93.5 -106.5t104.5 -36.5q61 0 94 37.5t38 85.5z" /> + <glyph glyph-name="uniF2C5" unicode="" horiz-adv-x="2304" +d="M453 -101q0 -21 -16 -37.5t-37 -16.5q-1 0 -13 3q-63 15 -162 140q-225 284 -225 676q0 341 213 614q39 51 95 103.5t94 52.5q19 0 35 -13.5t16 -32.5q0 -27 -63 -90q-98 -102 -147 -184q-119 -199 -119 -449q0 -281 123 -491q50 -85 136 -173q2 -3 14.5 -16t19.5 -21 +t17 -20.5t14.5 -23.5t4.5 -21zM1796 33q0 -29 -17.5 -48.5t-46.5 -19.5h-1081q-26 0 -45 19t-19 45q0 29 17.5 48.5t46.5 19.5h1081q26 0 45 -19t19 -45zM1581 644q0 -134 -67 -233q-25 -38 -69.5 -78.5t-83.5 -60.5q-16 -10 -27 -10q-7 0 -15 6t-8 12q0 9 19 30t42 46 +t42 67.5t19 88.5q0 76 -35 130q-29 42 -46 42q-3 0 -3 -5q0 -12 7.5 -35.5t7.5 -36.5q0 -22 -21.5 -35t-44.5 -13q-66 0 -66 76q0 15 1.5 44t1.5 44q0 25 -10 46q-13 25 -42 53.5t-51 28.5q-5 0 -7 -0.5t-3.5 -2.5t-1.5 -6q0 -2 16 -26t16 -54q0 -37 -19 -68t-46 -54 +t-53.5 -46t-45.5 -54t-19 -68q0 -98 42 -160q29 -43 79 -63q16 -5 17 -10q1 -2 1 -5q0 -16 -18 -16q-6 0 -33 11q-119 43 -195 139.5t-76 218.5q0 55 24.5 115.5t60 115t70.5 108.5t59.5 113.5t24.5 111.5q0 53 -25 94q-29 48 -56 64q-19 9 -19 21q0 20 41 20q50 0 110 -29 +q41 -19 71 -44.5t49.5 -51t33.5 -62.5t22 -69t16 -80q0 -1 3 -17.5t4.5 -25t5.5 -25t9 -27t11 -21.5t14.5 -16.5t18.5 -5.5q23 0 37 14t14 37q0 25 -20 67t-20 52t10 10q27 0 93 -70q72 -76 102.5 -156t30.5 -186zM2304 615q0 -274 -138 -503q-19 -32 -48 -72t-68 -86.5 +t-81 -77t-74 -30.5q-16 0 -31 15.5t-15 31.5q0 15 29 50.5t68.5 77t48.5 52.5q183 230 183 531q0 131 -20.5 235t-72.5 211q-58 119 -163 228q-2 3 -13 13.5t-16.5 16.5t-15 17.5t-15 20t-9.5 18.5t-4 19q0 19 16 35.5t35 16.5q70 0 196 -169q98 -131 146 -273t60 -314 +q2 -42 2 -64z" /> + <glyph glyph-name="uniF2C6" unicode="" horiz-adv-x="1792" +d="M1189 229l147 693q9 44 -10.5 63t-51.5 7l-864 -333q-29 -11 -39.5 -25t-2.5 -26.5t32 -19.5l221 -69l513 323q21 14 32 6q7 -5 -4 -15l-415 -375v0v0l-16 -228q23 0 45 22l108 104l224 -165q64 -36 81 38zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71 +t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="uniF2C7" unicode="" horiz-adv-x="1024" +d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 60 35 110t93 71v907h128v-907q58 -21 93 -71t35 -110zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5 +t93.5 226.5zM896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192 +v128h192z" /> + <glyph glyph-name="uniF2C8" unicode="" horiz-adv-x="1024" +d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 60 35 110t93 71v651h128v-651q58 -21 93 -71t35 -110zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5 +t93.5 226.5zM896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192 +v128h192z" /> + <glyph glyph-name="uniF2C9" unicode="" horiz-adv-x="1024" +d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 60 35 110t93 71v395h128v-395q58 -21 93 -71t35 -110zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5 +t93.5 226.5zM896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192 +v128h192z" /> + <glyph glyph-name="uniF2CA" unicode="" horiz-adv-x="1024" +d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 60 35 110t93 71v139h128v-139q58 -21 93 -71t35 -110zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5 +t93.5 226.5zM896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192 +v128h192z" /> + <glyph glyph-name="uniF2CB" unicode="" horiz-adv-x="1024" +d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 79 56 135.5t136 56.5t136 -56.5t56 -135.5zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5t93.5 226.5z +M896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192v128h192z" /> + <glyph glyph-name="uniF2CC" unicode="" horiz-adv-x="1920" +d="M1433 1287q10 -10 10 -23t-10 -23l-626 -626q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l44 44q-72 91 -81.5 207t46.5 215q-74 71 -176 71q-106 0 -181 -75t-75 -181v-1280h-256v1280q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5q106 0 201 -41 +t166 -115q94 39 197 24.5t185 -79.5l44 44q10 10 23 10t23 -10zM1344 1024q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1600 896q-26 0 -45 19t-19 45t19 45t45 19t45 -19t19 -45t-19 -45t-45 -19zM1856 1024q26 0 45 -19t19 -45t-19 -45t-45 -19 +t-45 19t-19 45t19 45t45 19zM1216 896q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1408 832q0 26 19 45t45 19t45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45zM1728 896q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1088 768 +q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1344 640q-26 0 -45 19t-19 45t19 45t45 19t45 -19t19 -45t-19 -45t-45 -19zM1600 768q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1216 512q-26 0 -45 19t-19 45t19 45t45 19t45 -19 +t19 -45t-19 -45t-45 -19zM1472 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1088 512q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1344 512q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1216 384 +q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1088 256q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19z" /> + <glyph glyph-name="uniF2CD" unicode="" horiz-adv-x="1792" +d="M1664 448v-192q0 -169 -128 -286v-194q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v118q-63 -22 -128 -22h-768q-65 0 -128 22v-110q0 -17 -9.5 -28.5t-22.5 -11.5h-64q-13 0 -22.5 11.5t-9.5 28.5v186q-128 117 -128 286v192h1536zM704 864q0 -14 -9 -23t-23 -9t-23 9 +t-9 23t9 23t23 9t23 -9t9 -23zM768 928q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM704 992q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM832 992q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM768 1056q0 -14 -9 -23t-23 -9t-23 9 +t-9 23t9 23t23 9t23 -9t9 -23zM704 1120q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM1792 608v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v640q0 106 75 181t181 75q108 0 184 -78q46 19 98 12t93 -39l22 22q11 11 22 0l42 -42 +q11 -11 0 -22l-314 -314q-11 -11 -22 0l-42 42q-11 11 0 22l22 22q-36 46 -40.5 104t23.5 108q-37 35 -88 35q-53 0 -90.5 -37.5t-37.5 -90.5v-640h1504q14 0 23 -9t9 -23zM896 1056q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM832 1120q0 -14 -9 -23t-23 -9 +t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM768 1184q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM960 1120q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM896 1184q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM832 1248q0 -14 -9 -23 +t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM1024 1184q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM960 1248q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM1088 1248q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23z" /> + <glyph glyph-name="uniF2CE" unicode="" +d="M994 344q0 -86 -17 -197q-31 -215 -55 -313q-22 -90 -152 -90t-152 90q-24 98 -55 313q-17 110 -17 197q0 168 224 168t224 -168zM1536 768q0 -240 -134 -434t-350 -280q-8 -3 -15 3t-6 15q7 48 10 66q4 32 6 47q1 9 9 12q159 81 255.5 234t96.5 337q0 180 -91 330.5 +t-247 234.5t-337 74q-124 -7 -237 -61t-193.5 -140.5t-128 -202t-46.5 -240.5q1 -184 99 -336.5t257 -231.5q7 -3 9 -12q3 -21 6 -45q1 -9 5 -32.5t6 -35.5q1 -9 -6.5 -15t-15.5 -2q-148 58 -261 169.5t-173.5 264t-52.5 319.5q7 143 66 273.5t154.5 227t225 157.5t272.5 70 +q164 10 315.5 -46.5t261 -160.5t175 -250.5t65.5 -308.5zM994 800q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5zM1282 768q0 -122 -53.5 -228.5t-146.5 -177.5q-8 -6 -16 -2t-10 14q-6 52 -29 92q-7 10 3 20 +q58 54 91 127t33 155q0 111 -58.5 204t-157.5 141.5t-212 36.5q-133 -15 -229 -113t-109 -231q-10 -92 23.5 -176t98.5 -144q10 -10 3 -20q-24 -41 -29 -93q-2 -9 -10 -13t-16 2q-95 74 -148.5 183t-51.5 234q3 131 69 244t177 181.5t241 74.5q144 7 268 -60t196.5 -187.5 +t72.5 -263.5z" /> + <glyph glyph-name="uniF2D0" unicode="" horiz-adv-x="1792" +d="M256 128h1280v768h-1280v-768zM1792 1248v-1216q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2D1" unicode="" horiz-adv-x="1792" +d="M1792 224v-192q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2D2" unicode="" horiz-adv-x="2048" +d="M256 0h768v512h-768v-512zM1280 512h512v768h-768v-256h96q66 0 113 -47t47 -113v-352zM2048 1376v-960q0 -66 -47 -113t-113 -47h-608v-352q0 -66 -47 -113t-113 -47h-960q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h608v352q0 66 47 113t113 47h960q66 0 113 -47 +t47 -113z" /> + <glyph glyph-name="uniF2D3" unicode="" horiz-adv-x="1792" +d="M1175 215l146 146q10 10 10 23t-10 23l-233 233l233 233q10 10 10 23t-10 23l-146 146q-10 10 -23 10t-23 -10l-233 -233l-233 233q-10 10 -23 10t-23 -10l-146 -146q-10 -10 -10 -23t10 -23l233 -233l-233 -233q-10 -10 -10 -23t10 -23l146 -146q10 -10 23 -10t23 10 +l233 233l233 -233q10 -10 23 -10t23 10zM1792 1248v-1216q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2D4" unicode="" horiz-adv-x="1792" +d="M1257 425l-146 -146q-10 -10 -23 -10t-23 10l-169 169l-169 -169q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l169 169l-169 169q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l169 -169l169 169q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23 +l-169 -169l169 -169q10 -10 10 -23t-10 -23zM256 128h1280v1024h-1280v-1024zM1792 1248v-1216q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2D5" unicode="" horiz-adv-x="1792" +d="M1070 358l306 564h-654l-306 -564h654zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="uniF2D6" unicode="" horiz-adv-x="1794" +d="M1291 1060q-15 17 -35 8.5t-26 -28.5t5 -38q14 -17 40 -14.5t34 20.5t-18 52zM895 814q-8 -8 -19.5 -8t-18.5 8q-8 8 -8 19t8 18q7 8 18.5 8t19.5 -8q7 -7 7 -18t-7 -19zM1060 740l-35 -35q-12 -13 -29.5 -13t-30.5 13l-38 38q-12 13 -12 30t12 30l35 35q12 12 29.5 12 +t30.5 -12l38 -39q12 -12 12 -29.5t-12 -29.5zM951 870q-7 -8 -18.5 -8t-19.5 8q-7 8 -7 19t7 19q8 8 19 8t19 -8t8 -19t-8 -19zM1354 968q-34 -64 -107.5 -85.5t-127.5 16.5q-38 28 -61 66.5t-21 87.5t39 92t75.5 53t70.5 -5t70 -51q2 -2 13 -12.5t14.5 -13.5t13 -13.5 +t12.5 -15.5t10 -15.5t8.5 -18t4 -18.5t1 -21t-5 -22t-9.5 -24zM1555 486q3 20 -8.5 34.5t-27.5 21.5t-33 17t-23 20q-40 71 -84 98.5t-113 11.5q19 13 40 18.5t33 4.5l12 -1q2 45 -34 90q6 20 6.5 40.5t-2.5 30.5l-3 10q43 24 71 65t34 91q10 84 -43 150.5t-137 76.5 +q-60 7 -114 -18.5t-82 -74.5q-30 -51 -33.5 -101t14.5 -87t43.5 -64t56.5 -42q-45 4 -88 36t-57 88q-28 108 32 222q-16 21 -29 32q-50 0 -89 -19q19 24 42 37t36 14l13 1q0 50 -13 78q-10 21 -32.5 28.5t-47 -3.5t-37.5 -40q2 4 4 7q-7 -28 -6.5 -75.5t19 -117t48.5 -122.5 +q-25 -14 -47 -36q-35 -16 -85.5 -70.5t-84.5 -101.5l-33 -46q-90 -34 -181 -125.5t-75 -162.5q1 -16 11 -27q-15 -12 -30 -30q-21 -25 -21 -54t21.5 -40t63.5 6q41 19 77 49.5t55 60.5q-2 2 -6.5 5t-20.5 7.5t-33 3.5q23 5 51 12.5t40 10t27.5 6t26 4t23.5 0.5q14 -7 22 34 +q7 37 7 90q0 102 -40 150q106 -103 101 -219q-1 -29 -15 -50t-27 -27l-13 -6q-4 -7 -19 -32t-26 -45.5t-26.5 -52t-25 -61t-17 -63t-6.5 -66.5t10 -63q-35 54 -37 80q-22 -24 -34.5 -39t-33.5 -42t-30.5 -46t-16.5 -41t-0.5 -38t25.5 -27q45 -25 144 64t190.5 221.5 +t122.5 228.5q86 52 145 115.5t86 119.5q47 -93 154 -178q104 -83 167 -80q39 2 46 43zM1794 640q0 -182 -71 -348t-191 -286t-286.5 -191t-348.5 -71t-348.5 71t-286.5 191t-191 286t-71 348t71 348t191 286t286.5 191t348.5 71t348.5 -71t286.5 -191t191 -286t71 -348z" /> + <glyph glyph-name="uniF2D7" unicode="" +d="M518 1353v-655q103 -1 191.5 1.5t125.5 5.5l37 3q68 2 90.5 24.5t39.5 94.5l33 142h103l-14 -322l7 -319h-103l-29 127q-15 68 -45 93t-84 26q-87 8 -352 8v-556q0 -78 43.5 -115.5t133.5 -37.5h357q35 0 59.5 2t55 7.5t54 18t48.5 32t46 50.5t39 73l93 216h89 +q-6 -37 -31.5 -252t-30.5 -276q-146 5 -263.5 8t-162.5 4h-44h-628l-376 -12v102l127 25q67 13 91.5 37t25.5 79l8 643q3 402 -8 645q-2 61 -25.5 84t-91.5 36l-127 24v102l376 -12h702q139 0 374 27q-6 -68 -14 -194.5t-12 -219.5l-5 -92h-93l-32 124q-31 121 -74 179.5 +t-113 58.5h-548q-28 0 -35.5 -8.5t-7.5 -30.5z" /> + <glyph glyph-name="uniF2D8" unicode="" +d="M922 739v-182q0 -4 0.5 -15t0 -15l-1.5 -12t-3.5 -11.5t-6.5 -7.5t-11 -5.5t-16 -1.5v309q9 0 16 -1t11 -5t6.5 -5.5t3.5 -9.5t1 -10.5v-13.5v-14zM1238 643v-121q0 -1 0.5 -12.5t0 -15.5t-2.5 -11.5t-7.5 -10.5t-13.5 -3q-9 0 -14 9q-4 10 -4 165v7v8.5v9t1.5 8.5l3.5 7 +t5 5.5t8 1.5q6 0 10 -1.5t6.5 -4.5t4 -6t2 -8.5t0.5 -8v-9.5v-9zM180 407h122v472h-122v-472zM614 407h106v472h-159l-28 -221q-20 148 -32 221h-158v-472h107v312l45 -312h76l43 319v-319zM1039 712q0 67 -5 90q-3 16 -11 28.5t-17 20.5t-25 14t-26.5 8.5t-31 4t-29 1.5 +h-29.5h-12h-91v-472h56q169 -1 197 24.5t25 180.5q-1 62 -1 100zM1356 515v133q0 29 -2 45t-9.5 33.5t-24.5 25t-46 7.5q-46 0 -77 -34v154h-117v-472h110l7 30q30 -36 77 -36q50 0 66 30.5t16 83.5zM1536 1248v-1216q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113 +v1216q0 66 47 113t113 47h1216q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2D9" unicode="" horiz-adv-x="2176" +d="M1143 -197q-6 1 -11 4q-13 8 -36 23t-86 65t-116.5 104.5t-112 140t-89.5 172.5q-17 3 -175 37q66 -213 235 -362t391 -184zM502 409l168 -28q-25 76 -41 167.5t-19 145.5l-4 53q-84 -82 -121 -224q5 -65 17 -114zM612 1018q-43 -64 -77 -148q44 46 74 68zM2049 584 +q0 161 -62 307t-167.5 252t-250.5 168.5t-304 62.5q-147 0 -281 -52.5t-240 -148.5q-30 -58 -45 -160q60 51 143 83.5t158.5 43t143 13.5t108.5 -1l40 -3q33 -1 53 -15.5t24.5 -33t6.5 -37t-1 -28.5q-126 11 -227.5 0.5t-183 -43.5t-142.5 -71.5t-131 -98.5 +q4 -36 11.5 -92.5t35.5 -178t62 -179.5q123 -6 247.5 14.5t214.5 53.5t162.5 67t109.5 59l37 24q22 16 39.5 20.5t30.5 -5t17 -34.5q14 -97 -39 -121q-208 -97 -467 -134q-135 -20 -317 -16q41 -96 110 -176.5t137 -127t130.5 -79t101.5 -43.5l39 -12q143 -23 263 15 +q195 99 314 289t119 418zM2123 621q-14 -135 -40 -212q-70 -208 -181.5 -346.5t-318.5 -253.5q-48 -33 -82 -44q-72 -26 -163 -16q-36 -3 -73 -3q-283 0 -504.5 173t-295.5 442q-1 0 -4 0.5t-5 0.5q-6 -50 2.5 -112.5t26 -115t36 -98t31.5 -71.5l14 -26q8 -12 54 -82 +q-71 38 -124.5 106.5t-78.5 140t-39.5 137t-17.5 107.5l-2 42q-5 2 -33.5 12.5t-48.5 18t-53 20.5t-57.5 25t-50 25.5t-42.5 27t-25 25.5q19 -10 50.5 -25.5t113 -45.5t145.5 -38l2 32q11 149 94 290q41 202 176 365q28 115 81 214q15 28 32 45t49 32q158 74 303.5 104 +t302 11t306.5 -97q220 -115 333 -336t87 -474z" /> + <glyph glyph-name="uniF2DA" unicode="" horiz-adv-x="1792" +d="M1341 752q29 44 -6.5 129.5t-121.5 142.5q-58 39 -125.5 53.5t-118 4.5t-68.5 -37q-12 -23 -4.5 -28t42.5 -10q23 -3 38.5 -5t44.5 -9.5t56 -17.5q36 -13 67.5 -31.5t53 -37t40 -38.5t30.5 -38t22 -34.5t16.5 -28.5t12 -18.5t10.5 -6t11 9.5zM1704 178 +q-52 -127 -148.5 -220t-214.5 -141.5t-253 -60.5t-266 13.5t-251 91t-210 161.5t-141.5 235.5t-46.5 303.5q1 41 8.5 84.5t12.5 64t24 80.5t23 73q-51 -208 1 -397t173 -318t291 -206t346 -83t349 74.5t289 244.5q20 27 18 14q0 -4 -4 -14zM1465 627q0 -104 -40.5 -199 +t-108.5 -164t-162 -109.5t-198 -40.5t-198 40.5t-162 109.5t-108.5 164t-40.5 199t40.5 199t108.5 164t162 109.5t198 40.5t198 -40.5t162 -109.5t108.5 -164t40.5 -199zM1752 915q-65 147 -180.5 251t-253 153.5t-292 53.5t-301 -36.5t-275.5 -129t-220 -211.5t-131 -297 +t-10 -373q-49 161 -51.5 311.5t35.5 272.5t109 227t165.5 180.5t207 126t232 71t242.5 9t236 -54t216 -124.5t178 -197q33 -50 62 -121t31 -112zM1690 573q12 244 -136.5 416t-396.5 240q-8 0 -10 5t24 8q125 -4 230 -50t173 -120t116 -168.5t58.5 -199t-1 -208 +t-61.5 -197.5t-122.5 -167t-185 -117.5t-248.5 -46.5q108 30 201.5 80t174 123t129.5 176.5t55 225.5z" /> + <glyph glyph-name="uniF2DB" unicode="" +d="M192 256v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16q0 16 16 16h112zM192 512v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16q0 16 16 16h112zM192 768v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16 +q0 16 16 16h112zM192 1024v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16q0 16 16 16h112zM192 1280v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16q0 16 16 16h112zM1280 1440v-1472q0 -40 -28 -68t-68 -28h-832q-40 0 -68 28 +t-28 68v1472q0 40 28 68t68 28h832q40 0 68 -28t28 -68zM1536 208v-32q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16h48q16 0 16 -16zM1536 464v-32q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16h48q16 0 16 -16zM1536 720v-32 +q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16h48q16 0 16 -16zM1536 976v-32q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16h48q16 0 16 -16zM1536 1232v-32q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16 +h48q16 0 16 -16z" /> + <glyph glyph-name="uniF2DC" unicode="" horiz-adv-x="1664" +d="M1566 419l-167 -33l186 -107q23 -13 29.5 -38.5t-6.5 -48.5q-14 -23 -39 -29.5t-48 6.5l-186 106l55 -160q13 -38 -12 -63.5t-60.5 -20.5t-48.5 42l-102 300l-271 156v-313l208 -238q16 -18 17 -39t-11 -36.5t-28.5 -25t-37 -5.5t-36.5 22l-112 128v-214q0 -26 -19 -45 +t-45 -19t-45 19t-19 45v214l-112 -128q-16 -18 -36.5 -22t-37 5.5t-28.5 25t-11 36.5t17 39l208 238v313l-271 -156l-102 -300q-13 -37 -48.5 -42t-60.5 20.5t-12 63.5l55 160l-186 -106q-23 -13 -48 -6.5t-39 29.5q-13 23 -6.5 48.5t29.5 38.5l186 107l-167 33 +q-29 6 -42 29t-8.5 46.5t25.5 40t50 10.5l310 -62l271 157l-271 157l-310 -62q-4 -1 -13 -1q-27 0 -44 18t-19 40t11 43t40 26l167 33l-186 107q-23 13 -29.5 38.5t6.5 48.5t39 30t48 -7l186 -106l-55 160q-13 38 12 63.5t60.5 20.5t48.5 -42l102 -300l271 -156v313 +l-208 238q-16 18 -17 39t11 36.5t28.5 25t37 5.5t36.5 -22l112 -128v214q0 26 19 45t45 19t45 -19t19 -45v-214l112 128q16 18 36.5 22t37 -5.5t28.5 -25t11 -36.5t-17 -39l-208 -238v-313l271 156l102 300q13 37 48.5 42t60.5 -20.5t12 -63.5l-55 -160l186 106 +q23 13 48 6.5t39 -29.5q13 -23 6.5 -48.5t-29.5 -38.5l-186 -107l167 -33q27 -5 40 -26t11 -43t-19 -40t-44 -18q-9 0 -13 1l-310 62l-271 -157l271 -157l310 62q29 6 50 -10.5t25.5 -40t-8.5 -46.5t-42 -29z" /> + <glyph glyph-name="uniF2DD" unicode="" horiz-adv-x="1792" +d="M1473 607q7 118 -33 226.5t-113 189t-177 131t-221 57.5q-116 7 -225.5 -32t-192 -110.5t-135 -175t-59.5 -220.5q-7 -118 33 -226.5t113 -189t177.5 -131t221.5 -57.5q155 -9 293 59t224 195.5t94 283.5zM1792 1536l-349 -348q120 -117 180.5 -272t50.5 -321 +q-11 -183 -102 -339t-241 -255.5t-332 -124.5l-999 -132l347 347q-120 116 -180.5 271.5t-50.5 321.5q11 184 102 340t241.5 255.5t332.5 124.5q167 22 500 66t500 66z" /> + <glyph glyph-name="uniF2DE" unicode="" horiz-adv-x="1792" +d="M948 508l163 -329h-51l-175 350l-171 -350h-49l179 374l-78 33l21 49l240 -102l-21 -50zM563 1100l304 -130l-130 -304l-304 130zM907 915l240 -103l-103 -239l-239 102zM1188 765l191 -81l-82 -190l-190 81zM1680 640q0 159 -62 304t-167.5 250.5t-250.5 167.5t-304 62 +t-304 -62t-250.5 -167.5t-167.5 -250.5t-62 -304t62 -304t167.5 -250.5t250.5 -167.5t304 -62t304 62t250.5 167.5t167.5 250.5t62 304zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71 +t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="uniF2E0" unicode="" horiz-adv-x="1920" +d="M1334 302q-4 24 -27.5 34t-49.5 10.5t-48.5 12.5t-25.5 38q-5 47 33 139.5t75 181t32 127.5q-14 101 -117 103q-45 1 -75 -16l-3 -2l-5 -2.5t-4.5 -2t-5 -2t-5 -0.5t-6 1.5t-6 3.5t-6.5 5q-3 2 -9 8.5t-9 9t-8.5 7.5t-9.5 7.5t-9.5 5.5t-11 4.5t-11.5 2.5q-30 5 -48 -3 +t-45 -31q-1 -1 -9 -8.5t-12.5 -11t-15 -10t-16.5 -5.5t-17 3q-54 27 -84 40q-41 18 -94 -5t-76 -65q-16 -28 -41 -98.5t-43.5 -132.5t-40 -134t-21.5 -73q-22 -69 18.5 -119t110.5 -46q30 2 50.5 15t38.5 46q7 13 79 199.5t77 194.5q6 11 21.5 18t29.5 0q27 -15 21 -53 +q-2 -18 -51 -139.5t-50 -132.5q-6 -38 19.5 -56.5t60.5 -7t55 49.5q4 8 45.5 92t81.5 163.5t46 88.5q20 29 41 28q29 0 25 -38q-2 -16 -65.5 -147.5t-70.5 -159.5q-12 -53 13 -103t74 -74q17 -9 51 -15.5t71.5 -8t62.5 14t20 48.5zM383 86q3 -15 -5 -27.5t-23 -15.5 +q-14 -3 -26.5 5t-15.5 23q-3 14 5 27t22 16t27 -5t16 -23zM953 -177q12 -17 8.5 -37.5t-20.5 -32.5t-37.5 -8t-32.5 21q-11 17 -7.5 37.5t20.5 32.5t37.5 8t31.5 -21zM177 635q-18 -27 -49.5 -33t-57.5 13q-26 18 -32 50t12 58q18 27 49.5 33t57.5 -12q26 -19 32 -50.5 +t-12 -58.5zM1467 -42q19 -28 13 -61.5t-34 -52.5t-60.5 -13t-51.5 34t-13 61t33 53q28 19 60.5 13t52.5 -34zM1579 562q69 -113 42.5 -244.5t-134.5 -207.5q-90 -63 -199 -60q-20 -80 -84.5 -127t-143.5 -44.5t-140 57.5q-12 -9 -13 -10q-103 -71 -225 -48.5t-193 126.5 +q-50 73 -53 164q-83 14 -142.5 70.5t-80.5 128t-2 152t81 138.5q-36 60 -38 128t24.5 125t79.5 98.5t121 50.5q32 85 99 148t146.5 91.5t168 17t159.5 -66.5q72 21 140 17.5t128.5 -36t104.5 -80t67.5 -115t17.5 -140.5q52 -16 87 -57t45.5 -89t-5.5 -99.5t-58 -87.5z +M455 1222q14 -20 9.5 -44.5t-24.5 -38.5q-19 -14 -43.5 -9.5t-37.5 24.5q-14 20 -9.5 44.5t24.5 38.5q19 14 43.5 9.5t37.5 -24.5zM614 1503q4 -16 -5 -30.5t-26 -18.5t-31 5.5t-18 26.5q-3 17 6.5 31t25.5 18q17 4 31 -5.5t17 -26.5zM1800 555q4 -20 -6.5 -37t-30.5 -21 +q-19 -4 -36 6.5t-21 30.5t6.5 37t30.5 22q20 4 36.5 -7.5t20.5 -30.5zM1136 1448q16 -27 8.5 -58.5t-35.5 -47.5q-27 -16 -57.5 -8.5t-46.5 34.5q-16 28 -8.5 59t34.5 48t58 9t47 -36zM1882 792q4 -15 -4 -27.5t-23 -16.5q-15 -3 -27.5 5.5t-15.5 22.5q-3 15 5 28t23 16 +q14 3 26.5 -5t15.5 -23zM1691 1033q15 -22 10.5 -49t-26.5 -43q-22 -15 -49 -10t-42 27t-10 49t27 43t48.5 11t41.5 -28z" /> + <glyph glyph-name="uniF2E1" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2E2" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2E3" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2E4" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2E5" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2E6" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2E7" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="_698" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2E9" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2EA" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2EB" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2EC" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2ED" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2EE" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="lessequal" unicode="" horiz-adv-x="1792" + /> + </font> +</defs></svg> diff --git a/refs/pull/405/merge/_static/css/fonts/fontawesome-webfont.ttf b/refs/pull/405/merge/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 00000000..35acda2f Binary files /dev/null and b/refs/pull/405/merge/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/refs/pull/405/merge/_static/css/fonts/fontawesome-webfont.woff b/refs/pull/405/merge/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 00000000..400014a4 Binary files /dev/null and b/refs/pull/405/merge/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/refs/pull/405/merge/_static/css/fonts/fontawesome-webfont.woff2 b/refs/pull/405/merge/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 00000000..4d13fc60 Binary files /dev/null and b/refs/pull/405/merge/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/refs/pull/405/merge/_static/css/fonts/lato-bold-italic.woff b/refs/pull/405/merge/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 00000000..88ad05b9 Binary files /dev/null and b/refs/pull/405/merge/_static/css/fonts/lato-bold-italic.woff differ diff --git a/refs/pull/405/merge/_static/css/fonts/lato-bold-italic.woff2 b/refs/pull/405/merge/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 00000000..c4e3d804 Binary files /dev/null and b/refs/pull/405/merge/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/refs/pull/405/merge/_static/css/fonts/lato-bold.woff b/refs/pull/405/merge/_static/css/fonts/lato-bold.woff new file mode 100644 index 00000000..c6dff51f Binary files /dev/null and b/refs/pull/405/merge/_static/css/fonts/lato-bold.woff differ diff --git a/refs/pull/405/merge/_static/css/fonts/lato-bold.woff2 b/refs/pull/405/merge/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 00000000..bb195043 Binary files /dev/null and b/refs/pull/405/merge/_static/css/fonts/lato-bold.woff2 differ diff --git a/refs/pull/405/merge/_static/css/fonts/lato-normal-italic.woff b/refs/pull/405/merge/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 00000000..76114bc0 Binary files /dev/null and b/refs/pull/405/merge/_static/css/fonts/lato-normal-italic.woff differ diff --git a/refs/pull/405/merge/_static/css/fonts/lato-normal-italic.woff2 b/refs/pull/405/merge/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 00000000..3404f37e Binary files /dev/null and b/refs/pull/405/merge/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/refs/pull/405/merge/_static/css/fonts/lato-normal.woff b/refs/pull/405/merge/_static/css/fonts/lato-normal.woff new file mode 100644 index 00000000..ae1307ff Binary files /dev/null and b/refs/pull/405/merge/_static/css/fonts/lato-normal.woff differ diff --git a/refs/pull/405/merge/_static/css/fonts/lato-normal.woff2 b/refs/pull/405/merge/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 00000000..3bf98433 Binary files /dev/null and b/refs/pull/405/merge/_static/css/fonts/lato-normal.woff2 differ diff --git a/refs/pull/405/merge/_static/css/theme.css b/refs/pull/405/merge/_static/css/theme.css new file mode 100644 index 00000000..19a446a0 --- /dev/null +++ b/refs/pull/405/merge/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/refs/pull/405/merge/_static/doctools.js b/refs/pull/405/merge/_static/doctools.js new file mode 100644 index 00000000..0c15c009 --- /dev/null +++ b/refs/pull/405/merge/_static/doctools.js @@ -0,0 +1,311 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var bbox = span.getBBox(); + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + var parentOfText = node.parentNode.parentNode; + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('<a class="headerlink">\u00B6</a>'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('<a class="headerlink">\u00B6</a>'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('<p class="highlight-link"><a href="javascript:Documentation.' + + 'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keyup(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box or textarea + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); \ No newline at end of file diff --git a/refs/pull/405/merge/_static/down-pressed.png b/refs/pull/405/merge/_static/down-pressed.png new file mode 100644 index 00000000..5756c8ca Binary files /dev/null and b/refs/pull/405/merge/_static/down-pressed.png differ diff --git a/refs/pull/405/merge/_static/down.png b/refs/pull/405/merge/_static/down.png new file mode 100644 index 00000000..1b3bdad2 Binary files /dev/null and b/refs/pull/405/merge/_static/down.png differ diff --git a/refs/pull/405/merge/_static/file.png b/refs/pull/405/merge/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/refs/pull/405/merge/_static/file.png differ diff --git a/refs/pull/405/merge/_static/fonts/droidsansmono-webfont.eot b/refs/pull/405/merge/_static/fonts/droidsansmono-webfont.eot new file mode 100644 index 00000000..0a22d0cf Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/droidsansmono-webfont.eot differ diff --git a/refs/pull/405/merge/_static/fonts/droidsansmono-webfont.svg b/refs/pull/405/merge/_static/fonts/droidsansmono-webfont.svg new file mode 100644 index 00000000..03cbdefb --- /dev/null +++ b/refs/pull/405/merge/_static/fonts/droidsansmono-webfont.svg @@ -0,0 +1,243 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata></metadata> +<defs> +<font id="DroidSansMonoRegular" horiz-adv-x="1229" > +<font-face units-per-em="2048" ascent="1638" descent="-410" /> +<missing-glyph horiz-adv-x="500" /> +<glyph horiz-adv-x="2048" /> +<glyph horiz-adv-x="2048" /> +<glyph unicode=" " /> +<glyph unicode="!" d="M487 111q0 139 127 139t127 -139q0 -140 -127 -140t-127 140zM504 1462h223l-51 -1048h-121z" /> +<glyph unicode=""" d="M285 1462h237l-41 -528h-155zM707 1462h237l-41 -528h-155z" /> +<glyph unicode="#" d="M45 428v137h244l65 328h-233v137h258l82 432h147l-82 -432h293l84 432h144l-84 -432h221v-137h-248l-64 -328h240v-137h-266l-82 -428h-148l84 428h-290l-82 -428h-144l78 428h-217zM436 565h291l64 328h-291z" /> +<glyph unicode="$" d="M182 172v172q196 -92 365 -92v434q-193 64 -270.5 145.5t-77.5 219.5q0 131 92 217t256 106v180h137v-176q187 -9 336 -78l-66 -145q-140 62 -270 72v-422q199 -68 279.5 -148.5t80.5 -210.5q0 -280 -360 -335v-230h-137v221q-228 0 -365 70zM375 1049q0 -78 40.5 -121 t131.5 -74v369q-172 -29 -172 -174zM684 262q184 28 184 184q0 127 -184 189v-373z" /> +<glyph unicode="%" d="M0 1133q0 164 79 255t216 91q129 0 210 -93t81 -253q0 -162 -78.5 -255.5t-216.5 -93.5q-131 0 -211 94.5t-80 254.5zM152 1133q0 -230 141 -230q139 0 139 230q0 225 -139 225q-141 0 -141 -225zM170 0l729 1462h158l-729 -1462h-158zM643 330q0 164 79 255t216 91 q129 0 210 -93t81 -253q0 -161 -78.5 -254.5t-216.5 -93.5q-130 0 -210.5 94.5t-80.5 253.5zM795 330q0 -230 141 -230q139 0 139 230q0 225 -139 225q-141 0 -141 -225z" /> +<glyph unicode="&" d="M61 381q0 131 63.5 228.5t235.5 199.5q-163 192 -163 356q0 148 95.5 234t274.5 86q168 0 260.5 -85.5t92.5 -234.5q0 -203 -318 -389l281 -348q71 121 104 266h184q-53 -234 -178 -403l234 -291h-217l-131 166q-174 -186 -412 -186q-189 0 -297.5 107t-108.5 294z M252 387q0 -105 67 -175.5t160 -70.5q160 0 299 146l-323 401q-203 -123 -203 -301zM375 1165q0 -118 133 -268q134 79 183.5 138.5t49.5 133.5t-49.5 120t-130.5 46q-87 0 -136.5 -44.5t-49.5 -125.5z" /> +<glyph unicode="'" d="M496 1462h237l-41 -528h-155z" /> +<glyph unicode="(" d="M295 567q0 532 444 895h193q-449 -376 -449 -893q0 -521 447 -893h-191q-444 353 -444 891z" /> +<glyph unicode=")" d="M297 1462h192q445 -361 445 -895q0 -540 -445 -891h-190q446 371 446 893q0 518 -448 893z" /> +<glyph unicode="*" d="M133 1081l29 193l391 -111l-43 393h205l-43 -393l397 111l27 -193l-379 -28l246 -326l-179 -96l-176 358l-157 -358l-185 96l242 326z" /> +<glyph unicode="+" d="M152 647v150h387v389h149v-389h387v-150h-387v-385h-149v385h-387z" /> +<glyph unicode="," d="M440 -289q76 323 111 551h219l16 -24q-57 -224 -194 -527h-152z" /> +<glyph unicode="-" d="M285 465v168h659v-168h-659z" /> +<glyph unicode="." d="M463 135q0 166 151 166q152 0 152 -166t-152 -166q-151 0 -151 166z" /> +<glyph unicode="/" d="M211 0l627 1462h178l-627 -1462h-178z" /> +<glyph unicode="0" d="M147 733q0 752 465 752q232 0 350.5 -193.5t118.5 -558.5q0 -753 -469 -753q-229 0 -347 193.5t-118 559.5zM332 733q0 -318 67.5 -458t212.5 -140q147 0 216 140.5t69 457.5q0 315 -69 455.5t-216 140.5q-145 0 -212.5 -139.5t-67.5 -456.5z" /> +<glyph unicode="1" d="M225 1163l383 299h150v-1462h-176v913q0 122 8 361q-39 -43 -121 -113l-147 -121z" /> +<glyph unicode="2" d="M158 0v156l350 381q195 213 257 317.5t62 230.5q0 113 -63.5 178.5t-171.5 65.5q-160 0 -318 -137l-102 119q192 172 422 172q194 0 306 -106t112 -285q0 -119 -59 -244t-291 -375l-281 -299v-8h688v-166h-911z" /> +<glyph unicode="3" d="M131 59v170q184 -96 383 -96q354 0 354 289q0 258 -381 258h-133v151h133q160 0 248 76t88 201q0 102 -68 161.5t-182 59.5q-178 0 -344 -121l-92 125q187 150 436 150q206 0 321.5 -99t115.5 -264q0 -138 -82 -231t-234 -119v-6q361 -47 361 -348q0 -203 -138 -319.5 t-399 -116.5q-242 0 -387 79z" /> +<glyph unicode="4" d="M61 328v159l664 983h188v-976h213v-166h-213v-328h-176v328h-676zM240 494h497v356q0 176 13 432h-9q-36 -102 -90 -180z" /> +<glyph unicode="5" d="M172 59v172q144 -96 360 -96q336 0 336 314q0 294 -344 294q-89 0 -231 -26l-90 57l55 688h690v-166h-532l-39 -419q107 20 209 20q210 0 339.5 -114.5t129.5 -313.5q0 -234 -138 -361.5t-389 -127.5q-224 0 -356 79z" /> +<glyph unicode="6" d="M154 625q0 858 639 858q104 0 172 -19v-155q-71 24 -166 24q-224 0 -336.5 -141t-122.5 -447h12q95 170 307 170q195 0 305.5 -119t110.5 -325q0 -228 -120.5 -359.5t-323.5 -131.5q-218 0 -347.5 168.5t-129.5 476.5zM336 506q0 -152 81 -262.5t212 -110.5 q127 0 198.5 88t71.5 250q0 145 -68.5 223t-195.5 78t-213 -81t-86 -185z" /> +<glyph unicode="7" d="M143 1296v166h940v-145l-555 -1317h-194l563 1296h-754z" /> +<glyph unicode="8" d="M156 373q0 257 282 393q-235 146 -235 369q0 161 116.5 255.5t294.5 94.5q184 0 298 -95t114 -257q0 -230 -262 -359q309 -160 309 -393q0 -181 -126 -291t-333 -110q-216 0 -337 103.5t-121 289.5zM334 371q0 -240 276 -240q136 0 210.5 65.5t74.5 182.5q0 90 -63 159.5 t-214 143.5l-30 14q-254 -121 -254 -325zM381 1126q0 -90 49.5 -152.5t185.5 -125.5q232 103 232 278q0 101 -63 154t-173 53q-106 0 -168.5 -53t-62.5 -154z" /> +<glyph unicode="9" d="M154 991q0 228 120.5 360t323.5 132q220 0 348.5 -171t128.5 -474q0 -858 -639 -858q-105 0 -172 18v156q67 -25 166 -25q224 0 336.5 141t122.5 447h-12q-96 -170 -308 -170q-194 0 -304.5 118t-110.5 326zM330 991q0 -145 68.5 -223t195.5 -78t213 81.5t86 184.5 q0 151 -80 262t-213 111q-128 0 -199 -87t-71 -251z" /> +<glyph unicode=":" d="M487 111q0 139 127 139t127 -139q0 -140 -127 -140t-127 140zM487 987q0 139 127 139t127 -139t-127 -139t-127 139z" /> +<glyph unicode=";" d="M410 -264q62 255 100 502h199l14 -23q-51 -197 -176 -479h-137zM494 987q0 139 127 139t127 -139t-127 -139t-127 139z" /> +<glyph unicode="<" d="M152 672v102l923 451v-160l-715 -342l715 -342v-160z" /> +<glyph unicode="=" d="M152 442v150h923v-150h-923zM152 852v149h923v-149h-923z" /> +<glyph unicode=">" d="M152 221v160l714 342l-714 342v160l923 -451v-102z" /> +<glyph unicode="?" d="M168 1386q209 97 426 97q214 0 339.5 -97.5t125.5 -261.5q0 -133 -53.5 -216t-196.5 -191q-118 -87 -151 -141t-33 -144v-18h-160v37q0 120 46 195t161 157q130 97 171.5 155t41.5 158q0 92 -74.5 149.5t-206.5 57.5q-174 0 -371 -90zM426 111q0 139 127 139t127 -139 q0 -140 -127 -140t-127 140z" /> +<glyph unicode="@" d="M31 602q0 397 167 628.5t455 231.5q248 0 396.5 -196t148.5 -535q0 -231 -64 -370.5t-178 -139.5q-128 0 -157 180h-4q-74 -180 -230 -180q-120 0 -190 104.5t-70 280.5q0 206 97 332.5t255 126.5q137 0 256 -47l-22 -416q-2 -38 -2 -69v-7q0 -176 72 -176q100 0 100 383 q0 278 -111 436t-299 158q-226 0 -352.5 -192t-126.5 -527q0 -312 129.5 -482.5t368.5 -170.5q181 0 346 78v-133q-158 -82 -352 -82q-298 0 -465.5 207t-167.5 577zM465 602q0 -252 127 -252q131 0 145 312l15 253q-54 21 -103 21q-89 0 -136.5 -93.5t-47.5 -240.5z" /> +<glyph unicode="A" d="M33 0l483 1468h195l485 -1468h-192l-144 453h-491l-146 -453h-190zM422 618h385l-133 424q-39 124 -62 226q-20 -99 -46 -183z" /> +<glyph unicode="B" d="M135 0v1462h440q274 0 397.5 -87.5t123.5 -282.5q0 -128 -78.5 -213t-212.5 -103v-10q332 -54 332 -342q0 -198 -127.5 -311t-347.5 -113h-527zM322 158h307q311 0 311 274q0 254 -324 254h-294v-528zM322 842h284q156 0 227.5 55t71.5 182q0 120 -76.5 172t-242.5 52 h-264v-461z" /> +<glyph unicode="C" d="M129 733q0 346 179 548t489 202q220 0 383 -86l-78 -156q-154 78 -305 78q-215 0 -343 -158.5t-128 -429.5q0 -287 120 -437.5t351 -150.5q130 0 327 58v-162q-146 -59 -358 -59q-309 0 -473 196t-164 557z" /> +<glyph unicode="D" d="M135 0v1462h342q317 0 493.5 -189t176.5 -528q0 -361 -183 -553t-528 -192h-301zM322 160h96q532 0 532 579q0 564 -493 564h-135v-1143z" /> +<glyph unicode="E" d="M217 0v1462h842v-164h-656v-452h617v-162h-617v-520h656v-164h-842z" /> +<glyph unicode="F" d="M244 0v1462h841v-164h-655v-516h617v-164h-617v-618h-186z" /> +<glyph unicode="G" d="M117 733q0 351 162 550.5t446 199.5q192 0 346 -86l-72 -162q-146 84 -280 84q-192 0 -299 -155.5t-107 -432.5q0 -588 394 -588q97 0 202 29v436h-237v164h422v-717q-195 -75 -420 -75q-262 0 -409.5 199.5t-147.5 553.5z" /> +<glyph unicode="H" d="M135 0v1462h187v-616h585v616h187v-1462h-187v682h-585v-682h-187z" /> +<glyph unicode="I" d="M225 0v123l295 20v1176l-295 20v123h776v-123l-294 -20v-1176l294 -20v-123h-776z" /> +<glyph unicode="J" d="M137 39v166q162 -62 309 -62q161 0 254 79.5t93 226.5v1013h186v-1011q0 -216 -140.5 -343.5t-377.5 -127.5q-217 0 -324 59z" /> +<glyph unicode="K" d="M211 0v1462h186v-731l121 168l453 563h209l-521 -637l539 -825h-211l-450 698l-140 -114v-584h-186z" /> +<glyph unicode="L" d="M233 0v1462h187v-1296h635v-166h-822z" /> +<glyph unicode="M" d="M113 0v1462h247l248 -1192h6l250 1192h252v-1462h-153v887q0 102 14 391h-8l-283 -1278h-154l-278 1280h-8q18 -266 18 -406v-874h-151z" /> +<glyph unicode="N" d="M135 0v1462h213l578 -1204h6q-14 303 -14 404v800h174v-1462h-215l-580 1210h-8q18 -277 18 -417v-793h-172z" /> +<glyph unicode="O" d="M84 735q0 750 534 750q256 0 392.5 -195.5t136.5 -556.5t-138 -557t-393 -196q-532 0 -532 755zM281 733q0 -590 335 -590q173 0 253.5 145t80.5 445q0 303 -81.5 445.5t-250.5 142.5q-337 0 -337 -588z" /> +<glyph unicode="P" d="M176 0v1462h404q514 0 514 -428q0 -219 -138.5 -342t-402.5 -123h-191v-569h-186zM362 727h170q198 0 283.5 72t85.5 225q0 279 -338 279h-201v-576z" /> +<glyph unicode="Q" d="M84 735q0 750 534 750q256 0 392.5 -195.5t136.5 -556.5q0 -526 -285 -694q85 -180 279 -311l-121 -142q-236 171 -328 400q-36 -6 -76 -6q-532 0 -532 755zM281 733q0 -590 335 -590q173 0 253.5 145t80.5 445q0 303 -81.5 445.5t-250.5 142.5q-337 0 -337 -588z" /> +<glyph unicode="R" d="M186 0v1462h357q520 0 520 -415q0 -287 -289 -392l397 -655h-219l-350 604h-229v-604h-187zM373 762h164q171 0 252 66t81 210q0 141 -80 203t-258 62h-159v-541z" /> +<glyph unicode="S" d="M141 49v178q211 -86 414 -86q350 0 350 240q0 104 -70.5 160t-285.5 133q-208 73 -298.5 174.5t-90.5 263.5q0 174 128.5 272.5t352.5 98.5q229 0 416 -78l-64 -164q-193 78 -360 78q-293 0 -293 -209q0 -102 65.5 -164t270.5 -133q246 -88 328.5 -181.5t82.5 -240.5 q0 -192 -138.5 -301.5t-393.5 -109.5q-265 0 -414 69z" /> +<glyph unicode="T" d="M102 1298v164h1022v-164h-417v-1298h-187v1298h-418z" /> +<glyph unicode="U" d="M125 520v942h186v-932q0 -387 307 -387q295 0 300 389v932h186v-948q0 -260 -126 -398t-370 -138q-483 0 -483 540z" /> +<glyph unicode="V" d="M33 1462h196l295 -927q41 -127 88 -334q31 145 93 340l292 921h199l-489 -1462h-187z" /> +<glyph unicode="W" d="M2 1462h170l88 -663q23 -176 40 -378t17 -241q24 151 70 312l141 516h177l145 -521q61 -219 72 -307q2 53 65 619l70 663h170l-187 -1462h-190l-168 580q-40 138 -66 282q-32 -173 -65 -284l-156 -578h-190z" /> +<glyph unicode="X" d="M53 0l453 764l-422 698h199l331 -559l334 559h191l-422 -692l457 -770h-211l-355 635l-366 -635h-189z" /> +<glyph unicode="Y" d="M33 1462h203l376 -739l381 739h201l-487 -893v-569h-187v559z" /> +<glyph unicode="Z" d="M102 0v145l793 1151h-772v166h981v-145l-793 -1151h813v-166h-1022z" /> +<glyph unicode="[" d="M412 -324v1786h528v-149h-346v-1487h346v-150h-528z" /> +<glyph unicode="\" d="M211 1462h178l627 -1462h-178z" /> +<glyph unicode="]" d="M289 -174h346v1487h-346v149h528v-1786h-528v150z" /> +<glyph unicode="^" d="M111 549l424 924h102l481 -924h-162l-368 735l-318 -735h-159z" /> +<glyph unicode="_" d="M-16 -184h1259v-140h-1259v140z" /> +<glyph unicode="`" d="M418 1548v21h219q86 -178 174 -301v-27h-121q-166 142 -272 307z" /> +<glyph unicode="a" d="M135 307q0 332 510 348l203 7v69q0 236 -244 236q-147 0 -328 -82l-63 137q196 96 383 96q227 0 328.5 -87t101.5 -279v-752h-131l-37 152h-8q-77 -97 -158 -134.5t-209 -37.5q-163 0 -255.5 86t-92.5 241zM324 305q0 -178 200 -178q147 0 234.5 81.5t87.5 229.5v99 l-162 -7q-196 -8 -278 -61.5t-82 -163.5z" /> +<glyph unicode="b" d="M158 0v1556h182v-376q0 -81 -8 -226h8q107 164 322 164q201 0 315.5 -149.5t114.5 -417.5q0 -270 -115 -420.5t-315 -150.5q-207 0 -322 159h-12l-37 -139h-133zM340 551q0 -227 69.5 -323.5t221.5 -96.5q272 0 272 422q0 414 -274 414q-155 0 -222 -94t-67 -322z" /> +<glyph unicode="c" d="M172 543q0 281 145 428t408 147q178 0 336 -59l-62 -158q-150 57 -268 57q-371 0 -371 -413q0 -406 361 -406q157 0 321 62v-160q-134 -61 -329 -61q-257 0 -399 145.5t-142 417.5z" /> +<glyph unicode="d" d="M137 547q0 270 115 420.5t315 150.5q206 0 322 -160h12q-12 129 -12 162v436h182v-1556h-147l-27 147h-8q-113 -167 -322 -167q-201 0 -315.5 149.5t-114.5 417.5zM326 545q0 -414 274 -414q152 0 218.5 88.5t70.5 286.5v41q0 227 -69.5 323.5t-221.5 96.5 q-272 0 -272 -422z" /> +<glyph unicode="e" d="M133 541q0 266 135.5 421.5t362.5 155.5q212 0 338.5 -134t126.5 -357v-113h-774q8 -375 344 -375q195 0 370 76v-160q-166 -75 -364 -75q-245 0 -392 149.5t-147 411.5zM326 662h573q0 305 -272 305q-275 0 -301 -305z" /> +<glyph unicode="f" d="M156 961v110l317 33v96q0 193 90 280t299 87q129 0 252 -35l-41 -143q-104 28 -207 28q-123 0 -167 -50t-44 -165v-104h389v-137h-389v-961h-182v961h-317z" /> +<glyph unicode="g" d="M102 -186q0 212 240 270q-96 47 -96 154q0 112 133 192q-89 37 -140 122.5t-51 186.5q0 182 106.5 280.5t303.5 98.5q86 0 150 -20h378v-113l-196 -27q65 -85 65 -213q0 -161 -106.5 -256.5t-296.5 -95.5q-55 0 -86 6q-100 -56 -100 -133q0 -84 161 -84h187 q174 0 266 -77t92 -220q0 -377 -565 -377q-218 0 -331.5 80.5t-113.5 225.5zM274 -180q0 -174 271 -174q395 0 395 223q0 88 -50 118.5t-198 30.5h-188q-230 0 -230 -198zM367 745q0 -227 227 -227q223 0 223 230q0 239 -225 239t-225 -242z" /> +<glyph unicode="h" d="M160 0v1556h182v-462l-8 -144h10q103 168 336 168q389 0 389 -401v-717h-182v707q0 260 -238 260q-307 0 -307 -398v-569h-182z" /> +<glyph unicode="i" d="M197 0v123l344 20v811l-269 21v123h451v-955l352 -20v-123h-878zM526 1436q0 114 107 114q106 0 106 -114q0 -58 -31.5 -86.5t-74.5 -28.5q-107 0 -107 115z" /> +<glyph unicode="j" d="M135 -303q134 -39 289 -39q117 0 182.5 57t65.5 158v1081l-420 21v123h602v-1215q0 -180 -113 -277.5t-319 -97.5q-164 0 -287 35v154zM637 1436q0 114 106 114q107 0 107 -114q0 -115 -107 -115q-106 0 -106 115z" /> +<glyph unicode="k" d="M215 0v1556h180v-714l-16 -289h4l135 152l395 393h222l-494 -475l522 -623h-213l-426 504l-129 -82v-422h-180z" /> +<glyph unicode="l" d="M188 0v123l344 20v1270l-268 21v122h451v-1413l352 -20v-123h-879z" /> +<glyph unicode="m" d="M92 0v1098h127l27 -148h10q67 168 201 168q163 0 213 -182h6q76 182 219 182q128 0 186 -92.5t58 -308.5v-717h-162v707q0 146 -26.5 203t-88.5 57q-87 0 -126.5 -83t-39.5 -278v-606h-161v707q0 260 -125 260q-84 0 -120 -79.5t-36 -318.5v-569h-162z" /> +<glyph unicode="n" d="M160 0v1098h147l27 -148h10q103 168 336 168q389 0 389 -401v-717h-182v707q0 260 -238 260q-307 0 -307 -398v-569h-182z" /> +<glyph unicode="o" d="M115 551q0 263 135.5 415t365.5 152q218 0 357 -155t139 -412q0 -265 -137 -418t-365 -153q-216 0 -355.5 155.5t-139.5 415.5zM303 551q0 -420 311 -420q310 0 310 420q0 416 -312 416q-309 0 -309 -416z" /> +<glyph unicode="p" d="M158 -492v1590h147l27 -148h8q110 168 322 168q201 0 315.5 -149.5t114.5 -417.5q0 -270 -115 -420.5t-315 -150.5q-207 0 -322 159h-12q12 -129 12 -162v-469h-182zM340 551q0 -227 69.5 -323.5t221.5 -96.5q272 0 272 422q0 414 -274 414q-152 0 -218.5 -88t-70.5 -287 v-41z" /> +<glyph unicode="q" d="M137 547q0 270 115 420.5t315 150.5q207 0 322 -168h8l27 148h147v-1590h-182v469q0 41 12 170h-12q-113 -167 -322 -167q-201 0 -315.5 149.5t-114.5 417.5zM326 545q0 -414 274 -414q152 0 218.5 88.5t70.5 286.5v41q0 227 -69.5 323.5t-221.5 96.5q-272 0 -272 -422z " /> +<glyph unicode="r" d="M264 0v1098h148l22 -201h8q76 119 163 170t214 51q118 0 240 -45l-49 -166q-123 45 -224 45q-163 0 -251.5 -92.5t-88.5 -267.5v-592h-182z" /> +<glyph unicode="s" d="M203 49v166q193 -86 370 -86q275 0 275 162q0 57 -49 99t-226 106q-233 87 -293.5 159.5t-60.5 171.5q0 136 111.5 213.5t308.5 77.5q198 0 369 -74l-60 -149q-182 72 -319 72q-236 0 -236 -133q0 -61 50.5 -97.5t232.5 -101.5q211 -77 280.5 -151.5t69.5 -182.5 q0 -150 -117 -235.5t-331 -85.5q-248 0 -375 69z" /> +<glyph unicode="t" d="M139 961v94l267 49l77 287h105v-293h438v-137h-438v-637q0 -195 192 -195q93 0 240 21v-138q-130 -32 -252 -32q-362 0 -362 344v637h-267z" /> +<glyph unicode="u" d="M160 381v717h182v-707q0 -260 236 -260q161 0 235 92.5t74 304.5v570h182v-1098h-147l-27 147h-10q-105 -167 -334 -167q-391 0 -391 401z" /> +<glyph unicode="v" d="M82 1098h188l240 -652q85 -231 100 -325h6q7 44 101 325l239 652h189l-416 -1098h-231z" /> +<glyph unicode="w" d="M-4 1098h162l98 -543q34 -186 57 -393h6q31 185 68 358l133 578h193l127 -578q43 -195 67 -358h6q31 242 60 393l102 543h158l-225 -1098h-195l-131 596l-68 330h-6l-65 -334l-135 -592h-189z" /> +<glyph unicode="x" d="M96 0l414 563l-393 535h207l290 -410l291 410h207l-395 -535l413 -563h-206l-310 436l-311 -436h-207z" /> +<glyph unicode="y" d="M82 1098h188l262 -654q82 -205 89 -290h6q23 112 90 292l239 652h189l-475 -1241q-67 -174 -156 -261.5t-246 -87.5q-86 0 -168 17v145q62 -12 136 -12q96 0 149.5 41t95.5 141l58 150z" /> +<glyph unicode="z" d="M182 0v125l660 836h-627v137h811v-146l-647 -815h665v-137h-862z" /> +<glyph unicode="{" d="M225 492v155q338 0 338 189v333q0 287 438 293v-149q-144 -2 -200 -39.5t-56 -118.5v-332q0 -207 -233 -248v-12q233 -41 233 -248v-331q0 -81 56 -118.5t200 -39.5v-150q-438 6 -438 293v334q0 189 -338 189z" /> +<glyph unicode="|" d="M539 -492v2048h149v-2048h-149z" /> +<glyph unicode="}" d="M227 -174q143 1 199.5 39t56.5 119v331q0 207 234 248v12q-234 41 -234 248v332q0 81 -56.5 119t-199.5 39v149q439 -6 439 -293v-333q0 -189 338 -189v-155q-338 0 -338 -189v-334q0 -287 -439 -293v150z" /> +<glyph unicode="~" d="M152 586v162q99 108 247 108q100 0 248 -63q130 -56 201 -56q108 0 227 121v-162q-99 -108 -248 -108q-100 0 -247 63q-131 56 -201 56q-108 0 -227 -121z" /> +<glyph unicode=" " /> +<glyph unicode="¡" d="M487 979q0 139 127 139t127 -139t-127 -139t-127 139zM502 -373l51 1049h121l51 -1049h-223z" /> +<glyph unicode="¢" d="M172 743q0 494 434 568v172h137v-164q162 -3 318 -59l-62 -158q-150 57 -268 57q-371 0 -371 -414q0 -405 361 -405q153 0 321 61v-159q-122 -59 -299 -62v-200h-137v206q-434 69 -434 557z" /> +<glyph unicode="£" d="M119 0v154q200 49 200 284v213h-198v137h198v324q0 168 108.5 268.5t289.5 100.5q192 0 346 -80l-66 -144q-141 72 -272 72q-223 0 -223 -246v-295h377v-137h-377v-211q0 -196 -140 -274h748v-166h-991z" /> +<glyph unicode="¤" d="M174 1065l98 98l127 -129q101 68 215 68t213 -68l129 129l99 -96l-129 -129q67 -101 67 -215q0 -120 -67 -215l127 -127l-97 -96l-129 127q-99 -66 -213 -66q-118 0 -215 68l-127 -127l-96 96l127 127q-65 95 -65 213q0 114 65 213zM375 723q0 -100 70.5 -170t168.5 -70 q100 0 172 70t72 170q0 101 -71.5 172.5t-172.5 71.5q-99 0 -169 -71t-70 -173z" /> +<glyph unicode="¥" d="M78 1462h192l342 -739l346 739h191l-385 -768h240v-137h-302v-158h302v-137h-302v-262h-178v262h-301v137h301v158h-301v137h234z" /> +<glyph unicode="¦" d="M539 289h149v-781h-149v781zM539 776v780h149v-780h-149z" /> +<glyph unicode="§" d="M244 55v158q171 -82 323 -82q240 0 240 141q0 57 -43 97t-195 102q-197 84 -253 159t-56 179q0 179 160 258q-160 80 -160 236q0 120 104 192t277 72q162 0 326 -72l-56 -139q-156 67 -276 67q-201 0 -201 -116q0 -54 49.5 -93t196.5 -100q157 -62 231 -139.5t74 -190.5 q0 -182 -145 -270q145 -80 145 -225q0 -138 -110.5 -218.5t-307.5 -80.5q-204 0 -323 65zM414 831q0 -73 56.5 -126.5t207.5 -116.5l35 -15q114 76 114 185q0 89 -73.5 144.5t-206.5 103.5q-133 -48 -133 -175z" /> +<glyph unicode="¨" d="M330 1395q0 102 96 102t96 -102q0 -103 -96 -103t-96 103zM705 1395q0 102 96 102t96 -102q0 -103 -96 -103t-96 103z" /> +<glyph unicode="©" d="M6 731q0 343 160.5 547.5t447.5 204.5q286 0 447.5 -204t161.5 -548q0 -345 -162 -548t-447 -203q-286 0 -447 203.5t-161 547.5zM115 731q0 -301 129.5 -472t369.5 -171t370 170.5t130 472.5t-130 472.5t-370 170.5t-369.5 -171t-129.5 -472zM248 733q0 209 110 332 t301 123q128 0 254 -62l-61 -127q-110 54 -193 54q-121 0 -186 -85.5t-65 -236.5q0 -323 251 -323q94 0 215 45v-131q-107 -50 -221 -50q-195 0 -300 123.5t-105 337.5z" /> +<glyph unicode="ª" d="M276 989q0 116 85 167.5t276 57.5l125 5v10q0 133 -152 133q-112 0 -245 -51l-41 110q138 58 294 58q291 0 291 -238v-444h-110l-33 118q-104 -131 -268 -131q-222 0 -222 205zM428 987q0 -90 104 -90q105 0 167.5 55t62.5 146v20l-100 -2q-114 -2 -174 -28t-60 -101z " /> +<glyph unicode="«" d="M197 526v27l309 414l117 -78l-238 -348l238 -348l-117 -78zM604 526v27l309 414l117 -78l-237 -348l237 -348l-117 -78z" /> +<glyph unicode="¬" d="M152 647v150h923v-535h-149v385h-774z" /> +<glyph unicode="­" d="M285 465v168h659v-168h-659z" /> +<glyph unicode="®" d="M6 731q0 343 160.5 547.5t447.5 204.5q286 0 447.5 -204t161.5 -548q0 -345 -162 -548t-447 -203q-286 0 -447 203.5t-161 547.5zM115 731q0 -301 129.5 -472t369.5 -171t370 170.5t130 472.5t-130 472.5t-370 170.5t-369.5 -171t-129.5 -472zM348 285v893h234 q325 0 325 -265q0 -163 -159 -233l237 -395h-178l-207 352h-94v-352h-158zM506 768h72q170 0 170 141q0 74 -42 103.5t-131 29.5h-69v-274z" /> +<glyph unicode="¯" d="M-20 1556v140h1269v-140h-1269z" /> +<glyph unicode="°" d="M299 1167q0 129 92.5 222.5t222.5 93.5q129 0 222.5 -93.5t93.5 -222.5t-93 -221t-223 -92q-131 0 -223 92.5t-92 220.5zM422 1167q0 -78 56 -134t136 -56q79 0 136 56t57 134q0 81 -57.5 138t-135.5 57q-79 0 -135.5 -57.5t-56.5 -137.5z" /> +<glyph unicode="±" d="M152 0v150h923v-150h-923zM152 647v150h387v389h149v-389h387v-150h-387v-385h-149v385h-387z" /> +<glyph unicode="²" d="M348 672v102l187 199q111 118 141.5 168.5t30.5 107.5q0 115 -111 115q-81 0 -164 -76l-78 86q117 103 248 103q118 0 183 -60t65 -164q0 -66 -35 -134t-164 -197l-135 -136h363v-114h-531z" /> +<glyph unicode="³" d="M342 705v124q110 -65 203 -65q149 0 149 137q0 125 -147 125h-72v104h70q123 0 123 127q0 111 -97 111q-71 0 -161 -70l-66 86q111 93 238 93q109 0 173 -54.5t64 -148.5q0 -139 -149 -189q176 -39 176 -186q0 -116 -74.5 -180t-214.5 -64q-131 0 -215 50z" /> +<glyph unicode="´" d="M418 1241v27q94 133 174 301h219v-21q-112 -173 -272 -307h-121z" /> +<glyph unicode="µ" d="M180 -492v1590h182v-707q0 -260 218 -260q148 0 217 91t69 306v570h183v-1098h-148l-27 147h-10q-96 -167 -295 -167q-139 0 -213 88q6 -153 6 -240v-320h-182z" /> +<glyph unicode="¶" d="M66 1042q0 259 108.5 386.5t341.5 127.5h563v-1816h-121v1657h-206v-1657h-121v819q-61 -18 -146 -18q-419 0 -419 501z" /> +<glyph unicode="·" d="M487 723q0 139 127 139t127 -139t-127 -139t-127 139z" /> +<glyph unicode="¸" d="M428 -375q33 -6 80 -6q151 0 151 92q0 74 -172 113l91 176h120l-57 -115q160 -37 160 -172q0 -205 -291 -205q-34 0 -82 9v108z" /> +<glyph unicode="¹" d="M367 1309l219 151h135v-788h-146v465q0 69 9 200q-41 -44 -74 -65l-70 -51z" /> +<glyph unicode="º" d="M281 1133q0 162 90 254t245 92q145 0 238.5 -92.5t93.5 -253.5q0 -165 -92 -257t-244 -92q-144 0 -237.5 93t-93.5 256zM432 1133q0 -230 182 -230q181 0 181 230q0 225 -181 225q-182 0 -182 -225z" /> +<glyph unicode="»" d="M197 193l237 348l-237 348l116 78l310 -414v-27l-310 -411zM604 193l238 348l-238 348l117 78l309 -414v-27l-309 -411z" /> +<glyph unicode="¼" d="M22 1309l219 151h135v-788h-146v465q0 69 9 200q-41 -44 -74 -65l-70 -51zM170 0l729 1462h158l-729 -1462h-158zM606 175v98l377 523h141v-508h84v-113h-84v-174h-143v174h-375zM751 288h230v176q0 82 6 172q-40 -73 -80 -131z" /> +<glyph unicode="½" d="M3 1309l219 151h135v-788h-146v465q0 69 9 200q-41 -44 -74 -65l-70 -51zM105 0l729 1462h158l-729 -1462h-158zM694 1v102l187 199q111 118 141.5 168.5t30.5 107.5q0 115 -111 115q-81 0 -164 -76l-78 86q117 103 248 103q118 0 183 -60t65 -164q0 -66 -35 -134 t-164 -197l-135 -136h363v-114h-531z" /> +<glyph unicode="¾" d="M21 705v124q110 -65 203 -65q149 0 149 137q0 125 -147 125h-72v104h70q123 0 123 127q0 111 -97 111q-71 0 -161 -70l-66 86q111 93 238 93q109 0 173 -54.5t64 -148.5q0 -139 -149 -189q176 -39 176 -186q0 -116 -74.5 -180t-214.5 -64q-131 0 -215 50zM223 0l729 1462 h158l-729 -1462h-158zM627 175v98l377 523h141v-508h84v-113h-84v-174h-143v174h-375zM772 288h230v176q0 82 6 172q-40 -73 -80 -131z" /> +<glyph unicode="¿" d="M168 -35q0 134 53.5 217t196.5 191q119 87 151.5 140.5t32.5 143.5v19h160v-37q0 -119 -44.5 -193.5t-162.5 -158.5q-129 -97 -171 -155t-42 -159q0 -93 74.5 -149.5t206.5 -56.5q181 0 370 90l62 -144q-219 -106 -422 -106q-217 0 -341 97.5t-124 260.5zM547 979 q0 139 127 139t127 -139t-127 -139t-127 139z" /> +<glyph unicode="À" d="M33 0l483 1468h195l485 -1468h-192l-144 453h-491l-146 -453h-190zM341 1886v21h219q86 -178 174 -301v-27h-121q-166 142 -272 307zM422 618h385l-133 424q-39 124 -62 226q-20 -99 -46 -183z" /> +<glyph unicode="Á" d="M33 0l483 1468h195l485 -1468h-192l-144 453h-491l-146 -453h-190zM422 618h385l-133 424q-39 124 -62 226q-20 -99 -46 -183zM520 1579v27q94 133 174 301h219v-21q-112 -173 -272 -307h-121z" /> +<glyph unicode="Â" d="M33 0l483 1468h195l485 -1468h-192l-144 453h-491l-146 -453h-190zM283 1579v27q25 29 59 67q139 155 176 234h193q37 -79 176 -234l59 -67v-27h-121q-85 56 -211 186q-133 -136 -211 -186h-120zM422 618h385l-133 424q-39 124 -62 226q-20 -99 -46 -183z" /> +<glyph unicode="Ã" d="M33 0l483 1468h195l485 -1468h-192l-144 453h-491l-146 -453h-190zM253 1579q25 264 211 264q58 0 161 -56q102 -56 136 -56q80 0 106 114h105q-27 -264 -211 -264q-57 0 -157 57q-100 56 -140 56q-82 0 -107 -115h-104zM422 618h385l-133 424q-39 124 -62 226 q-20 -99 -46 -183z" /> +<glyph unicode="Ä" d="M33 0l483 1468h195l485 -1468h-192l-144 453h-491l-146 -453h-190zM330 1733q0 102 96 102t96 -102q0 -103 -96 -103t-96 103zM422 618h385l-133 424q-39 124 -62 226q-20 -99 -46 -183zM705 1733q0 102 96 102t96 -102q0 -103 -96 -103t-96 103z" /> +<glyph unicode="Å" d="M33 0l483 1468h195l485 -1468h-192l-144 453h-491l-146 -453h-190zM387 1581q0 99 60.5 157t162.5 58q101 0 165.5 -59t64.5 -154q0 -98 -63.5 -157.5t-166.5 -59.5q-102 0 -162.5 58t-60.5 157zM422 618h385l-133 424q-39 124 -62 226q-20 -99 -46 -183zM498 1581 q0 -113 112 -113q50 0 81.5 30t31.5 83t-31.5 83t-81.5 30q-49 0 -80.5 -30t-31.5 -83z" /> +<glyph unicode="Æ" d="M0 0l338 1462h872v-164h-477v-452h438v-162h-438v-520h477v-164h-653v453h-289l-96 -453h-172zM305 618h252v680h-106z" /> +<glyph unicode="Ç" d="M129 733q0 346 179 548t489 202q220 0 383 -86l-78 -156q-154 78 -305 78q-215 0 -343 -158.5t-128 -429.5q0 -287 120 -437.5t351 -150.5q130 0 327 58v-162q-146 -59 -358 -59q-309 0 -473 196t-164 557zM508 -375q33 -6 80 -6q151 0 151 92q0 74 -172 113l91 176h120 l-57 -115q160 -37 160 -172q0 -205 -291 -205q-34 0 -82 9v108z" /> +<glyph unicode="È" d="M217 0v1462h842v-164h-656v-452h617v-162h-617v-520h656v-164h-842zM345 1886v21h219q86 -178 174 -301v-27h-121q-166 142 -272 307z" /> +<glyph unicode="É" d="M217 0v1462h842v-164h-656v-452h617v-162h-617v-520h656v-164h-842zM481 1579v27q94 133 174 301h219v-21q-112 -173 -272 -307h-121z" /> +<glyph unicode="Ê" d="M217 0v1462h842v-164h-656v-452h617v-162h-617v-520h656v-164h-842zM318 1579v27q25 29 59 67q139 155 176 234h193q37 -79 176 -234l59 -67v-27h-121q-85 56 -211 186q-133 -136 -211 -186h-120z" /> +<glyph unicode="Ë" d="M217 0v1462h842v-164h-656v-452h617v-162h-617v-520h656v-164h-842zM355 1733q0 102 96 102t96 -102q0 -103 -96 -103t-96 103zM730 1733q0 102 96 102t96 -102q0 -103 -96 -103t-96 103z" /> +<glyph unicode="Ì" d="M225 0v123l295 20v1176l-295 20v123h776v-123l-294 -20v-1176l294 -20v-123h-776zM310 1886v21h219q86 -178 174 -301v-27h-121q-166 142 -272 307z" /> +<glyph unicode="Í" d="M225 0v123l295 20v1176l-295 20v123h776v-123l-294 -20v-1176l294 -20v-123h-776zM537 1579v27q94 133 174 301h219v-21q-112 -173 -272 -307h-121z" /> +<glyph unicode="Î" d="M225 0v123l295 20v1176l-295 20v123h776v-123l-294 -20v-1176l294 -20v-123h-776zM283 1579v27q25 29 59 67q139 155 176 234h193q37 -79 176 -234l59 -67v-27h-121q-85 56 -211 186q-133 -136 -211 -186h-120z" /> +<glyph unicode="Ï" d="M225 0v123l295 20v1176l-295 20v123h776v-123l-294 -20v-1176l294 -20v-123h-776zM332 1733q0 102 96 102t96 -102q0 -103 -96 -103t-96 103zM707 1733q0 102 96 102t96 -102q0 -103 -96 -103t-96 103z" /> +<glyph unicode="Ð" d="M0 659v162h135v641h342q317 0 493.5 -189t176.5 -528q0 -361 -183 -553t-528 -192h-301v659h-135zM322 160h96q532 0 532 579q0 564 -493 564h-135v-482h380v-162h-380v-499z" /> +<glyph unicode="Ñ" d="M135 0v1462h213l578 -1204h6q-14 303 -14 404v800h174v-1462h-215l-580 1210h-8q18 -277 18 -417v-793h-172zM258 1579q25 264 211 264q58 0 161 -56q102 -56 136 -56q80 0 106 114h105q-27 -264 -211 -264q-57 0 -157 57q-100 56 -140 56q-82 0 -107 -115h-104z" /> +<glyph unicode="Ò" d="M84 735q0 750 534 750q256 0 392.5 -195.5t136.5 -556.5t-138 -557t-393 -196q-532 0 -532 755zM281 733q0 -590 335 -590q173 0 253.5 145t80.5 445q0 303 -81.5 445.5t-250.5 142.5q-337 0 -337 -588zM337 1886v21h219q86 -178 174 -301v-27h-121q-166 142 -272 307z " /> +<glyph unicode="Ó" d="M84 735q0 750 534 750q256 0 392.5 -195.5t136.5 -556.5t-138 -557t-393 -196q-532 0 -532 755zM281 733q0 -590 335 -590q173 0 253.5 145t80.5 445q0 303 -81.5 445.5t-250.5 142.5q-337 0 -337 -588zM508 1579v27q94 133 174 301h219v-21q-112 -173 -272 -307h-121z " /> +<glyph unicode="Ô" d="M84 735q0 750 534 750q256 0 392.5 -195.5t136.5 -556.5t-138 -557t-393 -196q-532 0 -532 755zM281 733q0 -590 335 -590q173 0 253.5 145t80.5 445q0 303 -81.5 445.5t-250.5 142.5q-337 0 -337 -588zM283 1579v27q25 29 59 67q139 155 176 234h193q37 -79 176 -234 l59 -67v-27h-121q-85 56 -211 186q-133 -136 -211 -186h-120z" /> +<glyph unicode="Õ" d="M84 735q0 750 534 750q256 0 392.5 -195.5t136.5 -556.5t-138 -557t-393 -196q-532 0 -532 755zM262 1579q25 264 211 264q58 0 161 -56q102 -56 136 -56q80 0 106 114h105q-27 -264 -211 -264q-57 0 -157 57q-100 56 -140 56q-82 0 -107 -115h-104zM281 733 q0 -590 335 -590q173 0 253.5 145t80.5 445q0 303 -81.5 445.5t-250.5 142.5q-337 0 -337 -588z" /> +<glyph unicode="Ö" d="M84 735q0 750 534 750q256 0 392.5 -195.5t136.5 -556.5t-138 -557t-393 -196q-532 0 -532 755zM281 733q0 -590 335 -590q173 0 253.5 145t80.5 445q0 303 -81.5 445.5t-250.5 142.5q-337 0 -337 -588zM332 1733q0 102 96 102t96 -102q0 -103 -96 -103t-96 103z M707 1733q0 102 96 102t96 -102q0 -103 -96 -103t-96 103z" /> +<glyph unicode="×" d="M190 1042l105 105l317 -318l322 318l104 -103l-321 -321l319 -320l-102 -102l-322 317l-317 -315l-102 103l315 317z" /> +<glyph unicode="Ø" d="M80 2l121 197q-117 184 -117 536q0 750 534 750q186 0 310 -105l92 152l137 -78l-125 -201q115 -188 115 -520q0 -361 -138 -557t-393 -196q-189 0 -307 94l-92 -150zM281 733q0 -212 38 -342l515 836q-80 94 -216 94q-337 0 -337 -588zM403 229q80 -86 213 -86 q173 0 253.5 145t80.5 445q0 209 -35 328z" /> +<glyph unicode="Ù" d="M125 520v942h186v-932q0 -387 307 -387q295 0 300 389v932h186v-948q0 -260 -126 -398t-370 -138q-483 0 -483 540zM349 1886v21h219q86 -178 174 -301v-27h-121q-166 142 -272 307z" /> +<glyph unicode="Ú" d="M125 520v942h186v-932q0 -387 307 -387q295 0 300 389v932h186v-948q0 -260 -126 -398t-370 -138q-483 0 -483 540zM494 1579v27q94 133 174 301h219v-21q-112 -173 -272 -307h-121z" /> +<glyph unicode="Û" d="M125 520v942h186v-932q0 -387 307 -387q295 0 300 389v932h186v-948q0 -260 -126 -398t-370 -138q-483 0 -483 540zM283 1579v27q25 29 59 67q139 155 176 234h193q37 -79 176 -234l59 -67v-27h-121q-85 56 -211 186q-133 -136 -211 -186h-120z" /> +<glyph unicode="Ü" d="M125 520v942h186v-932q0 -387 307 -387q295 0 300 389v932h186v-948q0 -260 -126 -398t-370 -138q-483 0 -483 540zM332 1733q0 102 96 102t96 -102q0 -103 -96 -103t-96 103zM707 1733q0 102 96 102t96 -102q0 -103 -96 -103t-96 103z" /> +<glyph unicode="Ý" d="M33 1462h203l376 -739l381 739h201l-487 -893v-569h-187v559zM494 1579v27q94 133 174 301h219v-21q-112 -173 -272 -307h-121z" /> +<glyph unicode="Þ" d="M176 0v1462h186v-252h218q514 0 514 -428q0 -219 -138.5 -342t-402.5 -123h-191v-317h-186zM362 475h170q198 0 283.5 72t85.5 225q0 279 -338 279h-201v-576z" /> +<glyph unicode="ß" d="M164 0v1200q0 367 424 367q194 0 302.5 -79.5t108.5 -227.5q0 -132 -133 -249q-84 -74 -108.5 -105t-24.5 -64q0 -39 29 -69t151 -111q144 -95 191 -173t47 -176q0 -162 -100 -247.5t-283 -85.5q-182 0 -289 69v166q143 -86 277 -86q213 0 213 174q0 81 -45.5 132 t-143.5 112q-123 78 -173 139t-50 148q0 117 129 223t129 196q0 164 -227 164q-242 0 -242 -215v-1202h-182z" /> +<glyph unicode="à" d="M135 307q0 332 510 348l203 7v69q0 236 -244 236q-147 0 -328 -82l-63 137q196 96 383 96q227 0 328.5 -87t101.5 -279v-752h-131l-37 152h-8q-77 -97 -158 -134.5t-209 -37.5q-163 0 -255.5 86t-92.5 241zM324 305q0 -178 200 -178q147 0 234.5 81.5t87.5 229.5v99 l-162 -7q-196 -8 -278 -61.5t-82 -163.5zM333 1548v21h219q86 -178 174 -301v-27h-121q-166 142 -272 307z" /> +<glyph unicode="á" d="M135 307q0 332 510 348l203 7v69q0 236 -244 236q-147 0 -328 -82l-63 137q196 96 383 96q227 0 328.5 -87t101.5 -279v-752h-131l-37 152h-8q-77 -97 -158 -134.5t-209 -37.5q-163 0 -255.5 86t-92.5 241zM324 305q0 -178 200 -178q147 0 234.5 81.5t87.5 229.5v99 l-162 -7q-196 -8 -278 -61.5t-82 -163.5zM502 1241v27q94 133 174 301h219v-21q-112 -173 -272 -307h-121z" /> +<glyph unicode="â" d="M135 307q0 332 510 348l203 7v69q0 236 -244 236q-147 0 -328 -82l-63 137q196 96 383 96q227 0 328.5 -87t101.5 -279v-752h-131l-37 152h-8q-77 -97 -158 -134.5t-209 -37.5q-163 0 -255.5 86t-92.5 241zM291 1241v27q25 29 59 67q139 155 176 234h193q37 -79 176 -234 l59 -67v-27h-121q-85 56 -211 186q-133 -136 -211 -186h-120zM324 305q0 -178 200 -178q147 0 234.5 81.5t87.5 229.5v99l-162 -7q-196 -8 -278 -61.5t-82 -163.5z" /> +<glyph unicode="ã" d="M135 307q0 332 510 348l203 7v69q0 236 -244 236q-147 0 -328 -82l-63 137q196 96 383 96q227 0 328.5 -87t101.5 -279v-752h-131l-37 152h-8q-77 -97 -158 -134.5t-209 -37.5q-163 0 -255.5 86t-92.5 241zM264 1241q25 264 211 264q58 0 161 -56q102 -56 136 -56 q80 0 106 114h105q-27 -264 -211 -264q-57 0 -157 57q-100 56 -140 56q-82 0 -107 -115h-104zM324 305q0 -178 200 -178q147 0 234.5 81.5t87.5 229.5v99l-162 -7q-196 -8 -278 -61.5t-82 -163.5z" /> +<glyph unicode="ä" d="M135 307q0 332 510 348l203 7v69q0 236 -244 236q-147 0 -328 -82l-63 137q196 96 383 96q227 0 328.5 -87t101.5 -279v-752h-131l-37 152h-8q-77 -97 -158 -134.5t-209 -37.5q-163 0 -255.5 86t-92.5 241zM324 305q0 -178 200 -178q147 0 234.5 81.5t87.5 229.5v99 l-162 -7q-196 -8 -278 -61.5t-82 -163.5zM342 1395q0 102 96 102t96 -102q0 -103 -96 -103t-96 103zM717 1395q0 102 96 102t96 -102q0 -103 -96 -103t-96 103z" /> +<glyph unicode="å" d="M135 307q0 332 510 348l203 7v69q0 236 -244 236q-147 0 -328 -82l-63 137q196 96 383 96q227 0 328.5 -87t101.5 -279v-752h-131l-37 152h-8q-77 -97 -158 -134.5t-209 -37.5q-163 0 -255.5 86t-92.5 241zM324 305q0 -178 200 -178q147 0 234.5 81.5t87.5 229.5v99 l-162 -7q-196 -8 -278 -61.5t-82 -163.5zM386 1456q0 99 60.5 157t162.5 58q101 0 165.5 -59t64.5 -154q0 -98 -63.5 -157.5t-166.5 -59.5q-102 0 -162.5 58t-60.5 157zM497 1456q0 -113 112 -113q50 0 81.5 30t31.5 83t-31.5 83t-81.5 30q-49 0 -80.5 -30t-31.5 -83z" /> +<glyph unicode="æ" d="M45 307q0 332 328 348l149 7v69q0 236 -139 236q-107 0 -211 -82l-57 137q131 96 276 96q188 0 246 -178q78 178 240 178q137 0 223 -135.5t86 -355.5v-113h-496q3 -192 67 -283.5t169 -91.5q111 0 233 76v-162q-107 -73 -241 -73q-222 0 -316 229q-105 -229 -301 -229 q-115 0 -185.5 86.5t-70.5 240.5zM215 305q0 -83 32 -130.5t87 -47.5q82 0 134 82.5t52 228.5v99l-88 -7q-217 -17 -217 -225zM694 662h316q0 141 -40.5 223t-111.5 82q-68 0 -113 -78t-51 -227z" /> +<glyph unicode="ç" d="M172 543q0 281 145 428t408 147q178 0 336 -59l-62 -158q-150 57 -268 57q-371 0 -371 -413q0 -406 361 -406q157 0 321 62v-160q-134 -61 -329 -61q-257 0 -399 145.5t-142 417.5zM477 -375q33 -6 80 -6q151 0 151 92q0 74 -172 113l91 176h120l-57 -115 q160 -37 160 -172q0 -205 -291 -205q-34 0 -82 9v108z" /> +<glyph unicode="è" d="M133 541q0 266 135.5 421.5t362.5 155.5q212 0 338.5 -134t126.5 -357v-113h-774q8 -375 344 -375q195 0 370 76v-160q-166 -75 -364 -75q-245 0 -392 149.5t-147 411.5zM326 662h573q0 305 -272 305q-275 0 -301 -305zM374 1548v21h219q86 -178 174 -301v-27h-121 q-166 142 -272 307z" /> +<glyph unicode="é" d="M133 541q0 266 135.5 421.5t362.5 155.5q212 0 338.5 -134t126.5 -357v-113h-774q8 -375 344 -375q195 0 370 76v-160q-166 -75 -364 -75q-245 0 -392 149.5t-147 411.5zM326 662h573q0 305 -272 305q-275 0 -301 -305zM500 1241v27q94 133 174 301h219v-21 q-112 -173 -272 -307h-121z" /> +<glyph unicode="ê" d="M133 541q0 266 135.5 421.5t362.5 155.5q212 0 338.5 -134t126.5 -357v-113h-774q8 -375 344 -375q195 0 370 76v-160q-166 -75 -364 -75q-245 0 -392 149.5t-147 411.5zM299 1241v27q25 29 59 67q139 155 176 234h193q37 -79 176 -234l59 -67v-27h-121q-85 56 -211 186 q-133 -136 -211 -186h-120zM326 662h573q0 305 -272 305q-275 0 -301 -305z" /> +<glyph unicode="ë" d="M133 541q0 266 135.5 421.5t362.5 155.5q212 0 338.5 -134t126.5 -357v-113h-774q8 -375 344 -375q195 0 370 76v-160q-166 -75 -364 -75q-245 0 -392 149.5t-147 411.5zM326 662h573q0 305 -272 305q-275 0 -301 -305zM348 1395q0 102 96 102t96 -102q0 -103 -96 -103 t-96 103zM723 1395q0 102 96 102t96 -102q0 -103 -96 -103t-96 103z" /> +<glyph unicode="ì" d="M197 0v123l344 20v811l-269 21v123h451v-955l352 -20v-123h-878zM333 1548v21h219q86 -178 174 -301v-27h-121q-166 142 -272 307z" /> +<glyph unicode="í" d="M197 0v123l344 20v811l-269 21v123h451v-955l352 -20v-123h-878zM531 1241v27q94 133 174 301h219v-21q-112 -173 -272 -307h-121z" /> +<glyph unicode="î" d="M197 0v123l344 20v811l-269 21v123h451v-955l352 -20v-123h-878zM283 1241v27q25 29 59 67q139 155 176 234h193q37 -79 176 -234l59 -67v-27h-121q-85 56 -211 186q-133 -136 -211 -186h-120z" /> +<glyph unicode="ï" d="M197 0v123l344 20v811l-269 21v123h451v-955l352 -20v-123h-878zM330 1395q0 102 96 102t96 -102q0 -103 -96 -103t-96 103zM705 1395q0 102 96 102t96 -102q0 -103 -96 -103t-96 103z" /> +<glyph unicode="ð" d="M135 477q0 234 120.5 364t334.5 130q211 0 299 -119l8 4q-58 226 -242 391l-256 -153l-73 114l217 131q-104 71 -172 109l69 123q143 -70 246 -148l227 138l74 -113l-194 -117q301 -291 301 -758q0 -277 -128.5 -435t-353.5 -158q-213 0 -345 133.5t-132 363.5zM328 471 q0 -340 288 -340q154 0 221.5 99.5t67.5 295.5q0 129 -77.5 213t-213.5 84q-286 0 -286 -352z" /> +<glyph unicode="ñ" d="M160 0v1098h147l27 -148h10q103 168 336 168q389 0 389 -401v-717h-182v707q0 260 -238 260q-307 0 -307 -398v-569h-182zM260 1241q25 264 211 264q58 0 161 -56q102 -56 136 -56q80 0 106 114h105q-27 -264 -211 -264q-57 0 -157 57q-100 56 -140 56q-82 0 -107 -115 h-104z" /> +<glyph unicode="ò" d="M115 551q0 263 135.5 415t365.5 152q218 0 357 -155t139 -412q0 -265 -137 -418t-365 -153q-216 0 -355.5 155.5t-139.5 415.5zM303 551q0 -420 311 -420q310 0 310 420q0 416 -312 416q-309 0 -309 -416zM378 1548v21h219q86 -178 174 -301v-27h-121q-166 142 -272 307z " /> +<glyph unicode="ó" d="M115 551q0 263 135.5 415t365.5 152q218 0 357 -155t139 -412q0 -265 -137 -418t-365 -153q-216 0 -355.5 155.5t-139.5 415.5zM303 551q0 -420 311 -420q310 0 310 420q0 416 -312 416q-309 0 -309 -416zM498 1241v27q94 133 174 301h219v-21q-112 -173 -272 -307h-121z " /> +<glyph unicode="ô" d="M115 551q0 263 135.5 415t365.5 152q218 0 357 -155t139 -412q0 -265 -137 -418t-365 -153q-216 0 -355.5 155.5t-139.5 415.5zM278 1241v27q25 29 59 67q139 155 176 234h193q37 -79 176 -234l59 -67v-27h-121q-85 56 -211 186q-133 -136 -211 -186h-120zM303 551 q0 -420 311 -420q310 0 310 420q0 416 -312 416q-309 0 -309 -416z" /> +<glyph unicode="õ" d="M115 551q0 263 135.5 415t365.5 152q218 0 357 -155t139 -412q0 -265 -137 -418t-365 -153q-216 0 -355.5 155.5t-139.5 415.5zM254 1241q25 264 211 264q58 0 161 -56q102 -56 136 -56q80 0 106 114h105q-27 -264 -211 -264q-57 0 -157 57q-100 56 -140 56 q-82 0 -107 -115h-104zM303 551q0 -420 311 -420q310 0 310 420q0 416 -312 416q-309 0 -309 -416z" /> +<glyph unicode="ö" d="M115 551q0 263 135.5 415t365.5 152q218 0 357 -155t139 -412q0 -265 -137 -418t-365 -153q-216 0 -355.5 155.5t-139.5 415.5zM303 551q0 -420 311 -420q310 0 310 420q0 416 -312 416q-309 0 -309 -416zM323 1395q0 102 96 102t96 -102q0 -103 -96 -103t-96 103z M698 1395q0 102 96 102t96 -102q0 -103 -96 -103t-96 103z" /> +<glyph unicode="÷" d="M152 647v150h923v-150h-923zM498 373q0 125 114 125q115 0 115 -125t-115 -125q-114 0 -114 125zM498 1071q0 125 114 125q115 0 115 -125t-115 -125q-114 0 -114 125z" /> +<glyph unicode="ø" d="M115 551q0 266 133 416.5t368 150.5q128 0 236 -57l76 119l131 -84l-84 -131q137 -156 137 -414q0 -271 -134.5 -421t-367.5 -150q-129 0 -233 53l-76 -119l-131 84l84 131q-139 158 -139 422zM303 551q0 -180 53 -275l406 656q-66 35 -156 35q-161 0 -232 -103.5 t-71 -312.5zM467 164q61 -33 154 -33q161 0 232 105.5t71 314.5q0 164 -52 266z" /> +<glyph unicode="ù" d="M160 381v717h182v-707q0 -260 236 -260q161 0 235 92.5t74 304.5v570h182v-1098h-147l-27 147h-10q-105 -167 -334 -167q-391 0 -391 401zM341 1548v21h219q86 -178 174 -301v-27h-121q-166 142 -272 307z" /> +<glyph unicode="ú" d="M160 381v717h182v-707q0 -260 236 -260q161 0 235 92.5t74 304.5v570h182v-1098h-147l-27 147h-10q-105 -167 -334 -167q-391 0 -391 401zM500 1241v27q94 133 174 301h219v-21q-112 -173 -272 -307h-121z" /> +<glyph unicode="û" d="M160 381v717h182v-707q0 -260 236 -260q161 0 235 92.5t74 304.5v570h182v-1098h-147l-27 147h-10q-105 -167 -334 -167q-391 0 -391 401zM291 1241v27q25 29 59 67q139 155 176 234h193q37 -79 176 -234l59 -67v-27h-121q-85 56 -211 186q-133 -136 -211 -186h-120z" /> +<glyph unicode="ü" d="M160 381v717h182v-707q0 -260 236 -260q161 0 235 92.5t74 304.5v570h182v-1098h-147l-27 147h-10q-105 -167 -334 -167q-391 0 -391 401zM332 1395q0 102 96 102t96 -102q0 -103 -96 -103t-96 103zM707 1395q0 102 96 102t96 -102q0 -103 -96 -103t-96 103z" /> +<glyph unicode="ý" d="M82 1098h188l262 -654q82 -205 89 -290h6q23 112 90 292l239 652h189l-475 -1241q-67 -174 -156 -261.5t-246 -87.5q-86 0 -168 17v145q62 -12 136 -12q96 0 149.5 41t95.5 141l58 150zM494 1241v27q94 133 174 301h219v-21q-112 -173 -272 -307h-121z" /> +<glyph unicode="þ" d="M158 -492v2048h182v-458l-8 -148h8q110 168 322 168q201 0 315.5 -149.5t114.5 -417.5q0 -270 -115 -420.5t-315 -150.5q-207 0 -322 159h-12q12 -129 12 -162v-469h-182zM340 551q0 -227 69.5 -323.5t221.5 -96.5q272 0 272 422q0 414 -274 414q-152 0 -218.5 -88 t-70.5 -287v-41z" /> +<glyph unicode="ÿ" d="M82 1098h188l262 -654q82 -205 89 -290h6q23 112 90 292l239 652h189l-475 -1241q-67 -174 -156 -261.5t-246 -87.5q-86 0 -168 17v145q62 -12 136 -12q96 0 149.5 41t95.5 141l58 150zM338 1395q0 102 96 102t96 -102q0 -103 -96 -103t-96 103zM713 1395q0 102 96 102 t96 -102q0 -103 -96 -103t-96 103z" /> +<glyph unicode="Œ" d="M20 735q0 750 512 750q82 0 154 -23h541v-164h-398v-452h359v-162h-359v-520h398v-164h-574l-48 -10q-51 -10 -97 -10q-488 0 -488 755zM209 733q0 -590 309 -590q70 0 133 33v1112q-58 33 -131 33q-311 0 -311 -588z" /> +<glyph unicode="œ" d="M57 551q0 268 88 417.5t242 149.5q171 0 260 -217q84 217 242 217q131 0 208 -133.5t77 -357.5v-113h-439q3 -375 189 -375q108 0 204 76v-162q-94 -73 -217 -73q-87 0 -158.5 59t-101.5 162q-88 -221 -266 -221q-146 0 -237 153.5t-91 417.5zM227 551 q0 -211 39.5 -315.5t130.5 -104.5q168 0 168 410q0 426 -170 426q-90 0 -129 -103t-39 -313zM737 662h260q0 305 -123 305q-125 0 -137 -305z" /> +<glyph unicode="Ÿ" d="M33 1462h203l376 -739l381 739h201l-487 -893v-569h-187v559zM332 1733q0 102 96 102t96 -102q0 -103 -96 -103t-96 103zM707 1733q0 102 96 102t96 -102q0 -103 -96 -103t-96 103z" /> +<glyph unicode="ˆ" d="M283 1241v27q25 29 59 67q139 155 176 234h193q37 -79 176 -234l59 -67v-27h-121q-85 56 -211 186q-133 -136 -211 -186h-120z" /> +<glyph unicode="˜" d="M254 1241q25 264 211 264q58 0 161 -56q102 -56 136 -56q80 0 106 114h105q-27 -264 -211 -264q-57 0 -157 57q-100 56 -140 56q-82 0 -107 -115h-104z" /> +<glyph unicode=" " horiz-adv-x="953" /> +<glyph unicode=" " horiz-adv-x="1907" /> +<glyph unicode=" " horiz-adv-x="953" /> +<glyph unicode=" " horiz-adv-x="1907" /> +<glyph unicode=" " horiz-adv-x="635" /> +<glyph unicode=" " horiz-adv-x="476" /> +<glyph unicode=" " horiz-adv-x="317" /> +<glyph unicode=" " horiz-adv-x="317" /> +<glyph unicode=" " horiz-adv-x="238" /> +<glyph unicode=" " horiz-adv-x="381" /> +<glyph unicode=" " horiz-adv-x="105" /> +<glyph unicode="‐" d="M285 465v168h659v-168h-659z" /> +<glyph unicode="‑" d="M285 465v168h659v-168h-659z" /> +<glyph unicode="‒" d="M285 465v168h659v-168h-659z" /> +<glyph unicode="–" d="M184 465v168h860v-168h-860z" /> +<glyph unicode="—" d="M-6 465v168h1241v-168h-1241z" /> +<glyph unicode="‘" d="M446 983q54 206 177 479h157q-62 -255 -100 -501h-219z" /> +<glyph unicode="’" d="M446 961q65 266 101 501h219l14 -22q-55 -213 -176 -479h-158z" /> +<glyph unicode="‚" d="M457 -264q71 292 100 502h199l14 -23q-55 -213 -176 -479h-137z" /> +<glyph unicode="“" d="M233 983q54 206 177 479h157q-62 -255 -100 -501h-219zM659 983q54 206 177 479h157q-62 -255 -100 -501h-219z" /> +<glyph unicode="”" d="M233 961q65 266 101 501h219l14 -22q-55 -213 -176 -479h-158zM659 961q65 266 101 501h219l14 -22q-55 -213 -176 -479h-158z" /> +<glyph unicode="„" d="M244 -264q71 292 100 502h199l14 -23q-55 -213 -176 -479h-137zM670 -264q71 292 100 502h199l14 -23q-51 -197 -176 -479h-137z" /> +<glyph unicode="•" d="M379 748q0 262 235 262q236 0 236 -262q0 -128 -63.5 -195.5t-172.5 -67.5q-111 0 -173 67t-62 196z" /> +<glyph unicode="…" d="M78 111q0 139 127 139t127 -139q0 -140 -127 -140t-127 140zM487 111q0 139 127 139t127 -139q0 -140 -127 -140t-127 140zM897 111q0 139 127 139t127 -139q0 -140 -127 -140t-127 140z" /> +<glyph unicode=" " horiz-adv-x="381" /> +<glyph unicode="‹" d="M401 526v27l310 414l116 -78l-237 -348l237 -348l-116 -78z" /> +<glyph unicode="›" d="M401 193l238 348l-238 348l117 78l309 -414v-27l-309 -411z" /> +<glyph unicode=" " horiz-adv-x="476" /> +<glyph unicode="€" d="M96 502v137h148l-2 38l2 120h-148v137h160q39 262 179.5 405.5t359.5 143.5q191 0 335 -92l-79 -146q-122 74 -242 74q-136 0 -233 -99.5t-134 -285.5h432v-137h-446q0 -15 -1 -29l-1 -25v-62q0 -20 2 -42h385v-137h-367q73 -359 369 -359q136 0 268 58v-162 q-122 -59 -282 -59q-447 0 -541 522h-164z" /> +<glyph unicode="™" d="M0 1354v108h481v-108h-178v-613h-127v613h-176zM526 741v721h187l139 -534l149 534h179v-721h-127v342q0 87 10 207h-12l-154 -549h-100l-146 549h-12l10 -180v-369h-123z" /> +<glyph unicode="" horiz-adv-x="1100" d="M0 0v1100h1100v-1100h-1100z" /> +<glyph unicode="fi" d="M49 961v75l195 68v96q0 190 76.5 278.5t254.5 88.5q97 0 197 -37l-47 -141q-79 28 -143 28q-92 0 -124 -50.5t-32 -164.5v-104h246v-137h-246v-961h-182v961h-195zM854 1395q0 114 107 114q106 0 106 -114q0 -58 -31.5 -86.5t-74.5 -28.5q-107 0 -107 115zM868 0v1098 h183v-1098h-183z" /> +<glyph unicode="fl" d="M49 961v75l195 68v96q0 190 76.5 278.5t254.5 88.5q97 0 197 -37l-47 -141q-79 28 -143 28q-92 0 -124 -50.5t-32 -164.5v-104h246v-137h-246v-961h-182v961h-195zM868 0v1556h183v-1556h-183z" /> +<glyph unicode="ffi" d="M66 971v65l100 62v82q0 106 20 176.5t58.5 112.5t94.5 59.5t128 17.5q49 0 92.5 -11t77.5 -24q38 29 89 42.5t114 13.5q52 0 97.5 -11.5t82.5 -25.5l-41 -131q-29 11 -63.5 19.5t-71.5 8.5q-38 0 -65.5 -11t-45.5 -37t-26.5 -69.5t-8.5 -107.5v-104h367v-1098h-164v971 h-203v-971h-163v971h-205v-971h-164v971h-100zM330 1098h205v102q0 115 24 193q-20 6 -42.5 10t-45.5 4q-35 0 -61.5 -11t-44 -37t-26.5 -69.5t-9 -107.5v-84z" /> +<glyph unicode="ffl" d="M66 971v65l100 62v82q0 106 20 176.5t58.5 112.5t94.5 59.5t128 17.5q49 0 92.5 -11t77.5 -24q38 29 89 42.5t114 13.5q48 0 94 -11h131v-1556h-164v1421q-14 3 -28.5 4.5t-28.5 1.5q-38 0 -65.5 -11t-45.5 -37t-26.5 -69.5t-8.5 -107.5v-104h142v-127h-142v-971h-163 v971h-205v-971h-164v971h-100zM330 1098h205v102q0 115 24 193q-20 6 -42.5 10t-45.5 4q-35 0 -61.5 -11t-44 -37t-26.5 -69.5t-9 -107.5v-84z" /> +</font> +</defs></svg> \ No newline at end of file diff --git a/refs/pull/405/merge/_static/fonts/droidsansmono-webfont.ttf b/refs/pull/405/merge/_static/fonts/droidsansmono-webfont.ttf new file mode 100644 index 00000000..b06166f7 Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/droidsansmono-webfont.ttf differ diff --git a/refs/pull/405/merge/_static/fonts/droidsansmono-webfont.woff b/refs/pull/405/merge/_static/fonts/droidsansmono-webfont.woff new file mode 100644 index 00000000..2f0b1618 Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/droidsansmono-webfont.woff differ diff --git a/refs/pull/405/merge/_static/fonts/generator_config.txt b/refs/pull/405/merge/_static/fonts/generator_config.txt new file mode 100644 index 00000000..b3e2b92f --- /dev/null +++ b/refs/pull/405/merge/_static/fonts/generator_config.txt @@ -0,0 +1,5 @@ +# Font Squirrel Font-face Generator Configuration File +# Upload this file to the generator to recreate the settings +# you used to create these fonts. + +{"mode":"optimal","formats":["ttf","woff","eotz"],"tt_instructor":"default","fix_vertical_metrics":"Y","fix_gasp":"xy","add_spaces":"Y","add_hyphens":"Y","fallback":"none","fallback_custom":"100","options_subset":"basic","subset_custom":"","subset_custom_range":"","css_stylesheet":"stylesheet.css","filename_suffix":"-webfont","emsquare":"2048","spacing_adjustment":"0"} \ No newline at end of file diff --git a/refs/pull/405/merge/_static/fonts/opensans-italic-webfont.eot b/refs/pull/405/merge/_static/fonts/opensans-italic-webfont.eot new file mode 100644 index 00000000..bf9e21ae Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/opensans-italic-webfont.eot differ diff --git a/refs/pull/405/merge/_static/fonts/opensans-italic-webfont.svg b/refs/pull/405/merge/_static/fonts/opensans-italic-webfont.svg new file mode 100644 index 00000000..ff52169a --- /dev/null +++ b/refs/pull/405/merge/_static/fonts/opensans-italic-webfont.svg @@ -0,0 +1,244 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata></metadata> +<defs> +<font id="OpenSansItalic" horiz-adv-x="1128" > +<font-face units-per-em="2048" ascent="1638" descent="-410" /> +<missing-glyph horiz-adv-x="532" /> +<glyph unicode="fi" horiz-adv-x="1165" d="M-229 -330q64 -22 112 -22q76 0 117 62t66 177l227 1082h-193l13 67l206 66l23 100q46 200 127.5 282.5t241.5 82.5q40 0 98 -11.5t90 -25.5l-43 -129q-76 29 -137 29q-87 0 -133.5 -48.5t-75.5 -177.5l-25 -108h238l-25 -127h-237l-232 -1098q-39 -189 -120 -276 t-213 -87q-69 0 -125 21v141zM702 0l234 1096h168l-234 -1096h-168zM983 1376q0 56 32 91.5t83 35.5q88 0 88 -90q0 -55 -33.5 -93t-77.5 -38q-40 0 -66 24.5t-26 69.5z" /> +<glyph unicode="fl" horiz-adv-x="1165" d="M-229 -330q64 -22 112 -22q76 0 117 62t66 177l227 1082h-193l13 67l206 66l23 100q46 200 127.5 282.5t241.5 82.5q40 0 98 -11.5t90 -25.5l-43 -129q-76 29 -137 29q-87 0 -133.5 -48.5t-75.5 -177.5l-25 -108h238l-25 -127h-237l-232 -1098q-39 -189 -120 -276 t-213 -87q-69 0 -125 21v141zM700 0l332 1556h168l-332 -1556h-168z" /> +<glyph unicode="ffi" horiz-adv-x="1815" d="M-229 -330q64 -22 112 -22q70 0 114 58t69 181l227 1082h-193l13 67l206 66l23 100q46 200 127.5 282.5t241.5 82.5q40 0 98 -11.5t90 -25.5l-43 -129q-76 29 -137 29q-87 0 -133.5 -48.5t-75.5 -177.5l-25 -108h482l24 108q45 197 126 280t243 83q41 0 97.5 -11 t92.5 -26l-45 -129q-76 29 -137 29q-89 0 -135 -51t-74 -175l-24 -108h239l-26 -127h-238l-231 -1098q-43 -195 -123.5 -279t-210.5 -84q-71 0 -125 21v141q61 -22 115 -22q68 0 111 57.5t69 181.5l227 1082h-481l-232 -1098q-39 -189 -120 -276t-213 -87q-69 0 -125 21v141 zM1354 0l233 1096h168l-233 -1096h-168zM1634 1376q0 54 32 90.5t83 36.5q88 0 88 -90q0 -55 -33.5 -93t-77.5 -38q-38 0 -65 24.5t-27 69.5z" /> +<glyph unicode="ffl" horiz-adv-x="1815" d="M-229 -330q64 -22 112 -22q70 0 114 58t69 181l227 1082h-193l13 67l206 66l23 100q46 200 127.5 282.5t241.5 82.5q40 0 98 -11.5t90 -25.5l-43 -129q-76 29 -137 29q-87 0 -133.5 -48.5t-75.5 -177.5l-25 -108h482l24 108q45 197 126 280t243 83q41 0 97.5 -11 t92.5 -26l-45 -129q-76 29 -137 29q-89 0 -135 -51t-74 -175l-24 -108h239l-26 -127h-238l-231 -1098q-43 -195 -123.5 -279t-210.5 -84q-71 0 -125 21v141q61 -22 115 -22q68 0 111 57.5t69 181.5l227 1082h-481l-232 -1098q-39 -189 -120 -276t-213 -87q-69 0 -125 21v141 zM1352 0l331 1556h168l-331 -1556h-168z" /> +<glyph horiz-adv-x="0" /> +<glyph horiz-adv-x="2048" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="	" horiz-adv-x="532" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="!" horiz-adv-x="530" d="M43 78q0 76 39.5 120t107.5 44q45 0 73 -27.5t28 -81.5q0 -68 -39 -115t-105 -47q-49 0 -76.5 28t-27.5 79zM172 403q49 307 176 1059h207l-274 -1059h-109z" /> +<glyph unicode=""" horiz-adv-x="791" d="M225 934l72 528h188l-153 -528h-107zM573 934l72 528h189l-154 -528h-107z" /> +<glyph unicode="#" horiz-adv-x="1323" d="M63 430l13 129h284l101 340h-277l13 127h301l123 436h139l-125 -436h305l127 436h133l-125 -436h264l-12 -127h-291l-98 -340h285l-13 -129h-309l-125 -430h-139l129 430h-303l-127 -430h-133l121 430h-261zM500 559h303l96 340h-303z" /> +<glyph unicode="$" d="M72 176v154q82 -41 175.5 -63.5t166.5 -22.5l98 452q-139 49 -201.5 123.5t-62.5 188.5q0 159 108 255t299 113l39 176h133l-39 -178q159 -12 283 -76l-63 -135q-121 63 -248 72l-94 -440q149 -55 212.5 -125t63.5 -178q0 -162 -112.5 -263t-309.5 -123l-49 -225h-133 l49 223q-195 14 -315 72zM401 1010q0 -53 34.5 -97.5t107.5 -70.5l84 393q-108 -11 -167 -69t-59 -156zM549 250q107 13 170 75t63 154q0 54 -33 96t-114 74z" /> +<glyph unicode="%" horiz-adv-x="1624" d="M168 860q0 166 50.5 318.5t136.5 228.5t200 76q116 0 176 -72t60 -205q0 -108 -32 -237.5t-82.5 -217.5t-120.5 -137t-157 -49q-109 0 -170 75t-61 220zM231 0l1086 1462h151l-1085 -1462h-152zM307 864q0 -172 107 -172q52 0 94 39.5t73.5 114t50.5 175t19 171.5 q0 166 -108 166q-66 0 -119 -63t-85 -187.5t-32 -243.5zM909 274q0 166 50.5 318.5t136.5 228.5t200 76q116 0 176 -71.5t60 -204.5q0 -107 -31.5 -236t-82 -217.5t-121 -138t-156.5 -49.5q-110 0 -171 74.5t-61 219.5zM1049 279q0 -173 106 -173q65 0 117 65t86.5 198.5 t34.5 236.5q0 166 -109 166q-67 0 -119.5 -64.5t-84 -188.5t-31.5 -240z" /> +<glyph unicode="&" horiz-adv-x="1372" d="M66 342q0 148 90 257.5t303 211.5q-103 165 -103 309q0 164 106 264.5t281 100.5q149 0 236.5 -79t87.5 -212q0 -78 -32.5 -137t-87.5 -108t-127.5 -90t-153.5 -83l278 -389q127 110 199 295h168q-101 -236 -283 -412l203 -270h-201l-117 166q-120 -100 -230 -143 t-247 -43q-168 0 -269 96t-101 266zM229 354q0 -106 66.5 -170.5t175.5 -64.5q87 0 168 33t195 124l-306 433q-128 -67 -184 -116t-85.5 -107.5t-29.5 -131.5zM516 1118q0 -120 82 -235q139 71 191 110t83 85t31 104q0 77 -42.5 121.5t-123.5 44.5q-105 0 -163 -60t-58 -170 z" /> +<glyph unicode="'" horiz-adv-x="444" d="M225 934l72 528h188l-153 -528h-107z" /> +<glyph unicode="(" horiz-adv-x="584" d="M82 272q0 339 120 627t384 563h157q-246 -270 -371.5 -570t-125.5 -618q0 -339 114 -598h-131q-147 266 -147 596z" /> +<glyph unicode=")" horiz-adv-x="584" d="M-160 -324q496 551 496 1188q0 341 -113 598h131q146 -269 146 -598q0 -341 -121.5 -629.5t-382.5 -558.5h-156z" /> +<glyph unicode="*" horiz-adv-x="1130" d="M215 1194l55 154l371 -185l41 400l172 -35l-123 -383l422 18l-8 -157l-393 47l180 -383l-166 -52l-113 406l-258 -344l-116 121l309 284z" /> +<glyph unicode="+" d="M127 651v142h389v391h141v-391h390v-142h-390v-387h-141v387h-389z" /> +<glyph unicode="," horiz-adv-x="492" d="M-100 -264q126 286 204 502h187l8 -23q-113 -235 -270 -479h-129z" /> +<glyph unicode="-" horiz-adv-x="639" d="M55 469l35 158h479l-34 -158h-480z" /> +<glyph unicode="." horiz-adv-x="518" d="M43 74q0 77 40.5 122.5t111.5 45.5q43 0 69.5 -26t26.5 -79q0 -71 -40 -118.5t-108 -47.5q-46 0 -73 26t-27 77z" /> +<glyph unicode="/" horiz-adv-x="717" d="M-94 0l813 1462h174l-813 -1462h-174z" /> +<glyph unicode="0" d="M121 477q0 270 82 514.5t216.5 369t307.5 124.5q365 0 365 -471q0 -295 -78.5 -539t-214 -369.5t-314.5 -125.5q-176 0 -270 127.5t-94 369.5zM293 479q0 -172 50 -264t161 -92q115 0 209 114t150.5 328t56.5 453q0 323 -203 323q-113 0 -209 -115.5t-155.5 -323 t-59.5 -423.5z" /> +<glyph unicode="1" d="M303 1178l449 284h149l-313 -1462h-172l196 913q59 261 88 359q-50 -53 -139 -111l-178 -110z" /> +<glyph unicode="2" d="M12 0l31 147l465 420q102 93 176.5 163.5t123 133t72 124t23.5 136.5q0 99 -60 157t-163 58q-77 0 -150.5 -28.5t-162.5 -96.5l-82 115q191 154 413 154q176 0 278.5 -88.5t102.5 -243.5q0 -111 -39.5 -204t-131 -197t-294.5 -281l-352 -307v-8h678l-29 -154h-899z" /> +<glyph unicode="3" d="M47 59v164q94 -49 199 -75.5t190 -26.5q162 0 252 79.5t90 217.5q0 131 -79 198.5t-220 67.5h-131l31 143h139q165 0 274 87t109 227q0 92 -58 146t-157 54q-80 0 -157 -27t-175 -93l-80 118q195 144 424 144q179 0 277 -87t98 -237q0 -156 -101 -264.5t-280 -140.5v-9 q124 -23 195 -106.5t71 -208.5q0 -133 -62 -234.5t-181 -158.5t-283 -57q-210 0 -385 79z" /> +<glyph unicode="4" d="M16 334l29 158l834 978h196l-207 -983h232l-33 -153h-233l-72 -334h-164l74 334h-656zM219 487h486q46 220 78 373t116 445h-8q-17 -29 -66.5 -96.5t-72.5 -96.5z" /> +<glyph unicode="5" d="M80 59v164q164 -102 334 -102q191 0 298 96t107 268q0 126 -73.5 199.5t-204.5 73.5q-48 0 -97 -6.5t-139 -30.5l-74 57l197 684h668l-33 -153h-522l-127 -439q87 23 184 23q182 0 289.5 -104.5t107.5 -282.5q0 -161 -73 -283t-204 -182.5t-308 -60.5q-193 0 -330 79z " /> +<glyph unicode="6" d="M133 424q0 209 60.5 415t163.5 351.5t246 219t327 73.5q111 0 184 -23l-35 -145q-68 22 -170 22q-212 0 -356.5 -149t-212.5 -443h8q59 79 146.5 126t193.5 47q154 0 244 -98.5t90 -270.5q0 -161 -66.5 -294.5t-180.5 -204t-261 -70.5q-182 0 -281.5 115t-99.5 329z M299 416q0 -137 60.5 -216t172.5 -79q94 0 167.5 54t114 149t40.5 208q0 248 -221 248q-66 0 -128 -28.5t-110 -76t-72 -104.5t-24 -155z" /> +<glyph unicode="7" d="M174 0l768 1313h-719l31 149h891l-27 -139l-764 -1323h-180z" /> +<glyph unicode="8" d="M96 346q0 148 95 256t296 184q-95 69 -135.5 144.5t-40.5 171.5q0 111 54.5 198.5t153.5 136t222 48.5q174 0 271.5 -86.5t97.5 -235.5q0 -129 -78 -225t-266 -176q127 -78 180 -165t53 -202q0 -122 -60 -217.5t-172.5 -146.5t-264.5 -51q-190 0 -298 98.5t-108 267.5z M270 354q0 -107 69 -170t181 -63q139 0 222 74t83 196q0 99 -52 174t-165 135q-185 -60 -261.5 -143.5t-76.5 -202.5zM479 1100q0 -82 39 -144t127 -116q161 60 228 131.5t67 173.5q0 90 -57.5 143t-153.5 53q-114 0 -182 -65.5t-68 -175.5z" /> +<glyph unicode="9" d="M98 14v158q134 -47 246 -47q202 0 327 141t189 441h-10q-51 -75 -132.5 -118.5t-180.5 -43.5q-169 0 -261 98.5t-92 288.5q0 153 64.5 280.5t180 199t259.5 71.5q180 0 279.5 -114.5t99.5 -334.5q0 -194 -56 -406.5t-147.5 -360t-221.5 -217.5t-302 -70q-136 0 -242 34z M350 938q0 -124 54.5 -190t162.5 -66q76 0 140 28.5t108.5 81.5t65 114t20.5 151q0 131 -59 207.5t-160 76.5q-150 0 -241 -113t-91 -290z" /> +<glyph unicode=":" horiz-adv-x="518" d="M43 74q0 77 40.5 122.5t111.5 45.5q43 0 69.5 -26t26.5 -79q0 -71 -40 -118.5t-108 -47.5q-46 0 -73 26t-27 77zM203 956q0 77 40 122.5t111 45.5q97 0 97 -104q0 -73 -41.5 -119.5t-106.5 -46.5q-46 0 -73 26.5t-27 75.5z" /> +<glyph unicode=";" horiz-adv-x="518" d="M-100 -264q126 286 204 502h187l8 -23q-113 -235 -270 -479h-129zM203 956q0 77 40 122.5t111 45.5q97 0 97 -104q0 -73 -41.5 -119.5t-106.5 -46.5q-46 0 -73 26.5t-27 75.5z" /> +<glyph unicode="<" d="M121 664v98l919 479v-149l-747 -371l747 -328v-151z" /> +<glyph unicode="=" d="M127 444v142h920v-142h-920zM127 858v139h920v-139h-920z" /> +<glyph unicode=">" d="M121 242v151l745 328l-745 371v149l919 -479v-98z" /> +<glyph unicode="?" horiz-adv-x="874" d="M158 74q0 77 40 122.5t111 45.5q44 0 70.5 -26t26.5 -79q0 -73 -41.5 -119.5t-106.5 -46.5q-46 0 -73 26t-27 77zM197 1382q92 51 192 76t182 25q167 0 259 -84t92 -238q0 -123 -65.5 -226.5t-225.5 -223.5q-125 -91 -169 -147.5t-67 -160.5h-135q22 130 72.5 213.5 t165.5 174.5q128 100 168 144t63 94t23 112q0 93 -51.5 143.5t-147.5 50.5q-81 0 -155 -25.5t-140 -56.5z" /> +<glyph unicode="@" horiz-adv-x="1735" d="M111 504q0 261 126.5 485.5t343.5 347.5t486 123q191 0 329 -75.5t210.5 -213.5t72.5 -319q0 -179 -55 -324t-155 -227t-222 -82q-197 0 -213 184h-8q-111 -184 -291 -184q-115 0 -180.5 75.5t-65.5 209.5q0 157 68 284t188.5 199t260.5 72q65 0 127.5 -12t150.5 -48 q-64 -242 -98 -368t-31 -172q0 -117 102 -117q78 0 141.5 67t100.5 183.5t37 243.5q0 239 -128 367t-370 128q-228 0 -406.5 -107t-277 -295.5t-98.5 -416.5q0 -270 143.5 -418.5t409.5 -148.5q197 0 420 86v-127q-219 -90 -443 -90q-314 0 -494.5 184.5t-180.5 505.5z M639 518q0 -93 33 -134.5t98 -41.5q187 0 272 315l70 258q-63 23 -127 23q-94 0 -174 -55t-126 -153t-46 -212z" /> +<glyph unicode="A" horiz-adv-x="1137" d="M-117 0l799 1462h174l184 -1462h-170l-57 465h-496l-245 -465h-189zM401 621h394l-35 299q-24 179 -29 350q-37 -88 -80.5 -175t-249.5 -474z" /> +<glyph unicode="B" horiz-adv-x="1225" d="M86 0l309 1462h375q432 0 432 -336q0 -141 -87 -238t-245 -126v-10q115 -32 176.5 -110.5t61.5 -188.5q0 -212 -152 -332.5t-407 -120.5h-463zM287 145h266q181 0 278 80.5t97 227.5q0 116 -74.5 177.5t-214.5 61.5h-236zM434 836h248q156 0 249 73t93 199 q0 104 -66.5 155.5t-209.5 51.5h-211z" /> +<glyph unicode="C" horiz-adv-x="1198" d="M150 537q0 261 105.5 485.5t283.5 342.5t403 118q197 0 348 -80l-69 -141q-138 69 -279 69q-174 0 -311.5 -97t-218 -284.5t-80.5 -408.5q0 -187 97.5 -298.5t268.5 -111.5q139 0 322 57v-149q-86 -31 -164 -45t-188 -14q-242 0 -380 149.5t-138 407.5z" /> +<glyph unicode="D" horiz-adv-x="1364" d="M86 0l309 1462h342q276 0 419.5 -149.5t143.5 -435.5q0 -261 -105 -461t-300 -308t-457 -108h-352zM287 147h162q202 0 355 91.5t234.5 258.5t81.5 382t-103 325.5t-302 110.5h-178z" /> +<glyph unicode="E" horiz-adv-x="1047" d="M86 0l309 1462h735l-32 -153h-566l-98 -469h527l-29 -152h-529l-114 -536h565l-33 -152h-735z" /> +<glyph unicode="F" horiz-adv-x="967" d="M86 0l309 1462h735l-30 -153h-568l-110 -533h528l-32 -153h-529l-131 -623h-172z" /> +<glyph unicode="G" horiz-adv-x="1386" d="M150 528q0 269 101.5 489.5t281.5 343t399 122.5q117 0 219.5 -20t206.5 -64l-66 -152q-77 34 -165.5 59t-194.5 25q-169 0 -307.5 -101.5t-215.5 -283.5t-77 -407q0 -190 102.5 -299t286.5 -109q154 0 260 39l96 444h-289l33 152h459l-154 -711q-216 -75 -419 -75 q-264 0 -410.5 144.5t-146.5 403.5z" /> +<glyph unicode="H" horiz-adv-x="1389" d="M86 0l309 1462h170l-131 -622h660l133 622h168l-310 -1462h-167l143 688h-660l-145 -688h-170z" /> +<glyph unicode="I" horiz-adv-x="559" d="M86 0l311 1462h168l-311 -1462h-168z" /> +<glyph unicode="J" horiz-adv-x="547" d="M-319 -360l6 147q69 -20 145 -20q100 0 165.5 62.5t90.5 182.5l307 1450h170l-309 -1468q-79 -379 -422 -379q-105 0 -153 25z" /> +<glyph unicode="K" horiz-adv-x="1141" d="M86 0l309 1462h170l-151 -710l700 710h209l-639 -637l350 -825h-186q-72 181 -146.5 359.5t-146.5 361.5l-174 -131l-125 -590h-170z" /> +<glyph unicode="L" horiz-adv-x="971" d="M86 0l309 1462h170l-276 -1308h565l-33 -154h-735z" /> +<glyph unicode="M" horiz-adv-x="1714" d="M84 0l309 1462h244l149 -1204h9l659 1204h266l-303 -1462h-174q126 590 193 905.5t94 392.5h-6l-717 -1298h-131l-166 1296h-8q-7 -72 -28.5 -197.5t-37.5 -199.5l-190 -899h-162z" /> +<glyph unicode="N" horiz-adv-x="1438" d="M84 0l309 1462h180l459 -1220h6q30 224 72 405l174 815h164l-309 -1462h-181l-460 1223h-6q-32 -221 -74 -418l-172 -805h-162z" /> +<glyph unicode="O" horiz-adv-x="1475" d="M150 549q0 264 96 482t263.5 336t377.5 118q244 0 384 -154t140 -424q0 -269 -88 -481.5t-252 -329t-379 -116.5q-256 0 -399 149.5t-143 419.5zM332 553q0 -199 98 -310.5t266 -111.5q152 0 272.5 97.5t190.5 279.5t70 403q0 199 -94 310.5t-261 111.5q-157 0 -281 -101 t-192.5 -281t-68.5 -398z" /> +<glyph unicode="P" horiz-adv-x="1159" d="M86 0l309 1462h330q214 0 324 -94.5t110 -282.5q0 -248 -164 -379t-481 -131h-135l-123 -575h-170zM410 721h133q216 0 328 91t112 267q0 125 -69.5 180.5t-213.5 55.5h-163z" /> +<glyph unicode="Q" horiz-adv-x="1475" d="M150 549q0 264 96 482t263.5 336t377.5 118q244 0 384 -154t140 -424q0 -333 -139 -576t-375 -321l274 -358h-219l-227 330l-17 -2h-16q-256 0 -399 149.5t-143 419.5zM332 553q0 -199 98 -310.5t266 -111.5q158 0 279 100t187.5 280.5t66.5 399.5q0 199 -94 310.5 t-261 111.5q-157 0 -281 -101t-192.5 -281t-68.5 -398z" /> +<glyph unicode="R" horiz-adv-x="1165" d="M86 0l309 1462h320q446 0 446 -366q0 -348 -368 -449l239 -647h-186l-209 608h-252l-129 -608h-170zM416 754h168q193 0 297 85t104 244q0 121 -67.5 175.5t-219.5 54.5h-166q-102 -494 -116 -559z" /> +<glyph unicode="S" horiz-adv-x="1028" d="M39 43v170q162 -84 340 -84q162 0 257 75.5t95 207.5q0 78 -52.5 137.5t-195.5 140.5q-151 85 -209.5 170t-58.5 201q0 187 132 304.5t347 117.5q99 0 184.5 -19t180.5 -65l-66 -150q-66 38 -148 60t-151 22q-134 0 -215.5 -69.5t-81.5 -188.5q0 -54 17 -92.5t54 -72.5 t142 -95q147 -88 198.5 -138t78 -110.5t26.5 -140.5q0 -211 -140.5 -327.5t-395.5 -116.5q-106 0 -186.5 14.5t-151.5 48.5z" /> +<glyph unicode="T" horiz-adv-x="1020" d="M186 1311l33 151h985l-30 -151h-408l-279 -1311h-172l277 1311h-406z" /> +<glyph unicode="U" horiz-adv-x="1384" d="M164 383q0 81 24 201l189 878h170l-191 -891q-22 -106 -22 -188q0 -117 73 -184.5t218 -67.5q172 0 267.5 87.5t139.5 289.5l205 954h170l-205 -966q-55 -263 -197.5 -389.5t-388.5 -126.5q-230 0 -341 104t-111 299z" /> +<glyph unicode="V" horiz-adv-x="1122" d="M188 1462h170l97 -930q20 -196 20 -335h4q61 144 162 338l479 927h191l-781 -1462h-180z" /> +<glyph unicode="W" horiz-adv-x="1745" d="M223 1462h170l31 -901l2 -88q0 -98 -10 -258h6q89 243 156 383l405 864h178l43 -860q9 -153 9 -304l-1 -83h9q75 224 131 354l387 893h182l-664 -1462h-170l-49 965q-8 136 -8 282h-6q-25 -72 -61 -154.5t-504 -1092.5h-174z" /> +<glyph unicode="X" horiz-adv-x="1063" d="M-104 0l596 776l-263 686h172l203 -563l443 563h186l-555 -694l278 -768h-180l-213 641l-481 -641h-186z" /> +<glyph unicode="Y" horiz-adv-x="1030" d="M188 1462h170l179 -747l489 747h193l-627 -921l-113 -541h-172l119 549z" /> +<glyph unicode="Z" horiz-adv-x="1087" d="M-16 0l28 137l924 1170h-655l32 155h858l-26 -139l-924 -1169h697l-33 -154h-901z" /> +<glyph unicode="[" horiz-adv-x="586" d="M-16 -324l381 1786h387l-31 -141h-227l-318 -1503h227l-32 -142h-387z" /> +<glyph unicode="\" horiz-adv-x="717" d="M221 1462h154l217 -1462h-154z" /> +<glyph unicode="]" horiz-adv-x="586" d="M-150 -324l31 142h225l320 1503h-227l30 141h389l-380 -1786h-388z" /> +<glyph unicode="^" horiz-adv-x="1059" d="M53 553l598 920h109l266 -920h-145l-201 747l-467 -747h-160z" /> +<glyph unicode="_" horiz-adv-x="807" d="M-188 -324l30 140h811l-30 -140h-811z" /> +<glyph unicode="`" horiz-adv-x="1135" d="M575 1548v21h181q43 -136 147 -303v-25h-104q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="a" horiz-adv-x="1157" d="M98 350q0 208 71 386t196 279t274 101q92 0 164 -49.5t112 -142.5h11l67 172h127l-233 -1096h-133l26 209h-8q-179 -229 -377 -229q-139 0 -218 99t-79 271zM270 346q0 -114 47 -170.5t132 -56.5q97 0 193 92.5t156 241t60 297.5q0 103 -56 164t-147 61 q-104 0 -193.5 -86t-140.5 -233t-51 -310z" /> +<glyph unicode="b" horiz-adv-x="1182" d="M59 0l330 1556h168q-51 -242 -78.5 -370.5t-75.5 -300.5h9q93 118 183.5 173.5t186.5 55.5q141 0 220 -99t79 -272q0 -209 -68.5 -386.5t-191 -277t-276.5 -99.5q-97 0 -170.5 51t-110.5 139h-10l-70 -170h-125zM319 346q0 -110 55.5 -168.5t160.5 -58.5q99 0 184.5 81 t137.5 230.5t52 317.5q0 227 -178 227q-96 0 -195.5 -95t-158 -239t-58.5 -295z" /> +<glyph unicode="c" horiz-adv-x="922" d="M98 389q0 200 74 369t204.5 263.5t293.5 94.5q137 0 268 -51l-47 -141q-120 51 -219 51q-112 0 -204.5 -76.5t-145 -213t-52.5 -296.5q0 -128 66.5 -199t183.5 -71q72 0 136 20t126 47v-143q-124 -63 -276 -63q-194 0 -301 107t-107 302z" /> +<glyph unicode="d" horiz-adv-x="1182" d="M98 350q0 214 72 392t194.5 275t274.5 97q194 0 281 -190h10q17 155 45 274l78 358h166l-330 -1556h-139l22 209h-8q-101 -125 -189 -177t-182 -52q-139 0 -217 98t-78 272zM270 346q0 -227 179 -227q94 0 194 93.5t158.5 239t58.5 296.5q0 111 -54 169t-157 58 q-101 0 -187.5 -82.5t-139 -232t-52.5 -314.5z" /> +<glyph unicode="e" horiz-adv-x="1010" d="M98 391q0 188 74.5 360.5t197.5 268.5t271 96q153 0 230 -66.5t77 -185.5q0 -180 -166 -282.5t-475 -102.5h-33l-4 -80q0 -131 61.5 -204.5t190.5 -73.5q63 0 129.5 18t165.5 66v-146q-94 -44 -166 -61.5t-159 -17.5q-184 0 -289 109t-105 302zM299 618h12 q228 0 349.5 59.5t121.5 172.5q0 53 -36.5 88t-114.5 35q-103 0 -193.5 -94t-138.5 -261z" /> +<glyph unicode="f" horiz-adv-x="641" d="M-229 -330q64 -22 112 -22q76 0 117 62t66 177l227 1082h-193l13 67l206 66l23 100q46 200 127.5 282.5t241.5 82.5q40 0 98 -11.5t90 -25.5l-43 -129q-76 29 -137 29q-87 0 -133.5 -48.5t-75.5 -177.5l-25 -108h238l-25 -127h-237l-232 -1098q-39 -189 -120 -276 t-213 -87q-69 0 -125 21v141z" /> +<glyph unicode="g" horiz-adv-x="1026" d="M-127 -211q0 105 72 182t233 131q-78 41 -78 121q0 69 51 118.5t142 92.5q-63 32 -103 94.5t-40 145.5q0 194 119.5 318t305.5 124q78 0 154 -20h371l-25 -107l-211 -24q41 -62 41 -158q0 -191 -116.5 -304.5t-311.5 -113.5q-55 0 -84 8q-139 -53 -139 -131 q0 -41 33 -54.5t96 -21.5l117 -14q181 -22 262.5 -88t81.5 -194q0 -184 -146 -285t-411 -101q-194 0 -304 73.5t-110 207.5zM35 -195q0 -77 65 -122t193 -45q182 0 284.5 63.5t102.5 179.5q0 62 -54 98t-184 50l-159 16q-120 -25 -184 -88t-64 -152zM313 680 q0 -85 45 -129.5t125 -44.5q79 0 138 42t90.5 115.5t31.5 159.5q0 82 -44 125t-126 43q-78 0 -136.5 -40.5t-91 -113t-32.5 -157.5z" /> +<glyph unicode="h" horiz-adv-x="1182" d="M59 0l330 1556h168q-18 -82 -34.5 -159t-34 -156.5t-38 -166.5t-47.5 -189h11q94 123 185.5 176t191.5 53q131 0 202.5 -72t71.5 -204q0 -62 -23 -166q-39 -193 -145 -672h-168l148 692q18 94 18 135q0 148 -147 148q-89 0 -173.5 -59t-149 -171.5t-97.5 -271.5 l-101 -473h-168z" /> +<glyph unicode="i" horiz-adv-x="520" d="M59 0l234 1096h168l-234 -1096h-168zM340 1376q0 56 32 91.5t83 35.5q88 0 88 -90q0 -55 -33.5 -93t-77.5 -38q-40 0 -66 24.5t-26 69.5z" /> +<glyph unicode="j" horiz-adv-x="520" d="M-258 -330q61 -22 119 -22q125 0 168 205l264 1243h166l-266 -1258q-36 -171 -114.5 -250.5t-213.5 -79.5q-69 0 -123 21v141zM340 1376q0 56 32 91.5t83 35.5q86 0 86 -90q0 -55 -33.5 -93t-77.5 -38q-38 0 -64 24.5t-26 69.5z" /> +<glyph unicode="k" horiz-adv-x="999" d="M57 0l330 1556h170l-129 -602t-102 -395h4l526 537h201l-469 -467l295 -629h-187l-235 524l-152 -123l-82 -401h-170z" /> +<glyph unicode="l" horiz-adv-x="520" d="M57 0l332 1556h168l-332 -1556h-168z" /> +<glyph unicode="m" horiz-adv-x="1786" d="M59 0l234 1096h139l-22 -203h10q87 119 173.5 171t178.5 52q113 0 174 -65t72 -181h8q86 125 183 185.5t196 60.5q127 0 196.5 -68t69.5 -198q0 -68 -22 -178l-144 -672h-170l148 692q20 104 20 146q0 62 -34.5 99.5t-108.5 37.5q-81 0 -160 -58t-138.5 -164.5 t-90.5 -252.5l-107 -500h-168l148 692q18 94 18 135q0 70 -31 109t-106 39q-84 0 -163.5 -60t-140 -171.5t-93.5 -268.5l-101 -475h-168z" /> +<glyph unicode="n" horiz-adv-x="1182" d="M59 0l234 1096h139l-22 -203h10q96 122 185.5 172.5t185.5 50.5q127 0 200.5 -69.5t73.5 -194.5q0 -79 -23 -180l-143 -672h-170l148 692q20 104 20 144q0 63 -35.5 101t-113.5 38q-89 0 -173.5 -60t-149 -171t-97.5 -269l-101 -475h-168z" /> +<glyph unicode="o" horiz-adv-x="1149" d="M98 406q0 190 73 357.5t197 257t275 89.5q190 0 300 -112.5t110 -309.5q0 -188 -72 -355t-195 -258t-278 -91q-192 0 -301 113t-109 309zM270 397q0 -131 63.5 -202.5t182.5 -71.5q104 0 187 73t129.5 207.5t46.5 307.5q0 115 -62.5 186.5t-169.5 71.5q-109 0 -195.5 -74 t-134 -205.5t-47.5 -292.5z" /> +<glyph unicode="p" horiz-adv-x="1182" d="M-43 -492l336 1588h139l-26 -209h8q179 227 372 227q137 0 216 -97.5t79 -273.5q0 -212 -69 -389t-191 -275.5t-276 -98.5q-97 0 -170 50t-113 140h-10l-4 -38q-3 -25 -10.5 -70t-114.5 -554h-166zM319 346q0 -110 55.5 -168.5t160.5 -58.5q99 0 184.5 81t137.5 230.5 t52 317.5q0 227 -178 227q-96 0 -195.5 -95t-158 -239t-58.5 -295z" /> +<glyph unicode="q" horiz-adv-x="1182" d="M98 350q0 212 72.5 392t196 277t274.5 97q94 0 165.5 -50.5t108.5 -141.5h13l67 172h125l-336 -1588h-166l101 480q9 45 57 221h-8q-95 -121 -185 -175t-186 -54q-140 0 -219.5 97.5t-79.5 272.5zM270 346q0 -227 179 -227q92 0 190 92t158.5 237t60.5 300 q0 105 -54.5 166t-152.5 61q-101 0 -189 -84.5t-140 -233t-52 -311.5z" /> +<glyph unicode="r" horiz-adv-x="811" d="M59 0l234 1096h139l-22 -203h10q72 95 119 136.5t98.5 64t114.5 22.5q69 0 120 -14l-36 -150q-53 13 -105 13q-91 0 -170.5 -60t-139 -166.5t-87.5 -236.5l-107 -502h-168z" /> +<glyph unicode="s" horiz-adv-x="877" d="M8 49v158q70 -42 151 -65t150 -23q126 0 190 50t64 128q0 57 -35 96t-151 107q-130 73 -184 143t-54 166q0 138 101 222.5t266 84.5q171 0 330 -74l-54 -137l-56 25q-101 43 -220 43q-93 0 -146 -43.5t-53 -112.5q0 -56 35.5 -96t146.5 -103q107 -60 153.5 -103 t69.5 -92.5t23 -111.5q0 -156 -110.5 -243.5t-311.5 -87.5q-169 0 -305 69z" /> +<glyph unicode="t" horiz-adv-x="664" d="M90 969l14 73l185 78l125 228h98l-55 -252h274l-26 -127h-273l-129 -604q-18 -87 -18 -132q0 -56 29 -86t81 -30q55 0 144 26v-129q-34 -14 -84 -24t-80 -10q-125 0 -191.5 59.5t-66.5 177.5q0 66 18 150l127 602h-172z" /> +<glyph unicode="u" horiz-adv-x="1182" d="M113 248q0 62 22 172l146 676h170l-150 -695q-18 -89 -18 -139q0 -143 147 -143q88 0 173 60t150 172t99 270l100 475h166l-231 -1096h-139l22 203h-12q-98 -125 -187 -174t-184 -49q-128 0 -201 69.5t-73 198.5z" /> +<glyph unicode="v" horiz-adv-x="946" d="M98 1096h168l64 -613q24 -258 24 -362h6q127 275 179 371l325 604h178l-591 -1096h-228z" /> +<glyph unicode="w" horiz-adv-x="1468" d="M117 1096h164l18 -594v-88q0 -147 -8 -269h6q47 124 137 322l295 629h182l37 -594q6 -168 6 -262v-53l-2 -42h6q28 86 83 218.5t323 732.5h178l-506 -1096h-205l-32 602q-4 94 -4 172v156h-9l-50 -118l-83 -189l-291 -623h-202z" /> +<glyph unicode="x" horiz-adv-x="979" d="M-74 0l475 565l-239 531h170l174 -412l330 412h194l-455 -539l252 -557h-168l-192 434l-346 -434h-195z" /> +<glyph unicode="y" horiz-adv-x="946" d="M-197 -336q63 -18 131 -18q82 0 140.5 50.5t113.5 149.5l76 136l-166 1114h168l74 -545q10 -69 19.5 -203.5t9.5 -216.5h6q35 87 87 200t77 156l325 609h178l-696 -1282q-93 -172 -184 -239t-219 -67q-72 0 -140 21v135z" /> +<glyph unicode="z" horiz-adv-x="909" d="M-29 0l23 117l694 854h-479l27 125h657l-29 -140l-680 -831h531l-25 -125h-719z" /> +<glyph unicode="{" horiz-adv-x="715" d="M27 514l32 143q118 0 189.5 43.5t93.5 147.5l68 326q34 160 117.5 224t254.5 64h33l-31 -141q-105 0 -151 -36.5t-66 -123.5l-71 -321q-28 -123 -91 -184t-167 -78v-5q151 -41 151 -213q0 -59 -18 -131l-47 -211q-15 -58 -15 -98q0 -53 36.5 -77.5t119.5 -24.5v-142h-23 q-141 0 -216.5 52.5t-75.5 171.5q0 52 20 141q33 146 51.5 227.5t14.5 102.5q0 143 -209 143z" /> +<glyph unicode="|" d="M541 -496v2052h139v-2052h-139z" /> +<glyph unicode="}" horiz-adv-x="715" d="M-74 -182q115 0 167 36t71 123l72 322q25 117 88 179.5t170 80.5v6q-150 42 -150 211q0 59 18 131l50 213q14 65 14 99q0 53 -40.5 77.5t-139.5 24.5l28 141h11q144 0 220.5 -52.5t76.5 -170.5q0 -48 -21 -141l-49 -219q-16 -68 -16 -111q0 -143 209 -143l-33 -144 q-119 0 -190 -43t-93 -147l-67 -326q-36 -164 -119 -226.5t-264 -62.5h-13v142z" /> +<glyph unicode="~" d="M115 592v151q98 109 243 109q69 0 127 -14.5t144 -51.5q64 -27 112.5 -41t98.5 -14q55 0 119.5 33t115.5 88v-150q-100 -110 -244 -110q-72 0 -135 16.5t-135 48.5q-75 32 -120 44t-93 12q-54 0 -118.5 -34.5t-114.5 -86.5z" /> +<glyph unicode="¡" horiz-adv-x="530" d="M-14 -373l274 1057h109l-176 -1057h-207zM250 950q0 76 40.5 122t110.5 46q44 0 70.5 -26t26.5 -80q0 -71 -40.5 -117.5t-105.5 -46.5q-48 0 -75 25.5t-27 76.5z" /> +<glyph unicode="¢" d="M225 590q0 185 63.5 344t178.5 258.5t260 120.5l35 170h123l-37 -168q119 -9 217 -49l-47 -142q-109 52 -219 52q-112 0 -204.5 -76.5t-145 -213t-52.5 -296.5q0 -125 66 -198t184 -73q72 0 136 20t126 48v-143q-123 -62 -286 -66l-41 -198h-125l43 215 q-132 34 -203.5 137.5t-71.5 257.5z" /> +<glyph unicode="£" d="M-23 0l27 141q205 46 258 289l47 221h-200l26 127h201l76 350q75 353 430 353q184 0 336 -86l-66 -133q-146 79 -278 79q-213 0 -263 -237l-69 -326h370l-26 -127h-371l-47 -219q-22 -98 -66 -166.5t-124 -111.5h725l-33 -154h-953z" /> +<glyph unicode="¤" d="M168 1067l92 92l127 -129q103 70 217 70t215 -70l129 129l92 -90l-129 -129q70 -104 70 -217q0 -119 -70 -217l127 -127l-90 -90l-129 127q-98 -68 -215 -68q-119 0 -217 70l-127 -127l-90 90l127 127q-68 96 -68 215q0 117 68 215zM358 723q0 -103 71.5 -174.5 t174.5 -71.5q104 0 177 71.5t73 174.5q0 104 -73 177t-177 73q-102 0 -174 -72.5t-72 -177.5z" /> +<glyph unicode="¥" d="M127 266l29 133h290l33 160h-291l29 133h225l-202 770h163l179 -747l491 747h187l-533 -770h231l-28 -133h-297l-33 -160h297l-29 -133h-295l-57 -266h-154l56 266h-291z" /> +<glyph unicode="¦" d="M541 281h139v-777h-139v777zM541 780v776h139v-776h-139z" /> +<glyph unicode="§" horiz-adv-x="995" d="M59 53v148q56 -34 136.5 -56t156.5 -22q133 0 204 44.5t71 129.5q0 48 -50.5 89t-152.5 87q-138 61 -194 130.5t-56 166.5q0 201 238 307q-119 70 -119 203q0 127 103.5 206t279.5 79q189 0 321 -68l-53 -123q-148 60 -266 60q-102 0 -162.5 -40.5t-60.5 -109.5 q0 -49 38 -83.5t162 -90.5q100 -44 149 -83.5t75 -89.5t26 -114q0 -97 -61 -180t-172 -139q114 -71 114 -189q0 -152 -114 -237.5t-318 -85.5q-176 0 -295 61zM326 791q0 -70 50.5 -117t198.5 -111q80 44 127.5 107t47.5 131q0 60 -49.5 105.5t-186.5 103.5 q-82 -26 -135 -87.5t-53 -131.5z" /> +<glyph unicode="¨" horiz-adv-x="1135" d="M457 1378q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM821 1378q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="©" horiz-adv-x="1704" d="M139 731q0 200 100 375t275 276t377 101q197 0 370 -97t277 -272t104 -383q0 -204 -100.5 -376.5t-273 -273.5t-377.5 -101q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM244 731q0 -173 87 -323.5t237.5 -237t322.5 -86.5q174 0 323 87t236.5 235.5t87.5 324.5 q0 174 -87 323t-235.5 236.5t-324.5 87.5q-174 0 -323 -87t-236.5 -235.5t-87.5 -324.5zM520 733q0 208 110 330.5t300 122.5q130 0 248 -60l-60 -120q-106 53 -190 53q-125 0 -191.5 -87t-66.5 -241q0 -169 65 -249.5t193 -80.5q82 0 211 43v-122q-66 -28 -113 -38 t-104 -10q-192 0 -297 119.5t-105 339.5z" /> +<glyph unicode="ª" horiz-adv-x="686" d="M170 1014q0 127 41.5 234.5t116.5 169t170 61.5q114 0 153 -103h6l37 90h86l-139 -665h-92l14 117h-4q-40 -56 -90 -93t-123 -37q-77 0 -126.5 60t-49.5 166zM283 1030q0 -139 98 -139q61 0 112.5 49t86 137.5t34.5 167.5q0 62 -28.5 96.5t-85.5 34.5q-92 0 -154.5 -103 t-62.5 -243z" /> +<glyph unicode="«" horiz-adv-x="958" d="M88 555v29l391 374l78 -81l-297 -328l172 -387l-113 -49zM483 510v31l367 405l86 -69l-283 -365l158 -350l-113 -49z" /> +<glyph unicode="¬" d="M127 651v142h920v-529h-140v387h-780z" /> +<glyph unicode="­" horiz-adv-x="639" d="M55 469l35 158h479l-34 -158h-480z" /> +<glyph unicode="®" horiz-adv-x="1704" d="M139 731q0 200 100 375t275 276t377 101q197 0 370 -97t277 -272t104 -383q0 -204 -100.5 -376.5t-273 -273.5t-377.5 -101q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM244 731q0 -173 87 -323.5t237.5 -237t322.5 -86.5q174 0 323 87t236.5 235.5t87.5 324.5 q0 174 -87 323t-235.5 236.5t-324.5 87.5q-174 0 -323 -87t-236.5 -235.5t-87.5 -324.5zM645 291v880h229q163 0 241.5 -63t78.5 -193q0 -78 -47.5 -141t-132.5 -98l227 -385h-149l-207 352h-113v-352h-127zM772 762h92q195 0 195 149q0 76 -47.5 107t-149.5 31h-90v-287z " /> +<glyph unicode="¯" horiz-adv-x="782" d="M227 1556l33 132h787l-35 -132h-785z" /> +<glyph unicode="°" horiz-adv-x="877" d="M215 1171q0 128 90.5 220t220.5 92q83 0 155.5 -41.5t114.5 -114t42 -156.5q0 -128 -90.5 -218.5t-221.5 -90.5t-221 90.5t-90 218.5zM328 1171q0 -80 58 -138t140 -58q83 0 140 58.5t57 137.5q0 82 -57.5 140.5t-139.5 58.5q-80 0 -139 -58.5t-59 -140.5z" /> +<glyph unicode="±" d="M127 0v141h920v-141h-920zM127 643v141h389v392h141v-392h390v-141h-390v-387h-141v387h-389z" /> +<glyph unicode="²" horiz-adv-x="717" d="M96 586l23 106l264 228q115 100 158.5 149.5t63.5 93t20 90.5q0 53 -31 85t-90 32q-90 0 -195 -80l-59 90q125 101 274 101q109 0 171.5 -56.5t62.5 -150.5q0 -99 -52.5 -179.5t-197.5 -205.5l-221 -187h395l-25 -116h-561z" /> +<glyph unicode="³" horiz-adv-x="717" d="M119 625v127q125 -72 239 -72q205 0 205 170q0 137 -178 137h-90l22 107h95q97 0 155 41t58 112q0 60 -34.5 90.5t-93.5 30.5q-102 0 -196 -68l-55 93q109 88 268 88q114 0 178 -56t64 -151q0 -180 -207 -234v-4q69 -17 108 -68t39 -120q0 -132 -91 -205.5t-253 -73.5 q-125 0 -233 56z" /> +<glyph unicode="´" horiz-adv-x="1135" d="M532 1241v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="µ" horiz-adv-x="1194" d="M-43 -492l336 1588h168l-148 -695q-18 -92 -18 -135q0 -147 147 -147q89 0 172 59t148.5 171t99.5 269l105 478h163l-233 -1096h-139l24 205h-12q-93 -121 -183 -173t-188 -52q-112 0 -163 96h-9q-11 -78 -22.5 -148t-83.5 -420h-164z" /> +<glyph unicode="¶" horiz-adv-x="1341" d="M199 1042q0 260 109 387t341 127h557v-1816h-114v1661h-213v-1661h-115v819q-62 -18 -146 -18q-216 0 -317.5 125t-101.5 376z" /> +<glyph unicode="·" horiz-adv-x="518" d="M170 690q0 77 40.5 122.5t111.5 45.5q43 0 69.5 -26t26.5 -79q0 -71 -40 -118.5t-108 -47.5q-46 0 -73 26t-27 77z" /> +<glyph unicode="¸" horiz-adv-x="420" d="M-170 -383q38 -6 68 -6q174 0 174 110q0 46 -39 67.5t-99 29.5l101 182h106l-61 -121q131 -38 131 -155q0 -98 -81 -157t-214 -59q-41 0 -86 9v100z" /> +<glyph unicode="¹" horiz-adv-x="717" d="M258 1280l279 182h118l-186 -876h-135l112 526q25 103 58 225q-25 -25 -50 -46.5t-145 -100.5z" /> +<glyph unicode="º" horiz-adv-x="688" d="M168 1055q0 117 42 215.5t117.5 153.5t174.5 55q117 0 180 -67t63 -193q0 -191 -88.5 -311t-240.5 -120q-113 0 -180.5 71t-67.5 196zM281 1059q0 -85 38 -127.5t107 -42.5q94 0 152.5 88.5t58.5 232.5q0 166 -137 166q-102 0 -160.5 -87.5t-58.5 -229.5z" /> +<glyph unicode="»" horiz-adv-x="958" d="M23 197l282 360l-158 354l113 50l217 -402v-31l-368 -401zM401 197l297 323l-172 391l113 50l233 -447v-29l-393 -370z" /> +<glyph unicode="¼" horiz-adv-x="1518" d="M123 0l1085 1462h154l-1086 -1462h-153zM204 1280l279 182h118l-186 -876h-135l112 526q25 103 58 225q-25 -25 -50 -46.5t-145 -100.5zM706 203l23 101l481 579h133l-121 -563h127l-22 -117h-129l-43 -202h-127l43 202h-365zM870 320h225q69 322 90 395 q-20 -36 -110 -149z" /> +<glyph unicode="½" horiz-adv-x="1518" d="M66 0l1085 1462h154l-1086 -1462h-153zM148 1280l279 182h118l-186 -876h-135l112 526q25 103 58 225q-25 -25 -50 -46.5t-145 -100.5zM782 1l23 106l264 228q115 100 158.5 149.5t63.5 93t20 90.5q0 53 -31 85t-90 32q-90 0 -195 -80l-59 90q125 101 274 101 q109 0 171.5 -56.5t62.5 -150.5q0 -99 -52.5 -179.5t-197.5 -205.5l-221 -187h395l-25 -116h-561z" /> +<glyph unicode="¾" horiz-adv-x="1565" d="M87 625v127q125 -72 239 -72q205 0 205 170q0 137 -178 137h-90l22 107h95q97 0 155 41t58 112q0 60 -34.5 90.5t-93.5 30.5q-102 0 -196 -68l-55 93q109 88 268 88q114 0 178 -56t64 -151q0 -180 -207 -234v-4q69 -17 108 -68t39 -120q0 -132 -91 -205.5t-253 -73.5 q-125 0 -233 56zM273 0l1085 1462h154l-1086 -1462h-153zM856 203l23 101l481 579h133l-121 -563h127l-22 -117h-129l-43 -202h-127l43 202h-365zM1020 320h225q69 322 90 395q-20 -36 -110 -149z" /> +<glyph unicode="¿" horiz-adv-x="874" d="M-4 -78q0 124 66 228t225 223q132 98 172.5 152.5t62.5 154.5h135q-22 -130 -72 -212t-165 -175l-95 -75q-159 -127 -159 -275q0 -93 51.5 -144t147.5 -51q80 0 154 25.5t140 56.5l62 -129q-90 -48 -189 -74t-186 -26q-168 0 -259 83.5t-91 237.5zM512 946q0 71 40 118.5 t107 47.5q47 0 74 -25.5t27 -76.5q0 -77 -40.5 -122.5t-111.5 -45.5q-43 0 -69.5 26t-26.5 78z" /> +<glyph unicode="À" horiz-adv-x="1137" d="M-117 0l799 1462h174l184 -1462h-170l-57 465h-496l-245 -465h-189zM401 621h394l-35 299q-24 179 -29 350q-37 -88 -80.5 -175t-249.5 -474zM535 1886v21h181q43 -136 147 -303v-25h-104q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="Á" horiz-adv-x="1137" d="M-117 0l799 1462h174l184 -1462h-170l-57 465h-496l-245 -465h-189zM401 621h394l-35 299q-24 179 -29 350q-37 -88 -80.5 -175t-249.5 -474zM679 1579v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="Â" horiz-adv-x="1137" d="M-117 0l799 1462h174l184 -1462h-170l-57 465h-496l-245 -465h-189zM401 621h394l-35 299q-24 179 -29 350q-37 -88 -80.5 -175t-249.5 -474zM465 1579v27q145 133 204.5 197.5t82.5 103.5h158q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189 h-109z" /> +<glyph unicode="Ã" horiz-adv-x="1137" d="M-117 0l799 1462h174l184 -1462h-170l-57 465h-496l-245 -465h-189zM401 621h394l-35 299q-24 179 -29 350q-37 -88 -80.5 -175t-249.5 -474zM432 1579q58 258 231 258q44 0 83.5 -18t75 -39.5t66.5 -39.5t58 -18q44 0 69.5 27t51.5 90h100q-66 -258 -233 -258 q-40 0 -77.5 17.5t-73 39t-69 39t-65.5 17.5q-44 0 -69.5 -28.5t-47.5 -86.5h-100z" /> +<glyph unicode="Ä" horiz-adv-x="1137" d="M-117 0l799 1462h174l184 -1462h-170l-57 465h-496l-245 -465h-189zM401 621h394l-35 299q-24 179 -29 350q-37 -88 -80.5 -175t-249.5 -474zM523 1716q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM887 1716q0 46 28 79.5 t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="Å" horiz-adv-x="1137" d="M-117 0l799 1462h174l184 -1462h-170l-57 465h-496l-245 -465h-189zM401 621h394l-35 299q-24 179 -29 350q-37 -88 -80.5 -175t-249.5 -474zM553 1583q0 94 62 152.5t157 58.5q101 0 160 -57t59 -152q0 -99 -60 -157t-159 -58q-101 0 -160 57.5t-59 155.5zM657 1583 q0 -54 29.5 -84.5t85.5 -30.5q51 0 83 30.5t32 84.5q0 53 -32 84t-83 31q-49 0 -82 -31t-33 -84z" /> +<glyph unicode="Æ" horiz-adv-x="1673" d="M-119 0l938 1462h938l-33 -153h-565l-100 -469h528l-28 -150h-529l-115 -538h566l-33 -152h-737l98 465h-438l-293 -465h-197zM469 621h371l147 688h-84z" /> +<glyph unicode="Ç" horiz-adv-x="1198" d="M150 537q0 261 105.5 485.5t283.5 342.5t403 118q197 0 348 -80l-69 -141q-138 69 -279 69q-174 0 -311.5 -97t-218 -284.5t-80.5 -408.5q0 -187 97.5 -298.5t268.5 -111.5q139 0 322 57v-149q-86 -31 -164 -45t-188 -14q-242 0 -380 149.5t-138 407.5zM377 -383 q38 -6 68 -6q174 0 174 110q0 46 -39 67.5t-99 29.5l101 182h106l-61 -121q131 -38 131 -155q0 -98 -81 -157t-214 -59q-41 0 -86 9v100z" /> +<glyph unicode="È" horiz-adv-x="1047" d="M86 0l309 1462h735l-32 -153h-566l-98 -469h527l-29 -152h-529l-114 -536h565l-33 -152h-735zM570 1886v21h181q43 -136 147 -303v-25h-104q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="É" horiz-adv-x="1047" d="M86 0l309 1462h735l-32 -153h-566l-98 -469h527l-29 -152h-529l-114 -536h565l-33 -152h-735zM657 1579v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="Ê" horiz-adv-x="1047" d="M86 0l309 1462h735l-32 -153h-566l-98 -469h527l-29 -152h-529l-114 -536h565l-33 -152h-735zM469 1579v27q145 133 204.5 197.5t82.5 103.5h158q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="Ë" horiz-adv-x="1047" d="M86 0l309 1462h735l-32 -153h-566l-98 -469h527l-29 -152h-529l-114 -536h565l-33 -152h-735zM523 1716q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM887 1716q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34 q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="Ì" horiz-adv-x="559" d="M86 0l311 1462h168l-311 -1462h-168zM265 1886v21h181q43 -136 147 -303v-25h-104q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="Í" horiz-adv-x="559" d="M86 0l311 1462h168l-311 -1462h-168zM412 1579v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="Î" horiz-adv-x="559" d="M86 0l311 1462h168l-311 -1462h-168zM193 1579v27q145 133 204.5 197.5t82.5 103.5h158q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="Ï" horiz-adv-x="559" d="M86 0l311 1462h168l-311 -1462h-168zM265 1716q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM629 1716q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="Ð" horiz-adv-x="1364" d="M72 649l32 150h150l141 663h342q276 0 419.5 -149.5t143.5 -435.5q0 -261 -105 -461t-300 -308t-457 -108h-352l135 649h-149zM287 147h162q202 0 355 91.5t234.5 258.5t81.5 382t-103 325.5t-302 110.5h-178l-111 -516h330l-33 -150h-330z" /> +<glyph unicode="Ñ" horiz-adv-x="1438" d="M84 0l309 1462h180l459 -1220h6q30 224 72 405l174 815h164l-309 -1462h-181l-460 1223h-6q-32 -221 -74 -418l-172 -805h-162zM600 1579q58 258 231 258q44 0 83.5 -18t75 -39.5t66.5 -39.5t58 -18q44 0 69.5 27t51.5 90h100q-66 -258 -233 -258q-40 0 -77.5 17.5 t-73 39t-69 39t-65.5 17.5q-44 0 -69.5 -28.5t-47.5 -86.5h-100z" /> +<glyph unicode="Ò" horiz-adv-x="1475" d="M150 549q0 264 96 482t263.5 336t377.5 118q244 0 384 -154t140 -424q0 -269 -88 -481.5t-252 -329t-379 -116.5q-256 0 -399 149.5t-143 419.5zM332 553q0 -199 98 -310.5t266 -111.5q152 0 272.5 97.5t190.5 279.5t70 403q0 199 -94 310.5t-261 111.5q-157 0 -281 -101 t-192.5 -281t-68.5 -398zM679 1886v21h181q43 -136 147 -303v-25h-104q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="Ó" horiz-adv-x="1475" d="M150 549q0 264 96 482t263.5 336t377.5 118q244 0 384 -154t140 -424q0 -269 -88 -481.5t-252 -329t-379 -116.5q-256 0 -399 149.5t-143 419.5zM332 553q0 -199 98 -310.5t266 -111.5q152 0 272.5 97.5t190.5 279.5t70 403q0 199 -94 310.5t-261 111.5q-157 0 -281 -101 t-192.5 -281t-68.5 -398zM821 1579v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="Ô" horiz-adv-x="1475" d="M150 549q0 264 96 482t263.5 336t377.5 118q244 0 384 -154t140 -424q0 -269 -88 -481.5t-252 -329t-379 -116.5q-256 0 -399 149.5t-143 419.5zM332 553q0 -199 98 -310.5t266 -111.5q152 0 272.5 97.5t190.5 279.5t70 403q0 199 -94 310.5t-261 111.5q-157 0 -281 -101 t-192.5 -281t-68.5 -398zM612 1579v27q145 133 204.5 197.5t82.5 103.5h158q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="Õ" horiz-adv-x="1475" d="M150 549q0 264 96 482t263.5 336t377.5 118q244 0 384 -154t140 -424q0 -269 -88 -481.5t-252 -329t-379 -116.5q-256 0 -399 149.5t-143 419.5zM332 553q0 -199 98 -310.5t266 -111.5q152 0 272.5 97.5t190.5 279.5t70 403q0 199 -94 310.5t-261 111.5q-157 0 -281 -101 t-192.5 -281t-68.5 -398zM565 1579q58 258 231 258q44 0 83.5 -18t75 -39.5t66.5 -39.5t58 -18q44 0 69.5 27t51.5 90h100q-66 -258 -233 -258q-40 0 -77.5 17.5t-73 39t-69 39t-65.5 17.5q-44 0 -69.5 -28.5t-47.5 -86.5h-100z" /> +<glyph unicode="Ö" horiz-adv-x="1475" d="M150 549q0 264 96 482t263.5 336t377.5 118q244 0 384 -154t140 -424q0 -269 -88 -481.5t-252 -329t-379 -116.5q-256 0 -399 149.5t-143 419.5zM332 553q0 -199 98 -310.5t266 -111.5q152 0 272.5 97.5t190.5 279.5t70 403q0 199 -94 310.5t-261 111.5q-157 0 -281 -101 t-192.5 -281t-68.5 -398zM664 1716q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM1028 1716q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="×" d="M168 1044l98 99l320 -320l323 320l99 -96l-324 -324l322 -322l-97 -96l-323 320l-320 -318l-96 96l317 320z" /> +<glyph unicode="Ø" horiz-adv-x="1475" d="M119 8l137 170q-106 136 -106 371q0 264 96 482t263.5 336t377.5 118q99 0 178.5 -27t151.5 -84l131 166l114 -92l-149 -184q48 -62 73 -156t25 -201q0 -269 -88 -481.5t-252 -329t-379 -116.5q-200 0 -332 96l-129 -160zM332 553q0 -135 41 -227l737 919q-90 88 -236 88 q-157 0 -281 -101t-192.5 -281t-68.5 -398zM463 205q91 -74 233 -74q152 0 272.5 97.5t190.5 279.5t70 403q0 118 -33 205z" /> +<glyph unicode="Ù" horiz-adv-x="1384" d="M164 383q0 81 24 201l189 878h170l-191 -891q-22 -106 -22 -188q0 -117 73 -184.5t218 -67.5q172 0 267.5 87.5t139.5 289.5l205 954h170l-205 -966q-55 -263 -197.5 -389.5t-388.5 -126.5q-230 0 -341 104t-111 299zM663 1886v21h181q43 -136 147 -303v-25h-104 q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="Ú" horiz-adv-x="1384" d="M164 383q0 81 24 201l189 878h170l-191 -891q-22 -106 -22 -188q0 -117 73 -184.5t218 -67.5q172 0 267.5 87.5t139.5 289.5l205 954h170l-205 -966q-55 -263 -197.5 -389.5t-388.5 -126.5q-230 0 -341 104t-111 299zM823 1579v27q56 60 125.5 151.5t106.5 149.5h190v-21 q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="Û" horiz-adv-x="1384" d="M164 383q0 81 24 201l189 878h170l-191 -891q-22 -106 -22 -188q0 -117 73 -184.5t218 -67.5q172 0 267.5 87.5t139.5 289.5l205 954h170l-205 -966q-55 -263 -197.5 -389.5t-388.5 -126.5q-230 0 -341 104t-111 299zM602 1579v27q145 133 204.5 197.5t82.5 103.5h158 q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="Ü" horiz-adv-x="1384" d="M164 383q0 81 24 201l189 878h170l-191 -891q-22 -106 -22 -188q0 -117 73 -184.5t218 -67.5q172 0 267.5 87.5t139.5 289.5l205 954h170l-205 -966q-55 -263 -197.5 -389.5t-388.5 -126.5q-230 0 -341 104t-111 299zM643 1716q0 46 28 79.5t74 33.5q78 0 78 -80 q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM1007 1716q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="Ý" horiz-adv-x="1030" d="M188 1462h170l179 -747l489 747h193l-627 -921l-113 -541h-172l119 549zM616 1579v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="Þ" horiz-adv-x="1159" d="M86 0l309 1462h170l-53 -256h160q213 0 323.5 -95t110.5 -282q0 -248 -164 -379t-483 -131h-133l-70 -319h-170zM354 465h135q215 0 328 91t113 267q0 126 -70 181t-215 55h-166z" /> +<glyph unicode="ß" horiz-adv-x="1182" d="M-256 -328q61 -22 111 -22q65 0 107 47.5t65 157.5l280 1314q43 200 156 299t307 99q162 0 252 -71t90 -196q0 -57 -21 -106.5t-61.5 -95t-178.5 -150.5q-110 -83 -110 -151q0 -56 95 -122q47 -34 101 -87.5t79.5 -110t25.5 -123.5q0 -175 -108.5 -274.5t-292.5 -99.5 q-175 0 -268 71v160q51 -41 118.5 -66.5t129.5 -25.5q113 0 181 58t68 159q0 40 -10.5 71t-33.5 59t-89 83q-88 69 -122.5 124t-34.5 115q0 53 18.5 96t49.5 78.5t124 104.5q80 56 111 87.5t48 65t17 70.5q0 64 -52.5 100.5t-141.5 36.5q-119 0 -186 -62.5t-95 -190.5 l-274 -1303q-40 -189 -121 -276t-211 -87q-69 0 -123 21v143z" /> +<glyph unicode="à" horiz-adv-x="1157" d="M98 350q0 208 71 386t196 279t274 101q92 0 164 -49.5t112 -142.5h11l67 172h127l-233 -1096h-133l26 209h-8q-179 -229 -377 -229q-139 0 -218 99t-79 271zM270 346q0 -114 47 -170.5t132 -56.5q97 0 193 92.5t156 241t60 297.5q0 103 -56 164t-147 61 q-104 0 -193.5 -86t-140.5 -233t-51 -310zM496 1548v21h181q43 -136 147 -303v-25h-104q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="á" horiz-adv-x="1157" d="M98 350q0 208 71 386t196 279t274 101q92 0 164 -49.5t112 -142.5h11l67 172h127l-233 -1096h-133l26 209h-8q-179 -229 -377 -229q-139 0 -218 99t-79 271zM270 346q0 -114 47 -170.5t132 -56.5q97 0 193 92.5t156 241t60 297.5q0 103 -56 164t-147 61 q-104 0 -193.5 -86t-140.5 -233t-51 -310zM600 1241v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="â" horiz-adv-x="1157" d="M98 350q0 208 71 386t196 279t274 101q92 0 164 -49.5t112 -142.5h11l67 172h127l-233 -1096h-133l26 209h-8q-179 -229 -377 -229q-139 0 -218 99t-79 271zM270 346q0 -114 47 -170.5t132 -56.5q97 0 193 92.5t156 241t60 297.5q0 103 -56 164t-147 61 q-104 0 -193.5 -86t-140.5 -233t-51 -310zM390 1241v27q145 133 204.5 197.5t82.5 103.5h158q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="ã" horiz-adv-x="1157" d="M98 350q0 208 71 386t196 279t274 101q92 0 164 -49.5t112 -142.5h11l67 172h127l-233 -1096h-133l26 209h-8q-179 -229 -377 -229q-139 0 -218 99t-79 271zM270 346q0 -114 47 -170.5t132 -56.5q97 0 193 92.5t156 241t60 297.5q0 103 -56 164t-147 61 q-104 0 -193.5 -86t-140.5 -233t-51 -310zM354 1241q58 258 231 258q44 0 83.5 -18t75 -39.5t66.5 -39.5t58 -18q44 0 69.5 27t51.5 90h100q-66 -258 -233 -258q-40 0 -77.5 17.5t-73 39t-69 39t-65.5 17.5q-44 0 -69.5 -28.5t-47.5 -86.5h-100z" /> +<glyph unicode="ä" horiz-adv-x="1157" d="M98 350q0 208 71 386t196 279t274 101q92 0 164 -49.5t112 -142.5h11l67 172h127l-233 -1096h-133l26 209h-8q-179 -229 -377 -229q-139 0 -218 99t-79 271zM270 346q0 -114 47 -170.5t132 -56.5q97 0 193 92.5t156 241t60 297.5q0 103 -56 164t-147 61 q-104 0 -193.5 -86t-140.5 -233t-51 -310zM454 1378q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM818 1378q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="å" horiz-adv-x="1157" d="M98 350q0 208 71 386t196 279t274 101q92 0 164 -49.5t112 -142.5h11l67 172h127l-233 -1096h-133l26 209h-8q-179 -229 -377 -229q-139 0 -218 99t-79 271zM270 346q0 -114 47 -170.5t132 -56.5q97 0 193 92.5t156 241t60 297.5q0 103 -56 164t-147 61 q-104 0 -193.5 -86t-140.5 -233t-51 -310zM513 1454q0 94 62 152.5t157 58.5q101 0 160 -57t59 -152q0 -99 -60 -157t-159 -58q-101 0 -160 57.5t-59 155.5zM617 1454q0 -54 29.5 -84.5t85.5 -30.5q51 0 83 30.5t32 84.5q0 53 -32 84t-83 31q-49 0 -82 -31t-33 -84z" /> +<glyph unicode="æ" horiz-adv-x="1669" d="M98 348q0 206 70.5 385t191.5 281t263 102q82 0 145 -48.5t102 -143.5h11l67 172h109l-31 -146q123 166 332 166q119 0 192.5 -68t73.5 -184q0 -182 -166.5 -283.5t-472.5 -101.5h-39l-4 -80q0 -131 62.5 -204.5t193.5 -73.5q55 0 116.5 16.5t178.5 67.5v-150 q-164 -75 -328 -75q-108 0 -189.5 39.5t-121.5 119.5l-31 -139h-114l26 209h-8q-109 -132 -191.5 -180.5t-177.5 -48.5q-122 0 -191 99t-69 269zM270 348q0 -114 37 -171.5t105 -57.5q95 0 188.5 91.5t153 240.5t59.5 299q0 103 -45.5 164t-122.5 61q-99 0 -187 -86.5 t-138 -231.5t-50 -309zM973 618h14q226 0 348.5 58.5t122.5 169.5q0 61 -35 94t-98 33q-117 0 -211 -94.5t-141 -260.5z" /> +<glyph unicode="ç" horiz-adv-x="922" d="M98 389q0 200 74 369t204.5 263.5t293.5 94.5q137 0 268 -51l-47 -141q-120 51 -219 51q-112 0 -204.5 -76.5t-145 -213t-52.5 -296.5q0 -128 66.5 -199t183.5 -71q72 0 136 20t126 47v-143q-124 -63 -276 -63q-194 0 -301 107t-107 302zM211 -383q38 -6 68 -6 q174 0 174 110q0 46 -39 67.5t-99 29.5l101 182h106l-61 -121q131 -38 131 -155q0 -98 -81 -157t-214 -59q-41 0 -86 9v100z" /> +<glyph unicode="è" horiz-adv-x="1010" d="M98 391q0 188 74.5 360.5t197.5 268.5t271 96q153 0 230 -66.5t77 -185.5q0 -180 -166 -282.5t-475 -102.5h-33l-4 -80q0 -131 61.5 -204.5t190.5 -73.5q63 0 129.5 18t165.5 66v-146q-94 -44 -166 -61.5t-159 -17.5q-184 0 -289 109t-105 302zM299 618h12 q228 0 349.5 59.5t121.5 172.5q0 53 -36.5 88t-114.5 35q-103 0 -193.5 -94t-138.5 -261zM449 1548v21h181q43 -136 147 -303v-25h-104q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="é" horiz-adv-x="1010" d="M98 391q0 188 74.5 360.5t197.5 268.5t271 96q153 0 230 -66.5t77 -185.5q0 -180 -166 -282.5t-475 -102.5h-33l-4 -80q0 -131 61.5 -204.5t190.5 -73.5q63 0 129.5 18t165.5 66v-146q-94 -44 -166 -61.5t-159 -17.5q-184 0 -289 109t-105 302zM299 618h12 q228 0 349.5 59.5t121.5 172.5q0 53 -36.5 88t-114.5 35q-103 0 -193.5 -94t-138.5 -261zM585 1241v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="ê" horiz-adv-x="1010" d="M98 391q0 188 74.5 360.5t197.5 268.5t271 96q153 0 230 -66.5t77 -185.5q0 -180 -166 -282.5t-475 -102.5h-33l-4 -80q0 -131 61.5 -204.5t190.5 -73.5q63 0 129.5 18t165.5 66v-146q-94 -44 -166 -61.5t-159 -17.5q-184 0 -289 109t-105 302zM299 618h12 q228 0 349.5 59.5t121.5 172.5q0 53 -36.5 88t-114.5 35q-103 0 -193.5 -94t-138.5 -261zM351 1241v27q145 133 204.5 197.5t82.5 103.5h158q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="ë" horiz-adv-x="1010" d="M98 391q0 188 74.5 360.5t197.5 268.5t271 96q153 0 230 -66.5t77 -185.5q0 -180 -166 -282.5t-475 -102.5h-33l-4 -80q0 -131 61.5 -204.5t190.5 -73.5q63 0 129.5 18t165.5 66v-146q-94 -44 -166 -61.5t-159 -17.5q-184 0 -289 109t-105 302zM299 618h12 q228 0 349.5 59.5t121.5 172.5q0 53 -36.5 88t-114.5 35q-103 0 -193.5 -94t-138.5 -261zM413 1378q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM777 1378q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34 q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="ì" horiz-adv-x="520" d="M59 0l234 1096h168l-234 -1096h-168zM164 1548v21h181q43 -136 147 -303v-25h-104q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="í" horiz-adv-x="520" d="M59 0l234 1096h168l-234 -1096h-168zM324 1241v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="î" horiz-adv-x="520" d="M59 0l234 1096h168l-234 -1096h-168zM93 1241v27q145 133 204.5 197.5t82.5 103.5h158q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="ï" horiz-adv-x="520" d="M59 0l234 1096h168l-234 -1096h-168zM161 1378q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM525 1378q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="ð" horiz-adv-x="1165" d="M90 373q0 160 67.5 298t187 217t267.5 79q105 0 181.5 -45.5t111.5 -124.5l6 2v17q0 136 -36.5 240t-110.5 197l-270 -149l-56 108l238 131q-66 58 -146 113l95 117q118 -84 188 -154l260 146l64 -105l-240 -133q87 -115 126.5 -240.5t39.5 -269.5q0 -253 -71.5 -447 t-203 -292t-311.5 -98q-182 0 -284.5 104t-102.5 289zM262 377q0 -126 57.5 -191t167.5 -65q107 0 190 56t134 168t51 226q0 118 -65.5 187t-178.5 69q-109 0 -189 -57.5t-123.5 -161t-43.5 -231.5z" /> +<glyph unicode="ñ" horiz-adv-x="1182" d="M59 0l234 1096h139l-22 -203h10q96 122 185.5 172.5t185.5 50.5q127 0 200.5 -69.5t73.5 -194.5q0 -79 -23 -180l-143 -672h-170l148 692q20 104 20 144q0 63 -35.5 101t-113.5 38q-89 0 -173.5 -60t-149 -171t-97.5 -269l-101 -475h-168zM369 1241q58 258 231 258 q44 0 83.5 -18t75 -39.5t66.5 -39.5t58 -18q44 0 69.5 27t51.5 90h100q-66 -258 -233 -258q-40 0 -77.5 17.5t-73 39t-69 39t-65.5 17.5q-44 0 -69.5 -28.5t-47.5 -86.5h-100z" /> +<glyph unicode="ò" horiz-adv-x="1149" d="M98 406q0 190 73 357.5t197 257t275 89.5q190 0 300 -112.5t110 -309.5q0 -188 -72 -355t-195 -258t-278 -91q-192 0 -301 113t-109 309zM270 397q0 -131 63.5 -202.5t182.5 -71.5q104 0 187 73t129.5 207.5t46.5 307.5q0 115 -62.5 186.5t-169.5 71.5q-109 0 -195.5 -74 t-134 -205.5t-47.5 -292.5zM470 1548v21h181q43 -136 147 -303v-25h-104q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="ó" horiz-adv-x="1149" d="M98 406q0 190 73 357.5t197 257t275 89.5q190 0 300 -112.5t110 -309.5q0 -188 -72 -355t-195 -258t-278 -91q-192 0 -301 113t-109 309zM270 397q0 -131 63.5 -202.5t182.5 -71.5q104 0 187 73t129.5 207.5t46.5 307.5q0 115 -62.5 186.5t-169.5 71.5q-109 0 -195.5 -74 t-134 -205.5t-47.5 -292.5zM589 1241v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="ô" horiz-adv-x="1149" d="M98 406q0 190 73 357.5t197 257t275 89.5q190 0 300 -112.5t110 -309.5q0 -188 -72 -355t-195 -258t-278 -91q-192 0 -301 113t-109 309zM270 397q0 -131 63.5 -202.5t182.5 -71.5q104 0 187 73t129.5 207.5t46.5 307.5q0 115 -62.5 186.5t-169.5 71.5q-109 0 -195.5 -74 t-134 -205.5t-47.5 -292.5zM382 1241v27q145 133 204.5 197.5t82.5 103.5h158q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="õ" horiz-adv-x="1149" d="M98 406q0 190 73 357.5t197 257t275 89.5q190 0 300 -112.5t110 -309.5q0 -188 -72 -355t-195 -258t-278 -91q-192 0 -301 113t-109 309zM270 397q0 -131 63.5 -202.5t182.5 -71.5q104 0 187 73t129.5 207.5t46.5 307.5q0 115 -62.5 186.5t-169.5 71.5q-109 0 -195.5 -74 t-134 -205.5t-47.5 -292.5zM342 1241q58 258 231 258q44 0 83.5 -18t75 -39.5t66.5 -39.5t58 -18q44 0 69.5 27t51.5 90h100q-66 -258 -233 -258q-40 0 -77.5 17.5t-73 39t-69 39t-65.5 17.5q-44 0 -69.5 -28.5t-47.5 -86.5h-100z" /> +<glyph unicode="ö" horiz-adv-x="1149" d="M98 406q0 190 73 357.5t197 257t275 89.5q190 0 300 -112.5t110 -309.5q0 -188 -72 -355t-195 -258t-278 -91q-192 0 -301 113t-109 309zM270 397q0 -131 63.5 -202.5t182.5 -71.5q104 0 187 73t129.5 207.5t46.5 307.5q0 115 -62.5 186.5t-169.5 71.5q-109 0 -195.5 -74 t-134 -205.5t-47.5 -292.5zM433 1378q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM797 1378q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="÷" d="M127 651v142h920v-142h-920zM475 373q0 121 111 121q53 0 82.5 -30.5t29.5 -90.5q0 -58 -30 -89.5t-82 -31.5t-81.5 31t-29.5 90zM475 1071q0 121 111 121q53 0 82.5 -30.5t29.5 -90.5q0 -58 -30 -89.5t-82 -31.5t-81.5 31t-29.5 90z" /> +<glyph unicode="ø" horiz-adv-x="1149" d="M61 6l109 135q-68 103 -68 265q0 194 73.5 361t195.5 255t272 88q146 0 252 -68l104 129l105 -79l-119 -129q62 -97 62 -258q0 -189 -69.5 -360t-191.5 -266t-276 -95q-146 0 -246 65l-98 -125zM264 416q0 -92 17 -137l518 645q-54 47 -152 47q-108 0 -195.5 -73 t-137.5 -202t-50 -280zM358 166q57 -45 158 -45q103 0 188.5 71.5t133 200.5t47.5 295q0 84 -13 119z" /> +<glyph unicode="ù" horiz-adv-x="1182" d="M113 248q0 62 22 172l146 676h170l-150 -695q-18 -89 -18 -139q0 -143 147 -143q88 0 173 60t150 172t99 270l100 475h166l-231 -1096h-139l22 203h-12q-98 -125 -187 -174t-184 -49q-128 0 -201 69.5t-73 198.5zM472 1548v21h181q43 -136 147 -303v-25h-104 q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="ú" horiz-adv-x="1182" d="M113 248q0 62 22 172l146 676h170l-150 -695q-18 -89 -18 -139q0 -143 147 -143q88 0 173 60t150 172t99 270l100 475h166l-231 -1096h-139l22 203h-12q-98 -125 -187 -174t-184 -49q-128 0 -201 69.5t-73 198.5zM636 1241v27q56 60 125.5 151.5t106.5 149.5h190v-21 q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="û" horiz-adv-x="1182" d="M113 248q0 62 22 172l146 676h170l-150 -695q-18 -89 -18 -139q0 -143 147 -143q88 0 173 60t150 172t99 270l100 475h166l-231 -1096h-139l22 203h-12q-98 -125 -187 -174t-184 -49q-128 0 -201 69.5t-73 198.5zM409 1241v27q145 133 204.5 197.5t82.5 103.5h158 q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="ü" horiz-adv-x="1182" d="M113 248q0 62 22 172l146 676h170l-150 -695q-18 -89 -18 -139q0 -143 147 -143q88 0 173 60t150 172t99 270l100 475h166l-231 -1096h-139l22 203h-12q-98 -125 -187 -174t-184 -49q-128 0 -201 69.5t-73 198.5zM457 1378q0 46 28 79.5t74 33.5q78 0 78 -80 q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM821 1378q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="ý" horiz-adv-x="946" d="M-197 -336q63 -18 131 -18q82 0 140.5 50.5t113.5 149.5l76 136l-166 1114h168l74 -545q10 -69 19.5 -203.5t9.5 -216.5h6q35 87 87 200t77 156l325 609h178l-696 -1282q-93 -172 -184 -239t-219 -67q-72 0 -140 21v135zM500 1241v27q56 60 125.5 151.5t106.5 149.5h190 v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="þ" horiz-adv-x="1182" d="M-43 -492l432 2048h168q-95 -441 -115 -522t-39 -149h9q101 125 189 177t183 52q139 0 218 -97.5t79 -273.5q0 -212 -69 -389t-191 -275.5t-276 -98.5q-98 0 -172 51t-113 139h-10q-8 -104 -25 -176l-102 -486h-166zM319 346q0 -110 55.5 -168.5t160.5 -58.5 q99 0 184.5 81t137.5 230.5t52 317.5q0 227 -178 227q-96 0 -195.5 -95t-158 -239t-58.5 -295z" /> +<glyph unicode="ÿ" horiz-adv-x="946" d="M-197 -336q63 -18 131 -18q82 0 140.5 50.5t113.5 149.5l76 136l-166 1114h168l74 -545q10 -69 19.5 -203.5t9.5 -216.5h6q35 87 87 200t77 156l325 609h178l-696 -1282q-93 -172 -184 -239t-219 -67q-72 0 -140 21v135zM335 1378q0 46 28 79.5t74 33.5q78 0 78 -80 q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM699 1378q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="Œ" horiz-adv-x="1751" d="M150 549q0 264 96 482t263.5 336t377.5 118q152 0 237 -23h709l-31 -153h-565l-100 -469h528l-31 -150h-528l-115 -538h565l-32 -152h-674q-78 -20 -158 -20q-256 0 -399 149.5t-143 419.5zM332 553q0 -199 98 -310.5t266 -111.5q69 0 123 19l246 1161q-76 22 -191 22 q-157 0 -281 -101t-192.5 -281t-68.5 -398z" /> +<glyph unicode="œ" horiz-adv-x="1769" d="M98 406q0 193 75 360t201 255.5t281 88.5q270 0 359 -225q75 109 177.5 170t221.5 61q139 0 217 -65.5t78 -186.5q0 -183 -164.5 -284t-468.5 -101h-41l-4 -80q0 -131 61.5 -204.5t190.5 -73.5q75 0 145 24.5t150 59.5v-150q-162 -75 -326 -75q-270 0 -356 225 q-69 -107 -171.5 -164t-225.5 -57q-184 0 -292 114t-108 308zM270 410q0 -141 62 -214t172 -73q177 0 278 160.5t101 427.5q0 124 -59.5 191t-174.5 67q-109 0 -196 -73t-135 -202t-48 -284zM1053 618h18q231 0 351 61t120 177q0 48 -32 82.5t-97 34.5q-125 0 -220.5 -94.5 t-139.5 -260.5z" /> +<glyph unicode="Ÿ" horiz-adv-x="1030" d="M188 1462h170l179 -747l489 747h193l-627 -921l-113 -541h-172l119 549zM452 1716q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM816 1716q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22 t-23.5 62z" /> +<glyph unicode="ˆ" horiz-adv-x="1135" d="M399 1241v27q145 133 204.5 197.5t82.5 103.5h158q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="˜" horiz-adv-x="1135" d="M336 1241q58 258 231 258q44 0 83.5 -18t75 -39.5t66.5 -39.5t58 -18q44 0 69.5 27t51.5 90h100q-66 -258 -233 -258q-40 0 -77.5 17.5t-73 39t-69 39t-65.5 17.5q-44 0 -69.5 -28.5t-47.5 -86.5h-100z" /> +<glyph unicode=" " horiz-adv-x="953" /> +<glyph unicode=" " horiz-adv-x="1907" /> +<glyph unicode=" " horiz-adv-x="953" /> +<glyph unicode=" " horiz-adv-x="1907" /> +<glyph unicode=" " horiz-adv-x="635" /> +<glyph unicode=" " horiz-adv-x="476" /> +<glyph unicode=" " horiz-adv-x="317" /> +<glyph unicode=" " horiz-adv-x="317" /> +<glyph unicode=" " horiz-adv-x="238" /> +<glyph unicode=" " horiz-adv-x="381" /> +<glyph unicode=" " horiz-adv-x="105" /> +<glyph unicode="‐" horiz-adv-x="639" d="M55 469l35 158h479l-34 -158h-480z" /> +<glyph unicode="‑" horiz-adv-x="639" d="M55 469l35 158h479l-34 -158h-480z" /> +<glyph unicode="‒" horiz-adv-x="639" d="M55 469l35 158h479l-34 -158h-480z" /> +<glyph unicode="–" horiz-adv-x="983" d="M55 469l35 160h823l-34 -160h-824z" /> +<glyph unicode="—" horiz-adv-x="1966" d="M55 469l35 160h1806l-34 -160h-1807z" /> +<glyph unicode="‘" horiz-adv-x="348" d="M123 983q98 211 270 479h127q-147 -345 -203 -501h-188z" /> +<glyph unicode="’" horiz-adv-x="348" d="M125 961q134 298 203 501h188l8 -22q-40 -91 -111 -218.5t-159 -260.5h-129z" /> +<glyph unicode="‚" horiz-adv-x="492" d="M-100 -264q126 286 204 502h187l8 -23q-113 -235 -270 -479h-129z" /> +<glyph unicode="“" horiz-adv-x="719" d="M123 983q98 211 270 479h127q-147 -345 -203 -501h-188zM492 983q80 181 272 479h127q-162 -379 -203 -501h-188z" /> +<glyph unicode="”" horiz-adv-x="719" d="M125 961q134 298 203 501h188l8 -22q-40 -91 -111 -218.5t-159 -260.5h-129zM494 961q57 126 115.5 272.5t86.5 228.5h189l10 -22q-94 -206 -274 -479h-127z" /> +<glyph unicode="„" horiz-adv-x="858" d="M-100 -264q126 286 204 502h187l8 -23q-113 -235 -270 -479h-129zM268 -264q140 316 203 502h188l9 -23q-95 -205 -271 -479h-129z" /> +<glyph unicode="•" horiz-adv-x="774" d="M199 684q0 145 73.5 231t198.5 86q92 0 139 -49t47 -141q0 -141 -74 -230t-202 -89q-89 0 -135.5 49.5t-46.5 142.5z" /> +<glyph unicode="…" horiz-adv-x="1563" d="M43 74q0 77 40.5 122.5t111.5 45.5q43 0 69.5 -26t26.5 -79q0 -71 -40 -118.5t-108 -47.5q-46 0 -73 26t-27 77zM563 74q0 77 40.5 122.5t111.5 45.5q43 0 69.5 -26t26.5 -79q0 -71 -40 -118.5t-108 -47.5q-46 0 -73 26t-27 77zM1085 74q0 77 40.5 122.5t111.5 45.5 q43 0 69.5 -26t26.5 -79q0 -71 -40 -118.5t-108 -47.5q-46 0 -73 26t-27 77z" /> +<glyph unicode=" " horiz-adv-x="381" /> +<glyph unicode="‹" horiz-adv-x="580" d="M88 549v29l391 380l78 -81l-297 -334l172 -381l-113 -49z" /> +<glyph unicode="›" horiz-adv-x="580" d="M23 197l296 333l-172 381l113 50l232 -437v-28l-392 -381z" /> +<glyph unicode=" " horiz-adv-x="476" /> +<glyph unicode="€" d="M63 504l27 131h154q8 80 30 164h-151l27 133h159q97 267 259.5 408t369.5 141q89 0 160 -21.5t141 -70.5l-80 -138q-113 78 -231 78q-140 0 -254 -99t-189 -298h426l-26 -133h-441q-21 -65 -32 -164h381l-29 -131h-361q0 -373 297 -373q123 0 256 55v-147 q-127 -59 -278 -59q-212 0 -328.5 133.5t-116.5 378.5v12h-170z" /> +<glyph unicode="™" horiz-adv-x="1534" d="M121 1358v104h516v-104h-199v-617h-121v617h-196zM705 741v721h180l182 -557l193 557h170v-721h-121v430q0 73 4 121h-6l-197 -551h-96l-189 551h-6q4 -52 4 -121v-430h-118z" /> +<glyph unicode="" horiz-adv-x="1095" d="M0 0v1095h1095v-1095h-1095z" /> +</font> +</defs></svg> \ No newline at end of file diff --git a/refs/pull/405/merge/_static/fonts/opensans-italic-webfont.ttf b/refs/pull/405/merge/_static/fonts/opensans-italic-webfont.ttf new file mode 100644 index 00000000..3931cd3d Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/opensans-italic-webfont.ttf differ diff --git a/refs/pull/405/merge/_static/fonts/opensans-italic-webfont.woff b/refs/pull/405/merge/_static/fonts/opensans-italic-webfont.woff new file mode 100644 index 00000000..5a6305ee Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/opensans-italic-webfont.woff differ diff --git a/refs/pull/405/merge/_static/fonts/opensans-light-webfont.eot b/refs/pull/405/merge/_static/fonts/opensans-light-webfont.eot new file mode 100644 index 00000000..48414108 Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/opensans-light-webfont.eot differ diff --git a/refs/pull/405/merge/_static/fonts/opensans-light-webfont.svg b/refs/pull/405/merge/_static/fonts/opensans-light-webfont.svg new file mode 100644 index 00000000..45d9a051 --- /dev/null +++ b/refs/pull/405/merge/_static/fonts/opensans-light-webfont.svg @@ -0,0 +1,244 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata></metadata> +<defs> +<font id="OpenSansLightRegular" horiz-adv-x="1169" > +<font-face units-per-em="2048" ascent="1638" descent="-410" /> +<missing-glyph horiz-adv-x="532" /> +<glyph unicode="fi" horiz-adv-x="1077" d="M29 1001v58l202 37v84q0 200 73.5 293.5t240.5 93.5q90 0 180 -27l-23 -86q-80 25 -159 25q-116 0 -164.5 -68.5t-48.5 -222.5v-101h256v-86h-256v-1001h-99v1001h-202zM782 1389q0 96 63 96q31 0 48.5 -25t17.5 -71q0 -45 -17.5 -71t-48.5 -26q-63 0 -63 97zM796 0v1087 h99v-1087h-99z" /> +<glyph unicode="fl" horiz-adv-x="1077" d="M29 1001v58l202 37v84q0 200 73.5 293.5t240.5 93.5q90 0 180 -27l-23 -86q-80 25 -159 25q-116 0 -164.5 -68.5t-48.5 -222.5v-101h256v-86h-256v-1001h-99v1001h-202zM796 0v1556h99v-1556h-99z" /> +<glyph unicode="ffi" horiz-adv-x="1692" d="M29 1001v58l202 37v84q0 200 73.5 293.5t240.5 93.5q90 0 180 -27l-23 -86q-80 25 -159 25q-116 0 -164.5 -68.5t-48.5 -222.5v-101h256v-86h-256v-1001h-99v1001h-202zM643 1001v58l202 37v84q0 200 73.5 293.5t240.5 93.5q90 0 180 -27l-23 -86q-80 25 -159 25 q-116 0 -164.5 -68.5t-48.5 -222.5v-101h256v-86h-256v-1001h-99v1001h-202zM1397 1389q0 96 63 96q31 0 48.5 -25t17.5 -71q0 -45 -17.5 -71t-48.5 -26q-63 0 -63 97zM1411 0v1087h99v-1087h-99z" /> +<glyph unicode="ffl" horiz-adv-x="1692" d="M29 1001v58l202 37v84q0 200 73.5 293.5t240.5 93.5q90 0 180 -27l-23 -86q-80 25 -159 25q-116 0 -164.5 -68.5t-48.5 -222.5v-101h256v-86h-256v-1001h-99v1001h-202zM643 1001v58l202 37v84q0 200 73.5 293.5t240.5 93.5q90 0 180 -27l-23 -86q-80 25 -159 25 q-116 0 -164.5 -68.5t-48.5 -222.5v-101h256v-86h-256v-1001h-99v1001h-202zM1411 0v1556h99v-1556h-99z" /> +<glyph horiz-adv-x="0" /> +<glyph horiz-adv-x="2048" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="	" horiz-adv-x="532" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="!" horiz-adv-x="492" d="M164 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98zM186 1462h119l-29 -1085h-61z" /> +<glyph unicode=""" horiz-adv-x="723" d="M133 1462h127l-33 -528h-61zM463 1462h127l-33 -528h-61z" /> +<glyph unicode="#" horiz-adv-x="1323" d="M55 451v79h299l76 398h-297v80h311l86 454h91l-89 -454h365l88 454h86l-88 -454h285v-80h-301l-76 -398h303v-79h-320l-86 -451h-90l88 451h-360l-86 -451h-88l86 451h-283zM440 530h363l78 398h-363z" /> +<glyph unicode="$" d="M164 186v103q75 -36 179.5 -61t193.5 -25v508q-145 44 -215 88t-102 104t-32 146q0 124 94.5 208.5t254.5 104.5v192h81v-190q197 -9 351 -72l-33 -90q-141 62 -318 72v-486q213 -66 293 -144t80 -204q0 -133 -99 -217t-274 -106v-236h-81v232q-92 2 -200.5 22.5 t-172.5 50.5zM297 1049q0 -86 57 -141t183 -93v453q-119 -16 -179.5 -76t-60.5 -143zM618 209q122 13 192.5 75t70.5 160q0 85 -63 140.5t-200 95.5v-471z" /> +<glyph unicode="%" horiz-adv-x="1653" d="M113 1026q0 223 72 340t212 117q139 0 215 -120.5t76 -336.5q0 -226 -75 -343.5t-216 -117.5q-133 0 -208.5 120.5t-75.5 340.5zM211 1026q0 -186 45 -279.5t141 -93.5q193 0 193 373q0 184 -49.5 276.5t-143.5 92.5q-96 0 -141 -92.5t-45 -276.5zM373 0l811 1462h96 l-811 -1462h-96zM965 438q0 225 73.5 341t212.5 116q137 0 213 -120t76 -337q0 -226 -74 -343.5t-215 -117.5q-136 0 -211 121.5t-75 339.5zM1063 438q0 -185 45 -277.5t141 -92.5q193 0 193 370q0 369 -193 369q-96 0 -141 -91.5t-45 -277.5z" /> +<glyph unicode="&" horiz-adv-x="1460" d="M123 371q0 138 73.5 235t274.5 205l-75 82q-66 71 -98 139t-32 142q0 143 95.5 227t256.5 84q155 0 245.5 -81t90.5 -224q0 -105 -70 -192.5t-253 -194.5l452 -457q61 72 104 157t75 201h96q-63 -246 -209 -426l266 -268h-135l-193 197q-92 -90 -164 -131.5t-157.5 -63.5 t-194.5 -22q-209 0 -328.5 103t-119.5 288zM227 375q0 -143 93 -224t258 -81q128 0 234.5 43.5t209.5 146.5l-483 485q-136 -72 -196.5 -122.5t-88 -109.5t-27.5 -138zM373 1176q0 -79 40 -146t152 -174q159 85 221 159t62 169q0 94 -62 152.5t-168 58.5q-114 0 -179.5 -58 t-65.5 -161z" /> +<glyph unicode="'" horiz-adv-x="393" d="M133 1462h127l-33 -528h-61z" /> +<glyph unicode="(" horiz-adv-x="557" d="M82 561q0 265 77.5 496t223.5 405h113q-148 -182 -227 -412.5t-79 -486.5q0 -483 304 -887h-111q-147 170 -224 397t-77 488z" /> +<glyph unicode=")" horiz-adv-x="557" d="M61 1462h113q147 -175 224 -406.5t77 -494.5t-77.5 -490t-223.5 -395h-111q304 404 304 887q0 257 -79 487.5t-227 411.5z" /> +<glyph unicode="*" horiz-adv-x="1128" d="M104 1124l19 131l401 -104l-39 405h146l-37 -405l405 104l21 -131l-395 -39l247 -340l-124 -71l-191 379l-180 -379l-125 71l242 340z" /> +<glyph unicode="+" d="M111 682v82h432v434h82v-434h434v-82h-434v-432h-82v432h-432z" /> +<glyph unicode="," horiz-adv-x="440" d="M68 -264q77 275 110 502h117l12 -21q-75 -265 -174 -481h-65z" /> +<glyph unicode="-" horiz-adv-x="659" d="M92 512v82h475v-82h-475z" /> +<glyph unicode="." horiz-adv-x="487" d="M162 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98z" /> +<glyph unicode="/" horiz-adv-x="698" d="M25 0l544 1462h105l-545 -1462h-104z" /> +<glyph unicode="0" d="M115 735q0 382 115.5 566t351.5 184q231 0 352 -190.5t121 -559.5q0 -385 -117.5 -570t-355.5 -185q-229 0 -348 190.5t-119 564.5zM223 735q0 -340 89 -502.5t270 -162.5q189 0 275.5 168t86.5 497q0 324 -86.5 492t-275.5 168t-274 -168t-85 -492z" /> +<glyph unicode="1" d="M199 1165l397 297h86v-1462h-98v1065q0 145 12 301q-15 -15 -31 -29t-309 -243z" /> +<glyph unicode="2" d="M113 0v88l389 406q164 170 230 260t97 172t31 172q0 131 -86 213t-223 82q-183 0 -350 -133l-54 69q183 154 406 154q191 0 300.5 -102t109.5 -281q0 -145 -73.5 -280.5t-268.5 -334.5l-375 -385v-4h782v-96h-915z" /> +<glyph unicode="3" d="M94 63v99q84 -44 188.5 -69t196.5 -25q221 0 332 89.5t111 252.5q0 145 -113.5 223t-333.5 78h-158v96h160q182 0 288.5 86.5t106.5 234.5q0 122 -86.5 195.5t-226.5 73.5q-109 0 -199 -30.5t-202 -104.5l-49 67q85 71 205 112.5t243 41.5q202 0 312 -95.5t110 -269.5 q0 -136 -85.5 -229t-229.5 -119v-6q176 -22 268 -112t92 -242q0 -205 -139.5 -317.5t-401.5 -112.5q-223 0 -389 83z" /> +<glyph unicode="4" d="M43 373v67l725 1030h121v-1011h252v-86h-252v-373h-94v373h-752zM162 459h633v418q0 302 14 507h-8q-20 -37 -123 -188z" /> +<glyph unicode="5" d="M143 63v103q108 -55 192 -76.5t179 -21.5q192 0 308 101.5t116 274.5q0 163 -113 256t-307 93q-130 0 -272 -39l-60 39l58 669h704v-96h-610l-45 -516q156 29 244 29q234 0 368.5 -113t134.5 -311q0 -225 -140 -350t-386 -125q-109 0 -207 21.5t-164 61.5z" /> +<glyph unicode="6" d="M131 623q0 285 77.5 479.5t220 288.5t343.5 94q94 0 172 -23v-88q-73 27 -176 27q-247 0 -384.5 -178t-154.5 -518h13q76 98 174 148t207 50q205 0 320.5 -117t115.5 -323q0 -224 -121.5 -353.5t-327.5 -129.5q-222 0 -350.5 169.5t-128.5 473.5zM240 504 q0 -111 49.5 -213.5t134 -162.5t186.5 -60q164 0 255 103t91 294q0 168 -90 262t-245 94q-102 0 -189.5 -45t-139.5 -119.5t-52 -152.5z" /> +<glyph unicode="7" d="M109 1366v96h946v-73l-604 -1389h-117l602 1366h-827z" /> +<glyph unicode="8" d="M121 375q0 131 83 230t257 169q-161 76 -227 160.5t-66 202.5q0 105 53 184.5t148.5 122.5t212.5 43q186 0 299.5 -95t113.5 -257q0 -112 -70.5 -198t-228.5 -159q192 -79 270 -173t78 -228q0 -181 -126.5 -289t-339.5 -108q-221 0 -339 101t-118 294zM223 360 q0 -138 93.5 -214t261.5 -76q164 0 264 80.5t100 218.5q0 124 -78.5 201.5t-302.5 162.5q-184 -71 -261 -157t-77 -216zM268 1137q0 -70 31.5 -123.5t91 -97t199.5 -101.5q163 63 234 139t71 183q0 120 -84.5 190t-230.5 70q-141 0 -226.5 -69.5t-85.5 -190.5z" /> +<glyph unicode="9" d="M111 993q0 220 124.5 356t323.5 136q144 0 252 -75.5t166.5 -221.5t58.5 -346q0 -288 -75.5 -482t-220 -287t-349.5 -93q-104 0 -192 26v86q43 -14 103.5 -21.5t92.5 -7.5q247 0 387 178.5t156 520.5h-12q-73 -96 -174 -147.5t-211 -51.5q-203 0 -316.5 112t-113.5 318z M213 999q0 -174 87 -264t249 -90q101 0 188.5 45t139 119.5t51.5 151.5q0 117 -46.5 219t-130 159.5t-192.5 57.5q-158 0 -252 -106.5t-94 -291.5z" /> +<glyph unicode=":" horiz-adv-x="487" d="M162 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98zM162 971q0 98 80 98q82 0 82 -98q0 -53 -23.5 -76t-58.5 -23q-34 0 -57 23t-23 76z" /> +<glyph unicode=";" horiz-adv-x="487" d="M76 -264q29 97 62 245.5t48 256.5h117l12 -21q-75 -265 -174 -481h-65zM162 971q0 98 80 98q82 0 82 -98q0 -53 -23.5 -76t-58.5 -23q-34 0 -57 23t-23 76z" /> +<glyph unicode="<" d="M111 682v61l948 474v-95l-823 -405l823 -355v-96z" /> +<glyph unicode="=" d="M111 477v82h948v-82h-948zM111 885v82h948v-82h-948z" /> +<glyph unicode=">" d="M111 266v96l823 355l-823 405v95l948 -474v-61z" /> +<glyph unicode="?" horiz-adv-x="862" d="M57 1403q110 48 184.5 64t153.5 16q183 0 288 -98.5t105 -270.5q0 -68 -18 -119t-50.5 -94.5t-78.5 -84t-102 -87.5q-64 -54 -98.5 -98.5t-50 -93.5t-15.5 -146v-14h-82v37q0 123 37.5 201t138.5 167l91 79q72 61 103 121t31 138q0 127 -83.5 202t-219.5 75 q-79 0 -148 -17.5t-149 -56.5zM260 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98z" /> +<glyph unicode="@" horiz-adv-x="1815" d="M113 561q0 256 108.5 460.5t307 317.5t448.5 113q215 0 380.5 -89t255 -254.5t89.5 -383.5q0 -228 -90.5 -366t-245.5 -138q-89 0 -144.5 54t-64.5 147h-4q-43 -100 -124 -150.5t-189 -50.5q-148 0 -229 96.5t-81 270.5q0 202 120.5 330.5t314.5 128.5q138 0 286 -41 l-22 -464v-30q0 -104 35 -156.5t116 -52.5q103 0 168.5 116.5t65.5 303.5q0 194 -79 340t-225.5 224.5t-334.5 78.5q-230 0 -405.5 -99.5t-270 -281.5t-94.5 -418q0 -322 167 -497.5t474 -175.5q93 0 188.5 18t231.5 70v-99q-203 -80 -414 -80q-349 0 -544 200.5t-195 557.5 zM633 590q0 -143 55 -215t174 -72q255 0 273 346l16 291q-79 27 -193 27q-149 0 -237 -102.5t-88 -274.5z" /> +<glyph unicode="A" horiz-adv-x="1229" d="M0 0l588 1468h65l576 -1468h-115l-203 516h-594l-204 -516h-113zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174z" /> +<glyph unicode="B" horiz-adv-x="1284" d="M207 0v1462h401q271 0 398 -92t127 -278q0 -127 -77.5 -211.5t-226.5 -108.5v-6q175 -26 257.5 -110.5t82.5 -235.5q0 -202 -134 -311t-380 -109h-448zM309 90h344q406 0 406 330q0 301 -428 301h-322v-631zM309 811h322q206 0 299.5 68.5t93.5 214.5t-105.5 212 t-314.5 66h-295v-561z" /> +<glyph unicode="C" horiz-adv-x="1272" d="M129 735q0 223 84.5 393t243 262.5t368.5 92.5q214 0 383 -80l-41 -92q-160 80 -336 80q-275 0 -433 -176t-158 -482q0 -313 149 -486t426 -173q184 0 338 47v-90q-145 -51 -362 -51q-308 0 -485 199t-177 556z" /> +<glyph unicode="D" horiz-adv-x="1446" d="M207 0v1462h395q350 0 532.5 -183t182.5 -534q0 -368 -193 -556.5t-567 -188.5h-350zM309 90h242q655 0 655 651q0 314 -159.5 472.5t-468.5 158.5h-269v-1282z" /> +<glyph unicode="E" horiz-adv-x="1130" d="M207 0v1462h799v-94h-697v-553h658v-94h-658v-627h697v-94h-799z" /> +<glyph unicode="F" horiz-adv-x="1028" d="M207 0v1462h801v-94h-699v-620h660v-95h-660v-653h-102z" /> +<glyph unicode="G" horiz-adv-x="1481" d="M129 729q0 223 91.5 395.5t262 266.5t391.5 94q239 0 429 -88l-41 -92q-190 88 -394 88q-289 0 -458.5 -178.5t-169.5 -481.5q0 -330 161 -496.5t473 -166.5q202 0 343 57v514h-435v96h539v-667q-212 -90 -477 -90q-346 0 -530.5 195.5t-184.5 553.5z" /> +<glyph unicode="H" horiz-adv-x="1473" d="M207 0v1462h102v-649h854v649h103v-1462h-103v719h-854v-719h-102z" /> +<glyph unicode="I" horiz-adv-x="516" d="M207 0v1462h102v-1462h-102z" /> +<glyph unicode="J" horiz-adv-x="506" d="M-184 -254q78 -20 149 -20q242 0 242 264v1472h102v-1462q0 -369 -342 -369q-92 0 -151 27v88z" /> +<glyph unicode="K" horiz-adv-x="1190" d="M207 0v1462h102v-760l162 162l573 598h130l-599 -618l615 -844h-125l-561 772l-195 -172v-600h-102z" /> +<glyph unicode="L" horiz-adv-x="1051" d="M207 0v1462h102v-1366h697v-96h-799z" /> +<glyph unicode="M" horiz-adv-x="1767" d="M207 0v1462h158l518 -1286h6l518 1286h154v-1462h-103v1108q0 116 12 240h-8l-547 -1348h-65l-545 1350h-8q8 -124 8 -254v-1096h-98z" /> +<glyph unicode="N" horiz-adv-x="1477" d="M207 0v1462h102l865 -1296h6q-9 180 -9 342v954h99v-1462h-103l-866 1298h-8q12 -232 12 -350v-948h-98z" /> +<glyph unicode="O" horiz-adv-x="1565" d="M129 735q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5q0 -348 -174 -550.5t-480 -202.5q-305 0 -479 202.5t-174 552.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5t-401.5 168.5q-261 0 -402.5 -170 t-141.5 -483z" /> +<glyph unicode="P" horiz-adv-x="1198" d="M207 0v1462h358q522 0 522 -420q0 -212 -144 -325t-408 -113h-226v-604h-102zM309 692h201q247 0 357 81.5t110 264.5q0 169 -104 250.5t-322 81.5h-242v-678z" /> +<glyph unicode="Q" horiz-adv-x="1565" d="M129 735q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5q0 -294 -126 -486.5t-349 -246.5l333 -348h-166l-282 330l-33 -2h-31q-305 0 -479 202.5t-174 552.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5 t-401.5 168.5q-261 0 -402.5 -170t-141.5 -483z" /> +<glyph unicode="R" horiz-adv-x="1217" d="M207 0v1462h348q272 0 402 -100.5t130 -302.5q0 -147 -77.5 -248t-235.5 -145l397 -666h-122l-377 637h-363v-637h-102zM309 725h279q185 0 287 82.5t102 243.5q0 167 -100 243t-326 76h-242v-645z" /> +<glyph unicode="S" horiz-adv-x="1116" d="M111 39v102q158 -67 403 -67q180 0 285.5 82.5t105.5 216.5q0 83 -35 137.5t-114 99.5t-232 97q-224 77 -309.5 166.5t-85.5 238.5q0 164 128.5 267.5t330.5 103.5q206 0 387 -78l-37 -88q-182 76 -348 76q-162 0 -258 -75t-96 -204q0 -81 29.5 -133t96.5 -93.5 t230 -99.5q171 -59 257 -114.5t125.5 -126t39.5 -170.5q0 -183 -134.5 -290t-357.5 -107q-268 0 -411 59z" /> +<glyph unicode="T" horiz-adv-x="1073" d="M10 1366v96h1053v-96h-475v-1366h-103v1366h-475z" /> +<glyph unicode="U" horiz-adv-x="1473" d="M190 520v942h103v-946q0 -211 117 -328.5t331 -117.5q209 0 324 115.5t115 320.5v956h102v-946q0 -252 -146 -394t-407 -142q-254 0 -396.5 142.5t-142.5 397.5z" /> +<glyph unicode="V" horiz-adv-x="1182" d="M0 1462h109l368 -995q84 -225 113 -338q20 75 79 233l402 1100h111l-547 -1462h-90z" /> +<glyph unicode="W" horiz-adv-x="1827" d="M51 1462h107l256 -942q15 -57 28 -105.5t23.5 -91t19 -82t15.5 -79.5q24 136 102 413l250 887h113l293 -1018q51 -176 73 -284q13 72 33.5 153t308.5 1149h103l-404 -1462h-84l-321 1128q-40 139 -60 228q-16 -87 -45.5 -200t-322.5 -1156h-86z" /> +<glyph unicode="X" horiz-adv-x="1102" d="M0 0l492 762l-447 700h115l395 -626l401 626h109l-453 -698l490 -764h-117l-432 682l-440 -682h-113z" /> +<glyph unicode="Y" horiz-adv-x="1081" d="M0 1462h117l426 -800l428 800h110l-487 -897v-565h-105v557z" /> +<glyph unicode="Z" horiz-adv-x="1180" d="M82 0v76l856 1290h-817v96h954v-76l-858 -1290h881v-96h-1016z" /> +<glyph unicode="[" horiz-adv-x="653" d="M174 -324v1786h428v-94h-330v-1597h330v-95h-428z" /> +<glyph unicode="\" horiz-adv-x="698" d="M25 1462h102l547 -1462h-103z" /> +<glyph unicode="]" horiz-adv-x="653" d="M51 -229h330v1597h-330v94h428v-1786h-428v95z" /> +<glyph unicode="^" d="M88 561l465 912h68l460 -912h-100l-395 791l-398 -791h-100z" /> +<glyph unicode="_" horiz-adv-x="842" d="M-4 -184h850v-82h-850v82z" /> +<glyph unicode="`" horiz-adv-x="1182" d="M393 1552v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="a" horiz-adv-x="1085" d="M98 289q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227zM203 285q0 -102 62.5 -158.5t176.5 -56.5 q174 0 274.5 99.5t100.5 276.5v107l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5z" /> +<glyph unicode="b" horiz-adv-x="1219" d="M182 0v1556h99v-391q0 -88 -4 -162l-3 -85h7q62 98 149.5 144t210.5 46q228 0 343.5 -143.5t115.5 -419.5q0 -271 -121.5 -418t-341.5 -147q-116 0 -209 48t-147 136h-9l-28 -164h-62zM281 528q0 -246 86.5 -353t269.5 -107q178 0 268 124.5t90 354.5q0 471 -356 471 q-192 0 -275 -110t-83 -363v-17z" /> +<glyph unicode="c" horiz-adv-x="973" d="M119 537q0 270 137 420.5t375 150.5q141 0 270 -49l-27 -88q-141 47 -245 47q-200 0 -303 -123.5t-103 -355.5q0 -220 103 -344.5t288 -124.5q148 0 275 53v-92q-104 -51 -273 -51q-233 0 -365 147t-132 410z" /> +<glyph unicode="d" horiz-adv-x="1219" d="M119 528q0 282 118 431t343 149q118 0 204 -43t154 -147h6q-6 126 -6 247v391h98v-1556h-65l-25 166h-8q-124 -186 -356 -186q-225 0 -344 140t-119 408zM223 530q0 -462 359 -462q184 0 270 107t86 353v17q0 252 -84.5 362.5t-273.5 110.5q-178 0 -267.5 -125 t-89.5 -363z" /> +<glyph unicode="e" horiz-adv-x="1124" d="M119 535q0 260 128 416.5t345 156.5q192 0 303 -134t111 -364v-80h-783q2 -224 104.5 -342t293.5 -118q93 0 163.5 13t178.5 56v-90q-92 -40 -170 -54.5t-172 -14.5q-237 0 -369.5 146t-132.5 409zM229 618h672q0 189 -82 295.5t-227 106.5q-157 0 -252 -103.5 t-111 -298.5z" /> +<glyph unicode="f" horiz-adv-x="614" d="M29 1001v58l202 37v84q0 200 73.5 293.5t240.5 93.5q90 0 180 -27l-23 -86q-80 25 -159 25q-116 0 -164.5 -68.5t-48.5 -222.5v-101h256v-86h-256v-1001h-99v1001h-202z" /> +<glyph unicode="g" horiz-adv-x="1071" d="M45 -193q0 112 69.5 186t188.5 101q-49 21 -78.5 59.5t-29.5 88.5q0 109 139 192q-95 39 -148 122.5t-53 191.5q0 163 103.5 261.5t279.5 98.5q107 0 166 -21h348v-69l-225 -14q90 -112 90 -246q0 -157 -104.5 -254.5t-280.5 -97.5q-74 0 -104 6q-59 -31 -90 -73t-31 -89 q0 -52 39.5 -76t132.5 -24h190q177 0 271 -71.5t94 -211.5q0 -172 -139.5 -265.5t-397.5 -93.5q-205 0 -317.5 79t-112.5 220zM150 -184q0 -224 333 -224q428 0 428 273q0 98 -67 142t-217 44h-178q-299 0 -299 -235zM233 748q0 -126 76.5 -195.5t204.5 -69.5 q136 0 208.5 69t72.5 200q0 139 -74.5 208.5t-208.5 69.5q-130 0 -204.5 -74.5t-74.5 -207.5z" /> +<glyph unicode="h" horiz-adv-x="1208" d="M182 0v1556h99v-495l-5 -139h7q61 98 154 142t231 44q370 0 370 -397v-711h-98v705q0 164 -69 238.5t-214 74.5q-195 0 -285.5 -98.5t-90.5 -319.5v-600h-99z" /> +<glyph unicode="i" horiz-adv-x="463" d="M168 1389q0 96 63 96q31 0 48.5 -25t17.5 -71q0 -45 -17.5 -71t-48.5 -26q-63 0 -63 97zM182 0v1087h99v-1087h-99z" /> +<glyph unicode="j" horiz-adv-x="463" d="M-98 -381q69 -20 129 -20q151 0 151 176v1312h99v-1298q0 -135 -63.5 -208t-180.5 -73q-80 0 -135 25v86zM168 1389q0 96 63 96q31 0 48.5 -25t17.5 -71q0 -45 -17.5 -71t-48.5 -26q-63 0 -63 97z" /> +<glyph unicode="k" horiz-adv-x="991" d="M182 0v1556h99v-780l-7 -299h5l555 610h120l-428 -464l465 -623h-119l-413 549l-178 -162v-387h-99z" /> +<glyph unicode="l" horiz-adv-x="463" d="M182 0v1556h99v-1556h-99z" /> +<glyph unicode="m" horiz-adv-x="1808" d="M182 0v1087h82l21 -149h6q45 81 128 125.5t183 44.5q257 0 330 -193h4q53 93 142.5 143t203.5 50q178 0 267 -95t89 -302v-711h-98v713q0 159 -62 232t-190 73q-167 0 -247 -92t-80 -289v-637h-101v743q0 275 -252 275q-171 0 -249 -99.5t-78 -318.5v-600h-99z" /> +<glyph unicode="n" horiz-adv-x="1208" d="M182 0v1087h84l19 -149h6q106 170 377 170q370 0 370 -397v-711h-98v705q0 164 -69 238.5t-214 74.5q-195 0 -285.5 -98.5t-90.5 -319.5v-600h-99z" /> +<glyph unicode="o" horiz-adv-x="1200" d="M119 545q0 266 129 414.5t354 148.5q224 0 351.5 -150.5t127.5 -412.5q0 -266 -129 -415.5t-356 -149.5q-143 0 -252 69t-167 198t-58 298zM223 545q0 -224 98.5 -349.5t278.5 -125.5t278.5 125.5t98.5 349.5q0 225 -99.5 349t-279.5 124t-277.5 -123.5t-97.5 -349.5z " /> +<glyph unicode="p" horiz-adv-x="1219" d="M182 -492v1579h84l19 -155h6q112 176 358 176q220 0 335.5 -144.5t115.5 -420.5q0 -268 -121.5 -415.5t-331.5 -147.5q-251 0 -366 188h-7l3 -84q4 -74 4 -162v-414h-99zM281 541q0 -255 85.5 -364t278.5 -109q167 0 258.5 124t91.5 347q0 479 -346 479 q-190 0 -279 -104.5t-89 -340.5v-32z" /> +<glyph unicode="q" horiz-adv-x="1219" d="M119 532q0 275 118 425.5t338 150.5q236 0 353 -174h6l18 153h84v-1579h-98v414q0 122 6 248h-6q-118 -190 -369 -190q-214 0 -332 142t-118 410zM223 530q0 -229 89.5 -345.5t258.5 -116.5q198 0 282.5 109t84.5 366v12q0 245 -85 354t-271 109q-176 0 -267.5 -124 t-91.5 -364z" /> +<glyph unicode="r" horiz-adv-x="797" d="M182 0v1087h84l10 -196h7q67 120 143 168.5t184 48.5q69 0 148 -14l-19 -95q-68 17 -141 17q-139 0 -228 -118t-89 -298v-600h-99z" /> +<glyph unicode="s" horiz-adv-x="954" d="M84 47v107q164 -82 346 -82q161 0 244.5 53.5t83.5 142.5q0 82 -66.5 138t-218.5 110q-163 59 -229 101.5t-99.5 96t-33.5 130.5q0 122 102.5 193t286.5 71q176 0 334 -66l-37 -90q-160 66 -297 66q-133 0 -211 -44t-78 -122q0 -85 60.5 -136t236.5 -114 q147 -53 214 -95.5t100.5 -96.5t33.5 -127q0 -146 -111 -224.5t-315 -78.5q-218 0 -346 67z" /> +<glyph unicode="t" horiz-adv-x="686" d="M25 1001v58l161 45l50 246h51v-263h319v-86h-319v-688q0 -125 44 -185t138 -60t164 16v-80q-72 -24 -166 -24q-144 0 -212.5 77t-68.5 242v702h-161z" /> +<glyph unicode="u" horiz-adv-x="1208" d="M170 377v710h98v-704q0 -164 69 -238.5t214 -74.5q194 0 285.5 98t91.5 319v600h98v-1087h-84l-18 150h-6q-106 -170 -377 -170q-371 0 -371 397z" /> +<glyph unicode="v" horiz-adv-x="940" d="M0 1087h102l281 -739q56 -142 84 -248h6q41 136 84 250l281 737h102l-420 -1087h-100z" /> +<glyph unicode="w" horiz-adv-x="1481" d="M31 1087h106l174 -630q61 -234 80 -344h6q59 234 86 311l224 663h90l213 -661q72 -235 88 -311h6q8 65 80 348l166 624h100l-295 -1087h-104l-238 727q-23 74 -59 217h-6l-21 -74l-45 -145l-242 -725h-98z" /> +<glyph unicode="x" horiz-adv-x="1020" d="M55 0l394 559l-379 528h114l324 -458l321 458h109l-373 -528l400 -559h-115l-342 485l-344 -485h-109z" /> +<glyph unicode="y" horiz-adv-x="940" d="M0 1087h102l230 -610q105 -281 133 -379h6q42 129 137 385l230 604h102l-487 -1263q-59 -154 -99 -208t-93.5 -81t-129.5 -27q-57 0 -127 21v86q58 -16 125 -16q51 0 90 24t70.5 74.5t73 160t53.5 142.5z" /> +<glyph unicode="z" horiz-adv-x="944" d="M82 0v63l645 936h-598v88h727v-63l-649 -936h651v-88h-776z" /> +<glyph unicode="{" horiz-adv-x="723" d="M61 528v80q122 2 176 51t54 148v350q0 299 360 305v-90q-138 -5 -200 -58t-62 -157v-305q0 -130 -44 -194t-142 -85v-8q97 -20 141.5 -83.5t44.5 -186.5v-322q0 -102 59.5 -152.5t202.5 -53.5v-91q-195 0 -277.5 75t-82.5 231v337q0 205 -230 209z" /> +<glyph unicode="|" horiz-adv-x="1108" d="M508 -506v2067h92v-2067h-92z" /> +<glyph unicode="}" horiz-adv-x="723" d="M72 -233q141 2 201.5 52.5t60.5 153.5v322q0 123 44.5 186.5t141.5 83.5v8q-97 20 -141.5 84t-44.5 195v305q0 103 -61.5 156.5t-200.5 58.5v90q174 0 267 -77.5t93 -227.5v-350q0 -100 54.5 -148.5t175.5 -50.5v-80q-230 -4 -230 -209v-337q0 -155 -82.5 -230.5 t-277.5 -75.5v91z" /> +<glyph unicode="~" d="M111 625v94q108 110 233 110q61 0 115 -13.5t155 -57.5q126 -58 220 -58q56 0 109.5 30.5t115.5 94.5v-96q-48 -49 -104.5 -81t-129.5 -32q-116 0 -270 72q-124 57 -221 57q-49 0 -108 -30.5t-115 -89.5z" /> +<glyph unicode="¡" horiz-adv-x="492" d="M166 1010q0 98 80 98q82 0 82 -98q0 -53 -23.5 -76t-58.5 -23q-34 0 -57 23t-23 76zM186 -375l29 1086h61l29 -1086h-119z" /> +<glyph unicode="¢" d="M211 745q0 232 102.5 381.5t288.5 182.5v174h82v-166h14q131 0 275 -55l-31 -84q-134 51 -237 51q-187 0 -288.5 -122.5t-101.5 -358.5q0 -225 100.5 -349.5t280.5 -124.5q131 0 267 58v-92q-110 -56 -267 -56h-12v-204h-82v210q-186 30 -288.5 175t-102.5 380z" /> +<glyph unicode="£" d="M78 0v84q110 21 171.5 110t61.5 224v258h-211v82h211v297q0 204 98 315t281 111q175 0 330 -68l-35 -86q-157 66 -295 66q-141 0 -209.5 -81t-68.5 -253v-301h411v-82h-411v-256q0 -116 -35 -196t-113 -128h809v-96h-995z" /> +<glyph unicode="¤" d="M127 326l139 141q-90 106 -90 256q0 147 90 258l-139 141l59 60l138 -142q103 93 260 93q155 0 260 -93l137 142l59 -60l-139 -141q90 -111 90 -258q0 -151 -90 -256l139 -141l-59 -60l-137 142q-110 -93 -260 -93q-153 0 -260 93l-138 -142zM260 723q0 -136 94.5 -232 t229.5 -96q134 0 228.5 95.5t94.5 232.5q0 136 -95 233t-228 97q-134 0 -229 -97t-95 -233z" /> +<glyph unicode="¥" d="M43 1462h117l426 -796l428 796h110l-432 -788h283v-82h-338v-205h338v-82h-338v-305h-105v305h-337v82h337v205h-337v82h278z" /> +<glyph unicode="¦" horiz-adv-x="1108" d="M508 258h92v-764h-92v764zM508 797v764h92v-764h-92z" /> +<glyph unicode="§" horiz-adv-x="1057" d="M129 63v95q182 -78 332 -78q162 0 247 49.5t85 140.5q0 55 -25 87.5t-88.5 65.5t-190.5 79q-200 73 -272 141.5t-72 169.5q0 83 50.5 152.5t138.5 107.5q-86 47 -125 102t-39 136q0 117 101.5 183.5t275.5 66.5q175 0 336 -64l-35 -80q-91 34 -158.5 47t-144.5 13 q-134 0 -205.5 -44.5t-71.5 -119.5q0 -54 25.5 -88.5t85.5 -65.5t188 -74q192 -64 264 -132.5t72 -170.5q0 -173 -186 -274q86 -42 129 -96t43 -136q0 -135 -113 -207.5t-311 -72.5q-92 0 -171 15t-165 52zM246 825q0 -65 31.5 -104t105.5 -75t250 -99q82 41 126 98t44 121 q0 62 -32 102t-108.5 77t-236.5 87q-81 -23 -130.5 -79t-49.5 -128z" /> +<glyph unicode="¨" horiz-adv-x="1182" d="M336 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM717 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="©" horiz-adv-x="1704" d="M100 731q0 200 100 375t275 276t377 101q200 0 375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM193 731q0 -178 88.5 -329.5t240.5 -240.5t330 -89t329.5 88.5t240.5 240.5t89 330q0 174 -85.5 325 t-239 243t-334.5 92q-176 0 -328.5 -88.5t-241.5 -242.5t-89 -329zM489 725q0 208 111 332.5t297 124.5q119 0 227 -52l-37 -83q-98 45 -190 45q-142 0 -222.5 -94.5t-80.5 -264.5q0 -186 74.5 -275t220.5 -89q84 0 198 43v-88q-102 -45 -208 -45q-187 0 -288.5 115 t-101.5 331z" /> +<glyph unicode="ª" horiz-adv-x="686" d="M78 989q0 100 80 151.5t241 59.5l95 4v43q0 77 -38 114.5t-106 37.5q-87 0 -196 -49l-33 73q117 56 231 56q228 0 228 -215v-451h-68l-25 72q-84 -84 -202 -84q-95 0 -151 49t-56 139zM168 993q0 -54 35 -85t96 -31q90 0 142.5 50t52.5 142v64l-88 -5q-116 -6 -177 -36.5 t-61 -98.5z" /> +<glyph unicode="«" horiz-adv-x="885" d="M82 516v27l309 393l62 -43l-254 -363l254 -362l-62 -43zM442 516v27l310 393l61 -43l-254 -363l254 -362l-61 -43z" /> +<glyph unicode="¬" d="M111 682v82h927v-494h-82v412h-845z" /> +<glyph unicode="­" horiz-adv-x="659" d="M92 512v82h475v-82h-475z" /> +<glyph unicode="®" horiz-adv-x="1704" d="M100 731q0 200 100 375t275 276t377 101q200 0 375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM193 731q0 -178 88.5 -329.5t240.5 -240.5t330 -89t329.5 88.5t240.5 240.5t89 330q0 174 -85.5 325 t-239 243t-334.5 92q-176 0 -328.5 -88.5t-241.5 -242.5t-89 -329zM608 291v880h211q143 0 222 -62t79 -191q0 -79 -38.5 -139.5t-110.5 -94.5l237 -393h-121l-210 360h-168v-360h-101zM709 731h112q91 0 143 46.5t52 135.5q0 172 -197 172h-110v-354z" /> +<glyph unicode="¯" horiz-adv-x="1024" d="M-6 1556v82h1036v-82h-1036z" /> +<glyph unicode="°" horiz-adv-x="877" d="M139 1184q0 132 86.5 215.5t212.5 83.5t212.5 -83.5t86.5 -215.5t-86.5 -215.5t-212.5 -83.5q-130 0 -214.5 83t-84.5 216zM229 1184q0 -91 61 -154t148 -63q86 0 147.5 62t61.5 155q0 92 -60 154.5t-149 62.5q-90 0 -149.5 -64t-59.5 -153z" /> +<glyph unicode="±" d="M111 1v82h948v-82h-948zM111 682v82h432v434h82v-434h434v-82h-434v-432h-82v432h-432z" /> +<glyph unicode="²" horiz-adv-x="688" d="M53 586v78l242 237q125 121 172 193t47 149q0 71 -46.5 112.5t-123.5 41.5q-108 0 -217 -82l-49 65q119 103 270 103q124 0 194 -63.5t70 -174.5q0 -47 -13 -89t-40 -85.5t-68.5 -90t-308.5 -306.5h447v-88h-576z" /> +<glyph unicode="³" horiz-adv-x="688" d="M41 629v88q136 -62 266 -62q115 0 174.5 49t59.5 136q0 83 -59.5 122t-178.5 39h-131v84h135q105 0 158 43.5t53 120.5q0 67 -47 107.5t-127 40.5q-128 0 -246 -78l-47 70q130 94 293 94q127 0 199.5 -60t72.5 -163q0 -78 -44 -131.5t-117 -75.5q186 -45 186 -211 q0 -130 -88.5 -201.5t-247.5 -71.5q-144 0 -264 60z" /> +<glyph unicode="´" horiz-adv-x="1182" d="M393 1241v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="µ" horiz-adv-x="1221" d="M182 -492v1579h99v-704q0 -164 69 -238.5t213 -74.5q194 0 285.5 98t91.5 319v600h98v-1087h-84l-18 150h-6q-50 -77 -150 -123.5t-217 -46.5q-99 0 -167.5 27.5t-119.5 84.5q5 -92 5 -170v-414h-99z" /> +<glyph unicode="¶" horiz-adv-x="1341" d="M113 1042q0 260 109 387t341 127h543v-1816h-100v1722h-228v-1722h-100v819q-64 -18 -146 -18q-216 0 -317.5 125t-101.5 376z" /> +<glyph unicode="·" horiz-adv-x="487" d="M162 721q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98z" /> +<glyph unicode="¸" horiz-adv-x="420" d="M43 -393q30 -10 92 -10q78 0 119 28t41 80q0 94 -193 121l93 174h96l-66 -117q168 -37 168 -174q0 -100 -67.5 -150.5t-188.5 -50.5q-68 0 -94 11v88z" /> +<glyph unicode="¹" horiz-adv-x="688" d="M76 1298l274 164h92v-876h-98v547q0 99 12 233q-26 -23 -233 -145z" /> +<glyph unicode="º" horiz-adv-x="739" d="M70 1141q0 162 78 250t223 88q142 0 220.5 -87t78.5 -251q0 -161 -80 -250.5t-223 -89.5t-220 86t-77 254zM160 1141q0 -264 209 -264t209 264q0 131 -50 194.5t-159 63.5t-159 -63.5t-50 -194.5z" /> +<glyph unicode="»" horiz-adv-x="885" d="M72 168l254 362l-254 363l61 43l309 -391v-27l-309 -393zM432 168l254 362l-254 363l62 43l309 -391v-27l-309 -393z" /> +<glyph unicode="¼" horiz-adv-x="1516" d="M59 1298l274 164h92v-876h-98v547q0 99 12 233q-26 -23 -233 -145zM243 0l811 1462h94l-811 -1462h-94zM760 242v60l407 581h96v-563h129v-78h-129v-241h-90v241h-413zM864 320h309v221q0 132 8 232q-6 -12 -21.5 -35.5t-295.5 -417.5z" /> +<glyph unicode="½" horiz-adv-x="1516" d="M11 1298l274 164h92v-876h-98v547q0 99 12 233q-26 -23 -233 -145zM168 0l811 1462h94l-811 -1462h-94zM827 1v78l242 237q125 121 172 193t47 149q0 71 -46.5 112.5t-123.5 41.5q-108 0 -217 -82l-49 65q119 103 270 103q124 0 194 -63.5t70 -174.5q0 -47 -13 -89 t-40 -85.5t-68.5 -90t-308.5 -306.5h447v-88h-576z" /> +<glyph unicode="¾" horiz-adv-x="1516" d="M41 629v88q136 -62 266 -62q115 0 174.5 49t59.5 136q0 83 -59.5 122t-178.5 39h-131v84h135q105 0 158 43.5t53 120.5q0 67 -47 107.5t-127 40.5q-128 0 -246 -78l-47 70q130 94 293 94q127 0 199.5 -60t72.5 -163q0 -78 -44 -131.5t-117 -75.5q186 -45 186 -211 q0 -130 -88.5 -201.5t-247.5 -71.5q-144 0 -264 60zM395 0l811 1462h94l-811 -1462h-94zM863 242v60l407 581h96v-563h129v-78h-129v-241h-90v241h-413zM967 320h309v221q0 132 8 232q-6 -12 -21.5 -35.5t-295.5 -417.5z" /> +<glyph unicode="¿" horiz-adv-x="862" d="M74 -27q0 70 20 124t58.5 102t171.5 159q64 53 98.5 98.5t49.5 94t15 145.5v15h82v-37q0 -125 -39.5 -204.5t-136.5 -164.5l-90 -79q-73 -61 -104 -120.5t-31 -138.5q0 -124 82 -200t221 -76q125 0 233 46l64 27l37 -79q-111 -48 -185.5 -64t-152.5 -16q-184 0 -288.5 99 t-104.5 269zM440 1010q0 98 80 98q82 0 82 -98q0 -53 -23.5 -76t-58.5 -23q-34 0 -57 23t-23 76z" /> +<glyph unicode="À" horiz-adv-x="1229" d="M0 0l588 1468h65l576 -1468h-115l-203 516h-594l-204 -516h-113zM337 1890v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174z" /> +<glyph unicode="Á" horiz-adv-x="1229" d="M0 0l588 1468h65l576 -1468h-115l-203 516h-594l-204 -516h-113zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174zM504 1579v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="Â" horiz-adv-x="1229" d="M0 0l588 1468h65l576 -1468h-115l-203 516h-594l-204 -516h-113zM328 1579v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174z" /> +<glyph unicode="Ã" horiz-adv-x="1229" d="M0 0l588 1468h65l576 -1468h-115l-203 516h-594l-204 -516h-113zM287 1581q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20 q-45 0 -75 -34.5t-48 -121.5h-73zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174z" /> +<glyph unicode="Ä" horiz-adv-x="1229" d="M0 0l588 1468h65l576 -1468h-115l-203 516h-594l-204 -516h-113zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174zM367 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM748 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="Å" horiz-adv-x="1229" d="M0 0l588 1468h65l576 -1468h-115l-203 516h-594l-204 -516h-113zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174zM402 1610q0 94 60 152.5t157 58.5t157 -59t60 -152q0 -97 -60 -155t-157 -58t-157 58t-60 155zM482 1610q0 -66 37.5 -103.5t99.5 -37.5 t99.5 37.5t37.5 103.5q0 64 -39 101.5t-98 37.5q-62 0 -99.5 -38t-37.5 -101z" /> +<glyph unicode="Æ" horiz-adv-x="1653" d="M-2 0l653 1462h877v-94h-615v-553h576v-94h-576v-627h615v-94h-717v516h-475l-227 -516h-111zM377 608h434v760h-100z" /> +<glyph unicode="Ç" horiz-adv-x="1272" d="M129 735q0 223 84.5 393t243 262.5t368.5 92.5q214 0 383 -80l-41 -92q-160 80 -336 80q-275 0 -433 -176t-158 -482q0 -313 149 -486t426 -173q184 0 338 47v-90q-145 -51 -362 -51q-308 0 -485 199t-177 556zM561 -393q30 -10 92 -10q78 0 119 28t41 80q0 94 -193 121 l93 174h96l-66 -117q168 -37 168 -174q0 -100 -67.5 -150.5t-188.5 -50.5q-68 0 -94 11v88z" /> +<glyph unicode="È" horiz-adv-x="1130" d="M207 0v1462h799v-94h-697v-553h658v-94h-658v-627h697v-94h-799zM314 1890v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="É" horiz-adv-x="1130" d="M207 0v1462h799v-94h-697v-553h658v-94h-658v-627h697v-94h-799zM463 1579v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="Ê" horiz-adv-x="1130" d="M207 0v1462h799v-94h-697v-553h658v-94h-658v-627h697v-94h-799zM315 1579v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70z" /> +<glyph unicode="Ë" horiz-adv-x="1130" d="M207 0v1462h799v-94h-697v-553h658v-94h-658v-627h697v-94h-799zM354 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM735 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="Ì" horiz-adv-x="516" d="M-63 1890v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5zM207 0v1462h102v-1462h-102z" /> +<glyph unicode="Í" horiz-adv-x="516" d="M191 1579v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70zM207 0v1462h102v-1462h-102z" /> +<glyph unicode="Î" horiz-adv-x="516" d="M-32 1579v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70zM207 0v1462h102v-1462h-102z" /> +<glyph unicode="Ï" horiz-adv-x="516" d="M5 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM207 0v1462h102v-1462h-102zM386 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="Ð" horiz-adv-x="1466" d="M47 678v94h160v690h395q350 0 532.5 -183t182.5 -534q0 -368 -193 -556.5t-567 -188.5h-350v678h-160zM309 90h242q655 0 655 651q0 314 -159.5 472.5t-468.5 158.5h-269v-600h406v-94h-406v-588z" /> +<glyph unicode="Ñ" horiz-adv-x="1477" d="M207 0v1462h102l865 -1296h6q-9 180 -9 342v954h99v-1462h-103l-866 1298h-8q12 -232 12 -350v-948h-98zM400 1581q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61q-36 0 -75 18.5t-101 71.5 q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73z" /> +<glyph unicode="Ò" horiz-adv-x="1565" d="M129 735q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5q0 -348 -174 -550.5t-480 -202.5q-305 0 -479 202.5t-174 552.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5t-401.5 168.5q-261 0 -402.5 -170 t-141.5 -483zM502 1890v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="Ó" horiz-adv-x="1565" d="M129 735q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5q0 -348 -174 -550.5t-480 -202.5q-305 0 -479 202.5t-174 552.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5t-401.5 168.5q-261 0 -402.5 -170 t-141.5 -483zM686 1579v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="Ô" horiz-adv-x="1565" d="M129 735q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5q0 -348 -174 -550.5t-480 -202.5q-305 0 -479 202.5t-174 552.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5t-401.5 168.5q-261 0 -402.5 -170 t-141.5 -483zM492 1579v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70z" /> +<glyph unicode="Õ" horiz-adv-x="1565" d="M129 735q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5q0 -348 -174 -550.5t-480 -202.5q-305 0 -479 202.5t-174 552.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5t-401.5 168.5q-261 0 -402.5 -170 t-141.5 -483zM443 1581q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73z" /> +<glyph unicode="Ö" horiz-adv-x="1565" d="M129 735q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5q0 -348 -174 -550.5t-480 -202.5q-305 0 -479 202.5t-174 552.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5t-401.5 168.5q-261 0 -402.5 -170 t-141.5 -483zM529 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM910 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="×" d="M119 1130l57 58l408 -408l409 408l58 -58l-408 -407l406 -408l-58 -57l-407 408l-406 -408l-57 57l405 408z" /> +<glyph unicode="Ø" horiz-adv-x="1565" d="M129 735q0 349 175.5 549.5t479.5 200.5q232 0 392 -121l108 152l72 -60l-111 -153q191 -207 191 -570q0 -348 -174 -550.5t-480 -202.5q-236 0 -395 120l-86 -120l-74 59l90 127q-188 200 -188 569zM240 733q0 -312 139 -483l739 1034q-133 102 -334 102 q-261 0 -402.5 -170t-141.5 -483zM444 182q133 -106 338 -106q264 0 403.5 170t139.5 487q0 315 -139 486z" /> +<glyph unicode="Ù" horiz-adv-x="1473" d="M190 520v942h103v-946q0 -211 117 -328.5t331 -117.5q209 0 324 115.5t115 320.5v956h102v-946q0 -252 -146 -394t-407 -142q-254 0 -396.5 142.5t-142.5 397.5zM450 1890v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="Ú" horiz-adv-x="1473" d="M190 520v942h103v-946q0 -211 117 -328.5t331 -117.5q209 0 324 115.5t115 320.5v956h102v-946q0 -252 -146 -394t-407 -142q-254 0 -396.5 142.5t-142.5 397.5zM633 1579v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="Û" horiz-adv-x="1473" d="M190 520v942h103v-946q0 -211 117 -328.5t331 -117.5q209 0 324 115.5t115 320.5v956h102v-946q0 -252 -146 -394t-407 -142q-254 0 -396.5 142.5t-142.5 397.5zM444 1579v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207 q-108 -114 -221 -207h-70z" /> +<glyph unicode="Ü" horiz-adv-x="1473" d="M190 520v942h103v-946q0 -211 117 -328.5t331 -117.5q209 0 324 115.5t115 320.5v956h102v-946q0 -252 -146 -394t-407 -142q-254 0 -396.5 142.5t-142.5 397.5zM481 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM862 1727q0 46 15.5 66t47.5 20 q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="Ý" horiz-adv-x="1081" d="M0 1462h117l426 -800l428 800h110l-487 -897v-565h-105v557zM434 1579v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="Þ" horiz-adv-x="1198" d="M207 0v1462h102v-264h256q522 0 522 -420q0 -212 -144 -325t-408 -113h-226v-340h-102zM309 428h201q247 0 357 81.5t110 264.5q0 169 -104 250.5t-322 81.5h-242v-678z" /> +<glyph unicode="ß" horiz-adv-x="1194" d="M182 0v1206q0 173 103.5 267t292.5 94q188 0 285.5 -72.5t97.5 -210.5q0 -139 -139 -250q-81 -64 -110.5 -100.5t-29.5 -75.5q0 -44 14.5 -68t51.5 -57t102 -78q106 -75 151.5 -124.5t68 -103t22.5 -120.5q0 -156 -88 -241.5t-246 -85.5q-95 0 -174.5 18.5t-126.5 48.5 v107q65 -38 148.5 -62t152.5 -24q114 0 174.5 54.5t60.5 160.5q0 83 -39 144t-149 136q-127 87 -175 147t-48 146q0 60 32.5 110t106.5 108q74 57 106.5 105.5t32.5 106.5q0 93 -70 143t-202 50q-145 0 -226 -69t-81 -196v-1214h-99z" /> +<glyph unicode="à" horiz-adv-x="1085" d="M98 289q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227zM203 285q0 -102 62.5 -158.5t176.5 -56.5 q174 0 274.5 99.5t100.5 276.5v107l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5zM255 1552v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="á" horiz-adv-x="1085" d="M98 289q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227zM203 285q0 -102 62.5 -158.5t176.5 -56.5 q174 0 274.5 99.5t100.5 276.5v107l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5zM422 1241v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="â" horiz-adv-x="1085" d="M98 289q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227zM203 285q0 -102 62.5 -158.5t176.5 -56.5 q174 0 274.5 99.5t100.5 276.5v107l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5zM251 1241v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70z" /> +<glyph unicode="ã" horiz-adv-x="1085" d="M98 289q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227zM200 1243q10 111 63 174.5t137 63.5 q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73zM203 285q0 -102 62.5 -158.5t176.5 -56.5q174 0 274.5 99.5t100.5 276.5v107l-190 -8 q-229 -11 -326.5 -71.5t-97.5 -188.5z" /> +<glyph unicode="ä" horiz-adv-x="1085" d="M98 289q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227zM203 285q0 -102 62.5 -158.5t176.5 -56.5 q174 0 274.5 99.5t100.5 276.5v107l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5zM282 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM663 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="å" horiz-adv-x="1085" d="M98 289q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227zM203 285q0 -102 62.5 -158.5t176.5 -56.5 q174 0 274.5 99.5t100.5 276.5v107l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5zM325 1456q0 94 60 152.5t157 58.5t157 -59t60 -152q0 -97 -60 -155t-157 -58t-157 58t-60 155zM405 1456q0 -66 37.5 -103.5t99.5 -37.5t99.5 37.5t37.5 103.5q0 64 -39 101.5t-98 37.5 q-62 0 -99.5 -38t-37.5 -101z" /> +<glyph unicode="æ" horiz-adv-x="1731" d="M98 289q0 154 125 243t377 97l201 6v72q0 155 -61.5 234t-198.5 79q-148 0 -305 -84l-37 86q173 84 346 84q261 0 325 -211q111 213 347 213q184 0 289.5 -134.5t105.5 -363.5v-80h-715q0 -460 348 -460q85 0 150 12t174 57v-90q-92 -41 -165 -55t-161 -14 q-295 0 -397 256q-68 -133 -168 -194.5t-252 -61.5q-156 0 -242 82.5t-86 226.5zM203 285q0 -102 61 -158.5t170 -56.5q169 0 266 99.5t97 276.5v107l-187 -8q-219 -11 -313 -71.5t-94 -188.5zM903 618h604q0 188 -77.5 295t-212.5 107q-284 0 -314 -402z" /> +<glyph unicode="ç" horiz-adv-x="973" d="M119 537q0 270 137 420.5t375 150.5q141 0 270 -49l-27 -88q-141 47 -245 47q-200 0 -303 -123.5t-103 -355.5q0 -220 103 -344.5t288 -124.5q148 0 275 53v-92q-104 -51 -273 -51q-233 0 -365 147t-132 410zM373 -393q30 -10 92 -10q78 0 119 28t41 80q0 94 -193 121 l93 174h96l-66 -117q168 -37 168 -174q0 -100 -67.5 -150.5t-188.5 -50.5q-68 0 -94 11v88z" /> +<glyph unicode="è" horiz-adv-x="1124" d="M119 535q0 260 128 416.5t345 156.5q192 0 303 -134t111 -364v-80h-783q2 -224 104.5 -342t293.5 -118q93 0 163.5 13t178.5 56v-90q-92 -40 -170 -54.5t-172 -14.5q-237 0 -369.5 146t-132.5 409zM229 618h672q0 189 -82 295.5t-227 106.5q-157 0 -252 -103.5 t-111 -298.5zM302 1552v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="é" horiz-adv-x="1124" d="M119 535q0 260 128 416.5t345 156.5q192 0 303 -134t111 -364v-80h-783q2 -224 104.5 -342t293.5 -118q93 0 163.5 13t178.5 56v-90q-92 -40 -170 -54.5t-172 -14.5q-237 0 -369.5 146t-132.5 409zM229 618h672q0 189 -82 295.5t-227 106.5q-157 0 -252 -103.5 t-111 -298.5zM452 1241v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="ê" horiz-adv-x="1124" d="M119 535q0 260 128 416.5t345 156.5q192 0 303 -134t111 -364v-80h-783q2 -224 104.5 -342t293.5 -118q93 0 163.5 13t178.5 56v-90q-92 -40 -170 -54.5t-172 -14.5q-237 0 -369.5 146t-132.5 409zM229 618h672q0 189 -82 295.5t-227 106.5q-157 0 -252 -103.5 t-111 -298.5zM290 1241v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70z" /> +<glyph unicode="ë" horiz-adv-x="1124" d="M119 535q0 260 128 416.5t345 156.5q192 0 303 -134t111 -364v-80h-783q2 -224 104.5 -342t293.5 -118q93 0 163.5 13t178.5 56v-90q-92 -40 -170 -54.5t-172 -14.5q-237 0 -369.5 146t-132.5 409zM229 618h672q0 189 -82 295.5t-227 106.5q-157 0 -252 -103.5 t-111 -298.5zM331 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM712 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="ì" horiz-adv-x="463" d="M-34 1552v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5zM182 0v1087h99v-1087h-99z" /> +<glyph unicode="í" horiz-adv-x="463" d="M107 1241v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70zM182 0v1087h99v-1087h-99z" /> +<glyph unicode="î" horiz-adv-x="463" d="M-58 1241v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70zM182 0v1087h99v-1087h-99z" /> +<glyph unicode="ï" horiz-adv-x="463" d="M-21 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM182 0v1087h99v-1087h-99zM360 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="ð" horiz-adv-x="1174" d="M117 471q0 228 126.5 357.5t342.5 129.5q108 0 187.5 -33t148.5 -96l4 2q-64 270 -269 459l-270 -157l-49 77l244 146q-86 62 -199 119l45 81q147 -69 248 -145l225 137l49 -84l-202 -121q154 -151 230.5 -353t76.5 -431q0 -276 -124 -427.5t-349 -151.5 q-214 0 -339.5 130t-125.5 361zM221 463q0 -186 94.5 -289.5t268.5 -103.5q179 0 272.5 123t93.5 364q0 146 -97 228.5t-267 82.5q-185 0 -275 -100.5t-90 -304.5z" /> +<glyph unicode="ñ" horiz-adv-x="1208" d="M182 0v1087h84l19 -149h6q106 170 377 170q370 0 370 -397v-711h-98v705q0 164 -69 238.5t-214 74.5q-195 0 -285.5 -98.5t-90.5 -319.5v-600h-99zM282 1243q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76 q-16 -116 -69 -177t-132 -61q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73z" /> +<glyph unicode="ò" horiz-adv-x="1200" d="M119 545q0 266 129 414.5t354 148.5q224 0 351.5 -150.5t127.5 -412.5q0 -266 -129 -415.5t-356 -149.5q-143 0 -252 69t-167 198t-58 298zM223 545q0 -224 98.5 -349.5t278.5 -125.5t278.5 125.5t98.5 349.5q0 225 -99.5 349t-279.5 124t-277.5 -123.5t-97.5 -349.5z M335 1552v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="ó" horiz-adv-x="1200" d="M119 545q0 266 129 414.5t354 148.5q224 0 351.5 -150.5t127.5 -412.5q0 -266 -129 -415.5t-356 -149.5q-143 0 -252 69t-167 198t-58 298zM223 545q0 -224 98.5 -349.5t278.5 -125.5t278.5 125.5t98.5 349.5q0 225 -99.5 349t-279.5 124t-277.5 -123.5t-97.5 -349.5z M499 1241v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="ô" horiz-adv-x="1200" d="M119 545q0 266 129 414.5t354 148.5q224 0 351.5 -150.5t127.5 -412.5q0 -266 -129 -415.5t-356 -149.5q-143 0 -252 69t-167 198t-58 298zM223 545q0 -224 98.5 -349.5t278.5 -125.5t278.5 125.5t98.5 349.5q0 225 -99.5 349t-279.5 124t-277.5 -123.5t-97.5 -349.5z M309 1241v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70z" /> +<glyph unicode="õ" horiz-adv-x="1200" d="M119 545q0 266 129 414.5t354 148.5q224 0 351.5 -150.5t127.5 -412.5q0 -266 -129 -415.5t-356 -149.5q-143 0 -252 69t-167 198t-58 298zM223 545q0 -224 98.5 -349.5t278.5 -125.5t278.5 125.5t98.5 349.5q0 225 -99.5 349t-279.5 124t-277.5 -123.5t-97.5 -349.5z M264 1243q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73z" /> +<glyph unicode="ö" horiz-adv-x="1200" d="M119 545q0 266 129 414.5t354 148.5q224 0 351.5 -150.5t127.5 -412.5q0 -266 -129 -415.5t-356 -149.5q-143 0 -252 69t-167 198t-58 298zM223 545q0 -224 98.5 -349.5t278.5 -125.5t278.5 125.5t98.5 349.5q0 225 -99.5 349t-279.5 124t-277.5 -123.5t-97.5 -349.5z M346 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM727 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="÷" d="M111 682v82h948v-82h-948zM504 371q0 98 80 98q82 0 82 -98q0 -53 -23.5 -76t-58.5 -23q-34 0 -57 23t-23 76zM504 1075q0 99 80 99q82 0 82 -99q0 -52 -23.5 -75t-58.5 -23q-34 0 -57 23t-23 75z" /> +<glyph unicode="ø" horiz-adv-x="1200" d="M119 545q0 266 129 414.5t354 148.5q179 0 301 -104l96 124l74 -55l-104 -137q112 -147 112 -391q0 -266 -129 -415.5t-356 -149.5q-173 0 -291 98l-86 -113l-72 58l93 120q-121 153 -121 402zM223 545q0 -200 78 -322l543 705q-98 90 -246 90q-180 0 -277.5 -123.5 t-97.5 -349.5zM362 152q94 -82 238 -82q180 0 278.5 125.5t98.5 349.5q0 190 -72 309z" /> +<glyph unicode="ù" horiz-adv-x="1208" d="M170 377v710h98v-704q0 -164 69 -238.5t214 -74.5q194 0 285.5 98t91.5 319v600h98v-1087h-84l-18 150h-6q-106 -170 -377 -170q-371 0 -371 397zM304 1552v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="ú" horiz-adv-x="1208" d="M170 377v710h98v-704q0 -164 69 -238.5t214 -74.5q194 0 285.5 98t91.5 319v600h98v-1087h-84l-18 150h-6q-106 -170 -377 -170q-371 0 -371 397zM495 1241v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="û" horiz-adv-x="1208" d="M170 377v710h98v-704q0 -164 69 -238.5t214 -74.5q194 0 285.5 98t91.5 319v600h98v-1087h-84l-18 150h-6q-106 -170 -377 -170q-371 0 -371 397zM313 1241v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70z" /> +<glyph unicode="ü" horiz-adv-x="1208" d="M170 377v710h98v-704q0 -164 69 -238.5t214 -74.5q194 0 285.5 98t91.5 319v600h98v-1087h-84l-18 150h-6q-106 -170 -377 -170q-371 0 -371 397zM350 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM731 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86 q-63 0 -63 86z" /> +<glyph unicode="ý" horiz-adv-x="940" d="M0 1087h102l230 -610q105 -281 133 -379h6q42 129 137 385l230 604h102l-487 -1263q-59 -154 -99 -208t-93.5 -81t-129.5 -27q-57 0 -127 21v86q58 -16 125 -16q51 0 90 24t70.5 74.5t73 160t53.5 142.5zM361 1241v16q73 79 144.5 171.5t97.5 140.5h141v-17 q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="þ" horiz-adv-x="1219" d="M182 -492v2048h99v-391l-7 -247h7q114 190 368 190q220 0 335.5 -144.5t115.5 -420.5q0 -268 -121.5 -415.5t-331.5 -147.5q-251 0 -366 188h-7l3 -84q4 -74 4 -162v-414h-99zM281 541q0 -255 85.5 -364t278.5 -109q167 0 258.5 124t91.5 347q0 479 -348 479 q-193 0 -279.5 -105t-86.5 -354v-18z" /> +<glyph unicode="ÿ" horiz-adv-x="940" d="M0 1087h102l230 -610q105 -281 133 -379h6q42 129 137 385l230 604h102l-487 -1263q-59 -154 -99 -208t-93.5 -81t-129.5 -27q-57 0 -127 21v86q58 -16 125 -16q51 0 90 24t70.5 74.5t73 160t53.5 142.5zM214 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86 q-63 0 -63 86zM595 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="Œ" horiz-adv-x="1839" d="M129 735q0 347 174.5 545.5t480.5 198.5q78 0 183 -17h747v-94h-655v-553h616v-94h-616v-627h655v-94h-756q-76 -16 -176 -16q-305 0 -479 200t-174 551zM240 733q0 -315 140.5 -484t401.5 -169q109 0 174 18v1266q-62 16 -172 16q-262 0 -403 -167.5t-141 -479.5z" /> +<glyph unicode="œ" horiz-adv-x="1942" d="M119 545q0 266 129 414.5t354 148.5q151 0 251 -70t157 -209q110 279 399 279q192 0 303 -134t111 -364v-80h-762q2 -230 100.5 -345t276.5 -115q93 0 163.5 13t178.5 56v-90q-92 -40 -170 -54.5t-172 -14.5q-156 0 -266.5 67.5t-165.5 198.5q-59 -128 -158 -197 t-252 -69q-143 0 -252 69t-167 198t-58 298zM223 545q0 -224 98.5 -349.5t278.5 -125.5q174 0 265 122.5t91 352.5q0 224 -93 348.5t-265 124.5q-180 0 -277.5 -123.5t-97.5 -349.5zM1065 618h653q0 189 -82 295.5t-227 106.5q-155 0 -242 -104t-102 -298z" /> +<glyph unicode="Ÿ" horiz-adv-x="1081" d="M0 1462h117l426 -800l428 800h110l-487 -897v-565h-105v557zM288 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM669 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="ˆ" horiz-adv-x="1182" d="M299 1241v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70z" /> +<glyph unicode="˜" horiz-adv-x="1182" d="M283 1243q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73z" /> +<glyph unicode=" " horiz-adv-x="953" /> +<glyph unicode=" " horiz-adv-x="1907" /> +<glyph unicode=" " horiz-adv-x="953" /> +<glyph unicode=" " horiz-adv-x="1907" /> +<glyph unicode=" " horiz-adv-x="635" /> +<glyph unicode=" " horiz-adv-x="476" /> +<glyph unicode=" " horiz-adv-x="317" /> +<glyph unicode=" " horiz-adv-x="317" /> +<glyph unicode=" " horiz-adv-x="238" /> +<glyph unicode=" " horiz-adv-x="381" /> +<glyph unicode=" " horiz-adv-x="105" /> +<glyph unicode="‐" horiz-adv-x="659" d="M92 512v82h475v-82h-475z" /> +<glyph unicode="‑" horiz-adv-x="659" d="M92 512v82h475v-82h-475z" /> +<glyph unicode="‒" horiz-adv-x="659" d="M92 512v82h475v-82h-475z" /> +<glyph unicode="–" horiz-adv-x="1024" d="M82 512v82h860v-82h-860z" /> +<glyph unicode="—" horiz-adv-x="2048" d="M82 512v82h1884v-82h-1884z" /> +<glyph unicode="‘" horiz-adv-x="297" d="M29 981q32 112 81.5 251t92.5 230h65q-30 -101 -64.5 -257t-45.5 -244h-117z" /> +<glyph unicode="’" horiz-adv-x="297" d="M29 961q29 96 61 241.5t49 259.5h117l12 -20q-75 -265 -174 -481h-65z" /> +<glyph unicode="‚" horiz-adv-x="451" d="M68 -263q29 96 61 241.5t49 259.5h117l12 -20q-75 -265 -174 -481h-65z" /> +<glyph unicode="“" horiz-adv-x="614" d="M29 981q32 112 81.5 251t92.5 230h65q-30 -101 -64.5 -257t-45.5 -244h-117zM346 981q34 120 83 255t91 226h66q-30 -98 -63 -248.5t-48 -252.5h-117z" /> +<glyph unicode="”" horiz-adv-x="614" d="M29 961q29 96 61 241.5t49 259.5h117l12 -20q-75 -265 -174 -481h-65zM346 961q30 98 63 248.5t48 252.5h116l13 -20q-36 -128 -85 -261t-89 -220h-66z" /> +<glyph unicode="„" horiz-adv-x="768" d="M68 -263q29 96 61 241.5t49 259.5h117l12 -20q-75 -265 -174 -481h-65zM385 -263q30 98 63 248.5t48 252.5h116l13 -20q-36 -128 -85 -261t-89 -220h-66z" /> +<glyph unicode="•" horiz-adv-x="770" d="M231 748q0 89 40.5 134.5t113.5 45.5t113.5 -47t40.5 -133q0 -85 -41 -133t-113 -48t-113 47t-41 134z" /> +<glyph unicode="…" horiz-adv-x="1466" d="M162 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98zM651 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98zM1141 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98z" /> +<glyph unicode=" " horiz-adv-x="381" /> +<glyph unicode="‹" horiz-adv-x="524" d="M82 516v27l309 393l62 -43l-254 -363l254 -362l-62 -43z" /> +<glyph unicode="›" horiz-adv-x="524" d="M72 168l254 362l-254 363l61 43l309 -391v-27l-309 -393z" /> +<glyph unicode=" " horiz-adv-x="476" /> +<glyph unicode="€" d="M74 528v82h172q-4 38 -4 113l4 102h-172v82h184q39 272 183 425t362 153q88 0 161 -17t148 -57l-39 -86q-132 72 -270 72q-174 0 -288 -125.5t-155 -364.5h502v-82h-510l-4 -104v-24q0 -65 4 -87h449v-82h-443q30 -217 147.5 -338.5t301.5 -121.5q148 0 287 65v-94 q-81 -34 -150.5 -46.5t-140.5 -12.5q-228 0 -367.5 140t-181.5 408h-180z" /> +<glyph unicode="™" horiz-adv-x="1485" d="M10 1384v78h522v-78h-219v-643h-86v643h-217zM608 741v721h125l221 -606l224 606h125v-721h-86v398l4 207h-7l-227 -605h-74l-221 609h-6l4 -201v-408h-82z" /> +<glyph unicode="" horiz-adv-x="1085" d="M0 0v1085h1085v-1085h-1085z" /> +</font> +</defs></svg> \ No newline at end of file diff --git a/refs/pull/405/merge/_static/fonts/opensans-light-webfont.ttf b/refs/pull/405/merge/_static/fonts/opensans-light-webfont.ttf new file mode 100644 index 00000000..1218bd92 Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/opensans-light-webfont.ttf differ diff --git a/refs/pull/405/merge/_static/fonts/opensans-light-webfont.woff b/refs/pull/405/merge/_static/fonts/opensans-light-webfont.woff new file mode 100644 index 00000000..4dc04810 Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/opensans-light-webfont.woff differ diff --git a/refs/pull/405/merge/_static/fonts/opensans-lightitalic-webfont.eot b/refs/pull/405/merge/_static/fonts/opensans-lightitalic-webfont.eot new file mode 100644 index 00000000..7635c37b Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/opensans-lightitalic-webfont.eot differ diff --git a/refs/pull/405/merge/_static/fonts/opensans-lightitalic-webfont.svg b/refs/pull/405/merge/_static/fonts/opensans-lightitalic-webfont.svg new file mode 100644 index 00000000..b99917fc --- /dev/null +++ b/refs/pull/405/merge/_static/fonts/opensans-lightitalic-webfont.svg @@ -0,0 +1,244 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata></metadata> +<defs> +<font id="OpenSansLightItalic" horiz-adv-x="1128" > +<font-face units-per-em="2048" ascent="1638" descent="-410" /> +<missing-glyph horiz-adv-x="532" /> +<glyph unicode="fi" horiz-adv-x="1040" d="M-250 -383q53 -16 100 -16q88 0 134 53t75 186l246 1166h-205l14 67l205 14l35 160q35 168 116.5 244t227.5 76q73 0 166 -31l-25 -80q-87 27 -147 27q-96 0 -153.5 -53.5t-84.5 -178.5l-35 -164h248l-16 -81h-248l-252 -1190q-33 -161 -104 -234.5t-195 -73.5 q-48 0 -102 19v90zM641 0l231 1087h96l-229 -1087h-98zM915 1366q0 55 22 88t60 33q57 0 57 -72q0 -57 -22 -90t-57 -33q-29 0 -44.5 19.5t-15.5 54.5z" /> +<glyph unicode="fl" horiz-adv-x="1042" d="M-250 -383q53 -16 100 -16q88 0 134 53t75 186l246 1166h-205l14 67l205 14l35 160q35 168 116.5 244t227.5 76q73 0 166 -31l-25 -80q-87 27 -147 27q-96 0 -153.5 -53.5t-84.5 -178.5l-35 -164h248l-16 -81h-248l-252 -1190q-33 -161 -104 -234.5t-195 -73.5 q-48 0 -102 19v90zM643 0l334 1556h94l-334 -1556h-94z" /> +<glyph unicode="ffi" horiz-adv-x="1616" d="M-250 -383q53 -16 100 -16q88 0 134 53t75 186l246 1166h-205l14 67l205 14l35 160q35 168 116.5 244t227.5 76q73 0 166 -31l-25 -80q-87 27 -147 27q-96 0 -153.5 -53.5t-84.5 -178.5l-35 -164h477l35 160q35 168 116.5 244t227.5 76q73 0 166 -31l-24 -80 q-87 27 -148 27q-97 0 -154.5 -54.5t-82.5 -177.5l-35 -164h248l-17 -81h-248l-252 -1190q-34 -165 -105.5 -236.5t-193.5 -71.5q-48 0 -102 19v90q53 -16 100 -16q88 0 134 53t75 186l244 1166h-477l-252 -1190q-33 -161 -104 -234.5t-195 -73.5q-48 0 -102 19v90zM1217 0 l231 1087h96l-229 -1087h-98zM1491 1366q0 55 22 88t60 33q57 0 57 -72q0 -57 -22 -90t-57 -33q-29 0 -44.5 19.5t-15.5 54.5z" /> +<glyph unicode="ffl" horiz-adv-x="1626" d="M-250 -383q53 -16 100 -16q88 0 134 53t75 186l246 1166h-205l14 67l205 14l35 160q35 168 116.5 244t227.5 76q73 0 166 -31l-25 -80q-87 27 -147 27q-96 0 -153.5 -53.5t-84.5 -178.5l-35 -164h477l35 160q35 168 116.5 244t227.5 76q73 0 166 -31l-24 -80 q-87 27 -148 27q-97 0 -154.5 -54.5t-82.5 -177.5l-35 -164h248l-17 -81h-248l-252 -1190q-34 -165 -105.5 -236.5t-193.5 -71.5q-48 0 -102 19v90q53 -16 100 -16q88 0 134 53t75 186l244 1166h-477l-252 -1190q-33 -161 -104 -234.5t-195 -73.5q-48 0 -102 19v90zM1227 0 l334 1556h94l-334 -1556h-94z" /> +<glyph horiz-adv-x="0" /> +<glyph horiz-adv-x="2048" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="	" horiz-adv-x="532" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="!" horiz-adv-x="502" d="M80 57q0 56 25 88.5t69 32.5q66 0 66 -72q0 -53 -25 -87.5t-68 -34.5q-67 0 -67 73zM186 377l203 1085h119l-260 -1085h-62z" /> +<glyph unicode=""" horiz-adv-x="721" d="M248 934l80 528h127l-146 -528h-61zM578 934l79 528h127l-145 -528h-61z" /> +<glyph unicode="#" horiz-adv-x="1323" d="M82 451l8 79h299l119 398h-297l8 80h311l134 454h90l-136 -454h365l135 454h86l-135 -454h285l-8 -80h-302l-118 -398h303l-8 -79h-320l-133 -451h-90l135 451h-360l-134 -451h-88l134 451h-283zM475 530h363l120 398h-362z" /> +<glyph unicode="$" d="M141 182v94q65 -34 153.5 -53.5t160.5 -19.5l110 512q-110 53 -153 91t-66.5 87.5t-23.5 116.5q0 155 105.5 250.5t272.5 99.5l41 192h80l-41 -192q149 -5 277 -68l-35 -78q-110 61 -256 70l-109 -514q124 -60 172.5 -99.5t73.5 -88.5t25 -115q0 -151 -110.5 -243 t-297.5 -103l-53 -240h-82l51 240q-79 2 -158 18t-137 43zM410 1018q0 -78 37 -128.5t137 -96.5l102 491q-134 -9 -205 -80t-71 -186zM537 203q142 7 223.5 74.5t81.5 183.5q0 76 -48 129.5t-157 97.5z" /> +<glyph unicode="%" horiz-adv-x="1556" d="M145 862q0 160 52 312t138 229.5t193 77.5q232 0 232 -283q0 -175 -50 -327t-136 -230t-197 -78q-112 0 -172 75.5t-60 223.5zM213 0l1135 1462h110l-1139 -1462h-106zM231 868q0 -115 41 -173t113 -58q84 0 148.5 72t102.5 204t38 277q0 109 -36 163t-114 54 q-79 0 -145 -71.5t-107 -203t-41 -264.5zM905 276q0 160 52 312t138 229.5t193 77.5q121 0 176.5 -71.5t55.5 -211.5q0 -175 -50 -327t-136 -230t-197 -78q-112 0 -172 75.5t-60 223.5zM991 283q0 -116 41 -174t113 -58q130 0 209.5 166.5t79.5 386.5q0 109 -36 163t-114 54 q-80 0 -146.5 -72.5t-106.5 -202.5t-40 -263z" /> +<glyph unicode="&" horiz-adv-x="1331" d="M78 324q0 162 99 277.5t325 215.5l-41 67q-78 128 -78 251q0 157 101 253.5t264 96.5q145 0 227 -76.5t82 -206.5q0 -85 -41 -154t-121 -128t-256 -138l330 -463q73 75 135.5 176.5t91.5 186.5h111q-102 -247 -285 -436l184 -246h-123l-131 184q-121 -108 -242 -156 t-266 -48q-167 0 -266.5 94t-99.5 250zM176 328q0 -119 78 -192t211 -73q108 0 211.5 42.5t222.5 146.5l-352 493q-164 -79 -232 -134.5t-103.5 -124t-35.5 -158.5zM485 1135q0 -132 109 -281q203 89 279.5 163.5t76.5 182.5q0 91 -56.5 143t-145.5 52q-125 0 -194 -68 t-69 -192z" /> +<glyph unicode="'" horiz-adv-x="403" d="M254 934l80 528h127l-146 -528h-61z" /> +<glyph unicode="(" horiz-adv-x="526" d="M104 270q0 343 122 633t382 559h105q-259 -276 -384.5 -568t-125.5 -618q0 -317 127 -600h-80q-146 262 -146 594z" /> +<glyph unicode=")" horiz-adv-x="526" d="M-156 -324q257 274 383.5 566.5t126.5 619.5q0 148 -28.5 294t-98.5 306h80q146 -262 146 -594q0 -345 -123.5 -636t-380.5 -556h-105z" /> +<glyph unicode="*" horiz-adv-x="1137" d="M233 1217l39 102l394 -168l47 408l121 -19l-109 -405l438 8l-8 -107l-416 29l181 -401l-115 -37l-135 417l-285 -348l-78 78l318 318z" /> +<glyph unicode="+" d="M162 672v100h401v404h101v-404h401v-100h-401v-400h-101v400h-401z" /> +<glyph unicode="," horiz-adv-x="451" d="M-90 -264q79 132 141 271t88 231h111l8 -23q-34 -92 -114 -233.5t-160 -245.5h-74z" /> +<glyph unicode="-" horiz-adv-x="629" d="M82 502l18 90h457l-16 -90h-459z" /> +<glyph unicode="." horiz-adv-x="485" d="M82 55q0 56 25 88.5t69 32.5q66 0 66 -72q0 -53 -25 -87.5t-67 -34.5q-68 0 -68 73z" /> +<glyph unicode="/" horiz-adv-x="641" d="M-100 0l815 1462h112l-817 -1462h-110z" /> +<glyph unicode="0" d="M139 494q0 186 44.5 381.5t124 334t187 207t240.5 68.5q340 0 340 -469q0 -201 -41 -405t-116.5 -346t-183.5 -213.5t-242 -71.5q-176 0 -264.5 126.5t-88.5 387.5zM242 504q0 -222 62.5 -329t197.5 -107q139 0 244 112t166 337t61 489q0 199 -59.5 295t-190.5 96 q-134 0 -241.5 -113t-173.5 -329t-66 -451z" /> +<glyph unicode="1" d="M354 1204l406 258h90l-313 -1462h-105l225 1055q19 92 74 293q-42 -36 -75.5 -61t-249.5 -161z" /> +<glyph unicode="2" d="M39 0l22 104l449 402q198 177 284 276.5t126.5 186.5t40.5 180q0 112 -66 178t-197 66q-176 0 -333 -129l-54 73q180 146 394 146q173 0 268.5 -85t95.5 -237q0 -110 -43.5 -208.5t-141.5 -211.5t-311 -303l-383 -338v-4h736l-17 -96h-870z" /> +<glyph unicode="3" d="M55 53v101q172 -86 344 -86q197 0 303.5 89.5t106.5 252.5q0 145 -89 223t-247 78h-117l21 96h110q209 0 333 95.5t124 258.5q0 114 -63.5 175t-188.5 61q-167 0 -344 -131l-49 75q84 67 188 104.5t218 37.5q161 0 252.5 -82.5t91.5 -226.5q0 -162 -106 -275t-286 -143 v-4q117 -24 185.5 -115.5t68.5 -226.5q0 -134 -64 -233t-179.5 -148t-274.5 -49q-96 0 -184.5 20.5t-153.5 52.5z" /> +<glyph unicode="4" d="M23 371l20 96l881 1010h118l-215 -1018h265l-21 -88h-264l-80 -371h-96l80 371h-688zM150 459h579q79 369 119 558.5t86 354.5h-4q-66 -91 -129 -166z" /> +<glyph unicode="5" d="M88 51v107q170 -90 340 -90q208 0 328.5 114.5t120.5 313.5q0 140 -85 219.5t-225 79.5q-133 0 -243 -41l-66 49l193 659h624l-18 -96h-541l-149 -516q98 29 215 29q188 0 292.5 -102t104.5 -279q0 -237 -148 -377.5t-407 -140.5q-84 0 -177.5 20t-158.5 51z" /> +<glyph unicode="6" d="M170 428q0 283 105 544.5t269.5 385t383.5 123.5q123 0 182 -21l-18 -90q-86 23 -170 23q-233 0 -393.5 -174t-233.5 -502h8q68 94 164 143t211 49q161 0 250.5 -100.5t89.5 -282.5q0 -156 -60 -281t-171 -195t-257 -70q-171 0 -265.5 119t-94.5 329zM270 414 q0 -164 72.5 -255t200.5 -91q112 0 196.5 58.5t130 162t45.5 229.5q0 146 -67 224.5t-195 78.5q-81 0 -154 -31.5t-129 -87t-78 -115t-22 -173.5z" /> +<glyph unicode="7" d="M244 0l796 1366h-766l23 96h858l-20 -110l-779 -1352h-112z" /> +<glyph unicode="8" d="M98 326q0 159 100.5 268.5t321.5 187.5q-100 72 -144 152t-44 180q0 159 114 265t291 106q163 0 258 -85t95 -229q0 -138 -84 -234.5t-285 -172.5q130 -78 190 -170.5t60 -208.5t-58 -208t-165.5 -144.5t-260.5 -52.5q-178 0 -283.5 92.5t-105.5 253.5zM201 340 q0 -136 77.5 -206.5t219.5 -70.5q168 0 270 91t102 233q0 104 -62 189t-198 157q-218 -73 -313.5 -167.5t-95.5 -225.5zM428 1114q0 -91 41.5 -159t157.5 -142q192 62 279 144t87 206q0 109 -70.5 172.5t-195.5 63.5q-130 0 -214.5 -82t-84.5 -203z" /> +<glyph unicode="9" d="M115 2v90q87 -29 192 -29q474 0 627 674h-8q-140 -192 -367 -192q-162 0 -255 105t-93 284q0 155 59.5 281t170.5 196t257 70q174 0 267.5 -115.5t93.5 -333.5q0 -288 -101.5 -548t-263.5 -382t-393 -122q-114 0 -186 22zM313 942q0 -145 67.5 -225t192.5 -80 q83 0 157.5 32.5t129 87.5t76.5 114t22 176q0 166 -71 256t-201 90q-112 0 -197.5 -58.5t-130.5 -162.5t-45 -230z" /> +<glyph unicode=":" horiz-adv-x="485" d="M102 55q0 56 25.5 88.5t69.5 32.5q65 0 65 -72q0 -55 -25.5 -88.5t-66.5 -33.5q-68 0 -68 73zM260 989q0 57 25.5 89t68.5 32q66 0 66 -72q0 -55 -25 -89t-67 -34q-68 0 -68 74z" /> +<glyph unicode=";" horiz-adv-x="485" d="M-53 -264q79 132 141 271t88 231h111l8 -23q-35 -96 -118.5 -242t-156.5 -237h-73zM266 989q0 57 25.5 89t68.5 32q66 0 66 -72q0 -55 -25 -89t-67 -34q-68 0 -68 74z" /> +<glyph unicode="<" d="M137 676v74l914 471v-103l-801 -399l801 -350v-107z" /> +<glyph unicode="=" d="M168 461v98h903v-98h-903zM168 885v100h903v-100h-903z" /> +<glyph unicode=">" d="M170 262v107l801 350l-801 399v103l915 -471v-74z" /> +<glyph unicode="?" horiz-adv-x="799" d="M170 59q0 56 25 88.5t69 32.5q66 0 66 -71q0 -54 -24.5 -88.5t-67.5 -34.5q-68 0 -68 73zM182 1376q85 49 171.5 78t187.5 29q159 0 250.5 -84.5t91.5 -229.5q0 -127 -66 -234t-231 -226q-85 -61 -132.5 -108.5t-73 -95t-46.5 -143.5h-92l6 29q29 132 82 206.5t157 147.5 q118 84 175 145.5t86.5 127.5t29.5 141q0 108 -67.5 170t-182.5 62q-139 0 -307 -101z" /> +<glyph unicode="@" horiz-adv-x="1724" d="M125 508q0 276 121.5 493.5t337 337t473.5 119.5q189 0 330.5 -72.5t221 -213t79.5 -314.5q0 -179 -56 -323.5t-154.5 -227t-211.5 -82.5q-98 0 -154.5 55t-56.5 144h-4q-54 -97 -132.5 -148t-168.5 -51q-112 0 -178 73t-66 202q0 156 63 283t178 198.5t261 71.5 q122 0 252 -52l-84 -315q-39 -140 -39 -221q0 -71 34.5 -111.5t100.5 -40.5q86 0 160 73.5t117.5 198t43.5 251.5q0 156 -65 277t-187 188t-292 67q-235 0 -424.5 -108.5t-295.5 -304t-106 -439.5q0 -288 155 -449t435 -161q207 0 420 82v-90q-210 -82 -428 -82 q-203 0 -357.5 82.5t-238.5 239t-84 370.5zM610 506q0 -92 40.5 -142.5t113.5 -50.5q101 0 180.5 89t124.5 255l78 289q-66 23 -139 23q-113 0 -204.5 -59t-142.5 -165.5t-51 -238.5z" /> +<glyph unicode="A" horiz-adv-x="1059" d="M-111 0l822 1468h67l201 -1468h-105l-69 520h-512l-287 -520h-117zM344 612h449l-39 291q-31 242 -39 402q-30 -63 -64.5 -130t-306.5 -563z" /> +<glyph unicode="B" horiz-adv-x="1202" d="M102 0l310 1462h379q190 0 290.5 -84t100.5 -241q0 -153 -90 -249t-254 -124v-4q125 -31 188.5 -113.5t63.5 -204.5q0 -205 -140.5 -323.5t-390.5 -118.5h-457zM223 90h342q201 0 309.5 87.5t108.5 256.5q0 145 -90 216t-275 71h-260zM377 811h278q206 0 313 81t107 238 q0 119 -78 180.5t-229 61.5h-272z" /> +<glyph unicode="C" horiz-adv-x="1169" d="M170 535q0 266 104.5 488t284.5 341t402 119q177 0 307 -68l-45 -90q-55 30 -124.5 47t-137.5 17q-197 0 -351.5 -104.5t-245 -304.5t-90.5 -441q0 -225 110.5 -346t317.5 -121q140 0 304 51v-94q-156 -49 -316 -49q-252 0 -386 145t-134 410z" /> +<glyph unicode="D" horiz-adv-x="1350" d="M102 0l310 1462h305q282 0 426.5 -147.5t144.5 -435.5q0 -253 -109.5 -461.5t-300.5 -313t-446 -104.5h-330zM221 90h209q226 0 394.5 94.5t261 275.5t92.5 412q0 498 -476 498h-206z" /> +<glyph unicode="E" horiz-adv-x="1067" d="M102 0l310 1462h727l-21 -94h-624l-117 -553h590l-21 -94h-588l-135 -627h627l-21 -94h-727z" /> +<glyph unicode="F" horiz-adv-x="981" d="M102 0l310 1462h708l-20 -94h-604l-134 -620h570l-21 -95h-569l-137 -653h-103z" /> +<glyph unicode="G" horiz-adv-x="1374" d="M170 547q0 265 105 483.5t283.5 335.5t395.5 117q113 0 203 -19t184 -59l-38 -94q-110 46 -189.5 62t-167.5 16q-184 0 -339 -107.5t-244 -301.5t-89 -433q0 -229 114.5 -352t326.5 -123q155 0 309 47l117 526h-303l18 90h406l-150 -682q-211 -73 -405 -73 q-257 0 -397 146t-140 421z" /> +<glyph unicode="H" horiz-adv-x="1366" d="M102 0l310 1462h102l-139 -649h760l137 649h100l-309 -1462h-100l151 719h-760l-149 -719h-103z" /> +<glyph unicode="I" horiz-adv-x="504" d="M102 0l310 1462h98l-309 -1462h-99z" /> +<glyph unicode="J" horiz-adv-x="477" d="M-324 -336l11 92q57 -20 137 -20q213 0 262 241l309 1485h105l-314 -1491q-35 -170 -125 -250.5t-241 -80.5q-48 0 -88 8t-56 16z" /> +<glyph unicode="K" horiz-adv-x="1122" d="M102 0l310 1462h102l-158 -723l133 121l680 602h138l-699 -610l371 -852h-111l-342 788l-190 -153l-131 -635h-103z" /> +<glyph unicode="L" horiz-adv-x="938" d="M102 0l310 1462h102l-289 -1366h621l-23 -96h-721z" /> +<glyph unicode="M" horiz-adv-x="1669" d="M109 0l309 1462h143l205 -1257h6l733 1257h150l-301 -1462h-101l191 901q79 369 100 447h-6l-780 -1348h-51l-222 1348h-6q-20 -154 -78 -426l-196 -922h-96z" /> +<glyph unicode="N" horiz-adv-x="1372" d="M102 0l310 1462h80l522 -1294h8q23 176 74 416l188 878h94l-309 -1462h-86l-516 1284h-8q-23 -149 -48 -273t-214 -1011h-95z" /> +<glyph unicode="O" horiz-adv-x="1464" d="M172 559q0 262 93 477.5t255 331t373 115.5q247 0 378.5 -148.5t131.5 -423.5q0 -255 -94 -481.5t-252 -338t-365 -111.5q-250 0 -385 149t-135 430zM276 573q0 -245 109.5 -373t319.5 -128q169 0 300 98.5t210 300t79 430.5q0 240 -104.5 364t-310.5 124 q-174 0 -308.5 -101t-214.5 -298t-80 -417z" /> +<glyph unicode="P" horiz-adv-x="1145" d="M102 0l310 1462h315q202 0 310 -92.5t108 -267.5q0 -500 -610 -500h-201l-129 -602h-103zM350 694h191q252 0 373.5 96.5t121.5 305.5q0 274 -329 274h-211z" /> +<glyph unicode="Q" horiz-adv-x="1464" d="M172 559q0 262 93 477.5t255 331t373 115.5q247 0 378.5 -148.5t131.5 -423.5q0 -216 -70 -418t-186.5 -324t-274.5 -167l267 -350h-142l-231 332l-74 -4q-250 0 -385 149t-135 430zM276 573q0 -245 109.5 -373t319.5 -128q169 0 300 98.5t210 300t79 430.5 q0 240 -104.5 364t-310.5 124q-174 0 -308.5 -101t-214.5 -298t-80 -417z" /> +<glyph unicode="R" horiz-adv-x="1145" d="M102 0l310 1462h303q430 0 430 -360q0 -182 -103.5 -303t-281.5 -152q201 -591 221 -647h-111l-211 633h-323l-131 -633h-103zM358 725h252q208 0 317 95.5t109 281.5q0 268 -329 268h-211z" /> +<glyph unicode="S" horiz-adv-x="1020" d="M37 55v109q163 -92 348 -92q188 0 295.5 86.5t107.5 232.5q0 61 -17 104.5t-52.5 78.5t-91 68t-131.5 75q-150 76 -209.5 164t-59.5 206t59 207.5t165 139t237 49.5q99 0 180 -17.5t168 -60.5l-32 -94q-66 40 -151.5 63t-164.5 23q-163 0 -259.5 -82.5t-96.5 -218.5 q0 -103 49 -170t182 -133q154 -79 213.5 -130t89 -113t29.5 -147q0 -126 -65.5 -224.5t-179.5 -148.5t-269 -50q-88 0 -172.5 17t-171.5 58z" /> +<glyph unicode="T" horiz-adv-x="985" d="M193 1368l20 94h973l-19 -94h-440l-289 -1368h-102l289 1368h-432z" /> +<glyph unicode="U" horiz-adv-x="1370" d="M176 381q0 83 27 201l186 880h103l-193 -899q-20 -89 -20 -184q0 -309 342 -309q195 0 307.5 96.5t158.5 318.5l207 977h101l-207 -977q-58 -270 -197 -387.5t-375 -117.5q-440 0 -440 401z" /> +<glyph unicode="V" horiz-adv-x="1079" d="M201 1462h100l117 -950q26 -217 35 -365h4q51 111 124 247l572 1068h117l-799 -1462h-88z" /> +<glyph unicode="W" horiz-adv-x="1702" d="M238 1462h100l47 -1031l4 -165l-2 -86h6q85 226 170 398l434 884h105l61 -878q19 -266 19 -410h6q30 86 61.5 163t493.5 1125h108q-169 -365 -330.5 -731t-328.5 -731h-78l-78 1075q-11 142 -11 219l1 47h-8q-27 -76 -62 -153.5t-563 -1187.5h-82z" /> +<glyph unicode="X" horiz-adv-x="971" d="M-135 0l608 766l-272 696h106l240 -626l483 626h119l-555 -719l285 -743h-107l-254 678l-526 -678h-127z" /> +<glyph unicode="Y" horiz-adv-x="965" d="M193 1462h100l201 -817l544 817h117l-631 -932l-108 -530h-105l119 545z" /> +<glyph unicode="Z" d="M-12 0l22 92l1069 1276h-764l23 94h887l-19 -88l-1069 -1280h799l-23 -94h-925z" /> +<glyph unicode="[" horiz-adv-x="537" d="M-57 -324l376 1786h429l-19 -90h-330l-340 -1605h330l-20 -91h-426z" /> +<glyph unicode="\" horiz-adv-x="641" d="M209 1462h86l242 -1462h-82z" /> +<glyph unicode="]" horiz-adv-x="537" d="M-176 -324l18 91h330l340 1605h-330l21 90h426l-377 -1786h-428z" /> +<glyph unicode="^" horiz-adv-x="1047" d="M70 569l587 906h91l260 -906h-105l-217 809l-500 -809h-116z" /> +<glyph unicode="_" horiz-adv-x="801" d="M-182 -291l18 86h807l-18 -86h-807z" /> +<glyph unicode="`" horiz-adv-x="1135" d="M487 1548v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="a" horiz-adv-x="1133" d="M102 354q0 197 75 376t200.5 276.5t277.5 97.5q232 0 279 -219h6l59 202h80l-229 -1087h-82l45 274h-6q-84 -142 -187 -218t-237 -76q-281 0 -281 374zM205 365q0 -152 50 -223.5t151 -71.5q89 0 177.5 62t159 166t107.5 230t37 213q0 79 -26 141.5t-77 99t-127 36.5 q-124 0 -224 -82t-164 -245.5t-64 -325.5z" /> +<glyph unicode="b" horiz-adv-x="1151" d="M76 0l327 1556h95q-131 -628 -162 -751h6q93 156 199 229.5t231 73.5q281 0 281 -375q0 -203 -76 -380t-201 -273t-276 -96q-113 0 -186 59t-97 166h-6l-55 -209h-80zM268 346q0 -129 64 -202.5t166 -73.5q124 0 224 83t164 245t64 325q0 152 -49 223.5t-151 71.5 q-91 0 -180 -61.5t-160.5 -169.5t-106.5 -235t-35 -206z" /> +<glyph unicode="c" horiz-adv-x="887" d="M102 397q0 193 73.5 361.5t198.5 257t290 88.5q134 0 241 -43l-28 -90q-107 47 -218 47q-129 0 -232.5 -77t-162.5 -222t-59 -320q0 -158 73.5 -243.5t208.5 -85.5q71 0 131.5 13t131.5 46v-92q-116 -57 -273 -57q-174 0 -274.5 110.5t-100.5 306.5z" /> +<glyph unicode="d" horiz-adv-x="1133" d="M102 354q0 193 71.5 370t197.5 278.5t284 101.5q230 0 279 -219h4q12 66 143 671h99l-330 -1556h-82l45 274h-6q-173 -294 -424 -294q-281 0 -281 374zM205 365q0 -295 201 -295q89 0 178.5 62.5t160 168t106.5 231t36 209.5q0 126 -61.5 201.5t-168.5 75.5 q-124 0 -224 -83t-164 -242.5t-64 -327.5z" /> +<glyph unicode="e" horiz-adv-x="928" d="M102 395q0 181 71 347t195.5 264t274.5 98q114 0 182 -61t68 -166q0 -181 -163.5 -276t-485.5 -95h-33q-6 -44 -6 -98q0 -165 74 -251.5t213 -86.5q132 0 276 73v-94q-140 -69 -299 -69q-173 0 -270 109.5t-97 305.5zM225 594h49q517 0 517 270q0 67 -43.5 110.5 t-116.5 43.5q-131 0 -243.5 -115.5t-162.5 -308.5z" /> +<glyph unicode="f" horiz-adv-x="578" d="M-233 -383q53 -16 100 -16q88 0 134 53t75 186l246 1166h-205l14 67l205 14l35 160q35 168 116.5 244t227.5 76q73 0 166 -31l-25 -80q-87 27 -147 27q-96 0 -153.5 -53.5t-84.5 -178.5l-35 -164h248l-16 -81h-248l-252 -1190q-33 -161 -104 -234.5t-195 -73.5 q-48 0 -102 19v90z" /> +<glyph unicode="g" horiz-adv-x="1040" d="M-88 -217q0 236 309 334q-78 42 -78 123q0 123 191 202q-71 36 -110.5 105.5t-39.5 157.5q0 111 53.5 204t148 146t206.5 53q69 0 147 -21h361l-17 -79l-243 -11q26 -28 43.5 -84t17.5 -114q0 -109 -54.5 -206.5t-148 -145.5t-213.5 -48q-63 0 -77 9q-80 -33 -124 -73 t-44 -81t31.5 -64.5t113.5 -31.5l121 -11q346 -31 346 -264q0 -112 -65 -197.5t-187 -131.5t-291 -46q-186 0 -291.5 72t-105.5 203zM14 -207q0 -101 81 -150t224 -49q203 0 317 74.5t114 204.5q0 85 -62.5 130.5t-218.5 57.5l-160 15q-157 -45 -226 -114.5t-69 -168.5z M285 711q0 -112 58.5 -170t164.5 -58q88 0 154 37t102.5 114t36.5 169q0 104 -56 161.5t-157 57.5q-93 0 -161 -43t-105 -116t-37 -152z" /> +<glyph unicode="h" horiz-adv-x="1143" d="M76 0l332 1556h96l-86 -411q-44 -200 -66 -279h6q78 113 186.5 175.5t229.5 62.5q124 0 192 -65t68 -183q0 -70 -24 -182l-148 -674h-98l149 692q21 92 21 156q0 80 -43.5 125t-134.5 45q-112 0 -210.5 -67t-166 -188t-103.5 -286l-102 -477h-98z" /> +<glyph unicode="i" horiz-adv-x="475" d="M76 0l231 1087h96l-229 -1087h-98zM350 1366q0 55 22 88t60 33q57 0 57 -72q0 -57 -22 -90t-57 -33q-29 0 -44.5 19.5t-15.5 54.5z" /> +<glyph unicode="j" horiz-adv-x="475" d="M-279 -381q47 -22 113 -22q82 0 128.5 51.5t72.5 177.5l266 1261h96l-268 -1271q-35 -165 -106.5 -236.5t-188.5 -71.5q-62 0 -113 19v92zM350 1366q0 55 22 88t60 33q57 0 57 -72q0 -57 -22 -90t-57 -33q-29 0 -44.5 19.5t-15.5 54.5z" /> +<glyph unicode="k" horiz-adv-x="944" d="M76 0l330 1556h96l-166 -780l-70 -299h4l609 610h125l-474 -469l297 -618h-106l-264 559l-205 -188l-80 -371h-96z" /> +<glyph unicode="l" horiz-adv-x="475" d="M76 0l334 1556h94l-334 -1556h-94z" /> +<glyph unicode="m" horiz-adv-x="1751" d="M72 0l231 1087h80l-33 -210h6q80 113 181.5 170t212.5 57q106 0 163 -67t60 -195h6q77 129 181 195.5t222 66.5q117 0 182.5 -61.5t65.5 -176.5q0 -29 -2.5 -56.5t-19.5 -119.5l-152 -690h-100l149 680q25 120 25 176q0 77 -43 119.5t-119 42.5q-157 0 -277.5 -137.5 t-168.5 -362.5l-109 -518h-102l147 674q25 125 25 162q0 182 -154 182q-106 0 -200 -67.5t-159 -188.5t-100 -287l-100 -475h-98z" /> +<glyph unicode="n" horiz-adv-x="1143" d="M76 0l231 1087h82l-37 -221h6q164 238 416 238q130 0 195 -64t65 -184q0 -70 -24 -182l-148 -674h-98l149 692q21 92 21 156q0 80 -43.5 125t-134.5 45q-112 0 -210.5 -67t-166 -187.5t-103.5 -286.5l-102 -477h-98z" /> +<glyph unicode="o" horiz-adv-x="1124" d="M98 403q0 191 73 358t197 257t281 90q180 0 278.5 -108.5t98.5 -299.5q0 -197 -71.5 -368.5t-195.5 -261.5t-286 -90q-184 0 -279.5 109.5t-95.5 313.5zM201 408q0 -342 282 -342q127 0 225.5 77.5t157 228t58.5 330.5q0 154 -73 237t-210 83q-124 0 -223 -78.5 t-158 -225t-59 -310.5z" /> +<glyph unicode="p" horiz-adv-x="1149" d="M-33 -492l336 1579h82l-45 -274h6q91 153 195.5 224t228.5 71q135 0 208 -92.5t73 -282.5q0 -195 -72 -371t-197.5 -277t-283.5 -101q-230 0 -279 219h-4q-13 -72 -149 -695h-99zM266 346q0 -125 61.5 -200.5t168.5 -75.5q124 0 225 84t164 243.5t63 325.5 q0 295 -200 295q-87 0 -174 -58.5t-161.5 -167.5t-110.5 -237.5t-36 -208.5z" /> +<glyph unicode="q" horiz-adv-x="1157" d="M98 354q0 201 75.5 379t200.5 274.5t277 96.5q109 0 183.5 -58t99.5 -167h6l55 208h80l-327 -1556h-95l98 470l64 282h-6q-93 -156 -199 -229.5t-231 -73.5q-281 0 -281 374zM201 365q0 -143 45.5 -219t154.5 -76q92 0 182 62.5t160.5 171.5t105 236.5t34.5 200.5 q0 130 -63.5 203.5t-166.5 73.5q-124 0 -224 -83t-164 -245t-64 -325z" /> +<glyph unicode="r" horiz-adv-x="752" d="M72 0l231 1087h80l-29 -204h6q73 94 123 135.5t106.5 64.5t123.5 23q69 0 123 -14l-21 -93q-47 15 -113 15q-94 0 -179 -64t-153 -192t-100 -277l-100 -481h-98z" /> +<glyph unicode="s" horiz-adv-x="827" d="M25 55v107q74 -46 153 -71t148 -25q138 0 211 57.5t73 163.5q0 42 -15.5 74t-50 61.5t-132.5 85.5q-148 80 -200 145.5t-52 159.5q0 128 98.5 209.5t259.5 81.5q75 0 158.5 -17.5t140.5 -46.5l-35 -88q-136 64 -264 64q-116 0 -186 -53t-70 -138q0 -55 17 -88t60.5 -68.5 t119.5 -76.5q114 -63 161.5 -103.5t70 -86.5t22.5 -107q0 -144 -103 -229.5t-280 -85.5q-173 0 -305 75z" /> +<glyph unicode="t" horiz-adv-x="616" d="M113 1006l14 67l184 17l97 253h55l-55 -256h286l-18 -81h-283l-135 -635q-22 -99 -22 -164q0 -139 126 -139q68 0 152 26v-86q-101 -28 -170 -28q-99 0 -153 54.5t-54 158.5q0 73 29 206l129 607h-182z" /> +<glyph unicode="u" horiz-adv-x="1143" d="M109 227q0 60 22 170l150 690h100l-152 -698q-22 -106 -22 -158q0 -74 47.5 -117.5t138.5 -43.5q110 0 207.5 65.5t164 187t99.5 279.5l105 485h98l-231 -1087h-80l28 205h-6q-167 -221 -403 -221q-131 0 -198.5 62t-67.5 181z" /> +<glyph unicode="v" horiz-adv-x="895" d="M104 1087h101l108 -735q26 -165 33 -254h6q51 115 129 256l406 733h102l-600 -1087h-113z" /> +<glyph unicode="w" horiz-adv-x="1393" d="M121 1087h92l13 -821l-3 -157h6q61 134 150 297l373 681h77l64 -681q14 -147 14 -297h6l24 61l101 236l320 681h96l-508 -1087h-108l-60 686q-14 224 -14 266h-6q-34 -92 -144 -290l-356 -662h-117z" /> +<glyph unicode="x" horiz-adv-x="922" d="M-72 0l471 559l-245 528h100l207 -462l373 462h120l-448 -534l258 -553h-98l-224 483l-393 -483h-121z" /> +<glyph unicode="y" horiz-adv-x="920" d="M-217 -379q71 -27 137 -27q80 0 147 49.5t130 164.5t100 184l-174 1095h100l82 -548q51 -351 55 -449h11q43 105 186 367l348 630h103l-713 -1290q-72 -127 -122.5 -178t-114 -81t-146.5 -30q-68 0 -129 21v92z" /> +<glyph unicode="z" horiz-adv-x="887" d="M-29 0l15 72l776 932h-543l17 83h659l-18 -83l-762 -920h602l-17 -84h-729z" /> +<glyph unicode="{" horiz-adv-x="709" d="M59 528l21 78q126 0 191 49t89 158l89 393q30 135 106 195.5t215 60.5h29l-17 -86q-86 -2 -129 -20.5t-69.5 -61.5t-44.5 -120l-74 -338q-30 -134 -91.5 -194.5t-164.5 -78.5v-4q68 -18 105.5 -68.5t37.5 -121.5q0 -52 -24 -164l-47 -225q-13 -58 -13 -101 q0 -61 37.5 -89t138.5 -28v-86h-20q-256 0 -256 199q0 45 16 115l56 252q18 90 18 127q0 159 -199 159z" /> +<glyph unicode="|" d="M584 -510v2071h100v-2071h-100z" /> +<glyph unicode="}" horiz-adv-x="709" d="M-41 -238q96 2 138 21t68.5 61t43.5 121l74 338q27 126 87.5 189.5t168.5 82.5v5q-75 20 -109.5 72.5t-34.5 117.5q0 55 18 131l54 258q12 61 12 101q0 44 -18 69t-54 36t-116 11l20 86h21q131 0 189.5 -51t58.5 -147q0 -41 -17 -115l-55 -252q-19 -95 -19 -127 q0 -77 49.5 -118.5t149.5 -41.5l-20 -78q-125 0 -191 -48.5t-90 -157.5l-88 -394q-32 -139 -108.5 -197.5t-213.5 -58.5h-18v86z" /> +<glyph unicode="~" d="M127 625v94q108 110 233 110q61 0 115 -13.5t156 -57.5q126 -58 219 -58q54 0 107.5 29t117.5 96v-96q-111 -113 -233 -113q-117 0 -271 72q-62 29 -112.5 43t-108.5 14q-49 0 -108 -30.5t-115 -89.5z" /> +<glyph unicode="¡" horiz-adv-x="502" d="M4 -375l260 1086h62l-203 -1086h-119zM272 981q0 55 25 89t68 34q67 0 67 -74q0 -56 -25 -88.5t-69 -32.5q-66 0 -66 72z" /> +<glyph unicode="¢" d="M250 600q0 184 63.5 341t178 253t256.5 111l36 178h90l-38 -176q116 -4 217 -43l-29 -90q-107 47 -217 47q-130 0 -233 -76t-162.5 -221t-59.5 -322q0 -164 74.5 -247t208.5 -83q127 0 264 60v-92q-118 -58 -281 -58l-40 -202h-93l45 215q-132 25 -206 132.5t-74 272.5z " /> +<glyph unicode="£" d="M-4 0l16 84q93 11 165.5 95.5t107.5 236.5l57 260h-199l17 82h198l76 350q41 187 155 279t290 92q170 0 313 -78l-39 -84l-54 26q-108 50 -231 50q-134 0 -220.5 -74.5t-117.5 -220.5l-73 -340h409l-18 -82h-408l-57 -268q-50 -225 -188 -314h759l-20 -94h-938z" /> +<glyph unicode="¤" d="M207 1077l63 64l127 -129q105 78 230 78q118 0 223 -78l131 129l61 -62l-129 -129q78 -106 78 -227q0 -135 -78 -227l129 -127l-61 -62l-131 127q-104 -76 -223 -76q-126 0 -228 80l-129 -129l-61 62l127 127q-74 98 -74 225q0 118 74 225zM350 723q0 -116 80 -196.5 t197 -80.5t198.5 81t81.5 196q0 75 -36.5 140t-102.5 104t-141 39q-114 0 -195.5 -82t-81.5 -201z" /> +<glyph unicode="¥" d="M166 289l18 84h299l41 190h-301l17 76h258l-215 823h100l201 -817l544 817h117l-559 -823h266l-16 -76h-315l-39 -190h317l-18 -84h-316l-59 -289h-105l64 289h-299z" /> +<glyph unicode="¦" d="M578 246h100v-756h-100v756zM578 805v756h100v-756h-100z" /> +<glyph unicode="§" horiz-adv-x="995" d="M102 51v99q47 -27 126 -46.5t153 -19.5q149 0 228 52.5t79 150.5q0 62 -42.5 106t-166.5 96q-155 65 -211.5 130t-56.5 159q0 101 69.5 182t198.5 130q-64 31 -103.5 85.5t-39.5 120.5q0 74 46 134.5t132.5 94.5t202.5 34q163 0 289 -58l-31 -80q-138 54 -264 54 q-124 0 -202.5 -46.5t-78.5 -123.5q0 -59 46 -104.5t183 -106.5q112 -52 158.5 -89.5t71 -85t24.5 -110.5q0 -197 -249 -317q122 -64 122 -197q0 -86 -48 -153.5t-139.5 -105.5t-221.5 -38q-157 0 -275 53zM303 786q0 -57 24.5 -96.5t81 -73t187.5 -81.5q103 49 162 113.5 t59 156.5q0 72 -57.5 126t-200.5 107q-119 -30 -187.5 -97.5t-68.5 -154.5z" /> +<glyph unicode="¨" horiz-adv-x="1135" d="M492 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM836 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="©" horiz-adv-x="1704" d="M147 731q0 200 100 375t275 276t377 101q200 0 375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM240 731q0 -178 88.5 -329.5t240.5 -240.5t330 -89q174 0 325 85.5t243 239t92 334.5q0 178 -89 330 t-240.5 241t-330.5 89q-182 0 -335 -92t-238.5 -243t-85.5 -325zM537 725q0 207 110 332t297 125q119 0 227 -52l-36 -83q-99 45 -191 45q-142 0 -222.5 -94.5t-80.5 -264.5q0 -186 74.5 -275t220.5 -89q85 0 199 43v-88q-104 -45 -209 -45q-187 0 -288 116t-101 330z" /> +<glyph unicode="ª" horiz-adv-x="643" d="M170 1032q0 189 90.5 321t226.5 132q55 0 97.5 -29t66.5 -86h6l35 103h66l-137 -650h-72l22 125h-4q-96 -137 -223 -137q-80 0 -127 56.5t-47 164.5zM258 1028q0 -143 111 -143q66 0 133.5 75.5t97.5 184.5q16 51 16 123q0 58 -36 100.5t-93 42.5q-94 0 -161.5 -111.5 t-67.5 -271.5z" /> +<glyph unicode="«" horiz-adv-x="860" d="M61 541l2 26l363 365l57 -49l-317 -336l213 -385l-64 -39zM422 541l2 26l362 365l58 -49l-314 -336l209 -385l-63 -39z" /> +<glyph unicode="¬" d="M125 672v100h903v-500h-100v400h-803z" /> +<glyph unicode="­" horiz-adv-x="629" d="M77 502l18 90h457l-16 -90h-459z" /> +<glyph unicode="®" horiz-adv-x="1704" d="M150 731q0 207 103.5 382t276.5 272.5t371 97.5q200 0 375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-204 0 -376.5 100.5t-273.5 273t-101 377.5zM242 731q0 -178 88.5 -329.5t240.5 -240.5t330 -89q174 0 325 85.5t243 239t92 334.5q0 178 -89 330 t-240.5 241t-330.5 89q-182 0 -335 -92t-238.5 -243t-85.5 -325zM657 291v880h211q143 0 222 -62t79 -191q0 -80 -39.5 -141t-109.5 -93l237 -393h-120l-211 360h-168v-360h-101zM758 731h112q93 0 144 46.5t51 135.5q0 172 -197 172h-110v-354z" /> +<glyph unicode="¯" horiz-adv-x="655" d="M348 1556l53 97h654l-54 -97h-653z" /> +<glyph unicode="°" horiz-adv-x="877" d="M242 1190q0 120 85 206.5t208 86.5q122 0 207 -86.5t85 -206.5q0 -122 -85.5 -207.5t-206.5 -85.5q-122 0 -207.5 85.5t-85.5 207.5zM315 1190q0 -89 64.5 -153t155.5 -64q92 0 155.5 64t63.5 153q0 90 -64 155.5t-155 65.5q-90 0 -155 -65.5t-65 -155.5z" /> +<glyph unicode="±" d="M127 0v100h903v-100h-903zM127 629v98h401v406h101v-406h401v-98h-401v-400h-101v400h-401z" /> +<glyph unicode="²" horiz-adv-x="643" d="M82 586l16 80l297 258q137 118 182.5 190.5t45.5 153.5q0 59 -38.5 97t-105.5 38q-95 0 -194 -76l-41 62q108 90 239 90q73 0 125 -27t78.5 -72t26.5 -100q0 -106 -59 -198.5t-183 -194.5l-266 -223h416l-17 -78h-522z" /> +<glyph unicode="³" horiz-adv-x="643" d="M109 625v90q46 -28 108 -48t125 -20q99 0 159 52.5t60 142.5q0 162 -196 162h-84l16 79h86q102 0 168.5 49.5t66.5 129.5q0 68 -37.5 102.5t-105.5 34.5q-100 0 -199 -68l-40 64q109 86 251 86q100 0 159 -56.5t59 -148.5q0 -85 -48.5 -148t-154.5 -88v-4 q66 -16 105.5 -68t39.5 -124q0 -77 -39 -141t-109 -99t-161 -35q-59 0 -123.5 15.5t-105.5 40.5z" /> +<glyph unicode="´" horiz-adv-x="1135" d="M580 1241v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="µ" horiz-adv-x="1171" d="M-29 -492l338 1579h101l-152 -698q-20 -96 -20 -147q0 -82 48.5 -127t135.5 -45q110 0 207 64.5t162.5 182.5t101.5 285l104 485h99l-234 -1087h-78l29 205h-6q-164 -221 -404 -221q-85 0 -139 32.5t-76 89.5h-6q-18 -132 -51 -284l-63 -314h-97z" /> +<glyph unicode="¶" horiz-adv-x="1341" d="M215 1042q0 260 109 387t342 127h542v-1816h-100v1722h-227v-1722h-101v819q-64 -18 -145 -18q-216 0 -318 125t-102 376z" /> +<glyph unicode="·" horiz-adv-x="485" d="M207 698q0 56 25 88.5t69 32.5q66 0 66 -72q0 -53 -25 -87.5t-67 -34.5q-68 0 -68 73z" /> +<glyph unicode="¸" horiz-adv-x="420" d="M-174 -406q30 -6 72 -6q198 0 198 115q0 97 -151 107l110 190h80l-78 -137q140 -30 140 -152q0 -94 -75.5 -148.5t-217.5 -54.5q-46 0 -78 7v79z" /> +<glyph unicode="¹" horiz-adv-x="643" d="M254 1288l258 174h80l-186 -876h-84l118 569q5 21 11.5 50.5t14 60t15.5 59t15 49.5q-34 -31 -60 -51.5t-143 -93.5z" /> +<glyph unicode="º" horiz-adv-x="655" d="M190 1059q0 112 41.5 209.5t116 154t170.5 56.5q105 0 165 -64t60 -180q0 -115 -40 -214t-114 -156.5t-175 -57.5q-114 0 -169 67.5t-55 184.5zM270 1067q0 -186 156 -186q73 0 125.5 46.5t81.5 127.5t29 176q0 83 -39 128.5t-115 45.5q-70 0 -124 -46.5t-84 -124.5 t-30 -167z" /> +<glyph unicode="»" horiz-adv-x="860" d="M33 172l313 336l-209 385l64 39l254 -418l-2 -27l-363 -364zM393 172l314 336l-209 385l63 39l254 -418l-2 -27l-362 -364z" /> +<glyph unicode="¼" horiz-adv-x="1481" d="M129 0l1086 1462h108l-1087 -1462h-107zM251 1288l258 174h80l-186 -876h-84l118 569q5 21 11.5 50.5t14 60t15.5 59t15 49.5q-34 -31 -60 -51.5t-143 -93.5zM715 230l21 76l506 577h86l-125 -581h133l-17 -72h-131l-49 -229h-82l49 229h-391zM830 302h291 q61 294 79 365.5t29 105.5q-10 -16 -61 -79t-338 -392z" /> +<glyph unicode="½" horiz-adv-x="1458" d="M53 0l1086 1462h108l-1087 -1462h-107zM173 1288l258 174h80l-186 -876h-84l118 569q5 21 11.5 50.5t14 60t15.5 59t15 49.5q-34 -31 -60 -51.5t-143 -93.5zM756 1l16 80l297 258q137 118 182.5 190.5t45.5 153.5q0 59 -38.5 97t-105.5 38q-95 0 -194 -76l-41 62 q108 90 239 90q73 0 125 -27t78.5 -72t26.5 -100q0 -106 -59 -198.5t-183 -194.5l-266 -223h416l-17 -78h-522z" /> +<glyph unicode="¾" horiz-adv-x="1458" d="M71 625v90q46 -28 108 -48t125 -20q99 0 159 52.5t60 142.5q0 162 -196 162h-84l16 79h86q102 0 168.5 49.5t66.5 129.5q0 68 -37.5 102.5t-105.5 34.5q-100 0 -199 -68l-40 64q109 86 251 86q100 0 159 -56.5t59 -148.5q0 -85 -48.5 -148t-154.5 -88v-4 q66 -16 105.5 -68t39.5 -124q0 -77 -39 -141t-109 -99t-161 -35q-59 0 -123.5 15.5t-105.5 40.5zM213 0l1086 1462h108l-1087 -1462h-107zM776 230l21 76l506 577h86l-125 -581h133l-17 -72h-131l-49 -229h-82l49 229h-391zM891 302h291q61 294 79 365.5t29 105.5 q-10 -16 -61 -79t-338 -392z" /> +<glyph unicode="¿" horiz-adv-x="799" d="M0 -90q0 133 70 240.5t227 220.5q85 61 133.5 109t73 95t45.5 142h92l-6 -29q-28 -127 -79 -200t-161 -154q-118 -84 -175 -145.5t-86.5 -127.5t-29.5 -141q0 -106 65.5 -168.5t184.5 -62.5q141 0 308 100l38 -86q-85 -49 -170.5 -77.5t-187.5 -28.5q-159 0 -250.5 84.5 t-91.5 228.5zM553 971q0 56 25 89.5t67 33.5q68 0 68 -74q0 -56 -25.5 -88.5t-69.5 -32.5q-65 0 -65 72z" /> +<glyph unicode="À" horiz-adv-x="1059" d="M-111 0l822 1468h67l201 -1468h-105l-69 520h-512l-287 -520h-117zM344 612h449l-39 291q-31 242 -39 402q-30 -63 -64.5 -130t-306.5 -563zM536 1886v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="Á" horiz-adv-x="1059" d="M-111 0l822 1468h67l201 -1468h-105l-69 520h-512l-287 -520h-117zM344 612h449l-39 291q-31 242 -39 402q-30 -63 -64.5 -130t-306.5 -563zM668 1579v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="Â" horiz-adv-x="1059" d="M-111 0l822 1468h67l201 -1468h-105l-69 520h-512l-287 -520h-117zM344 612h449l-39 291q-31 242 -39 402q-30 -63 -64.5 -130t-306.5 -563zM493 1579v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5 t-125 -92.5h-54z" /> +<glyph unicode="Ã" horiz-adv-x="1059" d="M-111 0l822 1468h67l201 -1468h-105l-69 520h-512l-287 -520h-117zM344 612h449l-39 291q-31 242 -39 402q-30 -63 -64.5 -130t-306.5 -563zM426 1581q19 108 71 166.5t134 58.5q41 0 73.5 -14t117.5 -72q52 -36 94 -36q43 0 71.5 30.5t46.5 100.5h76 q-26 -118 -74.5 -173t-124.5 -55q-40 0 -77.5 19t-75.5 45q-34 23 -64.5 41t-68.5 18q-45 0 -74 -28.5t-51 -100.5h-74z" /> +<glyph unicode="Ä" horiz-adv-x="1059" d="M-111 0l822 1468h67l201 -1468h-105l-69 520h-512l-287 -520h-117zM344 612h449l-39 291q-31 242 -39 402q-30 -63 -64.5 -130t-306.5 -563zM535 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM879 1704q0 49 20.5 78t56.5 29q54 0 54 -64 q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="Å" horiz-adv-x="1059" d="M-111 0l822 1468h67l201 -1468h-105l-69 520h-512l-287 -520h-117zM344 612h449l-39 291q-31 242 -39 402q-30 -63 -64.5 -130t-306.5 -563zM539 1592q0 88 59.5 144t149.5 56q88 0 142.5 -50t54.5 -142t-57.5 -148.5t-145.5 -56.5q-93 0 -148 52t-55 145zM619 1592 q0 -57 33 -90t90 -33q56 0 90.5 36t34.5 93t-33.5 90t-87.5 33q-60 0 -93.5 -36t-33.5 -93z" /> +<glyph unicode="Æ" horiz-adv-x="1640" d="M-117 0l946 1462h883l-20 -94h-625l-117 -553h590l-20 -94h-588l-135 -627h626l-20 -94h-727l110 522h-444l-328 -522h-131zM408 627h401l156 741h-88z" /> +<glyph unicode="Ç" horiz-adv-x="1169" d="M170 535q0 266 104.5 488t284.5 341t402 119q177 0 307 -68l-45 -90q-55 30 -124.5 47t-137.5 17q-197 0 -351.5 -104.5t-245 -304.5t-90.5 -441q0 -225 110.5 -346t317.5 -121q140 0 304 51v-94q-156 -49 -316 -49q-252 0 -386 145t-134 410zM381 -406q30 -6 72 -6 q198 0 198 115q0 97 -151 107l110 190h80l-78 -137q140 -30 140 -152q0 -94 -75.5 -148.5t-217.5 -54.5q-46 0 -78 7v79z" /> +<glyph unicode="È" horiz-adv-x="1067" d="M102 0l310 1462h727l-21 -94h-624l-117 -553h590l-21 -94h-588l-135 -627h627l-21 -94h-727zM612 1886v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="É" horiz-adv-x="1067" d="M102 0l310 1462h727l-21 -94h-624l-117 -553h590l-21 -94h-588l-135 -627h627l-21 -94h-727zM654 1579v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="Ê" horiz-adv-x="1067" d="M102 0l310 1462h727l-21 -94h-624l-117 -553h590l-21 -94h-588l-135 -627h627l-21 -94h-727zM522 1579v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="Ë" horiz-adv-x="1067" d="M102 0l310 1462h727l-21 -94h-624l-117 -553h590l-21 -94h-588l-135 -627h627l-21 -94h-727zM558 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM902 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="Ì" horiz-adv-x="504" d="M102 0l310 1462h98l-309 -1462h-99zM246 1886v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="Í" horiz-adv-x="504" d="M102 0l310 1462h98l-309 -1462h-99zM419 1579v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="Î" horiz-adv-x="504" d="M102 0l310 1462h98l-309 -1462h-99zM224 1579v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="Ï" horiz-adv-x="504" d="M102 0l310 1462h98l-309 -1462h-99zM260 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM604 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="Ð" horiz-adv-x="1352" d="M90 676l21 96h155l146 690h305q282 0 426.5 -147.5t144.5 -435.5q0 -253 -109.5 -461.5t-300.5 -313t-446 -104.5h-330l144 676h-156zM221 90h209q226 0 394.5 94.5t261 275.5t92.5 412q0 498 -476 498h-206l-129 -598h378l-20 -96h-379z" /> +<glyph unicode="Ñ" horiz-adv-x="1372" d="M102 0l310 1462h80l522 -1294h8q23 176 74 416l188 878h94l-309 -1462h-86l-516 1284h-8q-23 -149 -48 -273t-214 -1011h-95zM577 1581q19 108 71 166.5t134 58.5q41 0 73.5 -14t117.5 -72q52 -36 94 -36q43 0 71.5 30.5t46.5 100.5h76q-26 -118 -74.5 -173t-124.5 -55 q-40 0 -77.5 19t-75.5 45q-34 23 -64.5 41t-68.5 18q-45 0 -74 -28.5t-51 -100.5h-74z" /> +<glyph unicode="Ò" horiz-adv-x="1464" d="M172 559q0 262 93 477.5t255 331t373 115.5q247 0 378.5 -148.5t131.5 -423.5q0 -255 -94 -481.5t-252 -338t-365 -111.5q-250 0 -385 149t-135 430zM276 573q0 -245 109.5 -373t319.5 -128q169 0 300 98.5t210 300t79 430.5q0 240 -104.5 364t-310.5 124 q-174 0 -308.5 -101t-214.5 -298t-80 -417zM710 1886v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="Ó" horiz-adv-x="1464" d="M172 559q0 262 93 477.5t255 331t373 115.5q247 0 378.5 -148.5t131.5 -423.5q0 -255 -94 -481.5t-252 -338t-365 -111.5q-250 0 -385 149t-135 430zM276 573q0 -245 109.5 -373t319.5 -128q169 0 300 98.5t210 300t79 430.5q0 240 -104.5 364t-310.5 124 q-174 0 -308.5 -101t-214.5 -298t-80 -417zM844 1579v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="Ô" horiz-adv-x="1464" d="M172 559q0 262 93 477.5t255 331t373 115.5q247 0 378.5 -148.5t131.5 -423.5q0 -255 -94 -481.5t-252 -338t-365 -111.5q-250 0 -385 149t-135 430zM276 573q0 -245 109.5 -373t319.5 -128q169 0 300 98.5t210 300t79 430.5q0 240 -104.5 364t-310.5 124 q-174 0 -308.5 -101t-214.5 -298t-80 -417zM657 1579v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="Õ" horiz-adv-x="1464" d="M172 559q0 262 93 477.5t255 331t373 115.5q247 0 378.5 -148.5t131.5 -423.5q0 -255 -94 -481.5t-252 -338t-365 -111.5q-250 0 -385 149t-135 430zM276 573q0 -245 109.5 -373t319.5 -128q169 0 300 98.5t210 300t79 430.5q0 240 -104.5 364t-310.5 124 q-174 0 -308.5 -101t-214.5 -298t-80 -417zM592 1581q19 108 71 166.5t134 58.5q41 0 73.5 -14t117.5 -72q52 -36 94 -36q43 0 71.5 30.5t46.5 100.5h76q-26 -118 -74.5 -173t-124.5 -55q-40 0 -77.5 19t-75.5 45q-34 23 -64.5 41t-68.5 18q-45 0 -74 -28.5t-51 -100.5h-74z " /> +<glyph unicode="Ö" horiz-adv-x="1464" d="M172 559q0 262 93 477.5t255 331t373 115.5q247 0 378.5 -148.5t131.5 -423.5q0 -255 -94 -481.5t-252 -338t-365 -111.5q-250 0 -385 149t-135 430zM276 573q0 -245 109.5 -373t319.5 -128q169 0 300 98.5t210 300t79 430.5q0 240 -104.5 364t-310.5 124 q-174 0 -308.5 -101t-214.5 -298t-80 -417zM687 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM1031 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="×" d="M221 1055l70 69l330 -329l333 329l68 -67l-332 -334l332 -332l-68 -67l-333 329l-330 -327l-68 67l328 330z" /> +<glyph unicode="Ø" horiz-adv-x="1464" d="M139 -14l146 172q-113 149 -113 401q0 263 94 479.5t256.5 330.5t370.5 114q219 0 352 -121l133 168l70 -53l-145 -183q45 -51 72.5 -161t27.5 -222q0 -187 -52 -365.5t-144.5 -304.5t-223 -193.5t-291.5 -67.5q-215 0 -348 112l-139 -170zM276 573q0 -105 21.5 -191 t56.5 -138l826 1032q-107 113 -301 113q-134 0 -244 -59.5t-188.5 -170t-124.5 -267.5t-46 -319zM412 172q107 -100 293 -100q170 0 301 100t209.5 296.5t78.5 432.5q0 85 -17.5 172t-43.5 129z" /> +<glyph unicode="Ù" horiz-adv-x="1370" d="M176 381q0 83 27 201l186 880h103l-193 -899q-20 -89 -20 -184q0 -309 342 -309q195 0 307.5 96.5t158.5 318.5l207 977h101l-207 -977q-58 -270 -197 -387.5t-375 -117.5q-440 0 -440 401zM667 1886v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="Ú" horiz-adv-x="1370" d="M176 381q0 83 27 201l186 880h103l-193 -899q-20 -89 -20 -184q0 -309 342 -309q195 0 307.5 96.5t158.5 318.5l207 977h101l-207 -977q-58 -270 -197 -387.5t-375 -117.5q-440 0 -440 401zM838 1579v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5 t-192.5 -146.5h-67z" /> +<glyph unicode="Û" horiz-adv-x="1370" d="M176 381q0 83 27 201l186 880h103l-193 -899q-20 -89 -20 -184q0 -309 342 -309q195 0 307.5 96.5t158.5 318.5l207 977h101l-207 -977q-58 -270 -197 -387.5t-375 -117.5q-440 0 -440 401zM634 1579v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5 t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="Ü" horiz-adv-x="1370" d="M176 381q0 83 27 201l186 880h103l-193 -899q-20 -89 -20 -184q0 -309 342 -309q195 0 307.5 96.5t158.5 318.5l207 977h101l-207 -977q-58 -270 -197 -387.5t-375 -117.5q-440 0 -440 401zM678 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29 q-55 0 -55 63zM1022 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="Ý" horiz-adv-x="965" d="M193 1462h100l201 -817l544 817h117l-631 -932l-108 -530h-105l119 545zM563 1579v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="Þ" horiz-adv-x="1145" d="M102 0l310 1462h102l-57 -266h213q200 0 308.5 -92.5t108.5 -267.5q0 -247 -153 -373.5t-457 -126.5h-201l-71 -336h-103zM293 428h190q256 0 376 98.5t120 302.5q0 275 -330 275h-211z" /> +<glyph unicode="ß" horiz-adv-x="1094" d="M-281 -379q53 -24 115 -24q79 0 123 50.5t66 153.5l305 1409q80 357 405 357q137 0 215 -61.5t78 -174.5q0 -75 -44.5 -140.5t-166.5 -148.5q-107 -76 -141.5 -124.5t-34.5 -106.5q0 -51 34 -88.5t93 -75.5q96 -63 138 -133.5t42 -165.5q0 -170 -106.5 -269t-286.5 -99 q-143 0 -234 65v109q45 -36 112.5 -59t129.5 -23q132 0 208.5 71t76.5 195q0 75 -31.5 129t-109.5 108q-82 58 -119 110.5t-37 121.5q0 57 21 103t60.5 88.5t137.5 113.5q101 70 131.5 116t30.5 101q0 70 -55 110t-150 40q-129 0 -205 -76t-108 -229l-291 -1377 q-33 -152 -103.5 -220.5t-179.5 -68.5q-73 0 -119 23v90z" /> +<glyph unicode="à" horiz-adv-x="1133" d="M102 354q0 197 75 376t200.5 276.5t277.5 97.5q232 0 279 -219h6l59 202h80l-229 -1087h-82l45 274h-6q-84 -142 -187 -218t-237 -76q-281 0 -281 374zM205 365q0 -152 50 -223.5t151 -71.5q89 0 177.5 62t159 166t107.5 230t37 213q0 79 -26 141.5t-77 99t-127 36.5 q-124 0 -224 -82t-164 -245.5t-64 -325.5zM530 1548v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="á" horiz-adv-x="1133" d="M102 354q0 197 75 376t200.5 276.5t277.5 97.5q232 0 279 -219h6l59 202h80l-229 -1087h-82l45 274h-6q-84 -142 -187 -218t-237 -76q-281 0 -281 374zM205 365q0 -152 50 -223.5t151 -71.5q89 0 177.5 62t159 166t107.5 230t37 213q0 79 -26 141.5t-77 99t-127 36.5 q-124 0 -224 -82t-164 -245.5t-64 -325.5zM586 1241v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="â" horiz-adv-x="1133" d="M102 354q0 197 75 376t200.5 276.5t277.5 97.5q232 0 279 -219h6l59 202h80l-229 -1087h-82l45 274h-6q-84 -142 -187 -218t-237 -76q-281 0 -281 374zM205 365q0 -152 50 -223.5t151 -71.5q89 0 177.5 62t159 166t107.5 230t37 213q0 79 -26 141.5t-77 99t-127 36.5 q-124 0 -224 -82t-164 -245.5t-64 -325.5zM441 1243v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="ã" horiz-adv-x="1133" d="M102 354q0 197 75 376t200.5 276.5t277.5 97.5q232 0 279 -219h6l59 202h80l-229 -1087h-82l45 274h-6q-84 -142 -187 -218t-237 -76q-281 0 -281 374zM205 365q0 -152 50 -223.5t151 -71.5q89 0 177.5 62t159 166t107.5 230t37 213q0 79 -26 141.5t-77 99t-127 36.5 q-124 0 -224 -82t-164 -245.5t-64 -325.5zM373 1243q19 108 71 166.5t134 58.5q41 0 73.5 -14t117.5 -72q52 -36 94 -36q43 0 71.5 30.5t46.5 100.5h76q-26 -118 -74.5 -173t-124.5 -55q-40 0 -77.5 19t-75.5 45q-34 23 -64.5 41t-68.5 18q-45 0 -74 -28.5t-51 -100.5h-74z " /> +<glyph unicode="ä" horiz-adv-x="1133" d="M102 354q0 197 75 376t200.5 276.5t277.5 97.5q232 0 279 -219h6l59 202h80l-229 -1087h-82l45 274h-6q-84 -142 -187 -218t-237 -76q-281 0 -281 374zM205 365q0 -152 50 -223.5t151 -71.5q89 0 177.5 62t159 166t107.5 230t37 213q0 79 -26 141.5t-77 99t-127 36.5 q-124 0 -224 -82t-164 -245.5t-64 -325.5zM491 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM835 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="å" horiz-adv-x="1133" d="M102 354q0 197 75 376t200.5 276.5t277.5 97.5q232 0 279 -219h6l59 202h80l-229 -1087h-82l45 274h-6q-84 -142 -187 -218t-237 -76q-281 0 -281 374zM205 365q0 -152 50 -223.5t151 -71.5q89 0 177.5 62t159 166t107.5 230t37 213q0 79 -26 141.5t-77 99t-127 36.5 q-124 0 -224 -82t-164 -245.5t-64 -325.5zM521 1440q0 88 59.5 144t149.5 56q88 0 142.5 -50t54.5 -142t-57.5 -148.5t-145.5 -56.5q-93 0 -148 52t-55 145zM601 1440q0 -57 33 -90t90 -33q56 0 90.5 36t34.5 93t-33.5 90t-87.5 33q-60 0 -93.5 -36t-33.5 -93z" /> +<glyph unicode="æ" horiz-adv-x="1602" d="M102 344q0 206 70.5 384.5t192.5 277t274 98.5q106 0 166 -56.5t74 -156.5h10l59 192h66l-35 -186q139 207 350 207q112 0 175 -61.5t63 -172.5q0 -179 -158.5 -271.5t-470.5 -92.5h-39q-8 -51 -8 -96q0 -161 69.5 -250.5t217.5 -89.5q69 0 133.5 21t130.5 52v-94 q-80 -37 -147 -53t-140 -16q-123 0 -211 60t-117 165l-39 -205h-77l41 254h-9q-94 -142 -189 -208t-208 -66q-120 0 -182 94t-62 270zM205 352q0 -150 42.5 -216t121.5 -66q67 0 138.5 42t134 117.5t106 170.5t63.5 199t20 165q0 118 -49 186t-141 68q-123 0 -223 -86 t-156.5 -240t-56.5 -340zM913 594h48q263 0 383 67t120 203q0 71 -38.5 112.5t-108.5 41.5q-119 0 -232 -115.5t-172 -308.5z" /> +<glyph unicode="ç" horiz-adv-x="887" d="M102 397q0 193 73.5 361.5t198.5 257t290 88.5q134 0 241 -43l-28 -90q-107 47 -218 47q-129 0 -232.5 -77t-162.5 -222t-59 -320q0 -158 73.5 -243.5t208.5 -85.5q71 0 131.5 13t131.5 46v-92q-116 -57 -273 -57q-174 0 -274.5 110.5t-100.5 306.5zM203 -406 q30 -6 72 -6q198 0 198 115q0 97 -151 107l110 190h80l-78 -137q140 -30 140 -152q0 -94 -75.5 -148.5t-217.5 -54.5q-46 0 -78 7v79z" /> +<glyph unicode="è" horiz-adv-x="928" d="M102 395q0 181 71 347t195.5 264t274.5 98q114 0 182 -61t68 -166q0 -181 -163.5 -276t-485.5 -95h-33q-6 -44 -6 -98q0 -165 74 -251.5t213 -86.5q132 0 276 73v-94q-140 -69 -299 -69q-173 0 -270 109.5t-97 305.5zM225 594h49q517 0 517 270q0 67 -43.5 110.5 t-116.5 43.5q-131 0 -243.5 -115.5t-162.5 -308.5zM472 1548v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="é" horiz-adv-x="928" d="M102 395q0 181 71 347t195.5 264t274.5 98q114 0 182 -61t68 -166q0 -181 -163.5 -276t-485.5 -95h-33q-6 -44 -6 -98q0 -165 74 -251.5t213 -86.5q132 0 276 73v-94q-140 -69 -299 -69q-173 0 -270 109.5t-97 305.5zM225 594h49q517 0 517 270q0 67 -43.5 110.5 t-116.5 43.5q-131 0 -243.5 -115.5t-162.5 -308.5zM532 1241v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="ê" horiz-adv-x="928" d="M102 395q0 181 71 347t195.5 264t274.5 98q114 0 182 -61t68 -166q0 -181 -163.5 -276t-485.5 -95h-33q-6 -44 -6 -98q0 -165 74 -251.5t213 -86.5q132 0 276 73v-94q-140 -69 -299 -69q-173 0 -270 109.5t-97 305.5zM225 594h49q517 0 517 270q0 67 -43.5 110.5 t-116.5 43.5q-131 0 -243.5 -115.5t-162.5 -308.5zM390 1241v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="ë" horiz-adv-x="928" d="M102 395q0 181 71 347t195.5 264t274.5 98q114 0 182 -61t68 -166q0 -181 -163.5 -276t-485.5 -95h-33q-6 -44 -6 -98q0 -165 74 -251.5t213 -86.5q132 0 276 73v-94q-140 -69 -299 -69q-173 0 -270 109.5t-97 305.5zM225 594h49q517 0 517 270q0 67 -43.5 110.5 t-116.5 43.5q-131 0 -243.5 -115.5t-162.5 -308.5zM436 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM780 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="ì" horiz-adv-x="475" d="M76 0l231 1087h96l-229 -1087h-98zM175 1548v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="í" horiz-adv-x="475" d="M76 0l231 1087h96l-229 -1087h-98zM284 1241v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="î" horiz-adv-x="475" d="M76 0l231 1087h96l-229 -1087h-98zM128 1241v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="ï" horiz-adv-x="475" d="M76 0l231 1087h96l-229 -1087h-98zM171 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM515 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="ð" horiz-adv-x="1124" d="M102 381q0 170 63 301.5t178.5 203.5t262.5 72q107 0 188 -49.5t121 -142.5h5q0 139 -43 289t-115 243l-295 -163l-39 73l285 156q-54 60 -158 139l59 68q32 -26 81 -66t100 -94l266 150l39 -74l-256 -141q87 -116 131.5 -276t44.5 -335q0 -355 -141.5 -555t-399.5 -200 q-177 0 -277 106.5t-100 294.5zM205 389q0 -153 73.5 -236t210.5 -83q118 0 208.5 61t144 186.5t53.5 270.5q0 77 -35 142t-100 101.5t-156 36.5q-124 0 -213.5 -61.5t-137.5 -169.5t-48 -248z" /> +<glyph unicode="ñ" horiz-adv-x="1143" d="M76 0l231 1087h82l-37 -221h6q164 238 416 238q130 0 195 -64t65 -184q0 -70 -24 -182l-148 -674h-98l149 692q21 92 21 156q0 80 -43.5 125t-134.5 45q-112 0 -210.5 -67t-166 -187.5t-103.5 -286.5l-102 -477h-98zM389 1243q19 108 71 166.5t134 58.5q41 0 73.5 -14 t117.5 -72q52 -36 94 -36q43 0 71.5 30.5t46.5 100.5h76q-26 -118 -74.5 -173t-124.5 -55q-40 0 -77.5 19t-75.5 45q-34 23 -64.5 41t-68.5 18q-45 0 -74 -28.5t-51 -100.5h-74z" /> +<glyph unicode="ò" horiz-adv-x="1124" d="M98 403q0 191 73 358t197 257t281 90q180 0 278.5 -108.5t98.5 -299.5q0 -197 -71.5 -368.5t-195.5 -261.5t-286 -90q-184 0 -279.5 109.5t-95.5 313.5zM201 408q0 -342 282 -342q127 0 225.5 77.5t157 228t58.5 330.5q0 154 -73 237t-210 83q-124 0 -223 -78.5 t-158 -225t-59 -310.5zM465 1548v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="ó" horiz-adv-x="1124" d="M98 403q0 191 73 358t197 257t281 90q180 0 278.5 -108.5t98.5 -299.5q0 -197 -71.5 -368.5t-195.5 -261.5t-286 -90q-184 0 -279.5 109.5t-95.5 313.5zM201 408q0 -342 282 -342q127 0 225.5 77.5t157 228t58.5 330.5q0 154 -73 237t-210 83q-124 0 -223 -78.5 t-158 -225t-59 -310.5zM573 1241v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="ô" horiz-adv-x="1124" d="M98 403q0 191 73 358t197 257t281 90q180 0 278.5 -108.5t98.5 -299.5q0 -197 -71.5 -368.5t-195.5 -261.5t-286 -90q-184 0 -279.5 109.5t-95.5 313.5zM201 408q0 -342 282 -342q127 0 225.5 77.5t157 228t58.5 330.5q0 154 -73 237t-210 83q-124 0 -223 -78.5 t-158 -225t-59 -310.5zM427 1241v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="õ" horiz-adv-x="1124" d="M98 403q0 191 73 358t197 257t281 90q180 0 278.5 -108.5t98.5 -299.5q0 -197 -71.5 -368.5t-195.5 -261.5t-286 -90q-184 0 -279.5 109.5t-95.5 313.5zM201 408q0 -342 282 -342q127 0 225.5 77.5t157 228t58.5 330.5q0 154 -73 237t-210 83q-124 0 -223 -78.5 t-158 -225t-59 -310.5zM354 1243q19 108 71 166.5t134 58.5q41 0 73.5 -14t117.5 -72q52 -36 94 -36q43 0 71.5 30.5t46.5 100.5h76q-26 -118 -74.5 -173t-124.5 -55q-40 0 -77.5 19t-75.5 45q-34 23 -64.5 41t-68.5 18q-45 0 -74 -28.5t-51 -100.5h-74z" /> +<glyph unicode="ö" horiz-adv-x="1124" d="M98 403q0 191 73 358t197 257t281 90q180 0 278.5 -108.5t98.5 -299.5q0 -197 -71.5 -368.5t-195.5 -261.5t-286 -90q-184 0 -279.5 109.5t-95.5 313.5zM201 408q0 -342 282 -342q127 0 225.5 77.5t157 228t58.5 330.5q0 154 -73 237t-210 83q-124 0 -223 -78.5 t-158 -225t-59 -310.5zM468 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM812 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="÷" d="M168 672v100h903v-100h-903zM522 373q0 106 96 106q48 0 73.5 -27.5t25.5 -78.5q0 -57 -29 -82t-70 -25q-96 0 -96 107zM522 1071q0 107 96 107q46 0 72.5 -27.5t26.5 -79.5q0 -57 -29 -81.5t-70 -24.5q-96 0 -96 106z" /> +<glyph unicode="ø" horiz-adv-x="1124" d="M45 -18l119 145q-66 106 -66 276q0 191 73 358t197 257t281 90q150 0 250 -82l109 133l65 -53l-117 -143q70 -105 70 -263q0 -197 -71.5 -368.5t-195.5 -261.5t-286 -90q-163 0 -254 83l-110 -135zM201 408q0 -125 32 -197l605 739q-74 72 -197 72q-124 0 -223 -78.5 t-158 -225t-59 -310.5zM281 139q67 -73 202 -73q127 0 225.5 77.5t157 228t58.5 330.5q0 101 -35 179z" /> +<glyph unicode="ù" horiz-adv-x="1143" d="M109 227q0 60 22 170l150 690h100l-152 -698q-22 -106 -22 -158q0 -74 47.5 -117.5t138.5 -43.5q110 0 207.5 65.5t164 187t99.5 279.5l105 485h98l-231 -1087h-80l28 205h-6q-167 -221 -403 -221q-131 0 -198.5 62t-67.5 181zM495 1548v21h115q46 -129 164 -303v-25h-66 q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="ú" horiz-adv-x="1143" d="M109 227q0 60 22 170l150 690h100l-152 -698q-22 -106 -22 -158q0 -74 47.5 -117.5t138.5 -43.5q110 0 207.5 65.5t164 187t99.5 279.5l105 485h98l-231 -1087h-80l28 205h-6q-167 -221 -403 -221q-131 0 -198.5 62t-67.5 181zM627 1241v21q66 51 150.5 142t129.5 165 h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="û" horiz-adv-x="1143" d="M109 227q0 60 22 170l150 690h100l-152 -698q-22 -106 -22 -158q0 -74 47.5 -117.5t138.5 -43.5q110 0 207.5 65.5t164 187t99.5 279.5l105 485h98l-231 -1087h-80l28 205h-6q-167 -221 -403 -221q-131 0 -198.5 62t-67.5 181zM443 1241v29q68 56 157.5 148.5 t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="ü" horiz-adv-x="1143" d="M109 227q0 60 22 170l150 690h100l-152 -698q-22 -106 -22 -158q0 -74 47.5 -117.5t138.5 -43.5q110 0 207.5 65.5t164 187t99.5 279.5l105 485h98l-231 -1087h-80l28 205h-6q-167 -221 -403 -221q-131 0 -198.5 62t-67.5 181zM483 1366q0 49 20.5 78t56.5 29 q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM827 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="ý" horiz-adv-x="920" d="M-217 -379q71 -27 137 -27q80 0 147 49.5t130 164.5t100 184l-174 1095h100l82 -548q51 -351 55 -449h11q43 105 186 367l348 630h103l-713 -1290q-72 -127 -122.5 -178t-114 -81t-146.5 -30q-68 0 -129 21v92zM505 1241v21q66 51 150.5 142t129.5 165h137v-23 q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="þ" horiz-adv-x="1163" d="M-33 -492l434 2048h99q-114 -535 -164 -751h6q93 156 199 229.5t231 73.5q133 0 206 -92.5t73 -282.5q0 -195 -72 -371t-197.5 -277t-283.5 -101q-230 0 -279 219h-4q-13 -72 -149 -695h-99zM266 346q0 -125 61.5 -200.5t168.5 -75.5q124 0 225 84t164 243.5t63 325.5 q0 295 -200 295q-86 0 -172.5 -57.5t-162.5 -169.5t-111.5 -238t-35.5 -207z" /> +<glyph unicode="ÿ" horiz-adv-x="920" d="M-217 -379q71 -27 137 -27q80 0 147 49.5t130 164.5t100 184l-174 1095h100l82 -548q51 -351 55 -449h11q43 105 186 367l348 630h103l-713 -1290q-72 -127 -122.5 -178t-114 -81t-146.5 -30q-68 0 -129 21v92zM354 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77 t-55 -29q-55 0 -55 63zM698 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="Œ" horiz-adv-x="1767" d="M172 559q0 263 96 482t262 330.5t381 111.5q130 0 240 -21h688l-20 -94h-625l-117 -553h590l-20 -94h-588l-135 -627h626l-20 -94h-666q-25 -6 -77.5 -13t-94.5 -7q-251 0 -385.5 149.5t-134.5 429.5zM276 573q0 -245 109 -373t320 -128q68 0 116 12l271 1290 q-110 15 -189 15q-182 0 -321.5 -98.5t-222.5 -293.5t-83 -424z" /> +<glyph unicode="œ" horiz-adv-x="1720" d="M98 403q0 191 73 358t197 257t281 90q141 0 237 -74.5t126 -212.5q70 132 182.5 207.5t241.5 75.5q114 0 182 -61t68 -166q0 -181 -163.5 -276t-486.5 -95h-32q-7 -38 -7 -98q0 -165 74 -251.5t213 -86.5q133 0 277 73v-94q-140 -69 -299 -69q-135 0 -228 69t-125 201 q-65 -127 -179 -198.5t-257 -71.5q-184 0 -279.5 109.5t-95.5 313.5zM201 408q0 -342 282 -342q127 0 225.5 77.5t157 228t58.5 330.5q0 154 -73 237t-210 83q-124 0 -223 -78.5t-158 -225t-59 -310.5zM1018 594h49q516 0 516 270q0 70 -44.5 112t-115.5 42 q-131 0 -243 -115t-162 -309z" /> +<glyph unicode="Ÿ" horiz-adv-x="965" d="M193 1462h100l201 -817l544 817h117l-631 -932l-108 -530h-105l119 545zM454 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM798 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="ˆ" horiz-adv-x="1135" d="M444 1241v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="˜" horiz-adv-x="1135" d="M346 1243q19 108 71 166.5t134 58.5q41 0 73.5 -14t117.5 -72q52 -36 94 -36q43 0 71.5 30.5t46.5 100.5h76q-26 -118 -74.5 -173t-124.5 -55q-40 0 -77.5 19t-75.5 45q-34 23 -64.5 41t-68.5 18q-45 0 -74 -28.5t-51 -100.5h-74z" /> +<glyph unicode=" " horiz-adv-x="953" /> +<glyph unicode=" " horiz-adv-x="1907" /> +<glyph unicode=" " horiz-adv-x="953" /> +<glyph unicode=" " horiz-adv-x="1907" /> +<glyph unicode=" " horiz-adv-x="635" /> +<glyph unicode=" " horiz-adv-x="476" /> +<glyph unicode=" " horiz-adv-x="317" /> +<glyph unicode=" " horiz-adv-x="317" /> +<glyph unicode=" " horiz-adv-x="238" /> +<glyph unicode=" " horiz-adv-x="381" /> +<glyph unicode=" " horiz-adv-x="105" /> +<glyph unicode="‐" horiz-adv-x="629" d="M82 502l18 90h457l-16 -90h-459z" /> +<glyph unicode="‑" horiz-adv-x="629" d="M82 502l18 90h457l-16 -90h-459z" /> +<glyph unicode="‒" horiz-adv-x="629" d="M82 502l18 90h457l-16 -90h-459z" /> +<glyph unicode="–" horiz-adv-x="983" d="M66 502l18 90h807l-17 -90h-808z" /> +<glyph unicode="—" horiz-adv-x="1966" d="M68 502l18 90h1788l-16 -90h-1790z" /> +<glyph unicode="‘" horiz-adv-x="299" d="M129 983q41 100 116 231t161 248h73q-66 -106 -129.5 -242.5t-103.5 -258.5h-113z" /> +<glyph unicode="’" horiz-adv-x="299" d="M129 961q66 106 129.5 242.5t103.5 258.5h113l4 -22q-43 -105 -117.5 -235.5t-158.5 -243.5h-74z" /> +<glyph unicode="‚" horiz-adv-x="451" d="M-100 -264q68 110 131.5 248t101.5 254h113l4 -23q-40 -97 -115.5 -230t-161.5 -249h-73z" /> +<glyph unicode="“" horiz-adv-x="631" d="M129 983q41 100 116 231t161 248h73q-66 -106 -129.5 -242.5t-103.5 -258.5h-113zM463 983q43 104 120 238.5t156 240.5h74q-66 -106 -129.5 -242.5t-103.5 -258.5h-113z" /> +<glyph unicode="”" horiz-adv-x="631" d="M129 961q66 106 129.5 242.5t103.5 258.5h113l4 -22q-43 -105 -117.5 -235.5t-158.5 -243.5h-74zM463 961q66 106 129.5 242.5t103.5 258.5h113l4 -22q-43 -105 -117.5 -235.5t-158.5 -243.5h-74z" /> +<glyph unicode="„" horiz-adv-x="776" d="M-119 -264q73 119 135.5 254.5t98.5 247.5h112l4 -23q-43 -105 -117.5 -235.5t-158.5 -243.5h-74zM215 -264q66 108 129 242.5t105 259.5h112l4 -23q-43 -105 -117.5 -235.5t-158.5 -243.5h-74z" /> +<glyph unicode="•" horiz-adv-x="793" d="M248 682q0 137 63 213t172 76q76 0 116 -39.5t40 -118.5q0 -125 -66 -207t-176 -82q-149 0 -149 158z" /> +<glyph unicode="…" horiz-adv-x="1489" d="M69 55q0 56 25 88.5t69 32.5q66 0 66 -72q0 -53 -25 -87.5t-67 -34.5q-68 0 -68 73zM569 55q0 56 25 88.5t69 32.5q66 0 66 -72q0 -53 -25 -87.5t-67 -34.5q-68 0 -68 73zM1071 55q0 56 25 88.5t69 32.5q66 0 66 -72q0 -53 -25 -87.5t-67 -34.5q-68 0 -68 73z" /> +<glyph unicode=" " horiz-adv-x="381" /> +<glyph unicode="‹" horiz-adv-x="537" d="M86 541l2 26l363 365l57 -49l-318 -336l213 -385l-63 -39z" /> +<glyph unicode="›" horiz-adv-x="537" d="M37 172l317 336l-213 385l64 39l254 -418l-2 -27l-363 -364z" /> +<glyph unicode=" " horiz-adv-x="476" /> +<glyph unicode="€" d="M80 541l16 82h172q5 101 35 217h-170l19 82h174q95 273 270 417t399 144q166 0 287 -90l-53 -82q-102 78 -238 78q-186 0 -330.5 -120.5t-226.5 -346.5h457l-21 -82h-460q-30 -98 -39 -217h442l-20 -82h-424q0 -243 89 -356t265 -113q115 0 252 57v-94q-129 -55 -270 -55 q-209 0 -325 139.5t-116 394.5v27h-184z" /> +<glyph unicode="™" horiz-adv-x="1534" d="M174 1384v78h522v-78h-219v-643h-86v643h-217zM772 741v721h125l221 -606l223 606h125v-721h-86v398l4 207h-6l-227 -605h-74l-221 609h-6l4 -201v-408h-82z" /> +<glyph unicode="" horiz-adv-x="1085" d="M0 0v1085h1085v-1085h-1085z" /> +</font> +</defs></svg> \ No newline at end of file diff --git a/refs/pull/405/merge/_static/fonts/opensans-lightitalic-webfont.ttf b/refs/pull/405/merge/_static/fonts/opensans-lightitalic-webfont.ttf new file mode 100644 index 00000000..ef7ae600 Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/opensans-lightitalic-webfont.ttf differ diff --git a/refs/pull/405/merge/_static/fonts/opensans-lightitalic-webfont.woff b/refs/pull/405/merge/_static/fonts/opensans-lightitalic-webfont.woff new file mode 100644 index 00000000..d70276ea Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/opensans-lightitalic-webfont.woff differ diff --git a/refs/pull/405/merge/_static/fonts/opensans-regular-webfont.eot b/refs/pull/405/merge/_static/fonts/opensans-regular-webfont.eot new file mode 100644 index 00000000..dc6f2696 Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/opensans-regular-webfont.eot differ diff --git a/refs/pull/405/merge/_static/fonts/opensans-regular-webfont.svg b/refs/pull/405/merge/_static/fonts/opensans-regular-webfont.svg new file mode 100644 index 00000000..8ea47510 --- /dev/null +++ b/refs/pull/405/merge/_static/fonts/opensans-regular-webfont.svg @@ -0,0 +1,244 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata></metadata> +<defs> +<font id="OpenSansRegular" horiz-adv-x="1171" > +<font-face units-per-em="2048" ascent="1638" descent="-410" /> +<missing-glyph horiz-adv-x="532" /> +<glyph unicode="fi" horiz-adv-x="1212" d="M29 967v75l196 60v61q0 404 353 404q87 0 204 -35l-43 -133q-96 31 -164 31q-94 0 -139 -62.5t-45 -200.5v-71h279v-129h-279v-967h-166v967h-196zM856 1393q0 57 28 83.5t70 26.5q40 0 69 -27t29 -83t-29 -83.5t-69 -27.5q-42 0 -70 27.5t-28 83.5zM870 0v1096h166 v-1096h-166z" /> +<glyph unicode="fl" horiz-adv-x="1212" d="M29 967v75l196 60v61q0 404 353 404q87 0 204 -35l-43 -133q-96 31 -164 31q-94 0 -139 -62.5t-45 -200.5v-71h279v-129h-279v-967h-166v967h-196zM870 0v1556h166v-1556h-166z" /> +<glyph unicode="ffi" horiz-adv-x="1909" d="M29 967v75l196 60v61q0 404 353 404q87 0 204 -35l-43 -133q-96 31 -164 31q-94 0 -139 -62.5t-45 -200.5v-71h279v-129h-279v-967h-166v967h-196zM717 967v75l196 60v61q0 404 353 404q87 0 204 -35l-43 -133q-96 31 -164 31q-94 0 -139 -62.5t-45 -200.5v-71h279v-129 h-279v-967h-166v967h-196zM1551 1393q0 57 28 83.5t70 26.5q40 0 69 -27t29 -83t-29 -83.5t-69 -27.5q-42 0 -70 27.5t-28 83.5zM1565 0v1096h166v-1096h-166z" /> +<glyph unicode="ffl" horiz-adv-x="1909" d="M29 967v75l196 60v61q0 404 353 404q87 0 204 -35l-43 -133q-96 31 -164 31q-94 0 -139 -62.5t-45 -200.5v-71h279v-129h-279v-967h-166v967h-196zM717 967v75l196 60v61q0 404 353 404q87 0 204 -35l-43 -133q-96 31 -164 31q-94 0 -139 -62.5t-45 -200.5v-71h279v-129 h-279v-967h-166v967h-196zM1565 0v1556h166v-1556h-166z" /> +<glyph horiz-adv-x="0" /> +<glyph horiz-adv-x="2048" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="	" horiz-adv-x="532" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="!" horiz-adv-x="547" d="M152 106q0 136 120 136q58 0 89.5 -35t31.5 -101q0 -64 -32 -99.5t-89 -35.5q-52 0 -86 31.5t-34 103.5zM170 1462h207l-51 -1059h-105z" /> +<glyph unicode=""" horiz-adv-x="821" d="M133 1462h186l-40 -528h-105zM502 1462h186l-41 -528h-104z" /> +<glyph unicode="#" horiz-adv-x="1323" d="M51 430v129h287l68 340h-277v127h299l82 436h139l-82 -436h305l84 436h134l-84 -436h264v-127h-289l-66 -340h283v-129h-307l-84 -430h-137l84 430h-303l-82 -430h-136l80 430h-262zM475 559h303l66 340h-303z" /> +<glyph unicode="$" d="M131 170v156q83 -37 191.5 -60.5t197.5 -23.5v440q-205 65 -287.5 151t-82.5 222q0 131 101.5 215t268.5 102v182h129v-180q184 -5 355 -74l-52 -131q-149 59 -303 70v-434q157 -50 235 -97.5t115 -109t37 -149.5q0 -136 -102 -224.5t-285 -111.5v-232h-129v223 q-112 0 -217 17.5t-172 48.5zM319 1057q0 -76 45 -122t156 -87v387q-99 -16 -150 -62.5t-51 -115.5zM649 252q217 30 217 184q0 72 -44.5 116.5t-172.5 88.5v-389z" /> +<glyph unicode="%" horiz-adv-x="1686" d="M104 1026q0 227 74.5 342t220.5 115q145 0 223 -119t78 -338q0 -228 -76.5 -344.5t-224.5 -116.5q-140 0 -217.5 119t-77.5 342zM242 1026q0 -170 37 -255t120 -85q164 0 164 340q0 338 -164 338q-83 0 -120 -84t-37 -254zM365 0l811 1462h147l-811 -1462h-147zM985 440 q0 227 74.5 342t220.5 115q142 0 221.5 -117.5t79.5 -339.5q0 -227 -76.5 -343.5t-224.5 -116.5q-142 0 -218.5 119t-76.5 341zM1122 440q0 -171 37 -255.5t121 -84.5t124 83.5t40 256.5q0 171 -40 253.5t-124 82.5t-121 -82.5t-37 -253.5z" /> +<glyph unicode="&" horiz-adv-x="1495" d="M113 379q0 130 69.5 230t249.5 202q-85 95 -115.5 144t-48.5 102t-18 110q0 150 98 234t273 84q162 0 255 -83.5t93 -232.5q0 -107 -68 -197.5t-225 -183.5l407 -391q56 62 89.5 145.5t56.5 182.5h168q-68 -286 -205 -434l299 -291h-229l-185 178q-118 -106 -240 -152 t-272 -46q-215 0 -333.5 106t-118.5 293zM285 383q0 -117 77.5 -185.5t206.5 -68.5q241 0 400 154l-437 424q-111 -68 -157 -112.5t-68 -95.5t-22 -116zM414 1171q0 -69 36 -131.5t123 -150.5q129 75 179.5 138.5t50.5 146.5q0 77 -51.5 125.5t-137.5 48.5q-89 0 -144.5 -48 t-55.5 -129z" /> +<glyph unicode="'" horiz-adv-x="453" d="M133 1462h186l-40 -528h-105z" /> +<glyph unicode="(" horiz-adv-x="606" d="M82 561q0 265 77.5 496t223.5 405h162q-144 -193 -216.5 -424t-72.5 -475q0 -240 74 -469t213 -418h-160q-147 170 -224 397t-77 488z" /> +<glyph unicode=")" horiz-adv-x="606" d="M61 1462h162q147 -175 224 -406.5t77 -494.5t-77.5 -490t-223.5 -395h-160q139 188 213 417.5t74 469.5q0 244 -72.5 475t-216.5 424z" /> +<glyph unicode="*" horiz-adv-x="1130" d="M86 1090l29 182l391 -111l-43 395h194l-43 -395l398 111l26 -182l-381 -31l248 -326l-172 -94l-176 362l-160 -362l-176 94l242 326z" /> +<glyph unicode="+" d="M104 653v138h410v428h139v-428h412v-138h-412v-426h-139v426h-410z" /> +<glyph unicode="," horiz-adv-x="502" d="M63 -264q27 104 59.5 257t45.5 245h182l15 -23q-26 -100 -75 -232.5t-102 -246.5h-125z" /> +<glyph unicode="-" horiz-adv-x="659" d="M84 473v152h491v-152h-491z" /> +<glyph unicode="." horiz-adv-x="545" d="M152 106q0 67 30.5 101.5t87.5 34.5q58 0 90.5 -34.5t32.5 -101.5q0 -65 -33 -100t-90 -35q-51 0 -84.5 31.5t-33.5 103.5z" /> +<glyph unicode="/" horiz-adv-x="752" d="M20 0l545 1462h166l-545 -1462h-166z" /> +<glyph unicode="0" d="M102 733q0 382 119 567t363 185q238 0 361.5 -193t123.5 -559q0 -379 -119.5 -566t-365.5 -187q-236 0 -359 191.5t-123 561.5zM270 733q0 -319 75 -464.5t239 -145.5q166 0 240.5 147.5t74.5 462.5t-74.5 461.5t-240.5 146.5q-164 0 -239 -144.5t-75 -463.5z" /> +<glyph unicode="1" d="M188 1163l387 299h140v-1462h-162v1042q0 130 8 246q-21 -21 -47 -44t-238 -195z" /> +<glyph unicode="2" d="M100 0v143l385 387q176 178 232 254t84 148t28 155q0 117 -71 185.5t-197 68.5q-91 0 -172.5 -30t-181.5 -109l-88 113q202 168 440 168q206 0 323 -105.5t117 -283.5q0 -139 -78 -275t-292 -344l-320 -313v-8h752v-154h-961z" /> +<glyph unicode="3" d="M94 59v158q95 -47 202.5 -71.5t203.5 -24.5q379 0 379 297q0 266 -418 266h-144v143h146q171 0 271 75.5t100 209.5q0 107 -73.5 168t-199.5 61q-96 0 -181 -26t-194 -96l-84 112q90 71 207.5 111.5t247.5 40.5q213 0 331 -97.5t118 -267.5q0 -140 -78.5 -229 t-222.5 -119v-8q176 -22 261 -112t85 -236q0 -209 -145 -321.5t-412 -112.5q-116 0 -212.5 17.5t-187.5 61.5z" /> +<glyph unicode="4" d="M43 336v145l694 989h176v-983h217v-151h-217v-336h-159v336h-711zM209 487h545v486q0 143 10 323h-8q-48 -96 -90 -159z" /> +<glyph unicode="5" d="M133 59v160q70 -45 174 -70.5t205 -25.5q176 0 273.5 83t97.5 240q0 306 -375 306q-95 0 -254 -29l-86 55l55 684h727v-153h-585l-37 -439q115 23 229 23q231 0 363.5 -114.5t132.5 -313.5q0 -227 -144.5 -356t-398.5 -129q-247 0 -377 79z" /> +<glyph unicode="6" d="M117 625q0 431 167.5 644.5t495.5 213.5q113 0 178 -19v-143q-77 25 -176 25q-235 0 -359 -146.5t-136 -460.5h12q110 172 348 172q197 0 310.5 -119t113.5 -323q0 -228 -124.5 -358.5t-336.5 -130.5q-227 0 -360 170.5t-133 474.5zM287 506q0 -103 40 -192t113.5 -141 t167.5 -52q142 0 220.5 89.5t78.5 258.5q0 145 -73 228t-218 83q-90 0 -165 -37t-119.5 -102t-44.5 -135z" /> +<glyph unicode="7" d="M94 1309v153h973v-133l-598 -1329h-184l606 1309h-797z" /> +<glyph unicode="8" d="M104 373q0 251 306 391q-138 78 -198 168.5t-60 202.5q0 159 117.5 253.5t314.5 94.5q200 0 317 -93t117 -257q0 -108 -67 -197t-214 -162q178 -85 253 -178.5t75 -216.5q0 -182 -127 -290.5t-348 -108.5q-234 0 -360 102.5t-126 290.5zM268 369q0 -120 83.5 -187 t234.5 -67q149 0 232 70t83 192q0 97 -78 172.5t-272 146.5q-149 -64 -216 -141.5t-67 -185.5zM315 1128q0 -92 59 -158t218 -132q143 60 202.5 129t59.5 161q0 101 -72.5 160.5t-199.5 59.5q-125 0 -196 -60t-71 -160z" /> +<glyph unicode="9" d="M106 991q0 228 127.5 360t335.5 132q149 0 260.5 -76.5t171.5 -223t60 -345.5q0 -858 -664 -858q-116 0 -184 20v143q80 -26 182 -26q240 0 362.5 148.5t133.5 455.5h-12q-55 -83 -146 -126.5t-205 -43.5q-194 0 -308 116t-114 324zM270 993q0 -144 72 -226.5t219 -82.5 q91 0 167.5 37t120.5 101t44 134q0 105 -41 194t-114.5 140t-168.5 51q-143 0 -221 -92t-78 -256z" /> +<glyph unicode=":" horiz-adv-x="545" d="M152 106q0 67 30.5 101.5t87.5 34.5q58 0 90.5 -34.5t32.5 -101.5q0 -65 -33 -100t-90 -35q-51 0 -84.5 31.5t-33.5 103.5zM152 989q0 135 118 135q123 0 123 -135q0 -65 -33 -100t-90 -35q-51 0 -84.5 31.5t-33.5 103.5z" /> +<glyph unicode=";" horiz-adv-x="545" d="M63 -264q27 104 59.5 257t45.5 245h182l15 -23q-26 -100 -75 -232.5t-102 -246.5h-125zM147 989q0 135 119 135q123 0 123 -135q0 -65 -33 -100t-90 -35q-58 0 -88.5 35t-30.5 100z" /> +<glyph unicode="<" d="M104 664v98l961 479v-149l-782 -371l782 -328v-151z" /> +<glyph unicode="=" d="M119 449v137h930v-137h-930zM119 858v137h930v-137h-930z" /> +<glyph unicode=">" d="M104 242v151l783 326l-783 373v149l961 -479v-98z" /> +<glyph unicode="?" horiz-adv-x="879" d="M27 1384q189 99 395 99q191 0 297 -94t106 -265q0 -73 -19.5 -128.5t-57.5 -105t-164 -159.5q-101 -86 -133.5 -143t-32.5 -152v-33h-129v54q0 117 36 192.5t134 159.5q136 115 171.5 173t35.5 140q0 102 -65.5 157.5t-188.5 55.5q-79 0 -154 -18.5t-172 -67.5zM240 106 q0 136 120 136q58 0 89.5 -35t31.5 -101q0 -64 -32 -99.5t-89 -35.5q-52 0 -86 31.5t-34 103.5z" /> +<glyph unicode="@" horiz-adv-x="1841" d="M121 571q0 260 107 463t305 314.5t454 111.5q215 0 382.5 -90.5t259 -257t91.5 -383.5q0 -142 -44 -260t-124 -183t-184 -65q-86 0 -145 52t-70 133h-8q-40 -87 -114.5 -136t-176.5 -49q-150 0 -234.5 102.5t-84.5 278.5q0 204 118 331.5t310 127.5q68 0 154 -12.5 t155 -34.5l-25 -470v-22q0 -178 133 -178q91 0 148 107.5t57 279.5q0 181 -74 317t-210.5 209.5t-313.5 73.5q-223 0 -388 -92.5t-252 -264t-87 -396.5q0 -305 161 -469t464 -164q210 0 436 86v-133q-192 -84 -436 -84q-363 0 -563.5 199.5t-200.5 557.5zM686 598 q0 -254 195 -254q207 0 225 313l14 261q-72 20 -157 20q-130 0 -203.5 -90t-73.5 -250z" /> +<glyph unicode="A" horiz-adv-x="1296" d="M0 0l578 1468h143l575 -1468h-176l-182 465h-586l-180 -465h-172zM412 618h473l-170 453q-33 86 -68 211q-22 -96 -63 -211z" /> +<glyph unicode="B" horiz-adv-x="1327" d="M201 0v1462h413q291 0 421 -87t130 -275q0 -130 -72.5 -214.5t-211.5 -109.5v-10q333 -57 333 -350q0 -196 -132.5 -306t-370.5 -110h-510zM371 145h305q177 0 266.5 68.5t89.5 214.5q0 136 -91.5 200t-278.5 64h-291v-547zM371 836h280q180 0 259 56.5t79 190.5 q0 123 -88 177.5t-280 54.5h-250v-479z" /> +<glyph unicode="C" horiz-adv-x="1292" d="M125 733q0 226 84.5 396t244 262t375.5 92q230 0 402 -84l-72 -146q-166 78 -332 78q-241 0 -380.5 -160.5t-139.5 -439.5q0 -287 134.5 -443.5t383.5 -156.5q153 0 349 55v-149q-152 -57 -375 -57q-323 0 -498.5 196t-175.5 557z" /> +<glyph unicode="D" horiz-adv-x="1493" d="M201 0v1462h448q341 0 530 -189t189 -528q0 -362 -196.5 -553.5t-565.5 -191.5h-405zM371 147h207q304 0 457 149.5t153 442.5q0 286 -143.5 431t-426.5 145h-247v-1168z" /> +<glyph unicode="E" horiz-adv-x="1139" d="M201 0v1462h815v-151h-645v-471h606v-150h-606v-538h645v-152h-815z" /> +<glyph unicode="F" horiz-adv-x="1057" d="M201 0v1462h815v-151h-645v-535h606v-151h-606v-625h-170z" /> +<glyph unicode="G" horiz-adv-x="1491" d="M125 731q0 228 91.5 399.5t263.5 262t403 90.5q234 0 436 -86l-66 -150q-198 84 -381 84q-267 0 -417 -159t-150 -441q0 -296 144.5 -449t424.5 -153q152 0 297 35v450h-327v152h497v-711q-116 -37 -236 -56t-278 -19q-332 0 -517 197.5t-185 553.5z" /> +<glyph unicode="H" horiz-adv-x="1511" d="M201 0v1462h170v-622h770v622h170v-1462h-170v688h-770v-688h-170z" /> +<glyph unicode="I" horiz-adv-x="571" d="M201 0v1462h170v-1462h-170z" /> +<glyph unicode="J" horiz-adv-x="547" d="M-160 -213q71 -20 148 -20q99 0 150.5 60t51.5 173v1462h170v-1448q0 -190 -96 -294.5t-276 -104.5q-94 0 -148 27v145z" /> +<glyph unicode="K" horiz-adv-x="1257" d="M201 0v1462h170v-725l663 725h201l-588 -635l610 -827h-200l-533 709l-153 -136v-573h-170z" /> +<glyph unicode="L" horiz-adv-x="1063" d="M201 0v1462h170v-1308h645v-154h-815z" /> +<glyph unicode="M" horiz-adv-x="1849" d="M201 0v1462h256l463 -1206h8l467 1206h254v-1462h-170v942q0 162 14 352h-8l-500 -1294h-137l-496 1296h-8q14 -154 14 -366v-930h-157z" /> +<glyph unicode="N" horiz-adv-x="1544" d="M201 0v1462h192l797 -1222h8q-2 28 -9 174q-5 114 -5 177v32v839h159v-1462h-194l-799 1227h-8q16 -216 16 -396v-831h-157z" /> +<glyph unicode="O" horiz-adv-x="1595" d="M125 735q0 357 176 553.5t500 196.5q315 0 492 -200t177 -552q0 -351 -177.5 -552t-493.5 -201q-323 0 -498.5 197.5t-175.5 557.5zM305 733q0 -297 126.5 -450.5t367.5 -153.5q243 0 367 153t124 451q0 295 -123.5 447.5t-365.5 152.5q-243 0 -369.5 -153.5 t-126.5 -446.5z" /> +<glyph unicode="P" horiz-adv-x="1233" d="M201 0v1462h379q548 0 548 -426q0 -222 -151.5 -341.5t-433.5 -119.5h-172v-575h-170zM371 721h153q226 0 327 73t101 234q0 145 -95 216t-296 71h-190v-594z" /> +<glyph unicode="Q" horiz-adv-x="1595" d="M125 735q0 357 176 553.5t500 196.5q315 0 492 -200t177 -552q0 -281 -113 -467t-319 -252l348 -362h-247l-285 330l-55 -2q-323 0 -498.5 197.5t-175.5 557.5zM305 733q0 -297 126.5 -450.5t367.5 -153.5q243 0 367 153t124 451q0 295 -123.5 447.5t-365.5 152.5 q-243 0 -369.5 -153.5t-126.5 -446.5z" /> +<glyph unicode="R" horiz-adv-x="1266" d="M201 0v1462h401q269 0 397.5 -103t128.5 -310q0 -290 -294 -392l397 -657h-201l-354 608h-305v-608h-170zM371 754h233q180 0 264 71.5t84 214.5q0 145 -85.5 209t-274.5 64h-221v-559z" /> +<glyph unicode="S" horiz-adv-x="1124" d="M106 47v164q90 -38 196 -60t210 -22q170 0 256 64.5t86 179.5q0 76 -30.5 124.5t-102 89.5t-217.5 93q-204 73 -291.5 173t-87.5 261q0 169 127 269t336 100q218 0 401 -80l-53 -148q-181 76 -352 76q-135 0 -211 -58t-76 -161q0 -76 28 -124.5t94.5 -89t203.5 -89.5 q230 -82 316.5 -176t86.5 -244q0 -193 -140 -301t-380 -108q-260 0 -400 67z" /> +<glyph unicode="T" horiz-adv-x="1133" d="M18 1311v151h1096v-151h-463v-1311h-170v1311h-463z" /> +<glyph unicode="U" horiz-adv-x="1491" d="M186 520v942h170v-954q0 -183 100 -281t294 -98q185 0 285 98.5t100 282.5v952h170v-946q0 -250 -151 -393t-415 -143t-408.5 144t-144.5 396z" /> +<glyph unicode="V" horiz-adv-x="1219" d="M0 1462h180l336 -946q58 -163 92 -317q36 162 94 323l334 940h183l-527 -1462h-168z" /> +<glyph unicode="W" horiz-adv-x="1896" d="M27 1462h180l231 -903q48 -190 70 -344q27 183 80 358l262 889h180l275 -897q48 -155 81 -350q19 142 72 346l230 901h180l-391 -1462h-168l-295 979q-21 65 -47 164t-27 119q-22 -132 -70 -289l-286 -973h-168z" /> +<glyph unicode="X" horiz-adv-x="1182" d="M8 0l486 764l-453 698h188l363 -579l366 579h181l-453 -692l488 -770h-193l-393 643l-400 -643h-180z" /> +<glyph unicode="Y" horiz-adv-x="1147" d="M0 1462h186l387 -731l390 731h184l-488 -895v-567h-172v559z" /> +<glyph unicode="Z" horiz-adv-x="1169" d="M82 0v133l776 1176h-752v153h959v-133l-776 -1175h798v-154h-1005z" /> +<glyph unicode="[" horiz-adv-x="674" d="M166 -324v1786h457v-141h-289v-1503h289v-142h-457z" /> +<glyph unicode="\" horiz-adv-x="752" d="M23 1462h163l547 -1462h-166z" /> +<glyph unicode="]" horiz-adv-x="674" d="M51 -182h289v1503h-289v141h457v-1786h-457v142z" /> +<glyph unicode="^" horiz-adv-x="1110" d="M49 551l434 922h99l477 -922h-152l-372 745l-334 -745h-152z" /> +<glyph unicode="_" horiz-adv-x="918" d="M-4 -184h926v-131h-926v131z" /> +<glyph unicode="`" horiz-adv-x="1182" d="M393 1548v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="a" horiz-adv-x="1139" d="M94 303q0 332 531 348l186 6v68q0 129 -55.5 190.5t-177.5 61.5q-137 0 -310 -84l-51 127q81 44 177.5 69t193.5 25q196 0 290.5 -87t94.5 -279v-748h-123l-33 156h-8q-82 -103 -163.5 -139.5t-203.5 -36.5q-163 0 -255.5 84t-92.5 239zM268 301q0 -90 54.5 -137 t152.5 -47q155 0 243.5 85t88.5 238v99l-166 -7q-198 -7 -285.5 -61.5t-87.5 -169.5z" /> +<glyph unicode="b" horiz-adv-x="1255" d="M176 0v1556h166v-378q0 -127 -8 -228h8q116 164 344 164q216 0 335.5 -147.5t119.5 -417.5t-120.5 -419.5t-334.5 -149.5q-107 0 -195.5 39.5t-148.5 121.5h-12l-35 -141h-119zM342 549q0 -231 77 -330.5t247 -99.5q153 0 228 111.5t75 320.5q0 214 -75 319t-232 105 q-170 0 -245 -97.5t-75 -328.5z" /> +<glyph unicode="c" horiz-adv-x="975" d="M115 541q0 275 132.5 425t377.5 150q79 0 158 -17t124 -40l-51 -141q-55 22 -120 36.5t-115 14.5q-334 0 -334 -426q0 -202 81.5 -310t241.5 -108q137 0 281 59v-147q-110 -57 -277 -57q-238 0 -368.5 146.5t-130.5 414.5z" /> +<glyph unicode="d" horiz-adv-x="1255" d="M115 545q0 271 120 421t334 150q223 0 342 -162h13l-7 79l-4 77v446h166v-1556h-135l-22 147h-9q-115 -167 -344 -167q-215 0 -334.5 147t-119.5 418zM287 543q0 -210 77 -317t226 -107q170 0 246.5 92.5t76.5 298.5v35q0 233 -77.5 332.5t-247.5 99.5 q-146 0 -223.5 -113.5t-77.5 -320.5z" /> +<glyph unicode="e" horiz-adv-x="1149" d="M115 539q0 265 130.5 421t350.5 156q206 0 326 -135.5t120 -357.5v-105h-755q5 -193 97.5 -293t260.5 -100q177 0 350 74v-148q-88 -38 -166.5 -54.5t-189.5 -16.5q-243 0 -383.5 148t-140.5 411zM291 653h573q0 157 -70 240.5t-200 83.5q-132 0 -210.5 -86t-92.5 -238z " /> +<glyph unicode="f" horiz-adv-x="694" d="M29 967v75l196 60v61q0 404 353 404q87 0 204 -35l-43 -133q-96 31 -164 31q-94 0 -139 -62.5t-45 -200.5v-71h279v-129h-279v-967h-166v967h-196z" /> +<glyph unicode="g" horiz-adv-x="1122" d="M39 -186q0 100 64 173t180 99q-42 19 -70.5 59t-28.5 93q0 60 32 105t101 87q-85 35 -138.5 119t-53.5 192q0 180 108 277.5t306 97.5q86 0 155 -20h379v-105l-203 -24q28 -35 50 -91.5t22 -127.5q0 -161 -110 -257t-302 -96q-49 0 -92 8q-106 -56 -106 -141 q0 -45 37 -66.5t127 -21.5h194q178 0 273.5 -75t95.5 -218q0 -182 -146 -277.5t-426 -95.5q-215 0 -331.5 80t-116.5 226zM199 -184q0 -89 75 -135t215 -46q209 0 309.5 62.5t100.5 169.5q0 89 -55 123.5t-207 34.5h-199q-113 0 -176 -54t-63 -155zM289 745q0 -115 65 -174 t181 -59q243 0 243 236q0 247 -246 247q-117 0 -180 -63t-63 -187z" /> +<glyph unicode="h" horiz-adv-x="1257" d="M176 0v1556h166v-471q0 -85 -8 -141h10q49 79 139.5 124.5t206.5 45.5q201 0 301.5 -95.5t100.5 -303.5v-715h-166v709q0 134 -61 200t-191 66q-173 0 -252.5 -94t-79.5 -308v-573h-166z" /> +<glyph unicode="i" horiz-adv-x="518" d="M162 1393q0 57 28 83.5t70 26.5q40 0 69 -27t29 -83t-29 -83.5t-69 -27.5q-42 0 -70 27.5t-28 83.5zM176 0v1096h166v-1096h-166z" /> +<glyph unicode="j" horiz-adv-x="518" d="M-111 -332q69 -20 136 -20q78 0 114.5 42.5t36.5 129.5v1276h166v-1264q0 -324 -299 -324q-95 0 -154 25v135zM162 1393q0 57 28 83.5t70 26.5q40 0 69 -27t29 -83t-29 -83.5t-69 -27.5q-42 0 -70 27.5t-28 83.5z" /> +<glyph unicode="k" horiz-adv-x="1075" d="M176 0v1556h164v-825q0 -55 -8 -170h8q43 61 131 160l354 375h197l-444 -467l475 -629h-201l-387 518l-125 -108v-410h-164z" /> +<glyph unicode="l" horiz-adv-x="518" d="M176 0v1556h166v-1556h-166z" /> +<glyph unicode="m" horiz-adv-x="1905" d="M176 0v1096h135l27 -150h8q47 80 132.5 125t191.5 45q257 0 336 -186h8q49 86 142 136t212 50q186 0 278.5 -95.5t92.5 -305.5v-715h-166v713q0 131 -56 196.5t-174 65.5q-155 0 -229 -89t-74 -274v-612h-166v713q0 131 -56 196.5t-175 65.5q-156 0 -228.5 -93.5 t-72.5 -306.5v-575h-166z" /> +<glyph unicode="n" horiz-adv-x="1257" d="M176 0v1096h135l27 -150h8q51 81 143 125.5t205 44.5q198 0 298 -95.5t100 -305.5v-715h-166v709q0 134 -61 200t-191 66q-172 0 -252 -93t-80 -307v-575h-166z" /> +<glyph unicode="o" horiz-adv-x="1237" d="M115 549q0 268 134 417.5t372 149.5q230 0 365.5 -153t135.5 -414q0 -268 -135 -418.5t-373 -150.5q-147 0 -261 69t-176 198t-62 302zM287 549q0 -210 84 -320t247 -110t247.5 109.5t84.5 320.5q0 209 -84.5 317.5t-249.5 108.5q-163 0 -246 -107t-83 -319z" /> +<glyph unicode="p" horiz-adv-x="1255" d="M176 -492v1588h135l23 -150h8q64 90 149 130t195 40q218 0 336.5 -149t118.5 -418q0 -270 -120.5 -419.5t-334.5 -149.5q-107 0 -195.5 39.5t-148.5 121.5h-12q12 -96 12 -182v-451h-166zM342 549q0 -231 77 -330.5t247 -99.5q142 0 222.5 115t80.5 317 q0 205 -80.5 314.5t-226.5 109.5q-168 0 -243 -93t-77 -296v-37z" /> +<glyph unicode="q" horiz-adv-x="1255" d="M115 545q0 269 120 420t334 151q225 0 346 -170h9l24 150h131v-1588h-166v469q0 100 11 170h-13q-115 -167 -346 -167q-212 0 -331 149t-119 416zM287 543q0 -207 76.5 -315.5t226.5 -108.5q166 0 242 89t81 300v37q0 230 -78 331t-247 101q-146 0 -223.5 -113.5 t-77.5 -320.5z" /> +<glyph unicode="r" horiz-adv-x="836" d="M176 0v1096h137l19 -203h8q61 107 147 165t189 58q73 0 131 -12l-23 -154q-68 15 -120 15q-133 0 -227.5 -108t-94.5 -269v-588h-166z" /> +<glyph unicode="s" horiz-adv-x="977" d="M106 827q0 134 109 211.5t299 77.5q177 0 346 -72l-59 -135q-165 68 -299 68q-118 0 -178 -37t-60 -102q0 -44 22.5 -75t72.5 -59t192 -81q195 -71 263.5 -143t68.5 -181q0 -153 -114 -236t-320 -83q-218 0 -340 69v154q79 -40 169.5 -63t174.5 -23q130 0 200 41.5 t70 126.5q0 64 -55.5 109.5t-216.5 107.5q-153 57 -217.5 99.5t-96 96.5t-31.5 129z" /> +<glyph unicode="t" horiz-adv-x="723" d="M31 967v80l157 69l70 234h96v-254h318v-129h-318v-645q0 -99 47 -152t129 -53q44 0 85 6.5t65 13.5v-127q-27 -13 -79.5 -21.5t-94.5 -8.5q-318 0 -318 335v652h-157z" /> +<glyph unicode="u" horiz-adv-x="1257" d="M164 379v717h168v-711q0 -134 61 -200t191 -66q172 0 251.5 94t79.5 307v576h166v-1096h-137l-24 147h-9q-51 -81 -141.5 -124t-206.5 -43q-200 0 -299.5 95t-99.5 304z" /> +<glyph unicode="v" horiz-adv-x="1026" d="M0 1096h178l236 -650q80 -228 94 -296h8q11 53 69.5 219.5t262.5 726.5h178l-416 -1096h-194z" /> +<glyph unicode="w" horiz-adv-x="1593" d="M23 1096h174q106 -413 161.5 -629t63.5 -291h8q11 57 35.5 147.5t42.5 143.5l201 629h180l196 -629q56 -172 76 -289h8q4 36 21.5 111t208.5 807h172l-303 -1096h-197l-201 643q-19 59 -71 268h-8q-40 -175 -70 -270l-207 -641h-192z" /> +<glyph unicode="x" horiz-adv-x="1073" d="M39 0l401 561l-381 535h189l289 -420l288 420h187l-381 -535l401 -561h-188l-307 444l-310 -444h-188z" /> +<glyph unicode="y" horiz-adv-x="1032" d="M2 1096h178l240 -625q79 -214 98 -309h8q13 51 54.5 174.5t271.5 759.5h178l-471 -1248q-70 -185 -163.5 -262.5t-229.5 -77.5q-76 0 -150 17v133q55 -12 123 -12q171 0 244 192l61 156z" /> +<glyph unicode="z" horiz-adv-x="958" d="M82 0v113l598 854h-561v129h743v-129l-590 -838h605v-129h-795z" /> +<glyph unicode="{" horiz-adv-x="776" d="M61 498v141q130 2 188 48t58 142v306q0 155 108 241t290 86v-139q-230 -6 -230 -199v-295q0 -215 -223 -254v-12q223 -39 223 -254v-297q0 -102 58.5 -148t171.5 -48v-140q-190 2 -294 87t-104 239v303q0 104 -63 148.5t-183 44.5z" /> +<glyph unicode="|" horiz-adv-x="1128" d="M494 -496v2052h141v-2052h-141z" /> +<glyph unicode="}" horiz-adv-x="776" d="M72 -184q111 2 169 48t58 148v297q0 114 55 174t168 80v12q-223 39 -223 254v295q0 193 -227 199v139q184 0 289.5 -87t105.5 -240v-306q0 -97 59 -142.5t189 -47.5v-141q-122 0 -185 -44.5t-63 -148.5v-303q0 -153 -102.5 -238.5t-292.5 -87.5v140z" /> +<glyph unicode="~" d="M104 592v151q100 109 244 109q68 0 124.5 -14t145.5 -52q66 -28 115 -41.5t96 -13.5q54 0 118 32t118 89v-150q-102 -110 -244 -110q-72 0 -135 16.5t-135 48.5q-75 32 -120 44t-93 12q-53 0 -116.5 -33.5t-117.5 -87.5z" /> +<glyph unicode="¡" horiz-adv-x="547" d="M152 983q0 63 31.5 99t88.5 36q51 0 86 -32t35 -103q0 -135 -121 -135q-60 0 -90 35.5t-30 99.5zM168 -373l51 1057h105l51 -1057h-207z" /> +<glyph unicode="¢" d="M190 741q0 508 396 570v172h135v-164q75 -3 146 -19.5t120 -39.5l-49 -140q-133 51 -242 51q-172 0 -253 -105.5t-81 -322.5q0 -212 79.5 -313.5t246.5 -101.5q141 0 283 59v-147q-105 -54 -252 -60v-200h-133v206q-203 32 -299.5 168.5t-96.5 386.5z" /> +<glyph unicode="£" d="M63 0v141q205 47 205 291v223h-198v127h198v316q0 178 112 280.5t302 102.5t360 -84l-61 -133q-154 77 -297 77q-123 0 -185.5 -62t-62.5 -202v-295h422v-127h-422v-221q0 -100 -32.5 -168t-106.5 -112h795v-154h-1029z" /> +<glyph unicode="¤" d="M123 1092l94 92l135 -133q104 73 234 73q127 0 229 -73l137 133l95 -92l-134 -138q74 -113 74 -231q0 -131 -74 -234l131 -135l-92 -92l-137 133q-102 -71 -229 -71q-134 0 -234 73l-135 -133l-92 92l133 136q-74 107 -74 231q0 122 74 229zM313 723q0 -112 78.5 -192 t194.5 -80t195 79.5t79 192.5q0 114 -80 195t-194 81q-116 0 -194.5 -82t-78.5 -194z" /> +<glyph unicode="¥" d="M31 1462h178l375 -727l379 727h174l-416 -770h262v-127h-317v-170h317v-127h-317v-268h-164v268h-316v127h316v170h-316v127h256z" /> +<glyph unicode="¦" horiz-adv-x="1128" d="M494 281h141v-777h-141v777zM494 780v776h141v-776h-141z" /> +<glyph unicode="§" horiz-adv-x="1057" d="M123 57v148q78 -37 175 -59.5t179 -22.5q134 0 204.5 38t70.5 109q0 46 -24 75t-78 58t-169 72q-142 52 -209 97t-100 102t-33 135q0 86 43 154.5t121 105.5q-74 40 -116 95.5t-42 140.5q0 121 103.5 190.5t300.5 69.5q94 0 173.5 -14.5t176.5 -53.5l-53 -131 q-98 39 -165.5 52.5t-143.5 13.5q-116 0 -174 -29.5t-58 -93.5q0 -60 61.5 -102t215.5 -97q186 -68 261 -143.5t75 -182.5q0 -90 -41 -160.5t-115 -111.5q153 -81 153 -227q0 -140 -117 -216.5t-329 -76.5q-218 0 -346 65zM285 829q0 -77 66 -129.5t233 -113.5l49 -19 q137 80 137 191q0 83 -73.5 139t-258.5 113q-68 -19 -110.5 -69t-42.5 -112z" /> +<glyph unicode="¨" horiz-adv-x="1182" d="M309 1393q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM690 1393q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="©" horiz-adv-x="1704" d="M100 731q0 200 100 375t275 276t377 101q200 0 375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM205 731q0 -173 87 -323.5t237.5 -237t322.5 -86.5q174 0 323 87t236.5 235.5t87.5 324.5q0 174 -87 323 t-235.5 236.5t-324.5 87.5q-174 0 -323 -87t-236.5 -235.5t-87.5 -324.5zM481 731q0 209 110.5 332t301.5 123q128 0 246 -60l-58 -118q-108 51 -188 51q-125 0 -192.5 -87t-67.5 -241q0 -168 63.5 -249t194.5 -81q86 0 211 45v-124q-48 -20 -98.5 -34t-120.5 -14 q-194 0 -298 120.5t-104 336.5z" /> +<glyph unicode="ª" horiz-adv-x="725" d="M70 989q0 102 77 154.5t242 58.5l117 4v39q0 133 -148 133q-100 0 -204 -51l-43 96q114 56 247 56q130 0 198.5 -52.5t68.5 -173.5v-452h-93l-24 84q-92 -97 -232 -97q-95 0 -150.5 49.5t-55.5 151.5zM193 989q0 -100 112 -100q201 0 201 180v49l-98 -4 q-112 -4 -163.5 -32.5t-51.5 -92.5z" /> +<glyph unicode="«" horiz-adv-x="1018" d="M82 524v27l342 407l119 -69l-289 -350l289 -351l-119 -71zM477 524v27l344 407l117 -69l-287 -350l287 -351l-117 -71z" /> +<glyph unicode="¬" d="M104 653v138h961v-527h-137v389h-824z" /> +<glyph unicode="­" horiz-adv-x="659" d="M84 473v152h491v-152h-491z" /> +<glyph unicode="®" horiz-adv-x="1704" d="M100 731q0 200 100 375t275 276t377 101q200 0 375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM205 731q0 -173 87 -323.5t237.5 -237t322.5 -86.5q174 0 323 87t236.5 235.5t87.5 324.5q0 174 -87 323 t-235.5 236.5t-324.5 87.5q-174 0 -323 -87t-236.5 -235.5t-87.5 -324.5zM575 285v891h261q166 0 243.5 -65t77.5 -198q0 -80 -42.5 -141.5t-119.5 -91.5l238 -395h-168l-207 354h-135v-354h-148zM723 762h108q80 0 128.5 41.5t48.5 105.5q0 75 -43 107.5t-136 32.5h-106 v-287z" /> +<glyph unicode="¯" horiz-adv-x="1024" d="M-6 1556v127h1036v-127h-1036z" /> +<glyph unicode="°" horiz-adv-x="877" d="M127 1171q0 130 90.5 221t220.5 91t221 -90.5t91 -221.5q0 -84 -41 -155.5t-114 -113.5t-157 -42q-130 0 -220.5 90t-90.5 221zM242 1171q0 -82 58.5 -139t139.5 -57q80 0 137.5 56.5t57.5 139.5q0 84 -56.5 140.5t-138.5 56.5q-83 0 -140.5 -57t-57.5 -140z" /> +<glyph unicode="±" d="M104 1v138h961v-138h-961zM104 653v138h410v428h139v-428h412v-138h-412v-426h-139v426h-410z" /> +<glyph unicode="²" horiz-adv-x="711" d="M49 586v104l236 230q89 86 130 134.5t57.5 86.5t16.5 92q0 68 -40 102.5t-103 34.5q-52 0 -101 -19t-118 -69l-66 88q131 111 283 111q132 0 205.5 -65t73.5 -177q0 -80 -44.5 -155.5t-191.5 -213.5l-174 -165h440v-119h-604z" /> +<glyph unicode="³" horiz-adv-x="711" d="M33 625v123q147 -68 270 -68q211 0 211 162q0 145 -231 145h-117v107h119q103 0 152.5 39.5t49.5 107.5q0 61 -40 95t-107 34q-66 0 -122 -21.5t-112 -56.5l-69 90q63 45 133 72t164 27q136 0 214.5 -59.5t78.5 -166.5q0 -80 -41 -131.5t-109 -74.5q176 -47 176 -209 q0 -128 -92 -199.5t-260 -71.5q-152 0 -268 56z" /> +<glyph unicode="´" horiz-adv-x="1182" d="M393 1241v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="µ" horiz-adv-x="1268" d="M176 -492v1588h166v-715q0 -262 254 -262q171 0 250.5 94.5t79.5 306.5v576h166v-1096h-136l-26 147h-10q-111 -167 -340 -167q-150 0 -238 92h-10q10 -84 10 -244v-320h-166z" /> +<glyph unicode="¶" horiz-adv-x="1341" d="M113 1042q0 260 109 387t341 127h557v-1816h-114v1712h-213v-1712h-115v819q-62 -18 -146 -18q-216 0 -317.5 125t-101.5 376z" /> +<glyph unicode="·" horiz-adv-x="545" d="M152 723q0 66 31 100.5t87 34.5q58 0 90.5 -34.5t32.5 -100.5q0 -65 -33 -100t-90 -35q-51 0 -84.5 31.5t-33.5 103.5z" /> +<glyph unicode="¸" horiz-adv-x="465" d="M37 -377q45 -8 104 -8q79 0 119.5 20t40.5 74q0 43 -39.5 69.5t-148.5 43.5l88 178h110l-55 -115q180 -39 180 -174q0 -97 -76.5 -150t-226.5 -53q-51 0 -96 9v106z" /> +<glyph unicode="¹" horiz-adv-x="711" d="M76 1280l262 182h143v-876h-133v579q0 91 6 181q-22 -22 -49 -44.5t-162 -117.5z" /> +<glyph unicode="º" horiz-adv-x="768" d="M66 1135q0 163 84 253.5t235 90.5q152 0 234.5 -91t82.5 -253q0 -164 -85.5 -255.5t-235.5 -91.5q-146 0 -230.5 93t-84.5 254zM188 1135q0 -122 45.5 -183t149.5 -61q105 0 151 61t46 183q0 123 -46 182t-151 59q-103 0 -149 -59t-46 -182z" /> +<glyph unicode="»" horiz-adv-x="1018" d="M80 188l287 351l-287 350l117 69l344 -407v-27l-344 -407zM475 188l287 351l-287 350l117 69l344 -407v-27l-344 -407z" /> +<glyph unicode="¼" horiz-adv-x="1597" d="M75 1280l262 182h143v-876h-133v579q0 91 6 181q-22 -22 -49 -44.5t-162 -117.5zM252 0l903 1462h143l-903 -1462h-143zM817 203v101l408 579h139v-563h125v-117h-125v-202h-145v202h-402zM957 320h262v195q0 134 6 209q-5 -12 -17 -31.5t-27 -42l-30 -45t-26 -39.5z" /> +<glyph unicode="½" horiz-adv-x="1597" d="M46 1280l262 182h143v-876h-133v579q0 91 6 181q-22 -22 -49 -44.5t-162 -117.5zM184 0l903 1462h143l-903 -1462h-143zM895 1v104l236 230q89 86 130 134.5t57.5 86.5t16.5 92q0 68 -40 102.5t-103 34.5q-52 0 -101 -19t-118 -69l-66 88q131 111 283 111 q132 0 205.5 -65t73.5 -177q0 -80 -44.5 -155.5t-191.5 -213.5l-174 -165h440v-119h-604z" /> +<glyph unicode="¾" horiz-adv-x="1597" d="M26 625v123q147 -68 270 -68q211 0 211 162q0 145 -231 145h-117v107h119q103 0 152.5 39.5t49.5 107.5q0 61 -40 95t-107 34q-66 0 -122 -21.5t-112 -56.5l-69 90q63 45 133 72t164 27q136 0 214.5 -59.5t78.5 -166.5q0 -80 -41 -131.5t-109 -74.5q176 -47 176 -209 q0 -128 -92 -199.5t-260 -71.5q-152 0 -268 56zM344 0l903 1462h143l-903 -1462h-143zM897 203v101l408 579h139v-563h125v-117h-125v-202h-145v202h-402zM1037 320h262v195q0 134 6 209q-5 -12 -17 -31.5t-27 -42l-30 -45t-26 -39.5z" /> +<glyph unicode="¿" horiz-adv-x="879" d="M51 -37q0 70 17.5 122.5t49.5 97t76.5 85.5t98.5 88q101 88 133.5 146t32.5 151v31h131v-51q0 -122 -37.5 -196t-134.5 -158q-121 -106 -151.5 -143.5t-43 -76t-12.5 -94.5q0 -100 66 -156.5t188 -56.5q80 0 155 19t173 67l59 -135q-197 -96 -395 -96q-190 0 -298 93 t-108 263zM397 983q0 64 33 99.5t88 35.5q51 0 86 -32t35 -103q0 -135 -121 -135q-59 0 -90 34.5t-31 100.5z" /> +<glyph unicode="À" horiz-adv-x="1296" d="M0 0l578 1468h143l575 -1468h-176l-182 465h-586l-180 -465h-172zM331 1886v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159zM412 618h473l-170 453q-33 86 -68 211q-22 -96 -63 -211z" /> +<glyph unicode="Á" horiz-adv-x="1296" d="M0 0l578 1468h143l575 -1468h-176l-182 465h-586l-180 -465h-172zM412 618h473l-170 453q-33 86 -68 211q-22 -96 -63 -211zM526 1579v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="Â" horiz-adv-x="1296" d="M0 0l578 1468h143l575 -1468h-176l-182 465h-586l-180 -465h-172zM303 1579v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186h-115zM412 618h473l-170 453q-33 86 -68 211q-22 -96 -63 -211z" /> +<glyph unicode="Ã" horiz-adv-x="1296" d="M0 0l578 1468h143l575 -1468h-176l-182 465h-586l-180 -465h-172zM268 1579q13 121 70.5 189.5t148.5 68.5q46 0 89 -18.5t82 -41t75 -41t68 -18.5q49 0 73 29.5t39 91.5h99q-13 -121 -69.5 -189.5t-150.5 -68.5q-43 0 -84 18.5t-80.5 41t-76 41t-70.5 18.5 q-50 0 -75.5 -30t-39.5 -91h-98zM412 618h473l-170 453q-33 86 -68 211q-22 -96 -63 -211z" /> +<glyph unicode="Ä" horiz-adv-x="1296" d="M0 0l578 1468h143l575 -1468h-176l-182 465h-586l-180 -465h-172zM364 1731q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM412 618h473l-170 453q-33 86 -68 211q-22 -96 -63 -211zM745 1731q0 52 26.5 75 t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="Å" horiz-adv-x="1296" d="M0 0l578 1468h143l575 -1468h-176l-182 465h-586l-180 -465h-172zM412 618h473l-170 453q-33 86 -68 211q-22 -96 -63 -211zM424 1585q0 98 60.5 155.5t160.5 57.5q101 0 163 -59.5t62 -151.5q0 -98 -61.5 -157.5t-163.5 -59.5q-101 0 -161 58.5t-60 156.5zM528 1585 q0 -56 30 -86.5t87 -30.5q52 0 84.5 30.5t32.5 86.5t-33 86.5t-84 30.5t-84 -30.5t-33 -86.5z" /> +<glyph unicode="Æ" horiz-adv-x="1788" d="M-2 0l698 1462h969v-151h-580v-471h541v-150h-541v-538h580v-152h-750v465h-514l-227 -465h-176zM469 618h446v693h-118z" /> +<glyph unicode="Ç" horiz-adv-x="1292" d="M125 733q0 226 84.5 396t244 262t375.5 92q230 0 402 -84l-72 -146q-166 78 -332 78q-241 0 -380.5 -160.5t-139.5 -439.5q0 -287 134.5 -443.5t383.5 -156.5q153 0 349 55v-149q-152 -57 -375 -57q-323 0 -498.5 196t-175.5 557zM551 -377q45 -8 104 -8q79 0 119.5 20 t40.5 74q0 43 -39.5 69.5t-148.5 43.5l88 178h110l-55 -115q180 -39 180 -174q0 -97 -76.5 -150t-226.5 -53q-51 0 -96 9v106z" /> +<glyph unicode="È" horiz-adv-x="1139" d="M201 0v1462h815v-151h-645v-471h606v-150h-606v-538h645v-152h-815zM320 1886v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="É" horiz-adv-x="1139" d="M201 0v1462h815v-151h-645v-471h606v-150h-606v-538h645v-152h-815zM456 1579v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="Ê" horiz-adv-x="1139" d="M201 0v1462h815v-151h-645v-471h606v-150h-606v-538h645v-152h-815zM263 1579v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186h-115z" /> +<glyph unicode="Ë" horiz-adv-x="1139" d="M201 0v1462h815v-151h-645v-471h606v-150h-606v-538h645v-152h-815zM327 1731q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM708 1731q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5 t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="Ì" horiz-adv-x="571" d="M5 1886v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159zM201 0v1462h170v-1462h-170z" /> +<glyph unicode="Í" horiz-adv-x="571" d="M179 1579v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111zM201 0v1462h170v-1462h-170z" /> +<glyph unicode="Î" horiz-adv-x="571" d="M-57 1579v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186h-115zM201 0v1462h170v-1462h-170z" /> +<glyph unicode="Ï" horiz-adv-x="571" d="M5 1731q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM201 0v1462h170v-1462h-170zM386 1731q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="Ð" horiz-adv-x="1479" d="M47 649v150h154v663h434q337 0 527 -187.5t190 -529.5q0 -362 -196.5 -553.5t-565.5 -191.5h-389v649h-154zM371 147h190q610 0 610 592q0 576 -569 576h-231v-516h379v-150h-379v-502z" /> +<glyph unicode="Ñ" horiz-adv-x="1544" d="M201 0v1462h192l797 -1222h8q-2 27 -9 173.5t-5 209.5v839h159v-1462h-194l-799 1227h-8q16 -216 16 -396v-831h-157zM411 1579q13 121 70.5 189.5t148.5 68.5q46 0 89 -18.5t82 -41t75 -41t68 -18.5q49 0 73 29.5t39 91.5h99q-13 -121 -69.5 -189.5t-150.5 -68.5 q-43 0 -84 18.5t-80.5 41t-76 41t-70.5 18.5q-50 0 -75.5 -30t-39.5 -91h-98z" /> +<glyph unicode="Ò" horiz-adv-x="1595" d="M125 735q0 357 176 553.5t500 196.5q315 0 492 -200t177 -552q0 -351 -177.5 -552t-493.5 -201q-323 0 -498.5 197.5t-175.5 557.5zM305 733q0 -297 126.5 -450.5t367.5 -153.5q243 0 367 153t124 451q0 295 -123.5 447.5t-365.5 152.5q-243 0 -369.5 -153.5 t-126.5 -446.5zM514 1886v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="Ó" horiz-adv-x="1595" d="M125 735q0 357 176 553.5t500 196.5q315 0 492 -200t177 -552q0 -351 -177.5 -552t-493.5 -201q-323 0 -498.5 197.5t-175.5 557.5zM305 733q0 -297 126.5 -450.5t367.5 -153.5q243 0 367 153t124 451q0 295 -123.5 447.5t-365.5 152.5q-243 0 -369.5 -153.5 t-126.5 -446.5zM659 1579v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="Ô" horiz-adv-x="1595" d="M125 735q0 357 176 553.5t500 196.5q315 0 492 -200t177 -552q0 -351 -177.5 -552t-493.5 -201q-323 0 -498.5 197.5t-175.5 557.5zM305 733q0 -297 126.5 -450.5t367.5 -153.5q243 0 367 153t124 451q0 295 -123.5 447.5t-365.5 152.5q-243 0 -369.5 -153.5 t-126.5 -446.5zM448 1579v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186h-115z" /> +<glyph unicode="Õ" horiz-adv-x="1595" d="M125 735q0 357 176 553.5t500 196.5q315 0 492 -200t177 -552q0 -351 -177.5 -552t-493.5 -201q-323 0 -498.5 197.5t-175.5 557.5zM305 733q0 -297 126.5 -450.5t367.5 -153.5q243 0 367 153t124 451q0 295 -123.5 447.5t-365.5 152.5q-243 0 -369.5 -153.5 t-126.5 -446.5zM418 1579q13 121 70.5 189.5t148.5 68.5q46 0 89 -18.5t82 -41t75 -41t68 -18.5q49 0 73 29.5t39 91.5h99q-13 -121 -69.5 -189.5t-150.5 -68.5q-43 0 -84 18.5t-80.5 41t-76 41t-70.5 18.5q-50 0 -75.5 -30t-39.5 -91h-98z" /> +<glyph unicode="Ö" horiz-adv-x="1595" d="M125 735q0 357 176 553.5t500 196.5q315 0 492 -200t177 -552q0 -351 -177.5 -552t-493.5 -201q-323 0 -498.5 197.5t-175.5 557.5zM305 733q0 -297 126.5 -450.5t367.5 -153.5q243 0 367 153t124 451q0 295 -123.5 447.5t-365.5 152.5q-243 0 -369.5 -153.5 t-126.5 -446.5zM522 1731q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM903 1731q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="×" d="M133 1075l100 101l353 -355l354 355l96 -99l-352 -354l350 -352l-96 -99l-354 351l-348 -351l-101 99l350 352z" /> +<glyph unicode="Ø" horiz-adv-x="1595" d="M125 735q0 357 176 553.5t500 196.5q209 0 366 -94l97 135l120 -80l-106 -148q192 -202 192 -565q0 -351 -177.5 -552t-493.5 -201q-235 0 -383 100l-101 -141l-120 79l108 154q-178 198 -178 563zM305 733q0 -262 101 -416l669 943q-106 73 -274 73 q-243 0 -369.5 -153.5t-126.5 -446.5zM508 211q115 -82 291 -82q243 0 367 153t124 451q0 272 -110 426z" /> +<glyph unicode="Ù" horiz-adv-x="1491" d="M186 520v942h170v-954q0 -183 100 -281t294 -98q185 0 285 98.5t100 282.5v952h170v-946q0 -250 -151 -393t-415 -143t-408.5 144t-144.5 396zM463 1886v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="Ú" horiz-adv-x="1491" d="M186 520v942h170v-954q0 -183 100 -281t294 -98q185 0 285 98.5t100 282.5v952h170v-946q0 -250 -151 -393t-415 -143t-408.5 144t-144.5 396zM600 1579v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="Û" horiz-adv-x="1491" d="M186 520v942h170v-954q0 -183 100 -281t294 -98q185 0 285 98.5t100 282.5v952h170v-946q0 -250 -151 -393t-415 -143t-408.5 144t-144.5 396zM393 1579v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186 h-115z" /> +<glyph unicode="Ü" horiz-adv-x="1491" d="M186 520v942h170v-954q0 -183 100 -281t294 -98q185 0 285 98.5t100 282.5v952h170v-946q0 -250 -151 -393t-415 -143t-408.5 144t-144.5 396zM461 1731q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5z M842 1731q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="Ý" horiz-adv-x="1147" d="M0 1462h186l387 -731l390 731h184l-488 -895v-567h-172v559zM442 1579v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="Þ" horiz-adv-x="1251" d="M201 0v1462h170v-256h215q281 0 420 -103.5t139 -318.5q0 -227 -151.5 -346t-438.5 -119h-184v-319h-170zM371 465h168q226 0 327 71.5t101 235.5q0 149 -95 218t-297 69h-204v-594z" /> +<glyph unicode="ß" horiz-adv-x="1274" d="M176 0v1202q0 178 110 271.5t332 93.5q206 0 318.5 -78.5t112.5 -222.5q0 -135 -143 -250q-88 -70 -116 -103.5t-28 -66.5q0 -32 13.5 -53t49 -49.5t113.5 -79.5q140 -95 191 -173.5t51 -179.5q0 -160 -97 -245.5t-276 -85.5q-188 0 -295 69v154q63 -39 141 -62.5 t150 -23.5q215 0 215 182q0 75 -41.5 128.5t-151.5 123.5q-127 82 -175 143.5t-48 145.5q0 63 34.5 116t105.5 106q75 57 107 102t32 98q0 80 -68 122.5t-195 42.5q-276 0 -276 -223v-1204h-166z" /> +<glyph unicode="à" horiz-adv-x="1139" d="M94 303q0 332 531 348l186 6v68q0 129 -55.5 190.5t-177.5 61.5q-137 0 -310 -84l-51 127q81 44 177.5 69t193.5 25q196 0 290.5 -87t94.5 -279v-748h-123l-33 156h-8q-82 -103 -163.5 -139.5t-203.5 -36.5q-163 0 -255.5 84t-92.5 239zM268 301q0 -90 54.5 -137 t152.5 -47q155 0 243.5 85t88.5 238v99l-166 -7q-198 -7 -285.5 -61.5t-87.5 -169.5zM279 1548v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="á" horiz-adv-x="1139" d="M94 303q0 332 531 348l186 6v68q0 129 -55.5 190.5t-177.5 61.5q-137 0 -310 -84l-51 127q81 44 177.5 69t193.5 25q196 0 290.5 -87t94.5 -279v-748h-123l-33 156h-8q-82 -103 -163.5 -139.5t-203.5 -36.5q-163 0 -255.5 84t-92.5 239zM268 301q0 -90 54.5 -137 t152.5 -47q155 0 243.5 85t88.5 238v99l-166 -7q-198 -7 -285.5 -61.5t-87.5 -169.5zM436 1241v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="â" horiz-adv-x="1139" d="M94 303q0 332 531 348l186 6v68q0 129 -55.5 190.5t-177.5 61.5q-137 0 -310 -84l-51 127q81 44 177.5 69t193.5 25q196 0 290.5 -87t94.5 -279v-748h-123l-33 156h-8q-82 -103 -163.5 -139.5t-203.5 -36.5q-163 0 -255.5 84t-92.5 239zM228 1241v23q127 136 178 200 t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186h-115zM268 301q0 -90 54.5 -137t152.5 -47q155 0 243.5 85t88.5 238v99l-166 -7q-198 -7 -285.5 -61.5t-87.5 -169.5z" /> +<glyph unicode="ã" horiz-adv-x="1139" d="M94 303q0 332 531 348l186 6v68q0 129 -55.5 190.5t-177.5 61.5q-137 0 -310 -84l-51 127q81 44 177.5 69t193.5 25q196 0 290.5 -87t94.5 -279v-748h-123l-33 156h-8q-82 -103 -163.5 -139.5t-203.5 -36.5q-163 0 -255.5 84t-92.5 239zM197 1241q13 121 70.5 189.5 t148.5 68.5q46 0 89 -18.5t82 -41t75 -41t68 -18.5q49 0 73 29.5t39 91.5h99q-13 -121 -69.5 -189.5t-150.5 -68.5q-43 0 -84 18.5t-80.5 41t-76 41t-70.5 18.5q-50 0 -75.5 -30t-39.5 -91h-98zM268 301q0 -90 54.5 -137t152.5 -47q155 0 243.5 85t88.5 238v99l-166 -7 q-198 -7 -285.5 -61.5t-87.5 -169.5z" /> +<glyph unicode="ä" horiz-adv-x="1139" d="M94 303q0 332 531 348l186 6v68q0 129 -55.5 190.5t-177.5 61.5q-137 0 -310 -84l-51 127q81 44 177.5 69t193.5 25q196 0 290.5 -87t94.5 -279v-748h-123l-33 156h-8q-82 -103 -163.5 -139.5t-203.5 -36.5q-163 0 -255.5 84t-92.5 239zM268 301q0 -90 54.5 -137 t152.5 -47q155 0 243.5 85t88.5 238v99l-166 -7q-198 -7 -285.5 -61.5t-87.5 -169.5zM279 1393q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM660 1393q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75 q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="å" horiz-adv-x="1139" d="M94 303q0 332 531 348l186 6v68q0 129 -55.5 190.5t-177.5 61.5q-137 0 -310 -84l-51 127q81 44 177.5 69t193.5 25q196 0 290.5 -87t94.5 -279v-748h-123l-33 156h-8q-82 -103 -163.5 -139.5t-203.5 -36.5q-163 0 -255.5 84t-92.5 239zM268 301q0 -90 54.5 -137 t152.5 -47q155 0 243.5 85t88.5 238v99l-166 -7q-198 -7 -285.5 -61.5t-87.5 -169.5zM358 1456q0 98 60.5 155.5t160.5 57.5q101 0 163 -59.5t62 -151.5q0 -98 -61.5 -157.5t-163.5 -59.5q-101 0 -161 58.5t-60 156.5zM462 1456q0 -56 30 -86.5t87 -30.5q52 0 84.5 30.5 t32.5 86.5t-33 86.5t-84 30.5t-84 -30.5t-33 -86.5z" /> +<glyph unicode="æ" horiz-adv-x="1757" d="M94 303q0 161 124 250.5t378 97.5l184 6v68q0 129 -58 190.5t-177 61.5q-144 0 -307 -84l-52 127q74 41 173.5 67.5t197.5 26.5q130 0 212.5 -43.5t123.5 -138.5q53 88 138.5 136t195.5 48q192 0 308 -133.5t116 -355.5v-107h-701q8 -395 322 -395q91 0 169.5 17.5 t162.5 56.5v-148q-86 -38 -160.5 -54.5t-175.5 -16.5q-289 0 -414 233q-81 -127 -179.5 -180t-232.5 -53q-163 0 -255.5 85t-92.5 238zM268 301q0 -95 53.5 -139.5t141.5 -44.5q145 0 229 84.5t84 238.5v99l-158 -7q-186 -8 -268 -62.5t-82 -168.5zM954 653h519 q0 156 -64 240t-184 84q-121 0 -190.5 -83t-80.5 -241z" /> +<glyph unicode="ç" horiz-adv-x="975" d="M115 541q0 275 132.5 425t377.5 150q79 0 158 -17t124 -40l-51 -141q-55 22 -120 36.5t-115 14.5q-334 0 -334 -426q0 -202 81.5 -310t241.5 -108q137 0 281 59v-147q-110 -57 -277 -57q-238 0 -368.5 146.5t-130.5 414.5zM363 -377q45 -8 104 -8q79 0 119.5 20t40.5 74 q0 43 -39.5 69.5t-148.5 43.5l88 178h110l-55 -115q180 -39 180 -174q0 -97 -76.5 -150t-226.5 -53q-51 0 -96 9v106z" /> +<glyph unicode="è" horiz-adv-x="1149" d="M115 539q0 265 130.5 421t350.5 156q206 0 326 -135.5t120 -357.5v-105h-755q5 -193 97.5 -293t260.5 -100q177 0 350 74v-148q-88 -38 -166.5 -54.5t-189.5 -16.5q-243 0 -383.5 148t-140.5 411zM291 653h573q0 157 -70 240.5t-200 83.5q-132 0 -210.5 -86t-92.5 -238z M318 1548v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="é" horiz-adv-x="1149" d="M115 539q0 265 130.5 421t350.5 156q206 0 326 -135.5t120 -357.5v-105h-755q5 -193 97.5 -293t260.5 -100q177 0 350 74v-148q-88 -38 -166.5 -54.5t-189.5 -16.5q-243 0 -383.5 148t-140.5 411zM291 653h573q0 157 -70 240.5t-200 83.5q-132 0 -210.5 -86t-92.5 -238z M471 1241v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="ê" horiz-adv-x="1149" d="M115 539q0 265 130.5 421t350.5 156q206 0 326 -135.5t120 -357.5v-105h-755q5 -193 97.5 -293t260.5 -100q177 0 350 74v-148q-88 -38 -166.5 -54.5t-189.5 -16.5q-243 0 -383.5 148t-140.5 411zM259 1241v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5 t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186h-115zM291 653h573q0 157 -70 240.5t-200 83.5q-132 0 -210.5 -86t-92.5 -238z" /> +<glyph unicode="ë" horiz-adv-x="1149" d="M115 539q0 265 130.5 421t350.5 156q206 0 326 -135.5t120 -357.5v-105h-755q5 -193 97.5 -293t260.5 -100q177 0 350 74v-148q-88 -38 -166.5 -54.5t-189.5 -16.5q-243 0 -383.5 148t-140.5 411zM291 653h573q0 157 -70 240.5t-200 83.5q-132 0 -210.5 -86t-92.5 -238z M319 1393q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM700 1393q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="ì" horiz-adv-x="518" d="M-38 1548v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159zM176 0v1096h166v-1096h-166z" /> +<glyph unicode="í" horiz-adv-x="518" d="M169 1241v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111zM176 0v1096h166v-1096h-166z" /> +<glyph unicode="î" horiz-adv-x="518" d="M-77 1241v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186h-115zM176 0v1096h166v-1096h-166z" /> +<glyph unicode="ï" horiz-adv-x="518" d="M-20 1393q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM176 0v1096h166v-1096h-166zM361 1393q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="ð" horiz-adv-x="1221" d="M113 475q0 230 131.5 361t351.5 131q226 0 326 -121l8 4q-57 214 -262 405l-271 -155l-73 108l233 133q-92 62 -186 111l69 117q156 -73 258 -148l238 138l76 -107l-207 -119q152 -143 234.5 -342t82.5 -428q0 -281 -130.5 -432t-377.5 -151q-222 0 -361.5 134.5 t-139.5 360.5zM281 469q0 -167 87.5 -258.5t249.5 -91.5q175 0 255.5 100.5t80.5 292.5q0 147 -90 232t-246 85q-337 0 -337 -360z" /> +<glyph unicode="ñ" horiz-adv-x="1257" d="M176 0v1096h135l27 -150h8q51 81 143 125.5t205 44.5q198 0 298 -95.5t100 -305.5v-715h-166v709q0 134 -61 200t-191 66q-172 0 -252 -93t-80 -307v-575h-166zM278 1241q13 121 70.5 189.5t148.5 68.5q46 0 89 -18.5t82 -41t75 -41t68 -18.5q49 0 73 29.5t39 91.5h99 q-13 -121 -69.5 -189.5t-150.5 -68.5q-43 0 -84 18.5t-80.5 41t-76 41t-70.5 18.5q-50 0 -75.5 -30t-39.5 -91h-98z" /> +<glyph unicode="ò" horiz-adv-x="1237" d="M115 549q0 268 134 417.5t372 149.5q230 0 365.5 -153t135.5 -414q0 -268 -135 -418.5t-373 -150.5q-147 0 -261 69t-176 198t-62 302zM287 549q0 -210 84 -320t247 -110t247.5 109.5t84.5 320.5q0 209 -84.5 317.5t-249.5 108.5q-163 0 -246 -107t-83 -319zM349 1548v21 h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="ó" horiz-adv-x="1237" d="M115 549q0 268 134 417.5t372 149.5q230 0 365.5 -153t135.5 -414q0 -268 -135 -418.5t-373 -150.5q-147 0 -261 69t-176 198t-62 302zM287 549q0 -210 84 -320t247 -110t247.5 109.5t84.5 320.5q0 209 -84.5 317.5t-249.5 108.5q-163 0 -246 -107t-83 -319zM479 1241v25 q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="ô" horiz-adv-x="1237" d="M115 549q0 268 134 417.5t372 149.5q230 0 365.5 -153t135.5 -414q0 -268 -135 -418.5t-373 -150.5q-147 0 -261 69t-176 198t-62 302zM282 1241v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186h-115z M287 549q0 -210 84 -320t247 -110t247.5 109.5t84.5 320.5q0 209 -84.5 317.5t-249.5 108.5q-163 0 -246 -107t-83 -319z" /> +<glyph unicode="õ" horiz-adv-x="1237" d="M115 549q0 268 134 417.5t372 149.5q230 0 365.5 -153t135.5 -414q0 -268 -135 -418.5t-373 -150.5q-147 0 -261 69t-176 198t-62 302zM249 1241q13 121 70.5 189.5t148.5 68.5q46 0 89 -18.5t82 -41t75 -41t68 -18.5q49 0 73 29.5t39 91.5h99q-13 -121 -69.5 -189.5 t-150.5 -68.5q-43 0 -84 18.5t-80.5 41t-76 41t-70.5 18.5q-50 0 -75.5 -30t-39.5 -91h-98zM287 549q0 -210 84 -320t247 -110t247.5 109.5t84.5 320.5q0 209 -84.5 317.5t-249.5 108.5q-163 0 -246 -107t-83 -319z" /> +<glyph unicode="ö" horiz-adv-x="1237" d="M115 549q0 268 134 417.5t372 149.5q230 0 365.5 -153t135.5 -414q0 -268 -135 -418.5t-373 -150.5q-147 0 -261 69t-176 198t-62 302zM287 549q0 -210 84 -320t247 -110t247.5 109.5t84.5 320.5q0 209 -84.5 317.5t-249.5 108.5q-163 0 -246 -107t-83 -319zM336 1393 q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM717 1393q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="÷" d="M104 653v138h961v-138h-961zM471 373q0 60 29.5 90.5t83.5 30.5q52 0 81 -31.5t29 -89.5q0 -57 -29.5 -89t-80.5 -32q-52 0 -82.5 31.5t-30.5 89.5zM471 1071q0 60 29.5 90.5t83.5 30.5q52 0 81 -31.5t29 -89.5q0 -57 -29.5 -89t-80.5 -32q-52 0 -82.5 31.5t-30.5 89.5z " /> +<glyph unicode="ø" horiz-adv-x="1237" d="M115 549q0 268 134 417.5t372 149.5q154 0 270 -76l84 119l117 -76l-97 -133q127 -152 127 -401q0 -268 -135 -418.5t-373 -150.5q-154 0 -266 69l-84 -117l-114 78l94 131q-129 152 -129 408zM287 549q0 -171 53 -273l465 646q-75 53 -189 53q-163 0 -246 -107t-83 -319 zM434 170q71 -51 184 -51q163 0 247.5 109.5t84.5 320.5q0 164 -51 264z" /> +<glyph unicode="ù" horiz-adv-x="1257" d="M164 379v717h168v-711q0 -134 61 -200t191 -66q172 0 251.5 94t79.5 307v576h166v-1096h-137l-24 147h-9q-51 -81 -141.5 -124t-206.5 -43q-200 0 -299.5 95t-99.5 304zM333 1548v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="ú" horiz-adv-x="1257" d="M164 379v717h168v-711q0 -134 61 -200t191 -66q172 0 251.5 94t79.5 307v576h166v-1096h-137l-24 147h-9q-51 -81 -141.5 -124t-206.5 -43q-200 0 -299.5 95t-99.5 304zM506 1241v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="û" horiz-adv-x="1257" d="M164 379v717h168v-711q0 -134 61 -200t191 -66q172 0 251.5 94t79.5 307v576h166v-1096h-137l-24 147h-9q-51 -81 -141.5 -124t-206.5 -43q-200 0 -299.5 95t-99.5 304zM286 1241v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119 q-88 55 -221 186q-136 -134 -219 -186h-115z" /> +<glyph unicode="ü" horiz-adv-x="1257" d="M164 379v717h168v-711q0 -134 61 -200t191 -66q172 0 251.5 94t79.5 307v576h166v-1096h-137l-24 147h-9q-51 -81 -141.5 -124t-206.5 -43q-200 0 -299.5 95t-99.5 304zM342 1393q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5 q-37 0 -63.5 24.5t-26.5 74.5zM723 1393q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="ý" horiz-adv-x="1032" d="M2 1096h178l240 -625q79 -214 98 -309h8q13 51 54.5 174.5t271.5 759.5h178l-471 -1248q-70 -185 -163.5 -262.5t-229.5 -77.5q-76 0 -150 17v133q55 -12 123 -12q171 0 244 192l61 156zM411 1241v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111 z" /> +<glyph unicode="þ" horiz-adv-x="1255" d="M176 -492v2048h166v-466q0 -52 -6 -142h8q66 89 151 128.5t191 39.5q215 0 335 -150t120 -417q0 -268 -120.5 -418.5t-334.5 -150.5q-222 0 -344 161h-12l4 -34q8 -77 8 -140v-459h-166zM342 549q0 -231 77 -330.5t247 -99.5q303 0 303 432q0 215 -74 319.5t-231 104.5 q-168 0 -244 -92t-78 -293v-41z" /> +<glyph unicode="ÿ" horiz-adv-x="1032" d="M2 1096h178l240 -625q79 -214 98 -309h8q13 51 54.5 174.5t271.5 759.5h178l-471 -1248q-70 -185 -163.5 -262.5t-229.5 -77.5q-76 0 -150 17v133q55 -12 123 -12q171 0 244 192l61 156zM234 1393q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5 t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM615 1393q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="Œ" horiz-adv-x="1890" d="M125 735q0 360 174 555t494 195q102 0 192 -23h782v-151h-589v-471h551v-150h-551v-538h589v-152h-768q-102 -20 -194 -20q-327 0 -503.5 196.5t-176.5 558.5zM305 733q0 -297 128.5 -450.5t375.5 -153.5q112 0 199 33v1141q-87 30 -197 30q-249 0 -377.5 -152.5 t-128.5 -447.5z" /> +<glyph unicode="œ" horiz-adv-x="1929" d="M113 549q0 265 131 415t366 150q131 0 233.5 -59.5t164.5 -173.5q58 112 154 172.5t222 60.5q201 0 320 -132.5t119 -358.5v-105h-729q8 -393 338 -393q94 0 174.5 17.5t167.5 56.5v-148q-88 -39 -164 -55t-180 -16q-293 0 -418 235q-62 -116 -166.5 -175.5t-241.5 -59.5 q-223 0 -357 152.5t-134 416.5zM287 549q0 -211 76 -320.5t243 -109.5q163 0 239.5 106.5t76.5 315.5q0 221 -77.5 327.5t-242.5 106.5q-166 0 -240.5 -108t-74.5 -318zM1098 653h544q0 158 -66 240t-194 82q-127 0 -199.5 -82t-84.5 -240z" /> +<glyph unicode="Ÿ" horiz-adv-x="1147" d="M0 1462h186l387 -731l390 731h184l-488 -895v-567h-172v559zM294 1731q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM675 1731q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5 t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="ˆ" horiz-adv-x="1212" d="M268 1241v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186h-115z" /> +<glyph unicode="˜" horiz-adv-x="1212" d="M264 1241q13 121 70.5 189.5t148.5 68.5q46 0 89 -18.5t82 -41t75 -41t68 -18.5q49 0 73 29.5t39 91.5h99q-13 -121 -69.5 -189.5t-150.5 -68.5q-43 0 -84 18.5t-80.5 41t-76 41t-70.5 18.5q-50 0 -75.5 -30t-39.5 -91h-98z" /> +<glyph unicode=" " horiz-adv-x="953" /> +<glyph unicode=" " horiz-adv-x="1907" /> +<glyph unicode=" " horiz-adv-x="953" /> +<glyph unicode=" " horiz-adv-x="1907" /> +<glyph unicode=" " horiz-adv-x="635" /> +<glyph unicode=" " horiz-adv-x="476" /> +<glyph unicode=" " horiz-adv-x="317" /> +<glyph unicode=" " horiz-adv-x="317" /> +<glyph unicode=" " horiz-adv-x="238" /> +<glyph unicode=" " horiz-adv-x="381" /> +<glyph unicode=" " horiz-adv-x="105" /> +<glyph unicode="‐" horiz-adv-x="659" d="M84 473v152h491v-152h-491z" /> +<glyph unicode="‑" horiz-adv-x="659" d="M84 473v152h491v-152h-491z" /> +<glyph unicode="‒" horiz-adv-x="659" d="M84 473v152h491v-152h-491z" /> +<glyph unicode="–" horiz-adv-x="1024" d="M82 473v152h860v-152h-860z" /> +<glyph unicode="—" horiz-adv-x="2048" d="M82 473v152h1884v-152h-1884z" /> +<glyph unicode="‘" horiz-adv-x="348" d="M25 983q22 90 71 224t105 255h123q-66 -254 -103 -501h-184z" /> +<glyph unicode="’" horiz-adv-x="348" d="M25 961q70 285 102 501h182l15 -22q-26 -100 -75 -232.5t-102 -246.5h-122z" /> +<glyph unicode="‚" horiz-adv-x="502" d="M63 -264q27 104 59.5 257t45.5 245h182l15 -23q-26 -100 -75 -232.5t-102 -246.5h-125z" /> +<glyph unicode="“" horiz-adv-x="717" d="M25 983q22 90 71 224t105 255h123q-66 -254 -103 -501h-184zM391 983q56 215 178 479h123q-30 -115 -59.5 -259.5t-42.5 -241.5h-184z" /> +<glyph unicode="”" horiz-adv-x="717" d="M25 961q70 285 102 501h182l15 -22q-26 -100 -75 -232.5t-102 -246.5h-122zM391 961q26 100 59 254t46 247h182l14 -22q-24 -91 -72 -224t-104 -255h-125z" /> +<glyph unicode="„" horiz-adv-x="829" d="M25 -263q70 285 102 501h182l15 -22q-26 -100 -75 -232.5t-102 -246.5h-122zM391 -263q26 100 59 254t46 247h182l14 -22q-24 -91 -72 -224t-104 -255h-125z" /> +<glyph unicode="•" horiz-adv-x="770" d="M164 748q0 121 56.5 184t164.5 63q105 0 163 -62t58 -185q0 -119 -57.5 -183.5t-163.5 -64.5q-107 0 -164 65.5t-57 182.5z" /> +<glyph unicode="…" horiz-adv-x="1606" d="M152 106q0 67 30.5 101.5t87.5 34.5q58 0 90.5 -34.5t32.5 -101.5q0 -65 -33 -100t-90 -35q-51 0 -84.5 31.5t-33.5 103.5zM682 106q0 67 30.5 101.5t87.5 34.5q58 0 90.5 -34.5t32.5 -101.5q0 -65 -33 -100t-90 -35q-51 0 -84.5 31.5t-33.5 103.5zM1213 106 q0 67 30.5 101.5t87.5 34.5q58 0 90.5 -34.5t32.5 -101.5q0 -65 -33 -100t-90 -35q-51 0 -84.5 31.5t-33.5 103.5z" /> +<glyph unicode=" " horiz-adv-x="381" /> +<glyph unicode="‹" horiz-adv-x="623" d="M82 524v27l342 407l119 -69l-289 -350l289 -351l-119 -71z" /> +<glyph unicode="›" horiz-adv-x="623" d="M80 188l287 351l-287 350l117 69l344 -407v-27l-344 -407z" /> +<glyph unicode=" " horiz-adv-x="476" /> +<glyph unicode="€" horiz-adv-x="1208" d="M63 506v129h152l-2 42v44l2 80h-152v129h164q39 261 185 407t383 146q201 0 366 -97l-71 -139q-166 86 -295 86q-319 0 -398 -403h510v-129h-524l-2 -57v-64l2 -45h463v-129h-447q37 -180 138.5 -278.5t271.5 -98.5q156 0 309 66v-150q-146 -65 -317 -65 q-237 0 -381.5 134.5t-190.5 391.5h-166z" /> +<glyph unicode="™" horiz-adv-x="1589" d="M37 1356v106h543v-106h-211v-615h-123v615h-209zM647 741v721h187l196 -559l203 559h180v-721h-127v420l6 137h-8l-211 -557h-104l-201 559h-8l6 -129v-430h-119z" /> +<glyph unicode="" horiz-adv-x="1095" d="M0 0v1095h1095v-1095h-1095z" /> +</font> +</defs></svg> \ No newline at end of file diff --git a/refs/pull/405/merge/_static/fonts/opensans-regular-webfont.ttf b/refs/pull/405/merge/_static/fonts/opensans-regular-webfont.ttf new file mode 100644 index 00000000..2cb04137 Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/opensans-regular-webfont.ttf differ diff --git a/refs/pull/405/merge/_static/fonts/opensans-regular-webfont.woff b/refs/pull/405/merge/_static/fonts/opensans-regular-webfont.woff new file mode 100644 index 00000000..4fbd4914 Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/opensans-regular-webfont.woff differ diff --git a/refs/pull/405/merge/_static/fonts/opensans-semibold-webfont.eot b/refs/pull/405/merge/_static/fonts/opensans-semibold-webfont.eot new file mode 100644 index 00000000..2d786b7a Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/opensans-semibold-webfont.eot differ diff --git a/refs/pull/405/merge/_static/fonts/opensans-semibold-webfont.svg b/refs/pull/405/merge/_static/fonts/opensans-semibold-webfont.svg new file mode 100644 index 00000000..5bf92e3d --- /dev/null +++ b/refs/pull/405/merge/_static/fonts/opensans-semibold-webfont.svg @@ -0,0 +1,244 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata></metadata> +<defs> +<font id="OpenSansSemiboldRegular" horiz-adv-x="1169" > +<font-face units-per-em="2048" ascent="1638" descent="-410" /> +<missing-glyph horiz-adv-x="532" /> +<glyph unicode="fi" horiz-adv-x="1315" d="M35 928v110l182 72v72q0 196 92 290.5t281 94.5q124 0 244 -41l-62 -178q-87 28 -166 28q-80 0 -116.5 -49.5t-36.5 -148.5v-72h270v-178h-270v-928h-236v928h-182zM897 1399q0 63 34.5 97t98.5 34q62 0 96.5 -34t34.5 -97q0 -60 -34.5 -94.5t-96.5 -34.5 q-64 0 -98.5 34.5t-34.5 94.5zM911 0v1106h235v-1106h-235z" /> +<glyph unicode="fl" horiz-adv-x="1315" d="M35 928v110l182 72v72q0 196 92 290.5t281 94.5q124 0 244 -41l-62 -178q-87 28 -166 28q-80 0 -116.5 -49.5t-36.5 -148.5v-72h270v-178h-270v-928h-236v928h-182zM911 0v1556h235v-1556h-235z" /> +<glyph unicode="ffi" horiz-adv-x="2058" d="M35 928v110l182 72v72q0 196 92 290.5t281 94.5q124 0 244 -41l-62 -178q-87 28 -166 28q-80 0 -116.5 -49.5t-36.5 -148.5v-72h270v-178h-270v-928h-236v928h-182zM778 928v110l182 72v72q0 196 92 290.5t281 94.5q124 0 244 -41l-62 -178q-87 28 -166 28 q-80 0 -116.5 -49.5t-36.5 -148.5v-72h270v-178h-270v-928h-236v928h-182zM1641 1399q0 63 34.5 97t98.5 34q62 0 96.5 -34t34.5 -97q0 -60 -34.5 -94.5t-96.5 -34.5q-64 0 -98.5 34.5t-34.5 94.5zM1655 0v1106h235v-1106h-235z" /> +<glyph unicode="ffl" horiz-adv-x="2058" d="M35 928v110l182 72v72q0 196 92 290.5t281 94.5q124 0 244 -41l-62 -178q-87 28 -166 28q-80 0 -116.5 -49.5t-36.5 -148.5v-72h270v-178h-270v-928h-236v928h-182zM778 928v110l182 72v72q0 196 92 290.5t281 94.5q124 0 244 -41l-62 -178q-87 28 -166 28 q-80 0 -116.5 -49.5t-36.5 -148.5v-72h270v-178h-270v-928h-236v928h-182zM1655 0v1556h235v-1556h-235z" /> +<glyph horiz-adv-x="0" /> +<glyph horiz-adv-x="2048" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="	" horiz-adv-x="532" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="!" horiz-adv-x="565" d="M133 125q0 74 39 112.5t111 38.5q71 0 109 -40t38 -111t-38.5 -112.5t-108.5 -41.5q-71 0 -110.5 40t-39.5 114zM145 1462h277l-51 -1018h-174z" /> +<glyph unicode=""" horiz-adv-x="893" d="M133 1462h232l-41 -528h-150zM528 1462h232l-41 -528h-150z" /> +<glyph unicode="#" horiz-adv-x="1323" d="M47 418v168h283l57 284h-264v168h293l80 422h180l-80 -422h252l80 422h174l-80 -422h252v-168h-285l-55 -284h270v-168h-303l-80 -418h-178l80 418h-248l-80 -418h-174l76 418h-250zM506 586h250l57 284h-250z" /> +<glyph unicode="$" d="M111 168v211q86 -42 201 -70.5t206 -29.5v374l-84 31q-164 63 -239.5 150.5t-75.5 216.5q0 138 107.5 227t291.5 108v168h133v-165q203 -7 385 -82l-73 -183q-157 62 -312 74v-364l76 -29q190 -73 263 -154t73 -198q0 -145 -106 -239t-306 -116v-217h-133v211 q-248 4 -407 76zM354 1053q0 -57 35.5 -95t128.5 -75v311q-80 -12 -122 -49t-42 -92zM651 287q176 27 176 151q0 58 -40.5 95.5t-135.5 72.5v-319z" /> +<glyph unicode="%" horiz-adv-x="1765" d="M84 1026q0 457 319 457q157 0 241.5 -118.5t84.5 -338.5q0 -230 -82.5 -345.5t-243.5 -115.5q-152 0 -235.5 119.5t-83.5 341.5zM279 1024q0 -149 29 -222t95 -73q132 0 132 295t-132 295q-66 0 -95 -73t-29 -222zM379 0l811 1462h194l-811 -1462h-194zM1036 440 q0 457 320 457q154 0 239.5 -118t85.5 -339q0 -230 -83 -345t-242 -115q-152 0 -236 118.5t-84 341.5zM1231 440q0 -149 29.5 -223t95.5 -74q131 0 131 297q0 293 -131 293q-66 0 -95.5 -72t-29.5 -221z" /> +<glyph unicode="&" horiz-adv-x="1516" d="M96 387q0 131 64 228.5t231 193.5q-95 111 -129.5 187.5t-34.5 158.5q0 152 108.5 240t291.5 88q177 0 278 -85.5t101 -230.5q0 -114 -67.5 -207t-225.5 -186l346 -334q81 107 135 314h242q-70 -284 -224 -463l301 -291h-303l-149 145q-102 -82 -217.5 -123.5 t-255.5 -41.5q-230 0 -361 109t-131 298zM344 403q0 -98 69.5 -159.5t186.5 -61.5q183 0 313 107l-383 377q-106 -68 -146 -127.5t-40 -135.5zM451 1147q0 -63 33.5 -119t93.5 -119q113 64 158.5 119.5t45.5 124.5q0 65 -43.5 104t-115.5 39q-79 0 -125.5 -40.5 t-46.5 -108.5z" /> +<glyph unicode="'" horiz-adv-x="498" d="M133 1462h232l-41 -528h-150z" /> +<glyph unicode="(" horiz-adv-x="649" d="M82 561q0 265 77.5 496t223.5 405h205q-139 -188 -213 -421.5t-74 -477.5t74 -473t211 -414h-203q-147 170 -224 397t-77 488z" /> +<glyph unicode=")" horiz-adv-x="649" d="M61 1462h205q147 -175 224 -406.5t77 -494.5t-77.5 -490t-223.5 -395h-203q138 187 211.5 415t73.5 472q0 245 -74 477.5t-213 421.5z" /> +<glyph unicode="*" horiz-adv-x="1122" d="M74 1065l35 217l376 -108l-41 382h228l-41 -382l385 108l28 -217l-360 -29l236 -311l-199 -107l-166 338l-149 -338l-205 107l231 311z" /> +<glyph unicode="+" d="M96 633v178h398v408h180v-408h399v-178h-399v-406h-180v406h-398z" /> +<glyph unicode="," horiz-adv-x="547" d="M63 -264q69 270 103 502h231l15 -23q-48 -186 -176 -479h-173z" /> +<glyph unicode="-" horiz-adv-x="659" d="M72 449v200h514v-200h-514z" /> +<glyph unicode="." horiz-adv-x="563" d="M133 125q0 73 38 112t110 39q73 0 111 -40.5t38 -110.5q0 -71 -38.5 -112.5t-110.5 -41.5t-110 41t-38 113z" /> +<glyph unicode="/" horiz-adv-x="799" d="M16 0l545 1462h221l-544 -1462h-222z" /> +<glyph unicode="0" d="M88 731q0 387 122.5 570.5t373.5 183.5q245 0 371 -192t126 -562q0 -381 -122.5 -566t-374.5 -185q-244 0 -370 191t-126 560zM326 731q0 -299 61.5 -427t196.5 -128t197.5 130t62.5 425q0 294 -62.5 425.5t-197.5 131.5t-196.5 -129t-61.5 -428z" /> +<glyph unicode="1" d="M154 1124l430 338h196v-1462h-235v944q0 169 8 268q-23 -24 -56.5 -53t-224.5 -184z" /> +<glyph unicode="2" d="M90 0v178l377 379q167 171 221.5 242.5t79.5 134.5t25 135q0 99 -59.5 156t-164.5 57q-84 0 -162.5 -31t-181.5 -112l-127 155q122 103 237 146t245 43q204 0 327 -106.5t123 -286.5q0 -99 -35.5 -188t-109 -183.5t-244.5 -255.5l-254 -246v-10h694v-207h-991z" /> +<glyph unicode="3" d="M86 59v209q93 -46 197 -71t200 -25q170 0 254 63t84 195q0 117 -93 172t-292 55h-127v191h129q350 0 350 242q0 94 -61 145t-180 51q-83 0 -160 -23.5t-182 -91.5l-115 164q201 148 467 148q221 0 345 -95t124 -262q0 -139 -81 -231.5t-228 -124.5v-8q176 -22 264 -109.5 t88 -232.5q0 -211 -149 -325.5t-424 -114.5q-243 0 -410 79z" /> +<glyph unicode="4" d="M39 319v181l668 966h229v-952h197v-195h-197v-319h-229v319h-668zM258 514h449v367q0 196 10 321h-8q-28 -66 -88 -160z" /> +<glyph unicode="5" d="M117 59v213q81 -46 186 -71t195 -25q159 0 242 71t83 208q0 262 -334 262q-47 0 -116 -9.5t-121 -21.5l-105 62l56 714h760v-209h-553l-33 -362q35 6 85.5 14t123.5 8q221 0 350 -117t129 -319q0 -234 -146.5 -365.5t-416.5 -131.5q-245 0 -385 79z" /> +<glyph unicode="6" d="M94 623q0 858 699 858q110 0 186 -17v-196q-76 22 -176 22q-235 0 -353 -126t-128 -404h12q47 81 132 125.5t200 44.5q199 0 310 -122t111 -331q0 -230 -128.5 -363.5t-350.5 -133.5q-157 0 -273 75.5t-178.5 220t-62.5 347.5zM332 508q0 -141 76.5 -237.5t195.5 -96.5 q121 0 186.5 78t65.5 223q0 126 -61.5 198t-184.5 72q-76 0 -140 -32.5t-101 -89t-37 -115.5z" /> +<glyph unicode="7" d="M74 1253v207h1011v-164l-575 -1296h-254l578 1253h-760z" /> +<glyph unicode="8" d="M88 371q0 122 68.5 219.5t224.5 173.5q-134 80 -191 169t-57 200q0 159 125 253.5t326 94.5q208 0 329 -95.5t121 -255.5q0 -225 -270 -358q172 -86 244.5 -181t72.5 -212q0 -181 -133 -290t-360 -109q-238 0 -369 102t-131 289zM313 379q0 -104 73 -161.5t198 -57.5 q129 0 200.5 59.5t71.5 161.5q0 81 -66 148t-200 124l-29 13q-132 -58 -190 -127.5t-58 -159.5zM360 1116q0 -52 22 -93t64 -74.5t142 -80.5q120 53 169.5 111.5t49.5 136.5q0 85 -61.5 134.5t-163.5 49.5q-100 0 -161 -49.5t-61 -134.5z" /> +<glyph unicode="9" d="M86 981q0 229 128.5 364.5t350.5 135.5q156 0 272 -76t179 -220.5t63 -346.5q0 -432 -174 -645t-524 -213q-133 0 -191 16v197q89 -25 179 -25q238 0 355 128t128 402h-12q-59 -90 -142.5 -130t-195.5 -40q-194 0 -305 121t-111 332zM317 983q0 -125 60.5 -196.5 t183.5 -71.5q119 0 200 71t81 166q0 89 -34.5 166.5t-96.5 122.5t-142 45q-122 0 -187 -79.5t-65 -223.5z" /> +<glyph unicode=":" horiz-adv-x="563" d="M133 125q0 73 38 112t110 39q73 0 111 -40.5t38 -110.5q0 -71 -38.5 -112.5t-110.5 -41.5t-110 41t-38 113zM133 979q0 151 148 151q75 0 112 -40t37 -111t-38.5 -112.5t-110.5 -41.5t-110 41t-38 113z" /> +<glyph unicode=";" horiz-adv-x="569" d="M63 -264q69 270 103 502h231l15 -23q-48 -186 -176 -479h-173zM131 979q0 151 148 151q75 0 112 -40t37 -111t-38.5 -112.5t-110.5 -41.5t-110 41t-38 113z" /> +<glyph unicode="<" d="M96 651v121l977 488v-195l-733 -344l733 -303v-197z" /> +<glyph unicode="=" d="M102 432v178h963v-178h-963zM102 831v179h963v-179h-963z" /> +<glyph unicode=">" d="M96 221v197l733 303l-733 344v195l977 -488v-121z" /> +<glyph unicode="?" horiz-adv-x="928" d="M16 1370q203 113 435 113q196 0 311 -96t115 -265q0 -75 -22 -133.5t-66.5 -111.5t-153.5 -138q-93 -73 -124.5 -121t-31.5 -129v-45h-196v64q0 110 40 183t140 151q119 94 153.5 146t34.5 124q0 84 -56 129t-161 45q-95 0 -176 -27t-158 -65zM242 125q0 151 147 151 q72 0 110 -39.5t38 -111.5q0 -71 -38.5 -112.5t-109.5 -41.5t-109 40.5t-38 113.5z" /> +<glyph unicode="@" horiz-adv-x="1839" d="M111 586q0 261 112 464.5t310.5 311.5t449.5 108q217 0 386.5 -90t263 -256.5t93.5 -384.5q0 -143 -45 -261.5t-126.5 -184.5t-188.5 -66q-79 0 -137 42t-78 114h-12q-49 -78 -121 -117t-162 -39q-163 0 -256.5 105t-93.5 284q0 206 124 334.5t333 128.5 q76 0 168.5 -13.5t164.5 -37.5l-22 -465v-24q0 -160 104 -160q79 0 125.5 102t46.5 260q0 171 -70 300.5t-199 199.5t-296 70q-213 0 -370.5 -88t-240.5 -251.5t-83 -379.5q0 -290 155 -446t445 -156q221 0 461 90v-164q-210 -86 -457 -86q-370 0 -577 199.5t-207 556.5z M698 612q0 -233 183 -233q193 0 211 293l12 239q-63 17 -135 17q-128 0 -199.5 -85t-71.5 -231z" /> +<glyph unicode="A" horiz-adv-x="1354" d="M0 0l547 1468h260l547 -1468h-254l-146 406h-559l-143 -406h-252zM465 612h426l-137 398q-15 40 -41.5 126t-36.5 126q-27 -123 -79 -269z" /> +<glyph unicode="B" horiz-adv-x="1352" d="M193 0v1462h434q302 0 436.5 -88t134.5 -278q0 -128 -66 -213t-190 -107v-10q154 -29 226.5 -114.5t72.5 -231.5q0 -197 -137.5 -308.5t-382.5 -111.5h-528zM432 201h254q150 0 226.5 57.5t76.5 181.5q0 114 -78 169t-237 55h-242v-463zM432 858h230q150 0 219 47.5 t69 161.5q0 103 -74.5 149t-236.5 46h-207v-404z" /> +<glyph unicode="C" horiz-adv-x="1298" d="M121 731q0 228 83.5 399t241.5 262t371 91q224 0 414 -94l-86 -199q-74 35 -156.5 61.5t-173.5 26.5q-206 0 -324 -146t-118 -403q0 -269 113.5 -407t328.5 -138q93 0 180 18.5t181 47.5v-205q-172 -65 -390 -65q-321 0 -493 194.5t-172 556.5z" /> +<glyph unicode="D" horiz-adv-x="1503" d="M193 0v1462h452q349 0 543 -188t194 -529q0 -362 -201 -553.5t-579 -191.5h-409zM432 201h170q528 0 528 536q0 525 -491 525h-207v-1061z" /> +<glyph unicode="E" horiz-adv-x="1143" d="M193 0v1462h827v-202h-588v-398h551v-200h-551v-459h588v-203h-827z" /> +<glyph unicode="F" horiz-adv-x="1090" d="M193 0v1462h825v-202h-588v-457h551v-203h-551v-600h-237z" /> +<glyph unicode="G" horiz-adv-x="1487" d="M121 731q0 353 203 552.5t559 199.5q229 0 434 -88l-84 -199q-178 82 -356 82q-234 0 -370 -147t-136 -402q0 -268 122.5 -407.5t352.5 -139.5q116 0 248 29v377h-303v205h538v-734q-132 -43 -253.5 -61t-262.5 -18q-332 0 -512 196.5t-180 554.5z" /> +<glyph unicode="H" horiz-adv-x="1538" d="M193 0v1462h239v-598h674v598h240v-1462h-240v659h-674v-659h-239z" /> +<glyph unicode="I" horiz-adv-x="625" d="M193 0v1462h239v-1462h-239z" /> +<glyph unicode="J" horiz-adv-x="612" d="M-156 -182q84 -21 146 -21q196 0 196 248v1417h240v-1409q0 -224 -106.5 -342.5t-311.5 -118.5q-98 0 -164 25v201z" /> +<glyph unicode="K" horiz-adv-x="1309" d="M193 0v1462h239v-698q98 120 195 231l395 467h272q-383 -450 -549 -641l564 -821h-277l-459 662l-141 -115v-547h-239z" /> +<glyph unicode="L" horiz-adv-x="1110" d="M193 0v1462h239v-1257h619v-205h-858z" /> +<glyph unicode="M" horiz-adv-x="1890" d="M193 0v1462h337l406 -1163h6l418 1163h338v-1462h-230v723q0 109 5.5 284t9.5 212h-8l-439 -1219h-211l-424 1221h-8q17 -272 17 -510v-711h-217z" /> +<glyph unicode="N" horiz-adv-x="1604" d="M193 0v1462h290l717 -1159h6q-2 23 -8 167.5t-6 225.5v766h219v-1462h-293l-719 1165h-8l5 -65q14 -186 14 -340v-760h-217z" /> +<glyph unicode="O" horiz-adv-x="1612" d="M121 735q0 362 178.5 556t509.5 194q326 0 504 -197t178 -555q0 -357 -178.5 -555t-505.5 -198q-331 0 -508.5 196.5t-177.5 558.5zM375 733q0 -270 109 -409.5t323 -139.5q213 0 321.5 138t108.5 411q0 269 -107.5 408t-320.5 139q-215 0 -324.5 -139t-109.5 -408z" /> +<glyph unicode="P" horiz-adv-x="1260" d="M193 0v1462h421q274 0 410.5 -112t136.5 -330q0 -229 -150 -351t-427 -122h-152v-547h-239zM432 748h127q184 0 270 64t86 200q0 126 -77 188t-240 62h-166v-514z" /> +<glyph unicode="Q" horiz-adv-x="1612" d="M121 735q0 362 178.5 556t509.5 194q326 0 504 -197t178 -555q0 -266 -101.5 -448t-295.5 -256l350 -377h-322l-276 328h-39q-331 0 -508.5 196.5t-177.5 558.5zM375 733q0 -270 109 -409.5t323 -139.5q213 0 321.5 138t108.5 411q0 269 -107.5 408t-320.5 139 q-215 0 -324.5 -139t-109.5 -408z" /> +<glyph unicode="R" horiz-adv-x="1309" d="M193 0v1462h413q283 0 419 -106t136 -320q0 -273 -284 -389l413 -647h-272l-350 584h-236v-584h-239zM432 782h166q167 0 242 62t75 184q0 124 -81 178t-244 54h-158v-478z" /> +<glyph unicode="S" horiz-adv-x="1126" d="M100 57v226q100 -47 212.5 -74t209.5 -27q142 0 209.5 54t67.5 145q0 82 -62 139t-256 135q-200 81 -282 185t-82 250q0 183 130 288t349 105q210 0 418 -92l-76 -195q-195 82 -348 82q-116 0 -176 -50.5t-60 -133.5q0 -57 24 -97.5t79 -76.5t198 -95q161 -67 236 -125 t110 -131t35 -172q0 -195 -141 -306t-389 -111t-406 77z" /> +<glyph unicode="T" horiz-adv-x="1159" d="M29 1257v205h1099v-205h-430v-1257h-239v1257h-430z" /> +<glyph unicode="U" horiz-adv-x="1520" d="M180 520v942h240v-925q0 -181 84 -267t258 -86q338 0 338 355v923h239v-946q0 -162 -69.5 -283.5t-201 -187t-314.5 -65.5q-272 0 -423 144t-151 396z" /> +<glyph unicode="V" horiz-adv-x="1274" d="M0 1462h246l305 -909q24 -65 51 -167.5t35 -152.5q13 76 40 176t44 148l305 905h248l-512 -1462h-252z" /> +<glyph unicode="W" horiz-adv-x="1937" d="M12 1462h244l209 -852q49 -205 70 -362q11 85 33 190t40 170l238 854h237l244 -858q35 -119 74 -356q15 143 72 364l208 850h242l-381 -1462h-260l-248 872q-16 57 -40 164.5t-29 149.5q-10 -64 -32.5 -166t-37.5 -152l-242 -868h-260l-189 732z" /> +<glyph unicode="X" horiz-adv-x="1274" d="M4 0l485 758l-454 704h266l338 -553l338 553h258l-457 -708l492 -754h-275l-366 598l-369 -598h-256z" /> +<glyph unicode="Y" horiz-adv-x="1212" d="M0 1462h260l346 -667l346 667h260l-487 -895v-567h-240v559z" /> +<glyph unicode="Z" horiz-adv-x="1178" d="M66 0v166l737 1091h-717v205h1006v-168l-740 -1089h760v-205h-1046z" /> +<glyph unicode="[" horiz-adv-x="676" d="M154 -324v1786h471v-176h-256v-1433h256v-177h-471z" /> +<glyph unicode="\" horiz-adv-x="799" d="M16 1462h222l544 -1462h-221z" /> +<glyph unicode="]" horiz-adv-x="676" d="M51 -147h256v1433h-256v176h469v-1786h-469v177z" /> +<glyph unicode="^" horiz-adv-x="1100" d="M29 535l436 935h121l485 -935h-194l-349 694l-307 -694h-192z" /> +<glyph unicode="_" horiz-adv-x="879" d="M-4 -184h887v-135h-887v135z" /> +<glyph unicode="`" horiz-adv-x="1212" d="M362 1548v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5z" /> +<glyph unicode="a" horiz-adv-x="1188" d="M90 317q0 171 127 258t387 95l191 6v59q0 106 -49.5 158.5t-153.5 52.5q-85 0 -163 -25t-150 -59l-76 168q90 47 197 71.5t202 24.5q211 0 318.5 -92t107.5 -289v-745h-168l-47 154h-8q-80 -101 -161 -137.5t-208 -36.5q-163 0 -254.5 88t-91.5 249zM334 315 q0 -74 44 -114.5t132 -40.5q128 0 205.5 71.5t77.5 200.5v96l-142 -6q-166 -6 -241.5 -55.5t-75.5 -151.5z" /> +<glyph unicode="b" horiz-adv-x="1276" d="M168 0v1556h235v-370q0 -41 -4 -122t-6 -103h10q112 165 330 165q207 0 322.5 -150t115.5 -421q0 -272 -117 -423.5t-325 -151.5q-210 0 -326 151h-16l-43 -131h-176zM403 555q0 -202 64 -292.5t209 -90.5q125 0 189.5 99t64.5 286q0 377 -258 377q-142 0 -204.5 -83.5 t-64.5 -279.5v-16z" /> +<glyph unicode="c" horiz-adv-x="1014" d="M102 547q0 279 136.5 429t394.5 150q175 0 315 -65l-71 -189q-149 58 -246 58q-287 0 -287 -381q0 -186 71.5 -279.5t209.5 -93.5q157 0 297 78v-205q-63 -37 -134.5 -53t-173.5 -16q-251 0 -381.5 146.5t-130.5 420.5z" /> +<glyph unicode="d" horiz-adv-x="1276" d="M102 551q0 272 117.5 423.5t325.5 151.5q218 0 332 -161h12q-17 119 -17 188v403h236v-1556h-184l-41 145h-11q-113 -165 -331 -165q-207 0 -323 150t-116 421zM344 547q0 -184 65 -280.5t195 -96.5q145 0 211 81.5t68 264.5v33q0 209 -68 297t-213 88 q-124 0 -191 -100.5t-67 -286.5z" /> +<glyph unicode="e" horiz-adv-x="1180" d="M102 545q0 271 135 426t371 155q219 0 346 -133t127 -366v-127h-737q5 -161 87 -247.5t231 -86.5q98 0 182.5 18.5t181.5 61.5v-191q-86 -41 -174 -58t-201 -17q-258 0 -403.5 150.5t-145.5 414.5zM348 670h502q-2 137 -66 207.5t-176 70.5t-179.5 -71t-80.5 -207z" /> +<glyph unicode="f" horiz-adv-x="743" d="M35 928v110l182 72v72q0 196 92 290.5t281 94.5q124 0 244 -41l-62 -178q-87 28 -166 28q-80 0 -116.5 -49.5t-36.5 -148.5v-72h270v-178h-270v-928h-236v928h-182z" /> +<glyph unicode="g" horiz-adv-x="1139" d="M23 -184q0 102 64.5 171.5t180.5 96.5q-47 20 -77.5 64.5t-30.5 93.5q0 62 35 105t104 85q-86 37 -139.5 120.5t-53.5 195.5q0 180 113.5 279t323.5 99q47 0 98.5 -6.5t77.5 -13.5h383v-129l-189 -35q26 -35 43 -86t17 -108q0 -171 -118 -269t-325 -98q-53 0 -96 8 q-76 -47 -76 -110q0 -38 35.5 -57t130.5 -19h193q183 0 278 -78t95 -225q0 -188 -155 -290t-448 -102q-226 0 -345 80t-119 228zM233 -172q0 -76 68.5 -117t192.5 -41q192 0 286 55t94 146q0 72 -51.5 102.5t-191.5 30.5h-178q-101 0 -160.5 -47.5t-59.5 -128.5zM334 748 q0 -104 53.5 -160t153.5 -56q204 0 204 218q0 108 -50.5 166.5t-153.5 58.5q-102 0 -154.5 -58t-52.5 -169z" /> +<glyph unicode="h" horiz-adv-x="1300" d="M168 0v1556h235v-395q0 -95 -12 -203h15q48 80 133.5 124t199.5 44q402 0 402 -405v-721h-236v680q0 128 -51.5 191t-163.5 63q-148 0 -217.5 -88.5t-69.5 -296.5v-549h-235z" /> +<glyph unicode="i" horiz-adv-x="571" d="M154 1399q0 63 34.5 97t98.5 34q62 0 96.5 -34t34.5 -97q0 -60 -34.5 -94.5t-96.5 -34.5q-64 0 -98.5 34.5t-34.5 94.5zM168 0v1106h235v-1106h-235z" /> +<glyph unicode="j" horiz-adv-x="571" d="M-121 -281q68 -18 139 -18q150 0 150 170v1235h235v-1251q0 -171 -89.5 -259t-258.5 -88q-106 0 -176 25v186zM154 1399q0 63 34.5 97t98.5 34q62 0 96.5 -34t34.5 -97q0 -60 -34.5 -94.5t-96.5 -34.5q-64 0 -98.5 34.5t-34.5 94.5z" /> +<glyph unicode="k" horiz-adv-x="1171" d="M168 0v1556h233v-759l-12 -213h6l133 166l334 356h271l-445 -475l473 -631h-276l-355 485l-129 -106v-379h-233z" /> +<glyph unicode="l" horiz-adv-x="571" d="M168 0v1556h235v-1556h-235z" /> +<glyph unicode="m" horiz-adv-x="1958" d="M168 0v1106h184l33 -145h12q46 79 133.5 122t192.5 43q255 0 338 -174h16q49 82 138 128t204 46q198 0 288.5 -100t90.5 -305v-721h-235v682q0 127 -48.5 189.5t-150.5 62.5q-137 0 -200.5 -85.5t-63.5 -262.5v-586h-236v682q0 127 -48 189.5t-150 62.5 q-136 0 -199.5 -88.5t-63.5 -294.5v-551h-235z" /> +<glyph unicode="n" horiz-adv-x="1300" d="M168 0v1106h184l33 -145h12q50 79 142 122t204 43q398 0 398 -405v-721h-236v680q0 128 -51.5 191t-163.5 63q-149 0 -218 -88t-69 -295v-551h-235z" /> +<glyph unicode="o" horiz-adv-x="1251" d="M102 555q0 269 138 420t389 151q240 0 380 -154.5t140 -416.5q0 -271 -139 -423t-387 -152q-155 0 -274 70t-183 201t-64 304zM344 555q0 -383 283 -383q280 0 280 383q0 379 -282 379q-148 0 -214.5 -98t-66.5 -281z" /> +<glyph unicode="p" horiz-adv-x="1276" d="M168 -492v1598h190q8 -31 33 -148h12q110 168 330 168q207 0 322.5 -150t115.5 -421t-117.5 -423t-324.5 -152q-210 0 -326 151h-14q14 -140 14 -170v-453h-235zM403 555q0 -202 64 -292.5t209 -90.5q122 0 188 100t66 285q0 186 -65.5 281.5t-192.5 95.5 q-140 0 -204.5 -82t-64.5 -262v-35z" /> +<glyph unicode="q" horiz-adv-x="1276" d="M102 551q0 270 118 422.5t325 152.5q104 0 186.5 -38.5t147.5 -126.5h8l26 145h195v-1598h-236v469q0 44 4 93t7 75h-13q-104 -165 -331 -165q-205 0 -321 150.5t-116 420.5zM344 547q0 -379 262 -379q148 0 212.5 85.5t64.5 258.5v37q0 205 -66.5 295t-214.5 90 q-126 0 -192 -100t-66 -287z" /> +<glyph unicode="r" horiz-adv-x="883" d="M168 0v1106h184l31 -195h12q55 99 143.5 157t190.5 58q71 0 117 -10l-23 -219q-50 12 -104 12q-141 0 -228.5 -92t-87.5 -239v-578h-235z" /> +<glyph unicode="s" horiz-adv-x="997" d="M98 827q0 142 114.5 220.5t311.5 78.5q195 0 369 -79l-76 -177q-179 74 -301 74q-186 0 -186 -106q0 -52 48.5 -88t211.5 -99q137 -53 199 -97t92 -101.5t30 -137.5q0 -162 -118 -248.5t-338 -86.5q-221 0 -355 67v203q195 -90 363 -90q217 0 217 131q0 42 -24 70t-79 58 t-153 68q-191 74 -258.5 148t-67.5 192z" /> +<glyph unicode="t" horiz-adv-x="805" d="M39 928v104l162 86l80 234h145v-246h315v-178h-315v-592q0 -85 42.5 -125.5t111.5 -40.5q86 0 172 27v-177q-39 -17 -100.5 -28.5t-127.5 -11.5q-334 0 -334 352v596h-151z" /> +<glyph unicode="u" horiz-adv-x="1300" d="M158 383v723h237v-682q0 -127 52 -190.5t163 -63.5q148 0 217.5 88.5t69.5 296.5v551h236v-1106h-185l-33 145h-12q-49 -77 -139.5 -121t-206.5 -44q-201 0 -300 100t-99 303z" /> +<glyph unicode="v" horiz-adv-x="1096" d="M0 1106h248l225 -643q58 -162 70 -262h8q9 72 70 262l225 643h250l-422 -1106h-254z" /> +<glyph unicode="w" horiz-adv-x="1673" d="M20 1106h240l141 -545q48 -202 68 -346h6q10 73 30.5 167.5t35.5 141.5l168 582h258l163 -582q15 -49 37.5 -150t26.5 -157h8q15 123 70 344l143 545h236l-312 -1106h-264l-143 516q-26 82 -94 381h-9q-58 -270 -92 -383l-147 -514h-260z" /> +<glyph unicode="x" horiz-adv-x="1128" d="M25 0l389 565l-371 541h268l252 -387l254 387h266l-372 -541l391 -565h-266l-273 414l-272 -414h-266z" /> +<glyph unicode="y" horiz-adv-x="1098" d="M0 1106h256l225 -627q51 -134 68 -252h8q9 55 33 133.5t254 745.5h254l-473 -1253q-129 -345 -430 -345q-78 0 -152 17v186q53 -12 121 -12q170 0 239 197l41 104z" /> +<glyph unicode="z" horiz-adv-x="979" d="M68 0v145l559 781h-525v180h789v-164l-547 -762h563v-180h-839z" /> +<glyph unicode="{" horiz-adv-x="791" d="M45 473v191q135 0 200.5 45.5t65.5 138.5v311q0 156 108.5 229.5t325.5 73.5v-182q-114 -5 -165.5 -46.5t-51.5 -123.5v-297q0 -199 -229 -238v-12q229 -36 229 -237v-299q0 -82 51 -124t166 -44v-183q-231 2 -332.5 78.5t-101.5 247.5v285q0 186 -266 186z" /> +<glyph unicode="|" horiz-adv-x="1128" d="M473 -481v2033h180v-2033h-180z" /> +<glyph unicode="}" horiz-adv-x="760" d="M45 -141q95 1 148 38.5t53 129.5v262q0 121 53 187t176 87v12q-229 39 -229 238v297q0 82 -45.5 123.5t-155.5 46.5v182q223 0 320.5 -76.5t97.5 -250.5v-287q0 -100 63.5 -142t188.5 -42v-191q-123 0 -187.5 -42.5t-64.5 -143.5v-307q0 -156 -99.5 -229t-318.5 -75v183z " /> +<glyph unicode="~" d="M96 571v191q99 108 250 108q66 0 125 -13t147 -50q131 -55 220 -55q52 0 114.5 31t120.5 89v-190q-105 -111 -250 -111q-65 0 -127.5 15.5t-146.5 50.5q-127 55 -219 55q-50 0 -111.5 -30t-122.5 -91z" /> +<glyph unicode="¡" horiz-adv-x="565" d="M133 965q0 69 38 111t110 42t110.5 -40.5t38.5 -112.5q0 -74 -37.5 -113t-111.5 -39q-72 0 -110 39.5t-38 112.5zM141 -371l52 1016h174l51 -1016h-277z" /> +<glyph unicode="¢" d="M166 741q0 254 100.5 397t306.5 175v170h158v-162q152 -5 283 -66l-70 -188q-146 59 -250 59q-146 0 -216 -95t-70 -288q0 -194 72 -283t210 -89q75 0 142.5 15t154.5 52v-200q-119 -59 -258 -64v-194h-156v200q-207 31 -307 171t-100 390z" /> +<glyph unicode="£" d="M72 0v195q98 30 145 96t47 178v184h-188v172h188v256q0 188 113.5 294t312.5 106q194 0 375 -82l-76 -182q-162 71 -284 71q-205 0 -205 -219v-244h397v-172h-397v-182q0 -91 -33 -155t-113 -109h756v-207h-1038z" /> +<glyph unicode="¤" d="M117 1069l121 119l131 -129q100 63 215 63t213 -65l133 131l121 -117l-131 -133q63 -100 63 -215q0 -119 -63 -217l129 -129l-119 -119l-133 129q-99 -61 -213 -61q-126 0 -215 61l-131 -127l-119 119l131 129q-64 99 -64 215q0 109 64 213zM354 723q0 -98 68 -164.5 t162 -66.5q97 0 165 66.5t68 164.5q0 97 -68 165t-165 68q-93 0 -161.5 -68t-68.5 -165z" /> +<glyph unicode="¥" d="M18 1462h246l320 -665l321 665h244l-399 -760h227v-151h-281v-154h281v-153h-281v-244h-225v244h-283v153h283v154h-283v151h224z" /> +<glyph unicode="¦" horiz-adv-x="1128" d="M473 315h180v-796h-180v796zM473 758v794h180v-794h-180z" /> +<glyph unicode="§" horiz-adv-x="1026" d="M115 57v179q77 -40 173 -65.5t177 -25.5q235 0 235 131q0 43 -21 70t-71 54t-147 65q-141 55 -206 101.5t-95.5 105t-30.5 135.5q0 80 38.5 145.5t111.5 108.5q-146 83 -146 235q0 129 109.5 202t294.5 73q91 0 174 -17t182 -59l-68 -162q-116 50 -176 63t-121 13 q-194 0 -194 -109q0 -54 55 -93.5t191 -90.5q175 -68 250 -146.5t75 -187.5q0 -177 -139 -266q139 -80 139 -223q0 -142 -118 -224.5t-326 -82.5q-212 0 -346 71zM313 827q0 -45 24 -80t78.5 -69t194.5 -90q109 65 109 168q0 75 -62 126.5t-221 104.5q-54 -16 -88.5 -61.5 t-34.5 -98.5z" /> +<glyph unicode="¨" horiz-adv-x="1212" d="M293 1399q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM686 1399q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="©" horiz-adv-x="1704" d="M100 731q0 200 100 375t275 276t377 101q200 0 375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM223 731q0 -170 84.5 -315.5t230.5 -229.5t314 -84q170 0 316 85.5t229.5 230t83.5 313.5q0 168 -84.5 314.5 t-231 230.5t-313.5 84q-168 0 -312.5 -83t-230.5 -229t-86 -317zM471 731q0 214 110 337.5t306 123.5q138 0 274 -70l-65 -143q-106 55 -203 55q-111 0 -171 -80.5t-60 -222.5q0 -147 54 -226t177 -79q55 0 118 15t109 36v-158q-115 -51 -235 -51q-197 0 -305.5 120.5 t-108.5 342.5z" /> +<glyph unicode="ª" horiz-adv-x="754" d="M57 981q0 104 84 159.5t252 61.5l107 4q0 72 -34.5 108t-103.5 36q-90 0 -210 -56l-54 115q144 70 285 70q138 0 207 -62.5t69 -187.5v-447h-112l-29 97q-46 -55 -105 -82t-130 -27q-113 0 -169.5 52.5t-56.5 158.5zM221 983q0 -88 96 -88q91 0 137 41t46 123v43l-99 -4 q-71 -2 -125.5 -34t-54.5 -81z" /> +<glyph unicode="«" horiz-adv-x="1139" d="M82 535v26l356 432l168 -94l-282 -350l282 -348l-168 -97zM532 535v26l357 432l168 -94l-283 -350l283 -348l-168 -97z" /> +<glyph unicode="¬" d="M96 633v178h977v-555h-178v377h-799z" /> +<glyph unicode="­" horiz-adv-x="659" d="M72 449v200h514v-200h-514z" /> +<glyph unicode="®" horiz-adv-x="1704" d="M100 731q0 200 100 375t275 276t377 101q200 0 375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM223 731q0 -170 84.5 -315.5t230.5 -229.5t314 -84q170 0 316 85.5t229.5 230t83.5 313.5q0 168 -84.5 314.5 t-231 230.5t-313.5 84q-168 0 -312.5 -83t-230.5 -229t-86 -317zM559 279v903h262q174 0 255 -68t81 -205q0 -171 -153 -233l237 -397h-211l-192 346h-90v-346h-189zM748 770h69q74 0 112 35t38 100q0 72 -36.5 100.5t-115.5 28.5h-67v-264z" /> +<glyph unicode="¯" horiz-adv-x="1024" d="M-6 1556v164h1036v-164h-1036z" /> +<glyph unicode="°" horiz-adv-x="877" d="M109 1153q0 135 95 232.5t234 97.5q138 0 233 -96t95 -234q0 -139 -96 -233.5t-232 -94.5q-88 0 -164.5 43.5t-120.5 119.5t-44 165zM262 1153q0 -70 51 -122t125 -52t125 51.5t51 122.5q0 76 -52 127t-124 51t-124 -52t-52 -126z" /> +<glyph unicode="±" d="M96 0v178h977v-178h-977zM96 664v178h398v407h180v-407h399v-178h-399v-406h-180v406h-398z" /> +<glyph unicode="²" horiz-adv-x="743" d="M51 586v135l230 225q117 112 149.5 165t32.5 112q0 52 -32 79t-83 27q-93 0 -201 -88l-94 121q139 119 309 119q136 0 211.5 -66t75.5 -180q0 -83 -46 -158.5t-183 -202.5l-139 -129h397v-159h-627z" /> +<glyph unicode="³" horiz-adv-x="743" d="M45 631v157q145 -79 270 -79q179 0 179 135q0 125 -199 125h-115v133h105q184 0 184 129q0 52 -34.5 80t-90.5 28q-57 0 -105.5 -20t-105.5 -57l-84 114q61 46 134 75.5t171 29.5q134 0 212.5 -61.5t78.5 -168.5q0 -75 -40.5 -122.5t-119.5 -86.5q94 -21 141.5 -76 t47.5 -132q0 -127 -93 -196t-266 -69q-148 0 -270 62z" /> +<glyph unicode="´" horiz-adv-x="1212" d="M362 1241v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="µ" horiz-adv-x="1309" d="M168 -492v1598h235v-684q0 -252 218 -252q146 0 215 88.5t69 296.5v551h236v-1106h-183l-34 147h-13q-48 -83 -119.5 -125t-175.5 -42q-140 0 -219 90h-4q3 -28 6.5 -117t3.5 -125v-320h-235z" /> +<glyph unicode="¶" horiz-adv-x="1341" d="M113 1042q0 260 109 387t341 127h580v-1816h-137v1663h-191v-1663h-137v819q-62 -18 -146 -18q-216 0 -317.5 125t-101.5 376z" /> +<glyph unicode="·" horiz-adv-x="563" d="M133 723q0 73 38 112t110 39q73 0 111 -40.5t38 -110.5q0 -71 -38.5 -112.5t-110.5 -41.5t-110 41t-38 113z" /> +<glyph unicode="¸" horiz-adv-x="442" d="M0 -340q54 -14 123 -14q54 0 85.5 16.5t31.5 61.5q0 85 -179 110l84 166h152l-41 -88q80 -21 125 -68.5t45 -113.5q0 -222 -305 -222q-66 0 -121 15v137z" /> +<glyph unicode="¹" horiz-adv-x="743" d="M84 1253l281 209h167v-876h-186v512l3 103l5 91q-17 -18 -40.5 -40t-141.5 -111z" /> +<glyph unicode="º" horiz-adv-x="780" d="M61 1124q0 169 88.5 262t241.5 93q152 0 240 -94.5t88 -260.5q0 -164 -87.5 -259t-244.5 -95q-150 0 -238 95.5t-88 258.5zM223 1124q0 -111 39 -166t127 -55t127 55t39 166q0 113 -39 167.5t-127 54.5t-127 -54.5t-39 -167.5z" /> +<glyph unicode="»" horiz-adv-x="1139" d="M80 201l282 348l-282 350l168 94l358 -432v-26l-358 -431zM530 201l283 348l-283 350l168 94l359 -432v-26l-359 -431z" /> +<glyph unicode="¼" horiz-adv-x="1700" d="M60 1253l281 209h167v-876h-186v512l3 103l5 91q-17 -18 -40.5 -40t-141.5 -111zM285 0l858 1462h190l-856 -1462h-192zM876 177v127l396 579h188v-563h125v-143h-125v-176h-192v176h-392zM1038 320h230v178q0 97 6 197q-52 -104 -88 -158z" /> +<glyph unicode="½" horiz-adv-x="1700" d="M46 1253l281 209h167v-876h-186v512l3 103l5 91q-17 -18 -40.5 -40t-141.5 -111zM250 0l858 1462h190l-856 -1462h-192zM981 1v135l230 225q117 112 149.5 165t32.5 112q0 52 -32 79t-83 27q-93 0 -201 -88l-94 121q139 119 309 119q136 0 211.5 -66t75.5 -180 q0 -83 -46 -158.5t-183 -202.5l-139 -129h397v-159h-627z" /> +<glyph unicode="¾" horiz-adv-x="1700" d="M55 631v157q145 -79 270 -79q179 0 179 135q0 125 -199 125h-115v133h105q184 0 184 129q0 52 -34.5 80t-90.5 28q-57 0 -105.5 -20t-105.5 -57l-84 114q61 46 134 75.5t171 29.5q134 0 212.5 -61.5t78.5 -168.5q0 -75 -40.5 -122.5t-119.5 -86.5q94 -21 141.5 -76 t47.5 -132q0 -127 -93 -196t-266 -69q-148 0 -270 62zM367 0l858 1462h190l-856 -1462h-192zM931 177v127l396 579h188v-563h125v-143h-125v-176h-192v176h-392zM1093 320h230v178q0 97 6 197q-52 -104 -88 -158z" /> +<glyph unicode="¿" horiz-adv-x="928" d="M55 -33q0 73 21 130t64 109t157 142q94 76 125 124.5t31 127.5v45h198v-63q0 -106 -41 -181t-143 -155q-124 -98 -155 -147t-31 -124q0 -78 54 -125t161 -47q90 0 174 27.5t166 65.5l82 -179q-220 -110 -424 -110q-207 0 -323 95.5t-116 264.5zM395 965q0 69 38 111 t110 42t110.5 -40.5t38.5 -112.5q0 -74 -37.5 -113t-111.5 -39q-72 0 -110 39.5t-38 112.5z" /> +<glyph unicode="À" horiz-adv-x="1354" d="M0 0l547 1468h260l547 -1468h-254l-146 406h-559l-143 -406h-252zM334 1886v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5zM465 612h426l-137 398q-15 40 -41.5 126t-36.5 126q-27 -123 -79 -269z" /> +<glyph unicode="Á" horiz-adv-x="1354" d="M0 0l547 1468h260l547 -1468h-254l-146 406h-559l-143 -406h-252zM465 612h426l-137 398q-15 40 -41.5 126t-36.5 126q-27 -123 -79 -269zM532 1579v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="Â" horiz-adv-x="1354" d="M0 0l547 1468h260l547 -1468h-254l-146 406h-559l-143 -406h-252zM286 1579v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158zM465 612h426l-137 398q-15 40 -41.5 126t-36.5 126q-27 -123 -79 -269z" /> +<glyph unicode="Ã" horiz-adv-x="1354" d="M0 0l547 1468h260l547 -1468h-254l-146 406h-559l-143 -406h-252zM281 1577q12 139 77.5 212t167.5 73q43 0 84 -17.5t80 -39t75.5 -39t70.5 -17.5q79 0 106 115h125q-12 -134 -77 -209.5t-169 -75.5q-42 0 -82.5 17.5t-79.5 39t-76 39t-71 17.5q-81 0 -109 -115h-122z M465 612h426l-137 398q-15 40 -41.5 126t-36.5 126q-27 -123 -79 -269z" /> +<glyph unicode="Ä" horiz-adv-x="1354" d="M0 0l547 1468h260l547 -1468h-254l-146 406h-559l-143 -406h-252zM363 1737q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM465 612h426l-137 398q-15 40 -41.5 126t-36.5 126q-27 -123 -79 -269zM756 1737 q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="Å" horiz-adv-x="1354" d="M0 0l547 1468h260l547 -1468h-254l-146 406h-559l-143 -406h-252zM438 1575q0 101 63.5 163.5t172.5 62.5q104 0 171.5 -62t67.5 -162q0 -102 -65.5 -165.5t-173.5 -63.5t-172 62.5t-64 164.5zM465 612h426l-137 398q-15 40 -41.5 126t-36.5 126q-27 -123 -79 -269z M567 1575q0 -106 107 -106q46 0 76 27.5t30 78.5q0 50 -30 78.5t-76 28.5q-47 0 -77 -28.5t-30 -78.5z" /> +<glyph unicode="Æ" horiz-adv-x="1868" d="M-2 0l678 1462h1071v-202h-571v-398h532v-200h-532v-459h571v-203h-811v406h-504l-188 -406h-246zM522 612h414v641h-123z" /> +<glyph unicode="Ç" horiz-adv-x="1298" d="M121 731q0 228 83.5 399t241.5 262t371 91q224 0 414 -94l-86 -199q-74 35 -156.5 61.5t-173.5 26.5q-206 0 -324 -146t-118 -403q0 -269 113.5 -407t328.5 -138q93 0 180 18.5t181 47.5v-205q-172 -65 -390 -65q-321 0 -493 194.5t-172 556.5zM526 -340q54 -14 123 -14 q54 0 85.5 16.5t31.5 61.5q0 85 -179 110l84 166h152l-41 -88q80 -21 125 -68.5t45 -113.5q0 -222 -305 -222q-66 0 -121 15v137z" /> +<glyph unicode="È" horiz-adv-x="1143" d="M193 0v1462h827v-202h-588v-398h551v-200h-551v-459h588v-203h-827zM289 1886v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5z" /> +<glyph unicode="É" horiz-adv-x="1143" d="M193 0v1462h827v-202h-588v-398h551v-200h-551v-459h588v-203h-827zM440 1579v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="Ê" horiz-adv-x="1143" d="M193 0v1462h827v-202h-588v-398h551v-200h-551v-459h588v-203h-827zM220 1579v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158z" /> +<glyph unicode="Ë" horiz-adv-x="1143" d="M193 0v1462h827v-202h-588v-398h551v-200h-551v-459h588v-203h-827zM297 1737q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM690 1737q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5 q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="Ì" horiz-adv-x="625" d="M-6 1886v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5zM193 0v1462h239v-1462h-239z" /> +<glyph unicode="Í" horiz-adv-x="625" d="M179 1579v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156zM193 0v1462h239v-1462h-239z" /> +<glyph unicode="Î" horiz-adv-x="625" d="M-75 1579v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158zM193 0v1462h239v-1462h-239z" /> +<glyph unicode="Ï" horiz-adv-x="625" d="M1 1737q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM193 0v1462h239v-1462h-239zM394 1737q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="Ð" horiz-adv-x="1497" d="M47 623v200h146v639h446q347 0 541 -188.5t194 -528.5q0 -360 -201 -552.5t-579 -192.5h-401v623h-146zM432 201h160q530 0 530 536q0 260 -124.5 392.5t-368.5 132.5h-197v-439h307v-200h-307v-422z" /> +<glyph unicode="Ñ" horiz-adv-x="1604" d="M193 0v1462h290l717 -1159h6q-2 23 -8 167.5t-6 225.5v766h219v-1462h-293l-719 1165h-8l5 -65q14 -186 14 -340v-760h-217zM414 1577q12 139 77.5 212t167.5 73q43 0 84 -17.5t80 -39t75.5 -39t70.5 -17.5q79 0 106 115h125q-12 -134 -77 -209.5t-169 -75.5 q-42 0 -82.5 17.5t-79.5 39t-76 39t-71 17.5q-81 0 -109 -115h-122z" /> +<glyph unicode="Ò" horiz-adv-x="1612" d="M121 735q0 362 178.5 556t509.5 194q326 0 504 -197t178 -555q0 -357 -178.5 -555t-505.5 -198q-331 0 -508.5 196.5t-177.5 558.5zM375 733q0 -270 109 -409.5t323 -139.5q213 0 321.5 138t108.5 411q0 269 -107.5 408t-320.5 139q-215 0 -324.5 -139t-109.5 -408z M481 1886v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5z" /> +<glyph unicode="Ó" horiz-adv-x="1612" d="M121 735q0 362 178.5 556t509.5 194q326 0 504 -197t178 -555q0 -357 -178.5 -555t-505.5 -198q-331 0 -508.5 196.5t-177.5 558.5zM375 733q0 -270 109 -409.5t323 -139.5q213 0 321.5 138t108.5 411q0 269 -107.5 408t-320.5 139q-215 0 -324.5 -139t-109.5 -408z M657 1579v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="Ô" horiz-adv-x="1612" d="M121 735q0 362 178.5 556t509.5 194q326 0 504 -197t178 -555q0 -357 -178.5 -555t-505.5 -198q-331 0 -508.5 196.5t-177.5 558.5zM375 733q0 -270 109 -409.5t323 -139.5q213 0 321.5 138t108.5 411q0 269 -107.5 408t-320.5 139q-215 0 -324.5 -139t-109.5 -408z M413 1579v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158z" /> +<glyph unicode="Õ" horiz-adv-x="1612" d="M121 735q0 362 178.5 556t509.5 194q326 0 504 -197t178 -555q0 -357 -178.5 -555t-505.5 -198q-331 0 -508.5 196.5t-177.5 558.5zM375 733q0 -270 109 -409.5t323 -139.5q213 0 321.5 138t108.5 411q0 269 -107.5 408t-320.5 139q-215 0 -324.5 -139t-109.5 -408z M410 1577q12 139 77.5 212t167.5 73q43 0 84 -17.5t80 -39t75.5 -39t70.5 -17.5q79 0 106 115h125q-12 -134 -77 -209.5t-169 -75.5q-42 0 -82.5 17.5t-79.5 39t-76 39t-71 17.5q-81 0 -109 -115h-122z" /> +<glyph unicode="Ö" horiz-adv-x="1612" d="M121 735q0 362 178.5 556t509.5 194q326 0 504 -197t178 -555q0 -357 -178.5 -555t-505.5 -198q-331 0 -508.5 196.5t-177.5 558.5zM375 733q0 -270 109 -409.5t323 -139.5q213 0 321.5 138t108.5 411q0 269 -107.5 408t-320.5 139q-215 0 -324.5 -139t-109.5 -408z M496 1737q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM889 1737q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="×" d="M131 1049l125 127l328 -326l329 326l125 -123l-329 -330l325 -328l-123 -125l-329 326l-324 -326l-125 125l324 328z" /> +<glyph unicode="Ø" horiz-adv-x="1612" d="M121 735q0 362 178.5 556t509.5 194q199 0 354 -82l90 129l142 -92l-99 -140q195 -199 195 -567q0 -357 -178.5 -555t-505.5 -198q-213 0 -361 81l-94 -137l-141 94l98 144q-188 196 -188 573zM375 733q0 -231 78 -362l587 850q-92 59 -231 59q-215 0 -324.5 -139 t-109.5 -408zM571 244q97 -60 236 -60q213 0 321.5 138t108.5 411q0 225 -80 361z" /> +<glyph unicode="Ù" horiz-adv-x="1520" d="M180 520v942h240v-925q0 -181 84 -267t258 -86q338 0 338 355v923h239v-946q0 -162 -69.5 -283.5t-201 -187t-314.5 -65.5q-272 0 -423 144t-151 396zM417 1886v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5z" /> +<glyph unicode="Ú" horiz-adv-x="1520" d="M180 520v942h240v-925q0 -181 84 -267t258 -86q338 0 338 355v923h239v-946q0 -162 -69.5 -283.5t-201 -187t-314.5 -65.5q-272 0 -423 144t-151 396zM600 1579v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="Û" horiz-adv-x="1520" d="M180 520v942h240v-925q0 -181 84 -267t258 -86q338 0 338 355v923h239v-946q0 -162 -69.5 -283.5t-201 -187t-314.5 -65.5q-272 0 -423 144t-151 396zM366 1579v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158z" /> +<glyph unicode="Ü" horiz-adv-x="1520" d="M180 520v942h240v-925q0 -181 84 -267t258 -86q338 0 338 355v923h239v-946q0 -162 -69.5 -283.5t-201 -187t-314.5 -65.5q-272 0 -423 144t-151 396zM445 1737q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88z M838 1737q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="Ý" horiz-adv-x="1212" d="M0 1462h260l346 -667l346 667h260l-487 -895v-567h-240v559zM450 1579v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="Þ" horiz-adv-x="1268" d="M193 0v1462h239v-243h197q268 0 404 -112t136 -331q0 -227 -146 -349t-423 -122h-168v-305h-239zM432 504h133q187 0 273 63t86 203q0 127 -78 188.5t-250 61.5h-164v-516z" /> +<glyph unicode="ß" horiz-adv-x="1364" d="M168 0v1169q0 193 128.5 295.5t367.5 102.5q225 0 355 -84t130 -230q0 -74 -38.5 -140.5t-104.5 -117.5q-90 -69 -117 -98t-27 -57q0 -30 22.5 -55.5t79.5 -63.5l95 -64q92 -62 135.5 -109.5t65.5 -103.5t22 -127q0 -165 -107 -251t-311 -86q-190 0 -299 65v199 q58 -37 139 -61.5t148 -24.5q192 0 192 151q0 61 -34.5 105t-155.5 118q-119 73 -171 135t-52 146q0 63 34 115.5t105 105.5q75 55 107 97.5t32 93.5q0 72 -67 112.5t-178 40.5q-127 0 -194 -54t-67 -159v-1165h-235z" /> +<glyph unicode="à" horiz-adv-x="1188" d="M90 317q0 171 127 258t387 95l191 6v59q0 106 -49.5 158.5t-153.5 52.5q-85 0 -163 -25t-150 -59l-76 168q90 47 197 71.5t202 24.5q211 0 318.5 -92t107.5 -289v-745h-168l-47 154h-8q-80 -101 -161 -137.5t-208 -36.5q-163 0 -254.5 88t-91.5 249zM259 1548v21h273 q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5zM334 315q0 -74 44 -114.5t132 -40.5q128 0 205.5 71.5t77.5 200.5v96l-142 -6q-166 -6 -241.5 -55.5t-75.5 -151.5z" /> +<glyph unicode="á" horiz-adv-x="1188" d="M90 317q0 171 127 258t387 95l191 6v59q0 106 -49.5 158.5t-153.5 52.5q-85 0 -163 -25t-150 -59l-76 168q90 47 197 71.5t202 24.5q211 0 318.5 -92t107.5 -289v-745h-168l-47 154h-8q-80 -101 -161 -137.5t-208 -36.5q-163 0 -254.5 88t-91.5 249zM334 315 q0 -74 44 -114.5t132 -40.5q128 0 205.5 71.5t77.5 200.5v96l-142 -6q-166 -6 -241.5 -55.5t-75.5 -151.5zM438 1241v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="â" horiz-adv-x="1188" d="M90 317q0 171 127 258t387 95l191 6v59q0 106 -49.5 158.5t-153.5 52.5q-85 0 -163 -25t-150 -59l-76 168q90 47 197 71.5t202 24.5q211 0 318.5 -92t107.5 -289v-745h-168l-47 154h-8q-80 -101 -161 -137.5t-208 -36.5q-163 0 -254.5 88t-91.5 249zM203 1241v25 q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158zM334 315q0 -74 44 -114.5t132 -40.5q128 0 205.5 71.5t77.5 200.5v96l-142 -6q-166 -6 -241.5 -55.5t-75.5 -151.5z" /> +<glyph unicode="ã" horiz-adv-x="1188" d="M90 317q0 171 127 258t387 95l191 6v59q0 106 -49.5 158.5t-153.5 52.5q-85 0 -163 -25t-150 -59l-76 168q90 47 197 71.5t202 24.5q211 0 318.5 -92t107.5 -289v-745h-168l-47 154h-8q-80 -101 -161 -137.5t-208 -36.5q-163 0 -254.5 88t-91.5 249zM208 1239 q12 139 77.5 212t167.5 73q43 0 84 -17.5t80 -39t75.5 -39t70.5 -17.5q79 0 106 115h125q-12 -134 -77 -209.5t-169 -75.5q-42 0 -82.5 17.5t-79.5 39t-76 39t-71 17.5q-81 0 -109 -115h-122zM334 315q0 -74 44 -114.5t132 -40.5q128 0 205.5 71.5t77.5 200.5v96l-142 -6 q-166 -6 -241.5 -55.5t-75.5 -151.5z" /> +<glyph unicode="ä" horiz-adv-x="1188" d="M90 317q0 171 127 258t387 95l191 6v59q0 106 -49.5 158.5t-153.5 52.5q-85 0 -163 -25t-150 -59l-76 168q90 47 197 71.5t202 24.5q211 0 318.5 -92t107.5 -289v-745h-168l-47 154h-8q-80 -101 -161 -137.5t-208 -36.5q-163 0 -254.5 88t-91.5 249zM282 1399 q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM334 315q0 -74 44 -114.5t132 -40.5q128 0 205.5 71.5t77.5 200.5v96l-142 -6q-166 -6 -241.5 -55.5t-75.5 -151.5zM675 1399q0 62 33.5 89.5t81.5 27.5q53 0 85 -31 t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="å" horiz-adv-x="1188" d="M90 317q0 171 127 258t387 95l191 6v59q0 106 -49.5 158.5t-153.5 52.5q-85 0 -163 -25t-150 -59l-76 168q90 47 197 71.5t202 24.5q211 0 318.5 -92t107.5 -289v-745h-168l-47 154h-8q-80 -101 -161 -137.5t-208 -36.5q-163 0 -254.5 88t-91.5 249zM334 315 q0 -74 44 -114.5t132 -40.5q128 0 205.5 71.5t77.5 200.5v96l-142 -6q-166 -6 -241.5 -55.5t-75.5 -151.5zM366 1466q0 101 63.5 163.5t172.5 62.5q104 0 171.5 -62t67.5 -162q0 -102 -65.5 -165.5t-173.5 -63.5t-172 62.5t-64 164.5zM495 1466q0 -106 107 -106 q46 0 76 27.5t30 78.5q0 50 -30 78.5t-76 28.5q-47 0 -77 -28.5t-30 -78.5z" /> +<glyph unicode="æ" horiz-adv-x="1817" d="M90 317q0 172 121.5 258.5t370.5 94.5l188 6v76q0 194 -201 194q-141 0 -307 -82l-74 166q88 47 192.5 71.5t203.5 24.5q241 0 340 -155q120 155 346 155q206 0 328 -134.5t122 -362.5v-127h-712q10 -336 301 -336q184 0 356 80v-191q-86 -41 -171.5 -58t-195.5 -17 q-140 0 -248.5 54.5t-175.5 164.5q-94 -125 -190.5 -172t-241.5 -47q-165 0 -258.5 90t-93.5 247zM334 315q0 -155 166 -155q124 0 196 72.5t72 199.5v96l-135 -6q-155 -6 -227 -54.5t-72 -152.5zM1014 670h473q0 130 -58.5 204t-162.5 74q-112 0 -177.5 -69.5t-74.5 -208.5 z" /> +<glyph unicode="ç" horiz-adv-x="1014" d="M102 547q0 279 136.5 429t394.5 150q175 0 315 -65l-71 -189q-149 58 -246 58q-287 0 -287 -381q0 -186 71.5 -279.5t209.5 -93.5q157 0 297 78v-205q-63 -37 -134.5 -53t-173.5 -16q-251 0 -381.5 146.5t-130.5 420.5zM356 -340q54 -14 123 -14q54 0 85.5 16.5 t31.5 61.5q0 85 -179 110l84 166h152l-41 -88q80 -21 125 -68.5t45 -113.5q0 -222 -305 -222q-66 0 -121 15v137z" /> +<glyph unicode="è" horiz-adv-x="1180" d="M102 545q0 271 135 426t371 155q219 0 346 -133t127 -366v-127h-737q5 -161 87 -247.5t231 -86.5q98 0 182.5 18.5t181.5 61.5v-191q-86 -41 -174 -58t-201 -17q-258 0 -403.5 150.5t-145.5 414.5zM281 1548v21h273q38 -70 103.5 -161t109.5 -142v-25h-158 q-69 52 -174.5 150.5t-153.5 156.5zM348 670h502q-2 137 -66 207.5t-176 70.5t-179.5 -71t-80.5 -207z" /> +<glyph unicode="é" horiz-adv-x="1180" d="M102 545q0 271 135 426t371 155q219 0 346 -133t127 -366v-127h-737q5 -161 87 -247.5t231 -86.5q98 0 182.5 18.5t181.5 61.5v-191q-86 -41 -174 -58t-201 -17q-258 0 -403.5 150.5t-145.5 414.5zM348 670h502q-2 137 -66 207.5t-176 70.5t-179.5 -71t-80.5 -207z M458 1241v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="ê" horiz-adv-x="1180" d="M102 545q0 271 135 426t371 155q219 0 346 -133t127 -366v-127h-737q5 -161 87 -247.5t231 -86.5q98 0 182.5 18.5t181.5 61.5v-191q-86 -41 -174 -58t-201 -17q-258 0 -403.5 150.5t-145.5 414.5zM227 1241v25q191 198 254 303h260q63 -110 256 -303v-25h-159 q-123 73 -228 180q-103 -103 -225 -180h-158zM348 670h502q-2 137 -66 207.5t-176 70.5t-179.5 -71t-80.5 -207z" /> +<glyph unicode="ë" horiz-adv-x="1180" d="M102 545q0 271 135 426t371 155q219 0 346 -133t127 -366v-127h-737q5 -161 87 -247.5t231 -86.5q98 0 182.5 18.5t181.5 61.5v-191q-86 -41 -174 -58t-201 -17q-258 0 -403.5 150.5t-145.5 414.5zM307 1399q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86 q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM348 670h502q-2 137 -66 207.5t-176 70.5t-179.5 -71t-80.5 -207zM700 1399q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="ì" horiz-adv-x="571" d="M-69 1548v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5zM168 0v1106h235v-1106h-235z" /> +<glyph unicode="í" horiz-adv-x="571" d="M156 1241v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156zM168 0v1106h235v-1106h-235z" /> +<glyph unicode="î" horiz-adv-x="571" d="M-100 1241v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158zM168 0v1106h235v-1106h-235z" /> +<glyph unicode="ï" horiz-adv-x="571" d="M-25 1399q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM168 0v1106h235v-1106h-235zM368 1399q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="ð" horiz-adv-x="1243" d="M102 481q0 231 131 365.5t351 134.5q214 0 301 -111l8 4q-62 189 -227 345l-250 -150l-88 133l204 119q-86 59 -167 102l84 146q140 -63 258 -144l231 138l88 -129l-188 -113q152 -140 231.5 -330t79.5 -424q0 -279 -137.5 -433t-388.5 -154q-235 0 -378 136t-143 365z M342 477q0 -153 74 -234t211 -81q148 0 215 91t67 269q0 127 -75.5 202t-206.5 75q-151 0 -218 -82t-67 -240z" /> +<glyph unicode="ñ" horiz-adv-x="1300" d="M168 0v1106h184l33 -145h12q50 79 142 122t204 43q398 0 398 -405v-721h-236v680q0 128 -51.5 191t-163.5 63q-149 0 -218 -88t-69 -295v-551h-235zM269 1239q12 139 77.5 212t167.5 73q43 0 84 -17.5t80 -39t75.5 -39t70.5 -17.5q79 0 106 115h125q-12 -134 -77 -209.5 t-169 -75.5q-42 0 -82.5 17.5t-79.5 39t-76 39t-71 17.5q-81 0 -109 -115h-122z" /> +<glyph unicode="ò" horiz-adv-x="1251" d="M102 555q0 269 138 420t389 151q240 0 380 -154.5t140 -416.5q0 -271 -139 -423t-387 -152q-155 0 -274 70t-183 201t-64 304zM293 1548v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5zM344 555q0 -383 283 -383q280 0 280 383 q0 379 -282 379q-148 0 -214.5 -98t-66.5 -281z" /> +<glyph unicode="ó" horiz-adv-x="1251" d="M102 555q0 269 138 420t389 151q240 0 380 -154.5t140 -416.5q0 -271 -139 -423t-387 -152q-155 0 -274 70t-183 201t-64 304zM344 555q0 -383 283 -383q280 0 280 383q0 379 -282 379q-148 0 -214.5 -98t-66.5 -281zM473 1241v25q57 70 117.5 156t95.5 147h273v-21 q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="ô" horiz-adv-x="1251" d="M102 555q0 269 138 420t389 151q240 0 380 -154.5t140 -416.5q0 -271 -139 -423t-387 -152q-155 0 -274 70t-183 201t-64 304zM239 1241v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158zM344 555q0 -383 283 -383 q280 0 280 383q0 379 -282 379q-148 0 -214.5 -98t-66.5 -281z" /> +<glyph unicode="õ" horiz-adv-x="1251" d="M102 555q0 269 138 420t389 151q240 0 380 -154.5t140 -416.5q0 -271 -139 -423t-387 -152q-155 0 -274 70t-183 201t-64 304zM235 1239q12 139 77.5 212t167.5 73q43 0 84 -17.5t80 -39t75.5 -39t70.5 -17.5q79 0 106 115h125q-12 -134 -77 -209.5t-169 -75.5 q-42 0 -82.5 17.5t-79.5 39t-76 39t-71 17.5q-81 0 -109 -115h-122zM344 555q0 -383 283 -383q280 0 280 383q0 379 -282 379q-148 0 -214.5 -98t-66.5 -281z" /> +<glyph unicode="ö" horiz-adv-x="1251" d="M102 555q0 269 138 420t389 151q240 0 380 -154.5t140 -416.5q0 -271 -139 -423t-387 -152q-155 0 -274 70t-183 201t-64 304zM311 1399q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM344 555q0 -383 283 -383 q280 0 280 383q0 379 -282 379q-148 0 -214.5 -98t-66.5 -281zM704 1399q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="÷" d="M96 633v178h977v-178h-977zM457 373q0 64 31.5 99.5t95.5 35.5q61 0 93 -36t32 -99t-34 -100t-91 -37q-60 0 -93.5 35.5t-33.5 101.5zM457 1071q0 64 31.5 99.5t95.5 35.5q61 0 93 -36t32 -99t-34 -100t-91 -37q-60 0 -93.5 35.5t-33.5 101.5z" /> +<glyph unicode="ø" horiz-adv-x="1251" d="M102 555q0 269 138 420t389 151q144 0 258 -63l69 100l136 -92l-78 -108q135 -152 135 -408q0 -271 -139 -423t-387 -152q-144 0 -250 57l-76 -109l-135 90l82 117q-142 155 -142 420zM344 555q0 -135 37 -219l391 559q-60 39 -147 39q-148 0 -214.5 -98t-66.5 -281z M487 205q54 -33 140 -33q280 0 280 383q0 121 -33 203z" /> +<glyph unicode="ù" horiz-adv-x="1300" d="M158 383v723h237v-682q0 -127 52 -190.5t163 -63.5q148 0 217.5 88.5t69.5 296.5v551h236v-1106h-185l-33 145h-12q-49 -77 -139.5 -121t-206.5 -44q-201 0 -300 100t-99 303zM289 1548v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5z " /> +<glyph unicode="ú" horiz-adv-x="1300" d="M158 383v723h237v-682q0 -127 52 -190.5t163 -63.5q148 0 217.5 88.5t69.5 296.5v551h236v-1106h-185l-33 145h-12q-49 -77 -139.5 -121t-206.5 -44q-201 0 -300 100t-99 303zM501 1241v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z " /> +<glyph unicode="û" horiz-adv-x="1300" d="M158 383v723h237v-682q0 -127 52 -190.5t163 -63.5q148 0 217.5 88.5t69.5 296.5v551h236v-1106h-185l-33 145h-12q-49 -77 -139.5 -121t-206.5 -44q-201 0 -300 100t-99 303zM260 1241v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180 q-103 -103 -225 -180h-158z" /> +<glyph unicode="ü" horiz-adv-x="1300" d="M158 383v723h237v-682q0 -127 52 -190.5t163 -63.5q148 0 217.5 88.5t69.5 296.5v551h236v-1106h-185l-33 145h-12q-49 -77 -139.5 -121t-206.5 -44q-201 0 -300 100t-99 303zM332 1399q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32 q-48 0 -81.5 29t-33.5 88zM725 1399q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="ý" horiz-adv-x="1098" d="M0 1106h256l225 -627q51 -134 68 -252h8q9 55 33 133.5t254 745.5h254l-473 -1253q-129 -345 -430 -345q-78 0 -152 17v186q53 -12 121 -12q170 0 239 197l41 104zM401 1241v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="þ" horiz-adv-x="1276" d="M168 -492v2048h235v-430l-7 -138l-3 -27h10q61 86 142.5 125.5t187.5 39.5q206 0 322 -151t116 -420q0 -272 -116.5 -423.5t-321.5 -151.5q-219 0 -330 149h-14l8 -72l6 -92v-457h-235zM403 555q0 -202 64 -292.5t209 -90.5q254 0 254 385q0 190 -61.5 283.5t-194.5 93.5 q-142 0 -206.5 -82t-64.5 -260v-37z" /> +<glyph unicode="ÿ" horiz-adv-x="1098" d="M0 1106h256l225 -627q51 -134 68 -252h8q9 55 33 133.5t254 745.5h254l-473 -1253q-129 -345 -430 -345q-78 0 -152 17v186q53 -12 121 -12q170 0 239 197l41 104zM239 1399q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29 t-33.5 88zM632 1399q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="Œ" horiz-adv-x="1942" d="M121 735q0 360 172 555t491 195q115 0 209 -23h826v-202h-576v-398h539v-200h-539v-459h576v-203h-820q-102 -20 -211 -20q-320 0 -493.5 196.5t-173.5 558.5zM371 733q0 -269 106 -409t314 -140q129 0 213 35v1024q-80 37 -211 37q-208 0 -315 -139t-107 -408z" /> +<glyph unicode="œ" horiz-adv-x="1966" d="M102 555q0 272 137 421.5t382 149.5q121 0 223 -49t168 -145q131 194 379 194q221 0 349 -133.5t128 -365.5v-127h-738q11 -164 85.5 -249t228.5 -85q102 0 187 18.5t181 61.5v-191q-84 -40 -171.5 -57.5t-202.5 -17.5q-281 0 -420 194q-132 -194 -400 -194 q-236 0 -376 155t-140 420zM344 555q0 -189 65.5 -286t211.5 -97q141 0 206.5 95.5t65.5 283.5q0 192 -66 287.5t-211 95.5q-143 0 -207.5 -95t-64.5 -284zM1137 670h497q0 134 -63 206t-178 72q-110 0 -177.5 -69.5t-78.5 -208.5z" /> +<glyph unicode="Ÿ" horiz-adv-x="1212" d="M0 1462h260l346 -667l346 667h260l-487 -895v-567h-240v559zM293 1737q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM686 1737q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5 q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="ˆ" horiz-adv-x="1227" d="M227 1241v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158z" /> +<glyph unicode="˜" horiz-adv-x="1227" d="M236 1239q12 139 77.5 212t167.5 73q43 0 84 -17.5t80 -39t75.5 -39t70.5 -17.5q79 0 106 115h125q-12 -134 -77 -209.5t-169 -75.5q-42 0 -82.5 17.5t-79.5 39t-76 39t-71 17.5q-81 0 -109 -115h-122z" /> +<glyph unicode=" " horiz-adv-x="953" /> +<glyph unicode=" " horiz-adv-x="1907" /> +<glyph unicode=" " horiz-adv-x="953" /> +<glyph unicode=" " horiz-adv-x="1907" /> +<glyph unicode=" " horiz-adv-x="635" /> +<glyph unicode=" " horiz-adv-x="476" /> +<glyph unicode=" " horiz-adv-x="317" /> +<glyph unicode=" " horiz-adv-x="317" /> +<glyph unicode=" " horiz-adv-x="238" /> +<glyph unicode=" " horiz-adv-x="381" /> +<glyph unicode=" " horiz-adv-x="105" /> +<glyph unicode="‐" horiz-adv-x="659" d="M72 449v200h514v-200h-514z" /> +<glyph unicode="‑" horiz-adv-x="659" d="M72 449v200h514v-200h-514z" /> +<glyph unicode="‒" horiz-adv-x="659" d="M72 449v200h514v-200h-514z" /> +<glyph unicode="–" horiz-adv-x="1024" d="M82 455v190h860v-190h-860z" /> +<glyph unicode="—" horiz-adv-x="2048" d="M82 455v190h1884v-190h-1884z" /> +<glyph unicode="‘" horiz-adv-x="395" d="M25 983q20 83 71 224t105 255h170q-64 -256 -101 -501h-233z" /> +<glyph unicode="’" horiz-adv-x="395" d="M25 961q69 289 100 501h231l15 -22q-53 -209 -176 -479h-170z" /> +<glyph unicode="‚" horiz-adv-x="549" d="M63 -264q69 270 103 502h231l15 -23q-48 -186 -176 -479h-173z" /> +<glyph unicode="“" horiz-adv-x="813" d="M25 983q20 83 71 224t105 255h170q-64 -256 -101 -501h-233zM440 983q53 203 178 479h170q-69 -296 -100 -501h-233z" /> +<glyph unicode="”" horiz-adv-x="813" d="M25 961q69 289 100 501h231l15 -22q-53 -209 -176 -479h-170zM440 961q69 271 103 501h231l14 -22q-53 -209 -176 -479h-172z" /> +<glyph unicode="„" horiz-adv-x="944" d="M43 -264q66 260 102 502h232l14 -23q-55 -214 -176 -479h-172zM461 -264q66 260 102 502h232l14 -23q-48 -186 -176 -479h-172z" /> +<glyph unicode="•" horiz-adv-x="770" d="M131 748q0 138 66 210t188 72q121 0 187.5 -72.5t66.5 -209.5q0 -135 -67 -209t-187 -74t-187 72.5t-67 210.5z" /> +<glyph unicode="…" horiz-adv-x="1677" d="M133 125q0 73 38 112t110 39q73 0 111 -40.5t38 -110.5q0 -71 -38.5 -112.5t-110.5 -41.5t-110 41t-38 113zM690 125q0 73 38 112t110 39q73 0 111 -40.5t38 -110.5q0 -71 -38.5 -112.5t-110.5 -41.5t-110 41t-38 113zM1247 125q0 73 38 112t110 39q73 0 111 -40.5 t38 -110.5q0 -71 -38.5 -112.5t-110.5 -41.5t-110 41t-38 113z" /> +<glyph unicode=" " horiz-adv-x="381" /> +<glyph unicode="‹" horiz-adv-x="688" d="M82 535v26l356 432l168 -94l-282 -350l282 -348l-168 -97z" /> +<glyph unicode="›" horiz-adv-x="688" d="M80 201l282 348l-282 350l168 94l358 -432v-26l-358 -431z" /> +<glyph unicode=" " horiz-adv-x="476" /> +<glyph unicode="€" horiz-adv-x="1188" d="M63 494v153h136l-2 37v37l2 65h-136v154h150q38 251 191 394t395 143q200 0 358 -88l-84 -187q-154 76 -274 76q-141 0 -230.5 -84t-119.5 -254h456v-154h-471l-2 -45v-55l2 -39h408v-153h-391q64 -312 364 -312q143 0 293 62v-203q-131 -61 -305 -61q-241 0 -391.5 132 t-196.5 382h-152z" /> +<glyph unicode="™" horiz-adv-x="1561" d="M27 1333v129h553v-129h-205v-592h-146v592h-202zM635 741v721h217l178 -534l187 534h210v-721h-147v414l4 129h-6l-193 -543h-122l-185 543h-6l4 -119v-424h-141z" /> +<glyph unicode="" horiz-adv-x="1105" d="M0 0v1105h1105v-1105h-1105z" /> +</font> +</defs></svg> \ No newline at end of file diff --git a/refs/pull/405/merge/_static/fonts/opensans-semibold-webfont.ttf b/refs/pull/405/merge/_static/fonts/opensans-semibold-webfont.ttf new file mode 100644 index 00000000..8d502590 Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/opensans-semibold-webfont.ttf differ diff --git a/refs/pull/405/merge/_static/fonts/opensans-semibold-webfont.woff b/refs/pull/405/merge/_static/fonts/opensans-semibold-webfont.woff new file mode 100644 index 00000000..67c4b988 Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/opensans-semibold-webfont.woff differ diff --git a/refs/pull/405/merge/_static/fonts/opensans-semibolditalic-webfont.eot b/refs/pull/405/merge/_static/fonts/opensans-semibolditalic-webfont.eot new file mode 100644 index 00000000..377ca0e8 Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/opensans-semibolditalic-webfont.eot differ diff --git a/refs/pull/405/merge/_static/fonts/opensans-semibolditalic-webfont.svg b/refs/pull/405/merge/_static/fonts/opensans-semibolditalic-webfont.svg new file mode 100644 index 00000000..47dfc0e0 --- /dev/null +++ b/refs/pull/405/merge/_static/fonts/opensans-semibolditalic-webfont.svg @@ -0,0 +1,244 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata></metadata> +<defs> +<font id="OpenSansSemiboldItalic" horiz-adv-x="1128" > +<font-face units-per-em="2048" ascent="1638" descent="-410" /> +<missing-glyph horiz-adv-x="532" /> +<glyph unicode="fi" horiz-adv-x="1257" d="M-225 -279q64 -20 114 -20q134 0 177 205l217 1022h-179l21 106l194 76l21 92q44 198 134.5 281.5t256.5 83.5q115 0 211 -43l-61 -176q-74 28 -136 28q-69 0 -110.5 -43t-63.5 -141l-18 -86h229l-37 -178h-229l-223 -1053q-40 -189 -131 -278t-238 -89q-90 0 -149 23 v190zM739 0l236 1106h235l-235 -1106h-236zM1022 1378q0 68 39 110t110 42q53 0 86 -26.5t33 -80.5q0 -71 -40 -112t-105 -41q-53 0 -88 26t-35 82z" /> +<glyph unicode="fl" horiz-adv-x="1257" d="M-225 -279q64 -20 114 -20q134 0 177 205l217 1022h-179l21 106l194 76l21 92q44 198 134.5 281.5t256.5 83.5q115 0 211 -43l-61 -176q-74 28 -136 28q-69 0 -110.5 -43t-63.5 -141l-18 -86h229l-37 -178h-229l-223 -1053q-40 -189 -131 -278t-238 -89q-90 0 -149 23 v190zM739 0l330 1556h235l-331 -1556h-234z" /> +<glyph unicode="ffi" horiz-adv-x="1931" d="M-225 -279q64 -20 114 -20q133 0 177 205l217 1022h-179l21 106l194 76l21 92q44 198 134.5 281.5t256.5 83.5q115 0 211 -43l-61 -176q-74 28 -136 28q-69 0 -110.5 -43t-63.5 -141l-18 -86h438l23 96q44 197 133 281t256 84q117 0 213 -43l-62 -176q-74 28 -135 28 q-71 0 -111.5 -43t-62.5 -141l-18 -86h229l-39 -178h-227l-223 -1053q-43 -192 -133.5 -279.5t-235.5 -87.5q-95 0 -149 23v190q60 -20 114 -20q136 0 176 205l215 1022h-438l-223 -1053q-40 -189 -131 -278t-238 -89q-90 0 -149 23v190zM1415 0l236 1106h233l-235 -1106 h-234zM1698 1378q0 68 39 110t108 42q54 0 86.5 -26.5t32.5 -80.5q0 -71 -39.5 -112t-105.5 -41q-51 0 -86 26t-35 82z" /> +<glyph unicode="ffl" horiz-adv-x="1931" d="M-225 -279q64 -20 114 -20q133 0 177 205l217 1022h-179l21 106l194 76l21 92q44 198 134.5 281.5t256.5 83.5q115 0 211 -43l-61 -176q-74 28 -136 28q-69 0 -110.5 -43t-63.5 -141l-18 -86h438l23 96q44 197 133 281t256 84q117 0 213 -43l-62 -176q-74 28 -135 28 q-71 0 -111.5 -43t-62.5 -141l-18 -86h229l-39 -178h-227l-223 -1053q-43 -192 -133.5 -279.5t-235.5 -87.5q-95 0 -149 23v190q60 -20 114 -20q136 0 176 205l215 1022h-438l-223 -1053q-40 -189 -131 -278t-238 -89q-90 0 -149 23v190zM1413 0l332 1556h233l-329 -1556 h-236z" /> +<glyph horiz-adv-x="0" /> +<glyph horiz-adv-x="2048" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="	" horiz-adv-x="532" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="!" horiz-adv-x="557" d="M33 96q0 80 45.5 130t130.5 50q57 0 91 -32.5t34 -93.5q0 -79 -47 -128t-123 -49q-62 0 -96.5 33.5t-34.5 89.5zM160 444l168 1018h272l-264 -1018h-176z" /> +<glyph unicode=""" horiz-adv-x="858" d="M213 934l72 528h231l-151 -528h-152zM588 934l74 528h231l-152 -528h-153z" /> +<glyph unicode="#" horiz-adv-x="1323" d="M51 418l17 168h280l84 286h-264l16 168h295l121 422h178l-121 -422h252l121 422h174l-121 -422h252l-14 -168h-285l-84 -286h271l-15 -168h-303l-121 -418h-180l123 418h-248l-121 -418h-174l117 418h-250zM526 586h250l82 286h-250z" /> +<glyph unicode="$" d="M61 172v209q78 -42 179.5 -70t193.5 -30l84 387q-156 56 -223.5 138.5t-67.5 199.5q0 167 118.5 267.5t324.5 117.5l37 163h135l-35 -165q161 -16 289 -82l-86 -185q-134 66 -244 74l-80 -371q128 -51 186.5 -95t86.5 -101t28 -135q0 -172 -119.5 -277t-337.5 -125 l-45 -211h-135l45 211q-197 13 -334 80zM451 1016q0 -98 110 -139l68 319q-89 -11 -133.5 -57.5t-44.5 -122.5zM571 285q86 11 136.5 60t50.5 126q0 101 -115 145z" /> +<glyph unicode="%" horiz-adv-x="1688" d="M141 872q0 166 53 313.5t142.5 222.5t208.5 75q127 0 193.5 -76t66.5 -221q0 -160 -55.5 -313.5t-146.5 -230.5t-206 -77q-124 0 -190 79t-66 228zM231 0l1086 1462h194l-1085 -1462h-195zM334 866q0 -135 80 -135q52 0 95.5 58t73 175.5t29.5 219.5q0 131 -82 131 q-55 0 -99 -61t-70.5 -173t-26.5 -215zM940 279q0 171 53 320t142.5 223.5t207.5 74.5q127 0 195 -75t68 -218q0 -161 -55.5 -315.5t-146.5 -231.5t-204 -77q-127 0 -193.5 76.5t-66.5 222.5zM1133 281q0 -134 81 -134q52 0 96 58.5t73.5 174.5t29.5 220q0 131 -84 131 q-52 0 -95.5 -57.5t-72 -171t-28.5 -221.5z" /> +<glyph unicode="&" horiz-adv-x="1411" d="M66 350q0 147 85.5 254t286.5 205q-88 151 -88 283q0 180 112.5 286.5t297.5 106.5q160 0 252 -81t92 -218q0 -129 -89.5 -230t-293.5 -192l235 -326q109 112 181 295h233q-113 -270 -297 -454l205 -279h-277l-94 131q-106 -80 -211 -115.5t-229 -35.5 q-190 0 -295.5 97.5t-105.5 272.5zM305 371q0 -86 56 -140.5t147 -54.5q77 0 147 27t144 82l-264 381q-133 -74 -181.5 -141.5t-48.5 -153.5zM567 1102q0 -109 62 -201q147 75 199.5 133.5t52.5 126.5q0 66 -36 101.5t-97 35.5q-87 0 -134 -54t-47 -142z" /> +<glyph unicode="'" horiz-adv-x="483" d="M213 934l72 528h231l-151 -528h-152z" /> +<glyph unicode="(" horiz-adv-x="639" d="M78 276q0 343 124.5 632.5t379.5 553.5h209q-498 -548 -498 -1190q0 -329 115 -596h-183q-147 261 -147 600z" /> +<glyph unicode=")" horiz-adv-x="639" d="M-154 -324q498 548 498 1190q0 327 -115 596h183q147 -265 147 -602q0 -342 -123 -629.5t-381 -554.5h-209z" /> +<glyph unicode="*" horiz-adv-x="1122" d="M193 1167l71 195l354 -178l37 383l213 -43l-116 -367l403 23l-12 -205l-367 45l170 -361l-205 -61l-102 371l-227 -312l-162 144l293 266z" /> +<glyph unicode="+" d="M117 631v180h379v381h180v-381h377v-180h-377v-375h-180v375h-379z" /> +<glyph unicode="," horiz-adv-x="530" d="M-102 -264q105 238 200 502h236l8 -23q-125 -260 -266 -479h-178z" /> +<glyph unicode="-" horiz-adv-x="649" d="M47 446l45 203h502l-45 -203h-502z" /> +<glyph unicode="." horiz-adv-x="551" d="M33 94q0 83 47 132.5t131 49.5q56 0 89.5 -31.5t33.5 -92.5q0 -78 -47.5 -129.5t-124.5 -51.5q-66 0 -97.5 35.5t-31.5 87.5z" /> +<glyph unicode="/" horiz-adv-x="788" d="M-92 0l811 1462h233l-811 -1462h-233z" /> +<glyph unicode="0" d="M92 471q0 284 83 526t222.5 365t321.5 123q187 0 284 -118.5t97 -354.5q0 -306 -79 -546.5t-219 -363t-325 -122.5q-194 0 -289.5 127.5t-95.5 363.5zM330 469q0 -143 39 -218t129 -75q100 0 182.5 113.5t132 316.5t49.5 414q0 268 -162 268q-97 0 -180 -112 t-136.5 -312.5t-53.5 -394.5z" /> +<glyph unicode="1" d="M242 1145l508 317h198l-311 -1462h-238l189 870q28 150 82 324q-57 -55 -135 -102l-187 -117z" /> +<glyph unicode="2" d="M-18 0l36 180l471 422q176 159 238.5 231t90.5 133.5t28 131.5q0 85 -49.5 134.5t-139.5 49.5q-70 0 -139 -30t-170 -109l-115 160q120 97 231 138.5t228 41.5q181 0 288 -93t107 -251q0 -108 -39 -201t-123 -190.5t-284 -268.5l-311 -264v-8h622l-41 -207h-929z" /> +<glyph unicode="3" d="M31 59v215q84 -49 185.5 -75.5t195.5 -26.5q157 0 245 71.5t88 196.5q0 219 -278 219h-133l37 183h106q164 0 267.5 74.5t103.5 199.5q0 79 -49.5 124.5t-139.5 45.5q-72 0 -146.5 -25.5t-162.5 -84.5l-104 161q120 81 225.5 113.5t226.5 32.5q183 0 286 -88.5 t103 -241.5q0 -158 -99 -264t-269 -137v-7q127 -24 196.5 -106t69.5 -205q0 -133 -68 -236.5t-196.5 -160.5t-304.5 -57q-225 0 -385 79z" /> +<glyph unicode="4" d="M-4 317l37 197l803 952h254l-201 -952h201l-43 -197h-201l-68 -317h-229l69 317h-622zM262 514h397l68 309q31 136 100 377h-8q-51 -86 -135 -186z" /> +<glyph unicode="5" d="M53 59v217q167 -100 342 -100q173 0 270 83t97 230q0 105 -62 168.5t-188 63.5q-95 0 -225 -35l-88 68l200 708h713l-45 -209h-506l-106 -364q93 18 155 18q181 0 288.5 -103.5t107.5 -285.5q0 -161 -70 -283t-204 -188.5t-324 -66.5q-214 0 -355 79z" /> +<glyph unicode="6" d="M111 446q0 205 60.5 406t165 343t251 215t342.5 73q117 0 203 -25l-43 -194q-72 22 -181 22q-205 0 -337 -129.5t-197 -392.5h6q125 170 326 170q156 0 243.5 -99t87.5 -272q0 -162 -68.5 -301t-185.5 -210.5t-270 -71.5q-194 0 -298.5 120t-104.5 346zM340 418 q0 -110 49.5 -177t140.5 -67q81 0 143 48.5t96 134.5t34 188q0 200 -178 200q-51 0 -95.5 -19t-79 -48t-58.5 -64.5t-39 -82t-13 -113.5z" /> +<glyph unicode="7" d="M125 0l754 1257h-674l43 205h932l-33 -168l-758 -1294h-264z" /> +<glyph unicode="8" d="M76 348q0 297 368 432q-91 70 -130.5 145t-39.5 162q0 179 127 288.5t330 109.5q179 0 283 -89t104 -239q0 -132 -79 -229.5t-248 -163.5q120 -78 172.5 -165.5t52.5 -201.5q0 -121 -61.5 -216.5t-175.5 -148t-271 -52.5q-203 0 -317.5 100t-114.5 268zM311 369 q0 -93 59 -149t158 -56q115 0 184.5 64t69.5 167q0 91 -48.5 157.5t-139.5 119.5q-149 -54 -216 -126.5t-67 -176.5zM504 1096q0 -83 39 -137t104 -93q115 43 177.5 105t62.5 157q0 81 -48 126.5t-128 45.5q-93 0 -150 -56t-57 -148z" /> +<glyph unicode="9" d="M92 12v207q121 -43 236 -43q188 0 306 123t177 389h-6q-113 -160 -305 -160q-165 0 -255.5 102t-90.5 288q0 156 67 289t186.5 204.5t274.5 71.5q192 0 294.5 -119.5t102.5 -345.5q0 -205 -58 -414.5t-152.5 -349t-226 -207t-310.5 -67.5q-133 0 -240 32zM387 932 q0 -105 46 -160t134 -55q117 0 198 94t81 240q0 108 -48 172.5t-134 64.5q-82 0 -145.5 -47t-97.5 -130t-34 -179z" /> +<glyph unicode=":" horiz-adv-x="551" d="M33 94q0 83 47 132.5t131 49.5q56 0 89.5 -31.5t33.5 -92.5q0 -78 -47.5 -129.5t-124.5 -51.5q-66 0 -97.5 35.5t-31.5 87.5zM205 948q0 83 47 132.5t131 49.5q56 0 89.5 -31.5t33.5 -92.5q0 -79 -48.5 -130t-125.5 -51q-66 0 -96.5 35.5t-30.5 87.5z" /> +<glyph unicode=";" horiz-adv-x="551" d="M-100 -264q95 214 198 502h236l8 -23q-125 -260 -266 -479h-176zM205 948q0 83 47 132.5t131 49.5q56 0 89.5 -31.5t33.5 -92.5q0 -79 -48.5 -130t-125.5 -51q-66 0 -96.5 35.5t-30.5 87.5z" /> +<glyph unicode="<" d="M115 651v121l936 488v-195l-697 -344l697 -303v-197z" /> +<glyph unicode="=" d="M117 430v180h936v-180h-936zM117 831v179h936v-179h-936z" /> +<glyph unicode=">" d="M115 221v197l694 303l-694 344v195l936 -488v-121z" /> +<glyph unicode="?" horiz-adv-x="907" d="M162 94q0 83 47 132.5t131 49.5q56 0 89.5 -31.5t33.5 -92.5q0 -79 -49 -129t-125 -50q-66 0 -96.5 34.5t-30.5 86.5zM186 1370q207 113 410 113q171 0 269 -85.5t98 -242.5q0 -120 -63.5 -217.5t-231.5 -216.5q-104 -74 -150 -133t-61 -144h-197q18 133 71.5 220.5 t176.5 177.5q107 77 146.5 117t58 80.5t18.5 88.5q0 70 -42.5 114t-123.5 44q-77 0 -150 -27.5t-151 -64.5z" /> +<glyph unicode="@" horiz-adv-x="1743" d="M100 502q0 270 122.5 489t343 344t493.5 125q200 0 346 -74.5t223.5 -214.5t77.5 -325q0 -176 -59.5 -322.5t-166.5 -229.5t-239 -83q-98 0 -150.5 46t-64.5 120h-6q-101 -166 -277 -166q-123 0 -189.5 78.5t-66.5 218.5q0 151 67.5 279.5t188 203t263.5 74.5 q52 0 94.5 -5t79.5 -13t129 -39l-101 -392q-30 -114 -30 -159q0 -92 79 -92q72 0 134 66.5t97.5 174.5t35.5 230q0 228 -128.5 347.5t-363.5 119.5q-214 0 -385 -99.5t-266.5 -281.5t-95.5 -406q0 -259 140.5 -401t391.5 -142q200 0 430 86v-155q-219 -90 -454 -90 q-210 0 -367 83.5t-241.5 239.5t-84.5 365zM676 522q0 -157 112 -157q82 0 141.5 72t100.5 220l64 240q-53 16 -105 16q-86 0 -158.5 -53.5t-113.5 -144t-41 -193.5z" /> +<glyph unicode="A" horiz-adv-x="1210" d="M-121 0l783 1464h274l166 -1464h-234l-41 406h-485l-209 -406h-254zM446 614h365q-40 416 -45.5 503.5t-5.5 139.5q-55 -139 -142 -307z" /> +<glyph unicode="B" horiz-adv-x="1247" d="M70 0l309 1462h399q222 0 335.5 -84t113.5 -248q0 -146 -86.5 -243t-239.5 -127v-8q108 -28 167.5 -103.5t59.5 -183.5q0 -217 -150 -341t-417 -124h-491zM348 201h223q147 0 230.5 68t83.5 194q0 98 -60 149.5t-176 51.5h-200zM489 858h199q139 0 215 60.5t76 171.5 q0 172 -223 172h-181z" /> +<glyph unicode="C" horiz-adv-x="1225" d="M135 545q0 260 105.5 483t281.5 339t402 116q217 0 389 -92l-94 -195q-63 34 -134 58t-161 24q-154 0 -275 -89t-193.5 -259.5t-72.5 -374.5q0 -180 82.5 -275.5t243.5 -95.5q141 0 329 68v-205q-180 -67 -374 -67q-248 0 -388.5 148.5t-140.5 416.5z" /> +<glyph unicode="D" horiz-adv-x="1374" d="M70 0l309 1462h369q271 0 417 -145t146 -424q0 -271 -100 -473t-291 -311t-449 -109h-401zM348 201h135q177 0 309 86t202.5 242t70.5 356q0 184 -88 280.5t-256 96.5h-146z" /> +<glyph unicode="E" horiz-adv-x="1077" d="M70 0l309 1462h776l-43 -205h-539l-84 -395h502l-41 -203h-504l-96 -456h539l-43 -203h-776z" /> +<glyph unicode="F" horiz-adv-x="1026" d="M70 0l309 1462h774l-43 -205h-537l-96 -454h502l-45 -203h-500l-127 -600h-237z" /> +<glyph unicode="G" horiz-adv-x="1399" d="M135 539q0 264 102.5 483t290 340t426.5 121q111 0 213 -20.5t205 -69.5l-90 -203q-174 86 -334 86q-158 0 -287 -90.5t-203.5 -258t-74.5 -372.5q0 -183 89 -277t253 -94q109 0 215 33l80 371h-277l43 205h512l-157 -736q-112 -40 -218.5 -58.5t-238.5 -18.5 q-261 0 -405 146t-144 413z" /> +<glyph unicode="H" horiz-adv-x="1411" d="M70 0l309 1462h237l-127 -598h566l127 598h237l-309 -1462h-238l140 659h-566l-139 -659h-237z" /> +<glyph unicode="I" horiz-adv-x="608" d="M70 0l311 1462h235l-311 -1462h-235z" /> +<glyph unicode="J" horiz-adv-x="612" d="M-322 -383l5 201q84 -21 153 -21q201 0 254 250l299 1415h238l-305 -1446q-46 -217 -161.5 -320.5t-312.5 -103.5q-104 0 -170 25z" /> +<glyph unicode="K" horiz-adv-x="1198" d="M70 0l309 1462h237l-151 -706l141 166l492 540h284l-616 -669l321 -793h-262l-252 655l-149 -100l-117 -555h-237z" /> +<glyph unicode="L" horiz-adv-x="1016" d="M70 0l309 1462h237l-266 -1257h539l-43 -205h-776z" /> +<glyph unicode="M" horiz-adv-x="1757" d="M68 0l309 1462h323l109 -1149h6l606 1149h344l-305 -1462h-227l182 872q39 186 86 342h-6l-643 -1214h-205l-115 1214h-6q-9 -118 -55 -340l-184 -874h-219z" /> +<glyph unicode="N" horiz-adv-x="1491" d="M68 0l309 1462h268l399 -1149h7q6 54 31 192.5t40 203.5l160 753h219l-309 -1462h-260l-410 1163h-6l-10 -69q-24 -149 -35.5 -212.5t-183.5 -881.5h-219z" /> +<glyph unicode="O" horiz-adv-x="1485" d="M135 543q0 267 98.5 487.5t269.5 337.5t388 117q251 0 390.5 -149t139.5 -414q0 -279 -95 -497t-261.5 -331.5t-386.5 -113.5q-259 0 -401 149.5t-142 413.5zM383 545q0 -173 81.5 -267t227.5 -94q138 0 248.5 95.5t172 265t61.5 375.5q0 170 -79 265t-223 95 q-138 0 -250 -96t-175.5 -266.5t-63.5 -372.5z" /> +<glyph unicode="P" horiz-adv-x="1174" d="M70 0l309 1462h334q229 0 345 -100.5t116 -300.5q0 -248 -169.5 -381t-472.5 -133h-110l-115 -547h-237zM465 748h94q178 0 275.5 79.5t97.5 225.5q0 109 -58.5 159t-179.5 50h-119z" /> +<glyph unicode="Q" horiz-adv-x="1485" d="M135 543q0 267 98.5 487.5t269.5 337.5t388 117q251 0 390.5 -149t139.5 -414q0 -322 -130 -563t-355 -332l264 -375h-289l-202 328h-31q-259 0 -401 149.5t-142 413.5zM383 545q0 -173 81.5 -267t227.5 -94q138 0 248.5 94t172 263.5t61.5 378.5q0 170 -79 265t-223 95 q-138 0 -250 -96t-175.5 -266.5t-63.5 -372.5z" /> +<glyph unicode="R" horiz-adv-x="1206" d="M70 0l309 1462h338q223 0 342 -94.5t119 -290.5q0 -165 -86.5 -278.5t-257.5 -165.5l249 -633h-260l-207 584h-186l-123 -584h-237zM473 782h123q170 0 254 75t84 206q0 105 -59 151t-183 46h-119z" /> +<glyph unicode="S" horiz-adv-x="1057" d="M39 55v224q173 -97 350 -97q137 0 216 58.5t79 162.5q0 69 -41 122.5t-172 136.5q-105 67 -155 122t-76.5 120.5t-26.5 144.5q0 128 61.5 227t174 153t253.5 54q205 0 381 -92l-86 -191q-161 78 -295 78q-109 0 -175 -58.5t-66 -152.5q0 -47 15 -82.5t46.5 -66 t134.5 -95.5q155 -97 214 -187.5t59 -207.5q0 -210 -144.5 -329t-398.5 -119q-210 0 -348 75z" /> +<glyph unicode="T" horiz-adv-x="1053" d="M176 1257l45 205h998l-43 -205h-381l-267 -1257h-237l264 1257h-379z" /> +<glyph unicode="U" horiz-adv-x="1399" d="M152 391q0 83 20 170l193 901h237l-192 -905q-21 -88 -21 -158q0 -102 59.5 -158.5t180.5 -56.5q145 0 230 80.5t124 261.5l199 936h237l-202 -956q-56 -267 -208 -396.5t-403 -129.5q-217 0 -335.5 106t-118.5 305z" /> +<glyph unicode="V" horiz-adv-x="1165" d="M186 1462h232l74 -905q9 -103 11 -233l-1 -76h4q70 178 137 309l455 905h254l-764 -1462h-258z" /> +<glyph unicode="W" horiz-adv-x="1788" d="M203 1462h229l19 -850q0 -136 -13 -346h6q83 221 142 355l387 841h225l31 -839l3 -169l-3 -188h8q28 88 70 197.5t61 152.5l358 846h246l-655 -1462h-258l-37 842l-6 185l4 106h-6q-47 -144 -117 -291l-385 -842h-256z" /> +<glyph unicode="X" horiz-adv-x="1151" d="M-111 0l586 770l-250 692h246l178 -540l402 540h266l-551 -710l274 -752h-256l-192 592l-438 -592h-265z" /> +<glyph unicode="Y" horiz-adv-x="1092" d="M186 1462h242l154 -669l432 669h266l-623 -913l-114 -549h-238l119 553z" /> +<glyph unicode="Z" horiz-adv-x="1092" d="M-39 0l33 168l850 1087h-598l43 207h897l-35 -172l-852 -1085h645l-43 -205h-940z" /> +<glyph unicode="[" horiz-adv-x="631" d="M-27 -324l381 1786h430l-39 -176h-221l-303 -1433h221l-39 -177h-430z" /> +<glyph unicode="\" horiz-adv-x="788" d="M221 1462h207l219 -1462h-209z" /> +<glyph unicode="]" horiz-adv-x="631" d="M-143 -324l37 177h219l305 1433h-221l39 176h430l-381 -1786h-428z" /> +<glyph unicode="^" horiz-adv-x="1069" d="M37 537l608 933h127l272 -933h-184l-188 690l-434 -690h-201z" /> +<glyph unicode="_" horiz-adv-x="813" d="M-188 -324l30 140h817l-30 -140h-817z" /> +<glyph unicode="`" horiz-adv-x="1135" d="M541 1548v21h245q47 -154 132 -303v-25h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="a" horiz-adv-x="1186" d="M94 367q0 202 69.5 378t191.5 278.5t268 102.5q97 0 167 -45.5t109 -132.5h10l62 158h180l-236 -1106h-182l21 176h-6q-158 -196 -349 -196q-141 0 -223 101.5t-82 285.5zM332 373q0 -102 40.5 -152.5t112.5 -50.5q82 0 161 77.5t130 207.5t51 284q0 88 -47 141.5 t-123 53.5q-85 0 -160 -77t-120 -209.5t-45 -274.5z" /> +<glyph unicode="b" horiz-adv-x="1200" d="M47 0l330 1556h235l-71 -333q-13 -63 -38 -156.5t-40 -140.5h8q90 113 165 156.5t161 43.5q145 0 226 -103.5t81 -285.5q0 -202 -69.5 -379.5t-190.5 -277.5t-266 -100q-98 0 -168.5 45t-110.5 131h-10l-64 -156h-178zM369 373q0 -96 46.5 -149.5t131.5 -53.5t159 78.5 t117 210t43 274.5q0 201 -155 201q-81 0 -162 -80t-130.5 -210.5t-49.5 -270.5z" /> +<glyph unicode="c" horiz-adv-x="954" d="M94 389q0 207 73.5 376.5t206.5 265t302 95.5q164 0 297 -61l-70 -184q-122 53 -221 53q-150 0 -250 -153.5t-100 -379.5q0 -111 56 -171t155 -60q74 0 138.5 22t129.5 54v-195q-140 -71 -305 -71q-196 0 -304 106t-108 303z" /> +<glyph unicode="d" horiz-adv-x="1198" d="M94 369q0 205 71.5 383t191.5 276t266 98q179 0 268 -178h8q13 146 37 250l76 358h233l-330 -1556h-184l19 176h-7q-88 -106 -170 -151t-174 -45q-143 0 -224 101.5t-81 287.5zM332 373q0 -203 157 -203q82 0 162.5 82t129 214t48.5 267q0 91 -43.5 146t-132.5 55 q-85 0 -159 -77t-118 -211t-44 -273z" /> +<glyph unicode="e" horiz-adv-x="1075" d="M94 401q0 198 77.5 368.5t210 263.5t296.5 93q161 0 250.5 -72.5t89.5 -205.5q0 -182 -166.5 -284.5t-474.5 -102.5h-43l-2 -31v-29q0 -111 56.5 -174t168.5 -63q72 0 143 19t168 65v-187q-96 -44 -176.5 -62.5t-179.5 -18.5q-197 0 -307.5 111t-110.5 310zM362 633h29 q188 0 294 53.5t106 151.5q0 51 -32 79.5t-95 28.5q-96 0 -180.5 -86t-121.5 -227z" /> +<glyph unicode="f" horiz-adv-x="702" d="M-225 -279q64 -20 114 -20q134 0 177 205l217 1022h-179l21 106l194 76l21 92q44 198 134.5 281.5t256.5 83.5q115 0 211 -43l-61 -176q-74 28 -136 28q-69 0 -110.5 -43t-63.5 -141l-18 -86h229l-37 -178h-229l-223 -1053q-40 -189 -131 -278t-238 -89q-90 0 -149 23 v190z" /> +<glyph unicode="g" horiz-adv-x="1067" d="M-121 -211q0 103 69.5 178t223.5 127q-76 45 -76 127q0 69 46.5 119.5t146.5 97.5q-135 81 -135 252q0 196 122.5 316t323.5 120q80 0 160 -20h383l-31 -137l-192 -33q28 -58 28 -137q0 -193 -119 -306.5t-319 -113.5q-52 0 -92 8q-111 -40 -111 -104q0 -38 31.5 -52 t91.5 -22l127 -16q176 -22 252 -87.5t76 -187.5q0 -196 -151 -303t-429 -107q-203 0 -314.5 75t-111.5 206zM92 -184q0 -65 55.5 -103.5t169.5 -38.5q163 0 255 54t92 155q0 51 -45 80t-158 41l-137 14q-112 -18 -172 -71t-60 -131zM377 680q0 -71 35.5 -109.5t101.5 -38.5 q65 0 112.5 39t74 107t26.5 149q0 142 -133 142q-65 0 -114 -38.5t-76 -105t-27 -145.5z" /> +<glyph unicode="h" horiz-adv-x="1208" d="M47 0l330 1556h235l-57 -262q-27 -126 -73 -293l-19 -75h8q84 106 168.5 153t177.5 47q136 0 208.5 -77.5t72.5 -221.5q0 -76 -23 -174l-139 -653h-234l142 672q18 90 18 127q0 135 -129 135q-112 0 -209.5 -125t-142.5 -342l-98 -467h-236z" /> +<glyph unicode="i" horiz-adv-x="563" d="M47 0l236 1106h235l-235 -1106h-236zM330 1378q0 68 39 110t110 42q53 0 86 -26.5t33 -80.5q0 -71 -40 -112t-105 -41q-53 0 -88 26t-35 82z" /> +<glyph unicode="j" horiz-adv-x="563" d="M-262 -279q64 -20 117 -20q131 0 170 186l260 1219h233l-266 -1247q-38 -181 -127.5 -266t-237.5 -85q-90 0 -149 23v190zM332 1378q0 68 38 110t109 42q54 0 86.5 -26.5t32.5 -80.5q0 -71 -40 -112t-105 -41q-53 0 -87 25.5t-34 82.5z" /> +<glyph unicode="k" horiz-adv-x="1081" d="M47 0l330 1556h235q-135 -627 -159.5 -729.5t-59.5 -226.5h4l490 506h272l-483 -485l291 -621h-262l-209 471l-136 -96l-77 -375h-236z" /> +<glyph unicode="l" horiz-adv-x="563" d="M47 0l330 1556h235l-331 -1556h-234z" /> +<glyph unicode="m" horiz-adv-x="1819" d="M47 0l236 1106h184l-21 -205h9q148 225 352 225q220 0 254 -235h8q75 116 170.5 175.5t198.5 59.5q133 0 202.5 -76.5t69.5 -215.5q0 -64 -22 -181l-140 -653h-235l143 672q19 95 19 133q0 129 -121 129q-108 0 -201.5 -124t-136.5 -329l-101 -481h-235l143 672 q17 82 17 127q0 135 -117 135q-110 0 -203.5 -127t-138.5 -338l-98 -469h-236z" /> +<glyph unicode="n" horiz-adv-x="1208" d="M47 0l236 1106h184l-21 -205h9q83 118 171 171.5t191 53.5q134 0 207.5 -76t73.5 -216q0 -69 -23 -181l-137 -653h-236l142 672q18 90 18 131q0 131 -129 131q-72 0 -142 -57t-126 -164.5t-84 -243.5l-98 -469h-236z" /> +<glyph unicode="o" horiz-adv-x="1174" d="M94 408q0 199 71.5 365t200.5 258.5t298 92.5q195 0 305 -116t110 -316q0 -202 -73 -367.5t-200.5 -254t-293.5 -88.5q-192 0 -305 114.5t-113 311.5zM332 403q0 -111 49.5 -170t146.5 -59q90 0 162 68t112 190.5t40 269.5q0 107 -49 167.5t-140 60.5q-93 0 -166.5 -71.5 t-114 -194t-40.5 -261.5z" /> +<glyph unicode="p" horiz-adv-x="1200" d="M-55 -492l338 1598h184l-21 -188h9q157 208 344 208q143 0 224 -103t81 -286q0 -204 -70 -381.5t-190.5 -276.5t-265.5 -99q-181 0 -269 176h-10q-7 -97 -25 -185l-96 -463h-233zM369 373q0 -96 46.5 -149.5t131.5 -53.5t159 78.5t117 210t43 274.5q0 201 -155 201 q-81 0 -161 -79.5t-130.5 -210.5t-50.5 -271z" /> +<glyph unicode="q" horiz-adv-x="1198" d="M94 367q0 208 73 387t192.5 275.5t265.5 96.5q183 0 274 -178h10l64 158h178l-340 -1598h-233l75 349q12 56 43.5 180t38.5 141h-8q-84 -108 -164 -153t-170 -45q-139 0 -219 102.5t-80 284.5zM332 373q0 -203 160 -203q80 0 159 81t127.5 213t48.5 269q0 94 -45.5 147.5 t-126.5 53.5q-86 0 -160 -77.5t-118.5 -209.5t-44.5 -274z" /> +<glyph unicode="r" horiz-adv-x="836" d="M47 0l236 1106h184l-21 -205h9q83 120 166 172.5t176 52.5q62 0 108 -12l-51 -219q-54 14 -102 14q-126 0 -225 -113t-138 -296l-106 -500h-236z" /> +<glyph unicode="s" horiz-adv-x="922" d="M14 47v203q153 -90 312 -90q97 0 157 40t60 109q0 51 -34.5 87.5t-141.5 97.5q-125 67 -176.5 136.5t-51.5 164.5q0 155 107 243t289 88q196 0 346 -84l-76 -176q-140 76 -266 76q-73 0 -118.5 -33t-45.5 -92q0 -45 33 -80t135 -90q105 -59 149 -101t67 -91.5t23 -114.5 q0 -173 -118 -266.5t-328 -93.5q-190 0 -322 67z" /> +<glyph unicode="t" horiz-adv-x="752" d="M92 928l21 110l190 82l129 232h146l-52 -246h279l-39 -178h-277l-122 -572q-13 -55 -13 -92q0 -43 25 -68.5t76 -25.5q68 0 151 31v-178q-35 -17 -95 -30t-120 -13q-274 0 -274 247q0 57 16 131l121 570h-162z" /> +<glyph unicode="u" horiz-adv-x="1208" d="M111 274q0 63 12 124.5t24 123.5l123 584h236l-129 -610q-31 -141 -31 -193q0 -133 127 -133q72 0 143 57t126 162.5t85 247.5l99 469h233l-233 -1106h-185l21 205h-8q-82 -116 -171 -170.5t-192 -54.5q-134 0 -207 76t-73 218z" /> +<glyph unicode="v" horiz-adv-x="997" d="M100 1106h232l55 -598q14 -159 14 -297h7q28 74 70 165t65 132l311 598h250l-598 -1106h-275z" /> +<glyph unicode="w" horiz-adv-x="1540" d="M121 1106h221l13 -646q-2 -87 -11 -245h6q66 176 109 272l278 619h254l19 -604l1 -53l-3 -234h6q17 50 57 158.5t63.5 163.5t251.5 569h244l-518 -1106h-268l-19 627l-1 70l3 200q-25 -62 -51.5 -125t-345.5 -772h-262z" /> +<glyph unicode="x" horiz-adv-x="1032" d="M-86 0l475 569l-231 537h245l144 -373l287 373h274l-461 -549l248 -557h-246l-160 387l-305 -387h-270z" /> +<glyph unicode="y" horiz-adv-x="1004" d="M-170 -285q75 -16 125 -16q74 0 134 43.5t124 155.5l51 92l-164 1116h232l63 -531q9 -62 16 -174.5t7 -181.5h6q86 215 135 313l293 574h254l-688 -1280q-90 -165 -196 -241.5t-249 -76.5q-76 0 -143 19v188z" /> +<glyph unicode="z" horiz-adv-x="920" d="M-39 0l29 147l635 781h-439l39 178h705l-37 -170l-623 -758h486l-37 -178h-758z" /> +<glyph unicode="{" horiz-adv-x="721" d="M8 485l39 187q120 0 191.5 42.5t93.5 143.5l59 275q28 134 73 201.5t120 97.5t198 30h60l-41 -184q-96 0 -139.5 -34t-61.5 -116l-70 -309q-24 -108 -87 -170.5t-179 -79.5v-6q160 -45 160 -215q0 -38 -16 -121l-43 -194q-11 -48 -11 -74q0 -51 32.5 -74.5t109.5 -23.5 v-185h-39q-316 0 -316 236q0 61 17 133l45 201q14 65 14 98q0 141 -209 141z" /> +<glyph unicode="|" d="M498 -481v2033h178v-2033h-178z" /> +<glyph unicode="}" horiz-adv-x="721" d="M-88 -141q106 2 152.5 36.5t64.5 114.5l70 309q24 109 87 170t179 78v6q-158 48 -158 215q0 55 17 121l43 197q10 44 10 74q0 58 -43 78t-121 20l35 184h22q318 0 318 -235q0 -61 -17 -133l-45 -203q-14 -65 -14 -98q0 -142 209 -142l-39 -186q-121 0 -192 -42t-93 -142 l-63 -306q-34 -165 -123.5 -232t-269.5 -67h-29v183z" /> +<glyph unicode="~" d="M111 571v191q100 108 249 108q64 0 118.5 -12t146.5 -51q70 -30 115 -42.5t94 -12.5q50 0 112.5 31t120.5 89v-190q-103 -111 -250 -111q-63 0 -124 16.5t-138 49.5q-76 32 -119.5 43.5t-91.5 11.5q-51 0 -112 -31t-121 -90z" /> +<glyph unicode="¡" horiz-adv-x="557" d="M-45 -373l266 1018h174l-166 -1018h-274zM221 936q0 82 49 132t127 50q65 0 95 -35.5t30 -89.5q0 -80 -47 -130t-127 -50q-59 0 -93 31.5t-34 91.5z" /> +<glyph unicode="¢" d="M195 586q0 190 63.5 351t178 260.5t261.5 121.5l35 164h156l-37 -164q124 -12 221 -57l-69 -185q-125 53 -222 53q-99 0 -180 -71.5t-125.5 -194.5t-44.5 -266q0 -111 56 -171t155 -60q74 0 138.5 21.5t129.5 53.5v-194q-133 -69 -293 -74l-40 -194h-156l45 213 q-132 34 -202 134.5t-70 258.5z" /> +<glyph unicode="£" d="M-18 0l38 193q200 45 250 276l35 164h-196l36 172h197l61 299q38 185 153 282t300 97q188 0 352 -86l-88 -183q-143 74 -258 74q-185 0 -227 -205l-57 -278h333l-34 -172h-336l-33 -152q-21 -98 -68.5 -165t-130.5 -109h690l-45 -207h-972z" /> +<glyph unicode="¤" d="M141 1057l119 119l127 -127q102 61 207 61q108 0 207 -63l127 129l121 -117l-129 -129q61 -99 61 -207q0 -114 -61 -209l127 -125l-119 -119l-127 127q-95 -59 -207 -59q-120 0 -207 59l-127 -125l-117 119l127 125q-61 95 -61 207q0 110 61 205zM377 723 q0 -91 62.5 -154t154.5 -63q91 0 156 62t65 155t-65 156t-156 63q-92 0 -154.5 -64t-62.5 -155z" /> +<glyph unicode="¥" d="M106 244l33 155h273l30 148h-272l35 155h211l-199 760h232l145 -669l432 669h248l-518 -760h217l-35 -155h-274l-31 -148h274l-33 -155h-272l-53 -244h-221l51 244h-273z" /> +<glyph unicode="¦" d="M498 315h178v-796h-178v796zM498 758v794h178v-794h-178z" /> +<glyph unicode="§" horiz-adv-x="995" d="M39 53v187q152 -93 319 -93q116 0 174 40.5t58 111.5q0 43 -39 79.5t-141 84.5q-130 60 -189 131.5t-59 169.5q0 188 219 307q-47 32 -78 82t-31 115q0 138 111.5 220.5t296.5 82.5q178 0 332 -78l-68 -158q-62 29 -129.5 50.5t-144.5 21.5q-86 0 -134.5 -34.5 t-48.5 -94.5q0 -43 36.5 -76.5t148.5 -83.5q127 -56 186.5 -127.5t59.5 -167.5q0 -92 -52.5 -171t-160.5 -140q102 -76 102 -193q0 -157 -123 -245t-330 -88q-188 0 -315 67zM358 793q0 -61 46.5 -104.5t173.5 -100.5q62 36 99.5 90.5t37.5 114.5t-49.5 104.5t-155.5 89.5 q-69 -26 -110.5 -79t-41.5 -115z" /> +<glyph unicode="¨" horiz-adv-x="1135" d="M426 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM809 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="©" horiz-adv-x="1704" d="M131 731q0 200 100 375t275 276t377 101q199 0 373.5 -99t276 -275.5t101.5 -377.5q0 -199 -98.5 -373t-272.5 -276t-380 -102q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM254 731q0 -168 83 -312.5t229 -230.5t317 -86q173 0 319.5 87t227.5 231.5t81 310.5 q0 165 -82 310.5t-227.5 232t-318.5 86.5q-168 0 -314.5 -84.5t-230.5 -231t-84 -313.5zM502 727q0 216 113.5 340.5t312.5 124.5q138 0 266 -66l-68 -147q-106 55 -196 55q-113 0 -175.5 -76t-62.5 -231q0 -301 238 -301q47 0 112 16t109 35v-158q-117 -51 -240 -51 q-197 0 -303 123.5t-106 335.5z" /> +<glyph unicode="ª" horiz-adv-x="729" d="M160 1016q0 128 47 238.5t122.5 167.5t168.5 57q113 0 166 -103h6l39 90h118l-147 -684h-123l10 105h-4q-50 -62 -98 -89.5t-109 -27.5q-91 0 -143.5 66t-52.5 180zM319 1022q0 -125 93 -125q50 0 97.5 48t77 127.5t29.5 158.5q0 119 -102 119q-82 0 -138.5 -97.5 t-56.5 -230.5z" /> +<glyph unicode="«" horiz-adv-x="1055" d="M80 553v22l395 420l135 -118l-288 -332l153 -369l-178 -76zM520 530v25l385 434l137 -112l-280 -351l147 -350l-180 -76z" /> +<glyph unicode="¬" d="M117 631v180h936v-555h-179v375h-757z" /> +<glyph unicode="­" horiz-adv-x="649" d="M47 446l45 203h502l-45 -203h-502z" /> +<glyph unicode="®" horiz-adv-x="1704" d="M131 731q0 200 100 375t275 276t377 101q199 0 373.5 -99t276 -275.5t101.5 -377.5q0 -199 -98.5 -373t-272.5 -276t-380 -102q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM254 731q0 -168 83 -312.5t229 -230.5t317 -86q173 0 319.5 87t227.5 231.5t81 310.5 q0 165 -82 310.5t-227.5 232t-318.5 86.5q-168 0 -314.5 -84.5t-230.5 -231t-84 -313.5zM608 291v878h269q337 0 337 -262q0 -83 -45.5 -145t-130.5 -98l211 -373h-200l-172 325h-91v-325h-178zM786 760h72q84 0 129 36t45 99q0 73 -45.5 101t-128.5 28h-72v-264z" /> +<glyph unicode="¯" horiz-adv-x="903" d="M111 1556l39 166h911l-41 -166h-909z" /> +<glyph unicode="°" horiz-adv-x="877" d="M188 1153q0 136 97 233t233 97t232 -97t96 -233q0 -137 -96 -231.5t-232 -94.5q-88 0 -165 44t-121 119t-44 163zM340 1153q0 -70 52 -122t126 -52q72 0 124 52t52 122q0 74 -51.5 126t-124.5 52q-74 0 -126 -51.5t-52 -126.5z" /> +<glyph unicode="±" d="M117 0v180h936v-180h-936zM117 657v181h379v381h180v-381h377v-181h-377v-374h-180v374h-379z" /> +<glyph unicode="²" horiz-adv-x="745" d="M78 586l28 135l269 223q111 95 148.5 136t55 77t17.5 74q0 46 -28 72t-76 26q-91 0 -191 -80l-80 123q68 54 142.5 81.5t168.5 27.5q115 0 183.5 -60t68.5 -155q0 -69 -23.5 -124.5t-74 -110.5t-168.5 -146l-174 -142h371l-33 -157h-604z" /> +<glyph unicode="³" horiz-adv-x="745" d="M104 625v159q126 -71 248 -71q90 0 139.5 37t49.5 106q0 113 -146 113h-108l28 133h93q89 0 142.5 34t53.5 99q0 100 -117 100q-92 0 -188 -65l-68 121q126 90 291 90q124 0 193 -55.5t69 -153.5q0 -90 -54.5 -149t-158.5 -85v-4q78 -18 115 -67t37 -115 q0 -129 -99.5 -206t-269.5 -77q-138 0 -250 56z" /> +<glyph unicode="´" horiz-adv-x="1135" d="M508 1241v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="µ" horiz-adv-x="1221" d="M-55 -492l338 1598h235l-141 -670q-19 -84 -19 -129q0 -65 33 -101t96 -36q113 0 209.5 125.5t141.5 337.5l102 473h231l-235 -1106h-184l22 190h-10q-75 -111 -153 -160.5t-165 -49.5q-108 0 -155 81h-8q-9 -73 -39 -235l-66 -318h-233z" /> +<glyph unicode="¶" horiz-adv-x="1341" d="M172 1042q0 260 109 387t342 127h581v-1816h-139v1638h-188v-1638h-140v819q-62 -18 -145 -18q-216 0 -318 125t-102 376z" /> +<glyph unicode="·" horiz-adv-x="551" d="M150 692q0 83 47 132.5t131 49.5q56 0 89.5 -31.5t33.5 -92.5q0 -78 -47.5 -129.5t-124.5 -51.5q-66 0 -97.5 35.5t-31.5 87.5z" /> +<glyph unicode="¸" horiz-adv-x="420" d="M-188 -342q47 -14 96 -14q137 0 137 96q0 40 -35 61.5t-104 30.5l98 168h146l-50 -96q72 -25 104 -67t32 -101q0 -106 -82 -167t-224 -61q-64 0 -118 15v135z" /> +<glyph unicode="¹" horiz-adv-x="745" d="M193 1247l339 215h162l-186 -876h-191l99 461q17 79 57 217q-21 -20 -49.5 -43t-153.5 -103z" /> +<glyph unicode="º" horiz-adv-x="721" d="M164 1047q0 122 44 221.5t125.5 155t188.5 55.5q124 0 189 -71.5t65 -201.5q0 -126 -42 -225t-121 -155t-189 -56q-122 0 -191 73t-69 204zM326 1042q0 -141 112 -141q77 0 127.5 87.5t50.5 219.5q0 138 -106 138q-81 0 -132.5 -87.5t-51.5 -216.5z" /> +<glyph unicode="»" horiz-adv-x="1055" d="M10 211l281 348l-146 352l179 76l211 -432v-25l-385 -432zM444 211l287 330l-153 370l180 76l217 -455v-22l-397 -418z" /> +<glyph unicode="¼" horiz-adv-x="1661" d="M149 0l1085 1462h195l-1083 -1462h-197zM151 1247l339 215h162l-186 -876h-191l99 461q17 79 57 217q-21 -20 -49.5 -43t-153.5 -103zM775 177l26 137l477 569h197l-121 -563h123l-29 -143h-122l-39 -176h-183l39 176h-368zM973 320h199l52 221l34 129q-32 -51 -98 -131z " /> +<glyph unicode="½" horiz-adv-x="1661" d="M121 0l1085 1462h195l-1083 -1462h-197zM122 1247l339 215h162l-186 -876h-191l99 461q17 79 57 217q-21 -20 -49.5 -43t-153.5 -103zM860 1l28 135l269 223q111 95 148.5 136t55 77t17.5 74q0 46 -28 72t-76 26q-91 0 -191 -80l-80 123q68 54 142.5 81.5t168.5 27.5 q115 0 183.5 -60t68.5 -155q0 -69 -23.5 -124.5t-74 -110.5t-168.5 -146l-174 -142h371l-33 -157h-604z" /> +<glyph unicode="¾" horiz-adv-x="1683" d="M108 625v159q126 -71 248 -71q90 0 139.5 37t49.5 106q0 113 -146 113h-108l28 133h93q89 0 142.5 34t53.5 99q0 100 -117 100q-92 0 -188 -65l-68 121q126 90 291 90q124 0 193 -55.5t69 -153.5q0 -90 -54.5 -149t-158.5 -85v-4q78 -18 115 -67t37 -115 q0 -129 -99.5 -206t-269.5 -77q-138 0 -250 56zM291 0l1085 1462h195l-1083 -1462h-197zM881 177l26 137l477 569h197l-121 -563h123l-29 -143h-122l-39 -176h-183l39 176h-368zM1079 320h199l52 221l34 129q-32 -51 -98 -131z" /> +<glyph unicode="¿" horiz-adv-x="907" d="M-35 -68q0 120 64 219t231 216q93 64 141 122.5t70 153.5h197q-25 -146 -79.5 -231t-170.5 -168q-107 -79 -145.5 -118t-57 -79t-18.5 -88q0 -71 42 -114.5t123 -43.5q76 0 149.5 27.5t152.5 65.5l75 -177q-205 -112 -409 -112q-174 0 -269.5 85.5t-95.5 241.5zM465 934 q0 78 46.5 129t125.5 51q66 0 97.5 -34t31.5 -87q0 -85 -48 -134.5t-130 -49.5q-56 0 -89.5 32.5t-33.5 92.5z" /> +<glyph unicode="À" horiz-adv-x="1210" d="M-121 0l783 1464h274l166 -1464h-234l-41 406h-485l-209 -406h-254zM446 614h365q-40 416 -45.5 503.5t-5.5 139.5q-55 -139 -142 -307zM538 1886v21h245q47 -154 132 -303v-25h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="Á" horiz-adv-x="1210" d="M-121 0l783 1464h274l166 -1464h-234l-41 406h-485l-209 -406h-254zM446 614h365q-40 416 -45.5 503.5t-5.5 139.5q-55 -139 -142 -307zM707 1579v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="Â" horiz-adv-x="1210" d="M-121 0l783 1464h274l166 -1464h-234l-41 406h-485l-209 -406h-254zM444 1579v25q138 128 201 195.5t90 107.5h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164zM446 614h365q-40 416 -45.5 503.5t-5.5 139.5q-55 -139 -142 -307z" /> +<glyph unicode="Ã" horiz-adv-x="1210" d="M-121 0l783 1464h274l166 -1464h-234l-41 406h-485l-209 -406h-254zM441 1577q57 285 256 285q46 0 85 -17.5t72.5 -38t63.5 -38t59 -17.5q40 0 65 26.5t48 86.5h137q-66 -285 -260 -285q-45 0 -82.5 17t-71.5 37.5t-65.5 37.5t-63.5 17q-38 0 -63 -27.5t-43 -83.5h-137z M446 614h365q-40 416 -45.5 503.5t-5.5 139.5q-55 -139 -142 -307z" /> +<glyph unicode="Ä" horiz-adv-x="1210" d="M-121 0l783 1464h274l166 -1464h-234l-41 406h-485l-209 -406h-254zM446 614h365q-40 416 -45.5 503.5t-5.5 139.5q-55 -139 -142 -307zM518 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM901 1718 q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="Å" horiz-adv-x="1210" d="M-121 0l783 1464h274l166 -1464h-234l-41 406h-485l-209 -406h-254zM446 614h365q-40 416 -45.5 503.5t-5.5 139.5q-55 -139 -142 -307zM568 1573q0 103 65 164.5t168 61.5q104 0 171 -60.5t67 -163.5q0 -104 -66 -165.5t-172 -61.5t-169.5 61t-63.5 164zM697 1573 q0 -49 26.5 -76.5t77.5 -27.5q47 0 77 27.5t30 76.5q0 50 -30 78.5t-77 28.5q-45 0 -74.5 -28.5t-29.5 -78.5z" /> +<glyph unicode="Æ" horiz-adv-x="1753" d="M-121 0l930 1462h1020l-43 -205h-539l-84 -395h504l-43 -200h-502l-98 -459h539l-43 -203h-777l86 406h-432l-256 -406h-262zM528 614h344l138 643h-82z" /> +<glyph unicode="Ç" horiz-adv-x="1225" d="M135 545q0 260 105.5 483t281.5 339t402 116q217 0 389 -92l-94 -195q-63 34 -134 58t-161 24q-154 0 -275 -89t-193.5 -259.5t-72.5 -374.5q0 -180 82.5 -275.5t243.5 -95.5q141 0 329 68v-205q-180 -67 -374 -67q-248 0 -388.5 148.5t-140.5 416.5zM367 -342 q47 -14 96 -14q137 0 137 96q0 40 -35 61.5t-104 30.5l98 168h146l-50 -96q72 -25 104 -67t32 -101q0 -106 -82 -167t-224 -61q-64 0 -118 15v135z" /> +<glyph unicode="È" horiz-adv-x="1077" d="M70 0l309 1462h776l-43 -205h-539l-84 -395h502l-41 -203h-504l-96 -456h539l-43 -203h-776zM526 1886v21h245q47 -154 132 -303v-25h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="É" horiz-adv-x="1077" d="M70 0l309 1462h776l-43 -205h-539l-84 -395h502l-41 -203h-504l-96 -456h539l-43 -203h-776zM633 1579v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="Ê" horiz-adv-x="1077" d="M70 0l309 1462h776l-43 -205h-539l-84 -395h502l-41 -203h-504l-96 -456h539l-43 -203h-776zM417 1579v25q138 128 201 195.5t90 107.5h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="Ë" horiz-adv-x="1077" d="M70 0l309 1462h776l-43 -205h-539l-84 -395h502l-41 -203h-504l-96 -456h539l-43 -203h-776zM479 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM862 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5 q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="Ì" horiz-adv-x="608" d="M70 0l311 1462h235l-311 -1462h-235zM253 1886v21h245q47 -154 132 -303v-25h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="Í" horiz-adv-x="608" d="M70 0l311 1462h235l-311 -1462h-235zM415 1579v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="Î" horiz-adv-x="608" d="M70 0l311 1462h235l-311 -1462h-235zM160 1579v25q138 128 201 195.5t90 107.5h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="Ï" horiz-adv-x="608" d="M70 0l311 1462h235l-311 -1462h-235zM243 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM626 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="Ð" horiz-adv-x="1374" d="M53 623l45 200h144l137 639h369q271 0 417 -145t146 -424q0 -271 -100 -473t-291 -311t-449 -109h-401l129 623h-146zM348 201h135q177 0 309 86t202.5 242t70.5 356q0 184 -88 280.5t-256 96.5h-146l-94 -439h285l-45 -200h-283z" /> +<glyph unicode="Ñ" horiz-adv-x="1491" d="M68 0l309 1462h268l399 -1149h7q6 54 31 192.5t40 203.5l160 753h219l-309 -1462h-260l-410 1163h-6l-10 -69q-24 -149 -35.5 -212.5t-183.5 -881.5h-219zM582 1577q57 285 256 285q46 0 85 -17.5t72.5 -38t63.5 -38t59 -17.5q40 0 65 26.5t48 86.5h137 q-66 -285 -260 -285q-45 0 -82.5 17t-71.5 37.5t-65.5 37.5t-63.5 17q-38 0 -63 -27.5t-43 -83.5h-137z" /> +<glyph unicode="Ò" horiz-adv-x="1485" d="M135 543q0 267 98.5 487.5t269.5 337.5t388 117q251 0 390.5 -149t139.5 -414q0 -279 -95 -497t-261.5 -331.5t-386.5 -113.5q-259 0 -401 149.5t-142 413.5zM383 545q0 -173 81.5 -267t227.5 -94q138 0 248.5 95.5t172 265t61.5 375.5q0 170 -79 265t-223 95 q-138 0 -250 -96t-175.5 -266.5t-63.5 -372.5zM652 1886v21h245q47 -154 132 -303v-25h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="Ó" horiz-adv-x="1485" d="M135 543q0 267 98.5 487.5t269.5 337.5t388 117q251 0 390.5 -149t139.5 -414q0 -279 -95 -497t-261.5 -331.5t-386.5 -113.5q-259 0 -401 149.5t-142 413.5zM383 545q0 -173 81.5 -267t227.5 -94q138 0 248.5 95.5t172 265t61.5 375.5q0 170 -79 265t-223 95 q-138 0 -250 -96t-175.5 -266.5t-63.5 -372.5zM787 1579v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="Ô" horiz-adv-x="1485" d="M135 543q0 267 98.5 487.5t269.5 337.5t388 117q251 0 390.5 -149t139.5 -414q0 -279 -95 -497t-261.5 -331.5t-386.5 -113.5q-259 0 -401 149.5t-142 413.5zM383 545q0 -173 81.5 -267t227.5 -94q138 0 248.5 95.5t172 265t61.5 375.5q0 170 -79 265t-223 95 q-138 0 -250 -96t-175.5 -266.5t-63.5 -372.5zM555 1579v25q138 128 201 195.5t90 107.5h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="Õ" horiz-adv-x="1485" d="M135 543q0 267 98.5 487.5t269.5 337.5t388 117q251 0 390.5 -149t139.5 -414q0 -279 -95 -497t-261.5 -331.5t-386.5 -113.5q-259 0 -401 149.5t-142 413.5zM383 545q0 -173 81.5 -267t227.5 -94q138 0 248.5 95.5t172 265t61.5 375.5q0 170 -79 265t-223 95 q-138 0 -250 -96t-175.5 -266.5t-63.5 -372.5zM543 1577q57 285 256 285q46 0 85 -17.5t72.5 -38t63.5 -38t59 -17.5q40 0 65 26.5t48 86.5h137q-66 -285 -260 -285q-45 0 -82.5 17t-71.5 37.5t-65.5 37.5t-63.5 17q-38 0 -63 -27.5t-43 -83.5h-137z" /> +<glyph unicode="Ö" horiz-adv-x="1485" d="M135 543q0 267 98.5 487.5t269.5 337.5t388 117q251 0 390.5 -149t139.5 -414q0 -279 -95 -497t-261.5 -331.5t-386.5 -113.5q-259 0 -401 149.5t-142 413.5zM383 545q0 -173 81.5 -267t227.5 -94q138 0 248.5 95.5t172 265t61.5 375.5q0 170 -79 265t-223 95 q-138 0 -250 -96t-175.5 -266.5t-63.5 -372.5zM623 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM1006 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5 z" /> +<glyph unicode="×" d="M147 1034l125 125l312 -309l313 309l127 -123l-315 -313l311 -313l-123 -123l-313 309l-312 -307l-122 123l307 311z" /> +<glyph unicode="Ø" horiz-adv-x="1485" d="M109 18l129 160q-103 138 -103 365q0 267 98.5 487.5t269.5 337.5t388 117q189 0 317 -94l119 149l133 -104l-133 -166q94 -130 94 -348q0 -279 -95 -497t-261.5 -331.5t-386.5 -113.5q-193 0 -318 83l-118 -149zM377 545q0 -88 24 -164l668 836q-80 65 -197 65 q-141 0 -253 -93t-177 -265t-65 -379zM500 238q75 -56 194 -56q139 0 250.5 95.5t173.5 264.5t62 378q0 88 -19 143z" /> +<glyph unicode="Ù" horiz-adv-x="1399" d="M152 391q0 83 20 170l193 901h237l-192 -905q-21 -88 -21 -158q0 -102 59.5 -158.5t180.5 -56.5q145 0 230 80.5t124 261.5l199 936h237l-202 -956q-56 -267 -208 -396.5t-403 -129.5q-217 0 -335.5 106t-118.5 305zM619 1886v21h245q47 -154 132 -303v-25h-144 q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="Ú" horiz-adv-x="1399" d="M152 391q0 83 20 170l193 901h237l-192 -905q-21 -88 -21 -158q0 -102 59.5 -158.5t180.5 -56.5q145 0 230 80.5t124 261.5l199 936h237l-202 -956q-56 -267 -208 -396.5t-403 -129.5q-217 0 -335.5 106t-118.5 305zM791 1579v25q97 108 225 303h264v-19 q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="Û" horiz-adv-x="1399" d="M152 391q0 83 20 170l193 901h237l-192 -905q-21 -88 -21 -158q0 -102 59.5 -158.5t180.5 -56.5q145 0 230 80.5t124 261.5l199 936h237l-202 -956q-56 -267 -208 -396.5t-403 -129.5q-217 0 -335.5 106t-118.5 305zM536 1579v25q138 128 201 195.5t90 107.5h248 q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="Ü" horiz-adv-x="1399" d="M152 391q0 83 20 170l193 901h237l-192 -905q-21 -88 -21 -158q0 -102 59.5 -158.5t180.5 -56.5q145 0 230 80.5t124 261.5l199 936h237l-202 -956q-56 -267 -208 -396.5t-403 -129.5q-217 0 -335.5 106t-118.5 305zM602 1718q0 60 35 98t98 38q48 0 76.5 -23.5 t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM985 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="Ý" horiz-adv-x="1092" d="M186 1462h242l154 -669l432 669h266l-623 -913l-114 -549h-238l119 553zM610 1579v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="Þ" horiz-adv-x="1174" d="M70 0l309 1462h237l-51 -243h97q227 0 344.5 -101t117.5 -301q0 -243 -166.5 -377.5t-476.5 -134.5h-108l-66 -305h-237zM414 506h96q176 0 274.5 78.5t98.5 226.5q0 109 -59.5 158t-180.5 49h-121z" /> +<glyph unicode="ß" horiz-adv-x="1266" d="M-258 -276q61 -21 113 -21q65 0 106.5 43.5t63.5 147.5l262 1234q48 231 173 333t349 102q188 0 292.5 -80t104.5 -215q0 -169 -179 -299q-118 -87 -148.5 -119.5t-30.5 -67.5q0 -44 74 -101q107 -84 143 -127t55 -92.5t19 -109.5q0 -172 -116 -272t-314 -100 q-182 0 -283 65v201q126 -86 252 -86q105 0 164 44t59 124q0 48 -23.5 85t-111.5 107q-82 64 -121 121.5t-39 126.5q0 75 44.5 139t135.5 124q98 66 138.5 112t40.5 98q0 65 -47 101t-132 36q-210 0 -262 -239l-264 -1260q-42 -197 -134.5 -284t-242.5 -87q-69 0 -141 23 v193z" /> +<glyph unicode="à" horiz-adv-x="1186" d="M94 367q0 202 69.5 378t191.5 278.5t268 102.5q97 0 167 -45.5t109 -132.5h10l62 158h180l-236 -1106h-182l21 176h-6q-158 -196 -349 -196q-141 0 -223 101.5t-82 285.5zM332 373q0 -102 40.5 -152.5t112.5 -50.5q82 0 161 77.5t130 207.5t51 284q0 88 -47 141.5 t-123 53.5q-85 0 -160 -77t-120 -209.5t-45 -274.5zM470 1548v21h245q47 -154 132 -303v-25h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="á" horiz-adv-x="1186" d="M94 367q0 202 69.5 378t191.5 278.5t268 102.5q97 0 167 -45.5t109 -132.5h10l62 158h180l-236 -1106h-182l21 176h-6q-158 -196 -349 -196q-141 0 -223 101.5t-82 285.5zM332 373q0 -102 40.5 -152.5t112.5 -50.5q82 0 161 77.5t130 207.5t51 284q0 88 -47 141.5 t-123 53.5q-85 0 -160 -77t-120 -209.5t-45 -274.5zM598 1241v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="â" horiz-adv-x="1186" d="M94 367q0 202 69.5 378t191.5 278.5t268 102.5q97 0 167 -45.5t109 -132.5h10l62 158h180l-236 -1106h-182l21 176h-6q-158 -196 -349 -196q-141 0 -223 101.5t-82 285.5zM332 373q0 -102 40.5 -152.5t112.5 -50.5q82 0 161 77.5t130 207.5t51 284q0 88 -47 141.5 t-123 53.5q-85 0 -160 -77t-120 -209.5t-45 -274.5zM351 1241v25q138 128 201 195.5t90 107.5h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="ã" horiz-adv-x="1186" d="M94 367q0 202 69.5 378t191.5 278.5t268 102.5q97 0 167 -45.5t109 -132.5h10l62 158h180l-236 -1106h-182l21 176h-6q-158 -196 -349 -196q-141 0 -223 101.5t-82 285.5zM332 373q0 -102 40.5 -152.5t112.5 -50.5q82 0 161 77.5t130 207.5t51 284q0 88 -47 141.5 t-123 53.5q-85 0 -160 -77t-120 -209.5t-45 -274.5zM344 1239q57 285 256 285q46 0 85 -17.5t72.5 -38t63.5 -38t59 -17.5q40 0 65 26.5t48 86.5h137q-66 -285 -260 -285q-45 0 -82.5 17t-71.5 37.5t-65.5 37.5t-63.5 17q-38 0 -63 -27.5t-43 -83.5h-137z" /> +<glyph unicode="ä" horiz-adv-x="1186" d="M94 367q0 202 69.5 378t191.5 278.5t268 102.5q97 0 167 -45.5t109 -132.5h10l62 158h180l-236 -1106h-182l21 176h-6q-158 -196 -349 -196q-141 0 -223 101.5t-82 285.5zM332 373q0 -102 40.5 -152.5t112.5 -50.5q82 0 161 77.5t130 207.5t51 284q0 88 -47 141.5 t-123 53.5q-85 0 -160 -77t-120 -209.5t-45 -274.5zM425 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM808 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5 t-31 74.5z" /> +<glyph unicode="å" horiz-adv-x="1186" d="M94 367q0 202 69.5 378t191.5 278.5t268 102.5q97 0 167 -45.5t109 -132.5h10l62 158h180l-236 -1106h-182l21 176h-6q-158 -196 -349 -196q-141 0 -223 101.5t-82 285.5zM332 373q0 -102 40.5 -152.5t112.5 -50.5q82 0 161 77.5t130 207.5t51 284q0 88 -47 141.5 t-123 53.5q-85 0 -160 -77t-120 -209.5t-45 -274.5zM517 1464q0 103 65 164.5t168 61.5q104 0 171 -60.5t67 -163.5q0 -104 -66 -165.5t-172 -61.5t-169.5 61t-63.5 164zM646 1464q0 -49 26.5 -76.5t77.5 -27.5q47 0 77 27.5t30 76.5q0 50 -30 78.5t-77 28.5 q-45 0 -74.5 -28.5t-29.5 -78.5z" /> +<glyph unicode="æ" horiz-adv-x="1726" d="M94 367q0 201 69 378t188.5 279t260.5 102q88 0 152 -43.5t108 -134.5h9l63 158h148l-25 -117q51 63 131 100t180 37q140 0 220.5 -76.5t80.5 -201.5q0 -182 -166.5 -284.5t-474.5 -102.5h-45l-4 -60q0 -117 60.5 -177t175.5 -60q125 0 305 84v-189q-175 -79 -344 -79 q-222 0 -305 137l-23 -117h-151l20 176h-8q-85 -106 -165.5 -151t-174.5 -45q-134 0 -209.5 103t-75.5 284zM332 373q0 -105 37 -154t96 -49q85 0 162.5 80.5t125.5 215.5t48 267q0 91 -38.5 146t-113.5 55q-85 0 -159.5 -80t-116 -211t-41.5 -270zM1022 633h31 q187 0 293 53.5t106 149.5q0 58 -34 84t-85 26q-103 0 -188.5 -86t-122.5 -227z" /> +<glyph unicode="ç" horiz-adv-x="954" d="M94 389q0 207 73.5 376.5t206.5 265t302 95.5q164 0 297 -61l-70 -184q-122 53 -221 53q-150 0 -250 -153.5t-100 -379.5q0 -111 56 -171t155 -60q74 0 138.5 22t129.5 54v-195q-140 -71 -305 -71q-196 0 -304 106t-108 303zM197 -342q47 -14 96 -14q137 0 137 96 q0 40 -35 61.5t-104 30.5l98 168h146l-50 -96q72 -25 104 -67t32 -101q0 -106 -82 -167t-224 -61q-64 0 -118 15v135z" /> +<glyph unicode="è" horiz-adv-x="1075" d="M94 401q0 198 77.5 368.5t210 263.5t296.5 93q161 0 250.5 -72.5t89.5 -205.5q0 -182 -166.5 -284.5t-474.5 -102.5h-43l-2 -31v-29q0 -111 56.5 -174t168.5 -63q72 0 143 19t168 65v-187q-96 -44 -176.5 -62.5t-179.5 -18.5q-197 0 -307.5 111t-110.5 310zM362 633h29 q188 0 294 53.5t106 151.5q0 51 -32 79.5t-95 28.5q-96 0 -180.5 -86t-121.5 -227zM436 1548v21h245q47 -154 132 -303v-25h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="é" horiz-adv-x="1075" d="M94 401q0 198 77.5 368.5t210 263.5t296.5 93q161 0 250.5 -72.5t89.5 -205.5q0 -182 -166.5 -284.5t-474.5 -102.5h-43l-2 -31v-29q0 -111 56.5 -174t168.5 -63q72 0 143 19t168 65v-187q-96 -44 -176.5 -62.5t-179.5 -18.5q-197 0 -307.5 111t-110.5 310zM362 633h29 q188 0 294 53.5t106 151.5q0 51 -32 79.5t-95 28.5q-96 0 -180.5 -86t-121.5 -227zM557 1241v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="ê" horiz-adv-x="1075" d="M94 401q0 198 77.5 368.5t210 263.5t296.5 93q161 0 250.5 -72.5t89.5 -205.5q0 -182 -166.5 -284.5t-474.5 -102.5h-43l-2 -31v-29q0 -111 56.5 -174t168.5 -63q72 0 143 19t168 65v-187q-96 -44 -176.5 -62.5t-179.5 -18.5q-197 0 -307.5 111t-110.5 310zM320 1241v25 q138 128 201 195.5t90 107.5h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164zM362 633h29q188 0 294 53.5t106 151.5q0 51 -32 79.5t-95 28.5q-96 0 -180.5 -86t-121.5 -227z" /> +<glyph unicode="ë" horiz-adv-x="1075" d="M94 401q0 198 77.5 368.5t210 263.5t296.5 93q161 0 250.5 -72.5t89.5 -205.5q0 -182 -166.5 -284.5t-474.5 -102.5h-43l-2 -31v-29q0 -111 56.5 -174t168.5 -63q72 0 143 19t168 65v-187q-96 -44 -176.5 -62.5t-179.5 -18.5q-197 0 -307.5 111t-110.5 310zM362 633h29 q188 0 294 53.5t106 151.5q0 51 -32 79.5t-95 28.5q-96 0 -180.5 -86t-121.5 -227zM388 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM771 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102 t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="ì" horiz-adv-x="563" d="M47 0l236 1106h235l-235 -1106h-236zM159 1548v21h245q47 -154 132 -303v-25h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="í" horiz-adv-x="563" d="M47 0l236 1106h235l-235 -1106h-236zM308 1241v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="î" horiz-adv-x="563" d="M47 0l236 1106h235l-235 -1106h-236zM64 1241v25q138 128 201 195.5t90 107.5h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="ï" horiz-adv-x="563" d="M47 0l236 1106h235l-235 -1106h-236zM142 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM525 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="ð" horiz-adv-x="1174" d="M80 389q0 162 65.5 299t184.5 215t266 78q96 0 168 -38.5t113 -108.5h6q-10 243 -133 383l-250 -142l-72 129l219 121q-44 41 -135 96l106 152q129 -72 209 -146l250 138l70 -127l-217 -121q155 -205 155 -512q0 -255 -73 -444.5t-204 -285t-312 -95.5q-197 0 -306.5 107 t-109.5 302zM317 377q0 -104 49 -159.5t142 -55.5q92 0 161.5 59.5t108.5 159t39 205.5q0 97 -52 155t-144 58q-91 0 -160.5 -56t-106.5 -153.5t-37 -212.5z" /> +<glyph unicode="ñ" horiz-adv-x="1208" d="M47 0l236 1106h184l-21 -205h9q83 118 171 171.5t191 53.5q134 0 207.5 -76t73.5 -216q0 -69 -23 -181l-137 -653h-236l142 672q18 90 18 131q0 131 -129 131q-72 0 -142 -57t-126 -164.5t-84 -243.5l-98 -469h-236zM363 1239q57 285 256 285q46 0 85 -17.5t72.5 -38 t63.5 -38t59 -17.5q40 0 65 26.5t48 86.5h137q-66 -285 -260 -285q-45 0 -82.5 17t-71.5 37.5t-65.5 37.5t-63.5 17q-38 0 -63 -27.5t-43 -83.5h-137z" /> +<glyph unicode="ò" horiz-adv-x="1174" d="M94 408q0 199 71.5 365t200.5 258.5t298 92.5q195 0 305 -116t110 -316q0 -202 -73 -367.5t-200.5 -254t-293.5 -88.5q-192 0 -305 114.5t-113 311.5zM332 403q0 -111 49.5 -170t146.5 -59q90 0 162 68t112 190.5t40 269.5q0 107 -49 167.5t-140 60.5q-93 0 -166.5 -71.5 t-114 -194t-40.5 -261.5zM444 1548v21h245q47 -154 132 -303v-25h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="ó" horiz-adv-x="1174" d="M94 408q0 199 71.5 365t200.5 258.5t298 92.5q195 0 305 -116t110 -316q0 -202 -73 -367.5t-200.5 -254t-293.5 -88.5q-192 0 -305 114.5t-113 311.5zM332 403q0 -111 49.5 -170t146.5 -59q90 0 162 68t112 190.5t40 269.5q0 107 -49 167.5t-140 60.5q-93 0 -166.5 -71.5 t-114 -194t-40.5 -261.5zM580 1241v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="ô" horiz-adv-x="1174" d="M94 408q0 199 71.5 365t200.5 258.5t298 92.5q195 0 305 -116t110 -316q0 -202 -73 -367.5t-200.5 -254t-293.5 -88.5q-192 0 -305 114.5t-113 311.5zM332 403q0 -111 49.5 -170t146.5 -59q90 0 162 68t112 190.5t40 269.5q0 107 -49 167.5t-140 60.5q-93 0 -166.5 -71.5 t-114 -194t-40.5 -261.5zM341 1241v25q138 128 201 195.5t90 107.5h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="õ" horiz-adv-x="1174" d="M94 408q0 199 71.5 365t200.5 258.5t298 92.5q195 0 305 -116t110 -316q0 -202 -73 -367.5t-200.5 -254t-293.5 -88.5q-192 0 -305 114.5t-113 311.5zM328 1239q57 285 256 285q46 0 85 -17.5t72.5 -38t63.5 -38t59 -17.5q40 0 65 26.5t48 86.5h137q-66 -285 -260 -285 q-45 0 -82.5 17t-71.5 37.5t-65.5 37.5t-63.5 17q-38 0 -63 -27.5t-43 -83.5h-137zM332 403q0 -111 49.5 -170t146.5 -59q90 0 162 68t112 190.5t40 269.5q0 107 -49 167.5t-140 60.5q-93 0 -166.5 -71.5t-114 -194t-40.5 -261.5z" /> +<glyph unicode="ö" horiz-adv-x="1174" d="M94 408q0 199 71.5 365t200.5 258.5t298 92.5q195 0 305 -116t110 -316q0 -202 -73 -367.5t-200.5 -254t-293.5 -88.5q-192 0 -305 114.5t-113 311.5zM332 403q0 -111 49.5 -170t146.5 -59q90 0 162 68t112 190.5t40 269.5q0 107 -49 167.5t-140 60.5q-93 0 -166.5 -71.5 t-114 -194t-40.5 -261.5zM409 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM792 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="÷" d="M117 631v180h936v-180h-936zM459 373q0 64 31.5 99.5t93.5 35.5t94.5 -36t32.5 -99q0 -64 -34.5 -100.5t-92.5 -36.5t-91.5 35.5t-33.5 101.5zM459 1071q0 64 31.5 99.5t93.5 35.5t94.5 -36t32.5 -99q0 -64 -34.5 -100.5t-92.5 -36.5t-91.5 35.5t-33.5 101.5z" /> +<glyph unicode="ø" horiz-adv-x="1174" d="M51 6l115 141q-70 104 -70 261q0 200 70.5 365t199.5 258t298 93q136 0 239 -61l86 108l125 -96l-100 -117q63 -100 63 -258q0 -208 -74 -376t-200.5 -255t-288.5 -87q-137 0 -235 59l-105 -131zM324 426q0 -39 8 -74l442 549q-45 35 -121 35q-141 0 -235 -145.5 t-94 -364.5zM408 201q41 -33 120 -33q89 0 163 66.5t116.5 184t42.5 257.5q0 45 -6 67z" /> +<glyph unicode="ù" horiz-adv-x="1208" d="M111 274q0 63 12 124.5t24 123.5l123 584h236l-129 -610q-31 -141 -31 -193q0 -133 127 -133q72 0 143 57t126 162.5t85 247.5l99 469h233l-233 -1106h-185l21 205h-8q-82 -116 -171 -170.5t-192 -54.5q-134 0 -207 76t-73 218zM446 1548v21h245q47 -154 132 -303v-25 h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="ú" horiz-adv-x="1208" d="M111 274q0 63 12 124.5t24 123.5l123 584h236l-129 -610q-31 -141 -31 -193q0 -133 127 -133q72 0 143 57t126 162.5t85 247.5l99 469h233l-233 -1106h-185l21 205h-8q-82 -116 -171 -170.5t-192 -54.5q-134 0 -207 76t-73 218zM623 1241v25q97 108 225 303h264v-19 q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="û" horiz-adv-x="1208" d="M111 274q0 63 12 124.5t24 123.5l123 584h236l-129 -610q-31 -141 -31 -193q0 -133 127 -133q72 0 143 57t126 162.5t85 247.5l99 469h233l-233 -1106h-185l21 205h-8q-82 -116 -171 -170.5t-192 -54.5q-134 0 -207 76t-73 218zM370 1241v25q138 128 201 195.5t90 107.5 h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="ü" horiz-adv-x="1208" d="M111 274q0 63 12 124.5t24 123.5l123 584h236l-129 -610q-31 -141 -31 -193q0 -133 127 -133q72 0 143 57t126 162.5t85 247.5l99 469h233l-233 -1106h-185l21 205h-8q-82 -116 -171 -170.5t-192 -54.5q-134 0 -207 76t-73 218zM432 1380q0 60 35 98t98 38 q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM815 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="ý" horiz-adv-x="1004" d="M-170 -285q75 -16 125 -16q74 0 134 43.5t124 155.5l51 92l-164 1116h232l63 -531q9 -62 16 -174.5t7 -181.5h6q86 215 135 313l293 574h254l-688 -1280q-90 -165 -196 -241.5t-249 -76.5q-76 0 -143 19v188zM501 1241v25q97 108 225 303h264v-19q-54 -66 -158 -161.5 t-175 -147.5h-156z" /> +<glyph unicode="þ" horiz-adv-x="1200" d="M-55 -492l432 2048h235q-48 -223 -73 -339t-76 -291h8q155 200 328 200q144 0 224.5 -102t80.5 -287q0 -204 -68 -381.5t-184.5 -276.5t-265.5 -99q-94 0 -165 45.5t-114 130.5h-8q-7 -91 -25 -185l-96 -463h-233zM369 373q0 -98 46 -150.5t132 -52.5t159.5 77t116.5 209 t43 277q0 100 -41 150.5t-118 50.5q-84 0 -163 -81t-127 -213.5t-48 -266.5z" /> +<glyph unicode="ÿ" horiz-adv-x="1004" d="M-170 -285q75 -16 125 -16q74 0 134 43.5t124 155.5l51 92l-164 1116h232l63 -531q9 -62 16 -174.5t7 -181.5h6q86 215 135 313l293 574h254l-688 -1280q-90 -165 -196 -241.5t-249 -76.5q-76 0 -143 19v188zM323 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5 q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM706 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="Œ" horiz-adv-x="1798" d="M135 543q0 267 98.5 487.5t269.5 337.5t388 117q145 0 223 -23h760l-43 -205h-539l-84 -395h504l-43 -200h-504l-96 -459h539l-43 -203h-717q-84 -20 -170 -20q-259 0 -401 149.5t-142 413.5zM383 545q0 -173 81.5 -267t227.5 -94q74 0 139 27l222 1038q-68 31 -181 31 q-138 0 -250 -96t-175.5 -266.5t-63.5 -372.5z" /> +<glyph unicode="œ" horiz-adv-x="1788" d="M94 410q0 206 73.5 372.5t201 254t293.5 87.5q237 0 335 -192q73 91 174 142.5t226 51.5q159 0 246.5 -74.5t87.5 -203.5q0 -183 -165.5 -285t-471.5 -102h-47l-3 -60q0 -111 56.5 -174t169.5 -63q69 0 134.5 17.5t176.5 66.5v-189q-91 -43 -175 -61t-181 -18 q-120 0 -212.5 46t-140.5 138q-137 -182 -374 -182q-186 0 -295 115.5t-109 312.5zM332 412q0 -116 48.5 -177t139.5 -61q143 0 229.5 146.5t86.5 381.5q0 111 -49.5 169.5t-139.5 58.5q-87 0 -157.5 -64t-114 -186.5t-43.5 -267.5zM1073 633h31q189 0 294 54t105 155 q0 48 -30 76t-87 28q-105 0 -192 -85.5t-121 -227.5z" /> +<glyph unicode="Ÿ" horiz-adv-x="1092" d="M186 1462h242l154 -669l432 669h266l-623 -913l-114 -549h-238l119 553zM440 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM823 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102 t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="ˆ" horiz-adv-x="1135" d="M354 1241v25q138 128 201 195.5t90 107.5h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="˜" horiz-adv-x="1135" d="M326 1239q57 285 256 285q46 0 85 -17.5t72.5 -38t63.5 -38t59 -17.5q40 0 65 26.5t48 86.5h137q-66 -285 -260 -285q-45 0 -82.5 17t-71.5 37.5t-65.5 37.5t-63.5 17q-38 0 -63 -27.5t-43 -83.5h-137z" /> +<glyph unicode=" " horiz-adv-x="953" /> +<glyph unicode=" " horiz-adv-x="1907" /> +<glyph unicode=" " horiz-adv-x="953" /> +<glyph unicode=" " horiz-adv-x="1907" /> +<glyph unicode=" " horiz-adv-x="635" /> +<glyph unicode=" " horiz-adv-x="476" /> +<glyph unicode=" " horiz-adv-x="317" /> +<glyph unicode=" " horiz-adv-x="317" /> +<glyph unicode=" " horiz-adv-x="238" /> +<glyph unicode=" " horiz-adv-x="381" /> +<glyph unicode=" " horiz-adv-x="105" /> +<glyph unicode="‐" horiz-adv-x="649" d="M47 446l45 203h502l-45 -203h-502z" /> +<glyph unicode="‑" horiz-adv-x="649" d="M47 446l45 203h502l-45 -203h-502z" /> +<glyph unicode="‒" horiz-adv-x="649" d="M47 446l45 203h502l-45 -203h-502z" /> +<glyph unicode="–" horiz-adv-x="983" d="M47 453l43 194h838l-43 -194h-838z" /> +<glyph unicode="—" horiz-adv-x="1966" d="M47 453l43 194h1821l-43 -194h-1821z" /> +<glyph unicode="‘" horiz-adv-x="393" d="M119 983q34 76 106.5 209t159.5 270h176q-122 -286 -199 -501h-237z" /> +<glyph unicode="’" horiz-adv-x="393" d="M115 961q43 95 106 255t92 246h238l8 -22q-37 -83 -110.5 -217.5t-155.5 -261.5h-178z" /> +<glyph unicode="‚" horiz-adv-x="530" d="M-102 -264q105 238 200 502h236l8 -23q-108 -233 -266 -479h-178z" /> +<glyph unicode="“" horiz-adv-x="803" d="M119 983q34 76 106.5 209t159.5 270h176q-122 -286 -199 -501h-237zM526 983q84 190 267 479h176q-122 -286 -199 -501h-235z" /> +<glyph unicode="”" horiz-adv-x="803" d="M115 961q43 95 106 255t92 246h238l8 -22q-37 -83 -110.5 -217.5t-155.5 -261.5h-178zM522 961q51 114 109 261t90 240h237l9 -22q-98 -220 -269 -479h-176z" /> +<glyph unicode="„" horiz-adv-x="938" d="M-102 -264q105 238 200 502h236l8 -23q-108 -233 -266 -479h-178zM307 -264q120 281 199 502h235l9 -23q-92 -206 -267 -479h-176z" /> +<glyph unicode="•" horiz-adv-x="756" d="M152 684q0 156 83.5 252t223.5 96q100 0 158.5 -54.5t58.5 -168.5q0 -156 -82 -252t-227 -96q-102 0 -158.5 57.5t-56.5 165.5z" /> +<glyph unicode="…" horiz-adv-x="1634" d="M293 94q0 83 47 132.5t131 49.5q56 0 89.5 -31.5t33.5 -92.5q0 -78 -47.5 -129.5t-124.5 -51.5q-66 0 -97.5 35.5t-31.5 87.5zM594 94q0 83 47 132.5t131 49.5q56 0 89.5 -31.5t33.5 -92.5q0 -78 -47.5 -129.5t-124.5 -51.5q-66 0 -97.5 35.5t-31.5 87.5zM834 94 q0 83 47 132.5t131 49.5q56 0 89.5 -31.5t33.5 -92.5q0 -78 -47.5 -129.5t-124.5 -51.5q-66 0 -97.5 35.5t-31.5 87.5z" /> +<glyph unicode=" " horiz-adv-x="381" /> +<glyph unicode="‹" horiz-adv-x="621" d="M80 549v24l395 422l135 -118l-288 -334l153 -367l-178 -76z" /> +<glyph unicode="›" horiz-adv-x="621" d="M10 211l289 334l-154 366l179 76l217 -448v-25l-396 -422z" /> +<glyph unicode=" " horiz-adv-x="476" /> +<glyph unicode="€" d="M51 492l33 155h139q15 95 27 139h-137l32 154h148q92 260 255.5 401.5t371.5 141.5q88 0 164.5 -22t156.5 -77l-102 -180q-54 34 -107 56t-119 22q-118 0 -214.5 -87t-161.5 -255h387l-33 -154h-402q-18 -67 -28 -139h340l-33 -155h-319q0 -161 60.5 -234.5t195.5 -73.5 q120 0 258 60v-203q-129 -61 -306 -61q-216 0 -330 130t-114 382h-162z" /> +<glyph unicode="™" horiz-adv-x="1534" d="M113 1335v127h540v-127h-198v-594h-146v594h-196zM709 741v721h215l170 -534l182 534h205v-721h-146v418l4 121h-6l-184 -539h-119l-178 539h-6l4 -115v-424h-141z" /> +<glyph unicode="" horiz-adv-x="1105" d="M0 0v1105h1105v-1105h-1105z" /> +</font> +</defs></svg> \ No newline at end of file diff --git a/refs/pull/405/merge/_static/fonts/opensans-semibolditalic-webfont.ttf b/refs/pull/405/merge/_static/fonts/opensans-semibolditalic-webfont.ttf new file mode 100644 index 00000000..a48ee420 Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/opensans-semibolditalic-webfont.ttf differ diff --git a/refs/pull/405/merge/_static/fonts/opensans-semibolditalic-webfont.woff b/refs/pull/405/merge/_static/fonts/opensans-semibolditalic-webfont.woff new file mode 100644 index 00000000..e30d1f64 Binary files /dev/null and b/refs/pull/405/merge/_static/fonts/opensans-semibolditalic-webfont.woff differ diff --git a/refs/pull/405/merge/_static/fonts/stylesheet.css b/refs/pull/405/merge/_static/fonts/stylesheet.css new file mode 100644 index 00000000..648f40e3 --- /dev/null +++ b/refs/pull/405/merge/_static/fonts/stylesheet.css @@ -0,0 +1,105 @@ +/* Generated by Font Squirrel (http://www.fontsquirrel.com) on June 8, 2012 */ + + + +@font-face { + font-family: 'Open Sans Italic'; + src: url('opensans-italic-webfont.eot'); + src: url('opensans-italic-webfont.eot?#iefix') format('embedded-opentype'), + url('opensans-italic-webfont.woff') format('woff'), + url('opensans-italic-webfont.ttf') format('truetype'), + url('opensans-italic-webfont.svg#OpenSansItalic') format('svg'); + font-weight: normal; + font-style: normal; + +} + + + + +@font-face { + font-family: 'Open Sans'; + src: url('opensans-regular-webfont.eot'); + src: url('opensans-regular-webfont.eot?#iefix') format('embedded-opentype'), + url('opensans-regular-webfont.woff') format('woff'), + url('opensans-regular-webfont.ttf') format('truetype'), + url('opensans-regular-webfont.svg#OpenSansRegular') format('svg'); + font-weight: normal; + font-style: normal; + +} + + + + +@font-face { + font-family: 'Open Sans Semibold'; + src: url('opensans-semibold-webfont.eot'); + src: url('opensans-semibold-webfont.eot?#iefix') format('embedded-opentype'), + url('opensans-semibold-webfont.woff') format('woff'), + url('opensans-semibold-webfont.ttf') format('truetype'), + url('opensans-semibold-webfont.svg#OpenSansSemiboldRegular') format('svg'); + font-weight: normal; + font-style: normal; + +} + + + + +@font-face { + font-family: 'Open Sans Semibold Italic'; + src: url('opensans-semibolditalic-webfont.eot'); + src: url('opensans-semibolditalic-webfont.eot?#iefix') format('embedded-opentype'), + url('opensans-semibolditalic-webfont.woff') format('woff'), + url('opensans-semibolditalic-webfont.ttf') format('truetype'), + url('opensans-semibolditalic-webfont.svg#OpenSansSemiboldItalic') format('svg'); + font-weight: normal; + font-style: normal; + +} + + + + +@font-face { + font-family: 'Droid Sans Mono'; + src: url('droidsansmono-webfont.eot'); + src: url('droidsansmono-webfont.eot?#iefix') format('embedded-opentype'), + url('droidsansmono-webfont.woff') format('woff'), + url('droidsansmono-webfont.ttf') format('truetype'), + url('droidsansmono-webfont.svg#DroidSansMonoRegular') format('svg'); + font-weight: normal; + font-style: normal; + +} + + + + +@font-face { + font-family: 'Open Sans Light'; + src: url('opensans-light-webfont.eot'); + src: url('opensans-light-webfont.eot?#iefix') format('embedded-opentype'), + url('opensans-light-webfont.woff') format('woff'), + url('opensans-light-webfont.ttf') format('truetype'), + url('opensans-light-webfont.svg#OpenSansLightRegular') format('svg'); + font-weight: normal; + font-style: normal; + +} + + + + +@font-face { + font-family: 'Open Sans Light Italic'; + src: url('opensans-lightitalic-webfont.eot'); + src: url('opensans-lightitalic-webfont.eot?#iefix') format('embedded-opentype'), + url('opensans-lightitalic-webfont.woff') format('woff'), + url('opensans-lightitalic-webfont.ttf') format('truetype'), + url('opensans-lightitalic-webfont.svg#OpenSansLightItalic') format('svg'); + font-weight: normal; + font-style: normal; + +} \ No newline at end of file diff --git a/refs/pull/405/merge/_static/init.js b/refs/pull/405/merge/_static/init.js new file mode 100644 index 00000000..6b436ebd --- /dev/null +++ b/refs/pull/405/merge/_static/init.js @@ -0,0 +1,2 @@ +SlideSync.init(SlideDeck); +SlideController.init(SlideSync); diff --git a/refs/pull/405/merge/_static/jquery-3.2.1.js b/refs/pull/405/merge/_static/jquery-3.2.1.js new file mode 100644 index 00000000..d2d8ca47 --- /dev/null +++ b/refs/pull/405/merge/_static/jquery-3.2.1.js @@ -0,0 +1,10253 @@ +/*! + * jQuery JavaScript Library v3.2.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2017-03-20T18:59Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var document = window.document; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + + + + function DOMEval( code, doc ) { + doc = doc || document; + + var script = doc.createElement( "script" ); + + script.text = code; + doc.head.appendChild( script ).parentNode.removeChild( script ); + } +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.2.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && Array.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + + // As of jQuery 3.0, isNumeric is limited to + // strings and numbers (primitives or objects) + // that can be coerced to finite numbers (gh-2662) + var type = jQuery.type( obj ); + return ( type === "number" || type === "string" ) && + + // parseFloat NaNs numeric-cast false positives ("") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + !isNaN( obj - parseFloat( obj ) ); + }, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE <=9 - 11, Edge 12 - 13 + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.3 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-08-08 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true && ("form" in elem || "label" in elem); + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + disabledAncestor( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( preferredDoc !== document && + (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( el ) { + el.className = "i"; + return !el.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( el ) { + el.appendChild( document.createComment("") ); + return !el.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID filter and find + if ( support.getById ) { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( (elem = elems[i++]) ) { + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( el ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" + + "<select id='" + expando + "-\r\\' msallowcapture=''>" + + "<option selected=''></option></select>"; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( el ) { + el.innerHTML = "<a href='' disabled='disabled'></a>" + + "<select disabled='disabled'><option/></select>"; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll(":enabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll(":disabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( el ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return (sel + "").replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( (oldCache = uniqueCache[ key ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( el ) { + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( el ) { + el.innerHTML = "<a href='#'></a>"; + return el.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( el ) { + el.innerHTML = "<input/>"; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( el ) { + return el.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Simple selector that can be filtered directly, removing non-Elements + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + // Complex selector, compare the two sets, removing non-Elements + qualifier = jQuery.filter( qualifier, elements ); + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; + } ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over <tag> to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( nodeName( elem, "iframe" ) ) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( jQuery.isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( jQuery.isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ jQuery.camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ jQuery.camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( jQuery.camelCase ); + } else { + key = jQuery.camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + jQuery.contains( elem.ownerDocument, elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + +var swap = function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, + scale = 1, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + do { + + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + initialInUnit = initialInUnit / scale; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // Break the loop if scale is unchanged or perfect, or if we've just had enough. + } while ( + scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations + ); + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); + +var rscriptType = ( /^$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE <=9 only + option: [ 1, "<select multiple='multiple'>", "</select>" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting <tbody> or other required elements. + thead: [ 1, "<table>", "</table>" ], + col: [ 2, "<table><colgroup>", "</colgroup></table>" ], + tr: [ 2, "<table><tbody>", "</tbody></table>" ], + td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = "<textarea>x</textarea>"; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG <use> instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: jQuery.isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /<script|<style|<link/i, + + // checked="checked" or checked + rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, + rscriptTypeMasked = /^true\/(.*)/, + rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( ">tbody", elem )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1></$2>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rmargin = ( /^margin/ ); + +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + div.style.cssText = + "box-sizing:border-box;" + + "position:relative;display:block;" + + "margin:auto;border:1px;padding:1px;" + + "top:1%;width:50%"; + div.innerHTML = ""; + documentElement.appendChild( container ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = divStyle.marginLeft === "2px"; + boxSizingReliableVal = divStyle.width === "4px"; + + // Support: Android 4.0 - 4.3 only + // Some styles come back with percentage values, even though they shouldn't + div.style.marginRight = "50%"; + pixelMarginRightVal = divStyle.marginRight === "4px"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + + "padding:0;margin-top:1px;position:absolute"; + container.appendChild( div ); + + jQuery.extend( support, { + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelMarginRight: function() { + computeStyleTests(); + return pixelMarginRightVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i, + val = 0; + + // If we already have the right measurement, avoid augmentation + if ( extra === ( isBorderBox ? "border" : "content" ) ) { + i = 4; + + // Otherwise initialize for horizontal or vertical properties + } else { + i = name === "width" ? 1 : 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // At this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + + // At this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // At this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with computed style + var valueIsBorderBox, + styles = getStyles( elem ), + val = curCSS( elem, name, styles ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test( val ) ) { + return val; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && + ( support.boxSizingReliable() || val === elem.style[ name ] ); + + // Fall back to offsetWidth/Height when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + if ( val === "auto" ) { + val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; + } + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + + // Use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + "float": "cssFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + } ) : + getWidthOrHeight( elem, name, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = extra && getStyles( elem ), + subtract = extra && augmentWidthOrHeight( + elem, + name, + extra, + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + styles + ); + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ name ] = value; + value = jQuery.css( elem, name ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = jQuery.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 13 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( jQuery.isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + jQuery.proxy( result.stop, result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = jQuery.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value; + + if ( typeof stateVal === "boolean" && type === "string" ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( jQuery.isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( type === "string" ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = value.match( rnothtmlwhite ) || []; + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, isFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup contextmenu" ).split( " " ), + function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; +} ); + +jQuery.fn.extend( { + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +} ); + + + + +support.focusin = "onfocusin" in window; + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = jQuery.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = jQuery.isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( jQuery.isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 13 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available, append data to url + if ( s.data ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( jQuery.isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( "<script>" ).prop( { + charset: s.scriptCharset, + src: s.url + } ).on( + "load error", + callback = function( evt ) { + script.remove(); + callback = null; + if ( evt ) { + complete( evt.type === "error" ? 404 : 200, evt.type ); + } + } + ); + + // Use native DOM manipulation to avoid our domManip AJAX trickery + document.head.appendChild( script[ 0 ] ); + }, + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +var oldCallbacks = [], + rjsonp = /(=)\?(?=&|$)|\?\?/; + +// Default jsonp settings +jQuery.ajaxSetup( { + jsonp: "callback", + jsonpCallback: function() { + var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); + this[ callback ] = true; + return callback; + } +} ); + +// Detect, normalize options and install callbacks for jsonp requests +jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { + + var callbackName, overwritten, responseContainer, + jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ? + "url" : + typeof s.data === "string" && + ( s.contentType || "" ) + .indexOf( "application/x-www-form-urlencoded" ) === 0 && + rjsonp.test( s.data ) && "data" + ); + + // Handle iff the expected data type is "jsonp" or we have a parameter to set + if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) { + + // Get callback name, remembering preexisting value associated with it + callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? + s.jsonpCallback() : + s.jsonpCallback; + + // Insert callback into url or form data + if ( jsonProp ) { + s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName ); + } else if ( s.jsonp !== false ) { + s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; + } + + // Use data converter to retrieve json after script execution + s.converters[ "script json" ] = function() { + if ( !responseContainer ) { + jQuery.error( callbackName + " was not called" ); + } + return responseContainer[ 0 ]; + }; + + // Force json dataType + s.dataTypes[ 0 ] = "json"; + + // Install callback + overwritten = window[ callbackName ]; + window[ callbackName ] = function() { + responseContainer = arguments; + }; + + // Clean-up function (fires after converters) + jqXHR.always( function() { + + // If previous value didn't exist - remove it + if ( overwritten === undefined ) { + jQuery( window ).removeProp( callbackName ); + + // Otherwise restore preexisting value + } else { + window[ callbackName ] = overwritten; + } + + // Save back as free + if ( s[ callbackName ] ) { + + // Make sure that re-using the options doesn't screw things around + s.jsonpCallback = originalSettings.jsonpCallback; + + // Save the callback name for future use + oldCallbacks.push( callbackName ); + } + + // Call if it was a function and we have a response + if ( responseContainer && jQuery.isFunction( overwritten ) ) { + overwritten( responseContainer[ 0 ] ); + } + + responseContainer = overwritten = undefined; + } ); + + // Delegate to script + return "script"; + } +} ); + + + + +// Support: Safari 8 only +// In Safari 8 documents created via document.implementation.createHTMLDocument +// collapse sibling forms: the second one becomes a child of the first one. +// Because of that, this security measure has to be disabled in Safari 8. +// https://bugs.webkit.org/show_bug.cgi?id=137337 +support.createHTMLDocument = ( function() { + var body = document.implementation.createHTMLDocument( "" ).body; + body.innerHTML = "<form></form><form></form>"; + return body.childNodes.length === 2; +} )(); + + +// Argument "data" should be string of html +// context (optional): If specified, the fragment will be created in this context, +// defaults to document +// keepScripts (optional): If true, will include scripts passed in the html string +jQuery.parseHTML = function( data, context, keepScripts ) { + if ( typeof data !== "string" ) { + return []; + } + if ( typeof context === "boolean" ) { + keepScripts = context; + context = false; + } + + var base, parsed, scripts; + + if ( !context ) { + + // Stop scripts or inline event handlers from being executed immediately + // by using document.implementation + if ( support.createHTMLDocument ) { + context = document.implementation.createHTMLDocument( "" ); + + // Set the base href for the created document + // so any parsed elements with URLs + // are based on the document's URL (gh-2965) + base = context.createElement( "base" ); + base.href = document.location.href; + context.head.appendChild( base ); + } else { + context = document; + } + } + + parsed = rsingleTag.exec( data ); + scripts = !keepScripts && []; + + // Single tag + if ( parsed ) { + return [ context.createElement( parsed[ 1 ] ) ]; + } + + parsed = buildFragment( [ data ], context, scripts ); + + if ( scripts && scripts.length ) { + jQuery( scripts ).remove(); + } + + return jQuery.merge( [], parsed.childNodes ); +}; + + +/** + * Load a url into a page + */ +jQuery.fn.load = function( url, params, callback ) { + var selector, type, response, + self = this, + off = url.indexOf( " " ); + + if ( off > -1 ) { + selector = stripAndCollapse( url.slice( off ) ); + url = url.slice( 0, off ); + } + + // If it's a function + if ( jQuery.isFunction( params ) ) { + + // We assume that it's the callback + callback = params; + params = undefined; + + // Otherwise, build a param string + } else if ( params && typeof params === "object" ) { + type = "POST"; + } + + // If we have elements to modify, make the request + if ( self.length > 0 ) { + jQuery.ajax( { + url: url, + + // If "type" variable is undefined, then "GET" method will be used. + // Make value of this field explicit since + // user can override it through ajaxSetup method + type: type || "GET", + dataType: "html", + data: params + } ).done( function( responseText ) { + + // Save response for use in complete callback + response = arguments; + + self.html( selector ? + + // If a selector was specified, locate the right elements in a dummy div + // Exclude scripts to avoid IE 'Permission Denied' errors + jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) : + + // Otherwise use the full result + responseText ); + + // If the request succeeds, this function gets "data", "status", "jqXHR" + // but they are ignored because response was set above. + // If it fails, this function gets "jqXHR", "status", "error" + } ).always( callback && function( jqXHR, status ) { + self.each( function() { + callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] ); + } ); + } ); + } + + return this; +}; + + + + +// Attach a bunch of functions for handling common AJAX events +jQuery.each( [ + "ajaxStart", + "ajaxStop", + "ajaxComplete", + "ajaxError", + "ajaxSuccess", + "ajaxSend" +], function( i, type ) { + jQuery.fn[ type ] = function( fn ) { + return this.on( type, fn ); + }; +} ); + + + + +jQuery.expr.pseudos.animated = function( elem ) { + return jQuery.grep( jQuery.timers, function( fn ) { + return elem === fn.elem; + } ).length; +}; + + + + +jQuery.offset = { + setOffset: function( elem, options, i ) { + var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, + position = jQuery.css( elem, "position" ), + curElem = jQuery( elem ), + props = {}; + + // Set position first, in-case top/left are set even on static elem + if ( position === "static" ) { + elem.style.position = "relative"; + } + + curOffset = curElem.offset(); + curCSSTop = jQuery.css( elem, "top" ); + curCSSLeft = jQuery.css( elem, "left" ); + calculatePosition = ( position === "absolute" || position === "fixed" ) && + ( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1; + + // Need to be able to calculate position if either + // top or left is auto and position is either absolute or fixed + if ( calculatePosition ) { + curPosition = curElem.position(); + curTop = curPosition.top; + curLeft = curPosition.left; + + } else { + curTop = parseFloat( curCSSTop ) || 0; + curLeft = parseFloat( curCSSLeft ) || 0; + } + + if ( jQuery.isFunction( options ) ) { + + // Use jQuery.extend here to allow modification of coordinates argument (gh-1848) + options = options.call( elem, i, jQuery.extend( {}, curOffset ) ); + } + + if ( options.top != null ) { + props.top = ( options.top - curOffset.top ) + curTop; + } + if ( options.left != null ) { + props.left = ( options.left - curOffset.left ) + curLeft; + } + + if ( "using" in options ) { + options.using.call( elem, props ); + + } else { + curElem.css( props ); + } + } +}; + +jQuery.fn.extend( { + offset: function( options ) { + + // Preserve chaining for setter + if ( arguments.length ) { + return options === undefined ? + this : + this.each( function( i ) { + jQuery.offset.setOffset( this, options, i ); + } ); + } + + var doc, docElem, rect, win, + elem = this[ 0 ]; + + if ( !elem ) { + return; + } + + // Return zeros for disconnected and hidden (display: none) elements (gh-2310) + // Support: IE <=11 only + // Running getBoundingClientRect on a + // disconnected node in IE throws an error + if ( !elem.getClientRects().length ) { + return { top: 0, left: 0 }; + } + + rect = elem.getBoundingClientRect(); + + doc = elem.ownerDocument; + docElem = doc.documentElement; + win = doc.defaultView; + + return { + top: rect.top + win.pageYOffset - docElem.clientTop, + left: rect.left + win.pageXOffset - docElem.clientLeft + }; + }, + + position: function() { + if ( !this[ 0 ] ) { + return; + } + + var offsetParent, offset, + elem = this[ 0 ], + parentOffset = { top: 0, left: 0 }; + + // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, + // because it is its only offset parent + if ( jQuery.css( elem, "position" ) === "fixed" ) { + + // Assume getBoundingClientRect is there when computed position is fixed + offset = elem.getBoundingClientRect(); + + } else { + + // Get *real* offsetParent + offsetParent = this.offsetParent(); + + // Get correct offsets + offset = this.offset(); + if ( !nodeName( offsetParent[ 0 ], "html" ) ) { + parentOffset = offsetParent.offset(); + } + + // Add offsetParent borders + parentOffset = { + top: parentOffset.top + jQuery.css( offsetParent[ 0 ], "borderTopWidth", true ), + left: parentOffset.left + jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true ) + }; + } + + // Subtract parent offsets and element margins + return { + top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ), + left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true ) + }; + }, + + // This method will return documentElement in the following cases: + // 1) For the element inside the iframe without offsetParent, this method will return + // documentElement of the parent window + // 2) For the hidden or detached element + // 3) For body or html element, i.e. in case of the html node - it will return itself + // + // but those exceptions were never presented as a real life use-cases + // and might be considered as more preferable results. + // + // This logic, however, is not guaranteed and can change at any point in the future + offsetParent: function() { + return this.map( function() { + var offsetParent = this.offsetParent; + + while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) { + offsetParent = offsetParent.offsetParent; + } + + return offsetParent || documentElement; + } ); + } +} ); + +// Create scrollLeft and scrollTop methods +jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) { + var top = "pageYOffset" === prop; + + jQuery.fn[ method ] = function( val ) { + return access( this, function( elem, method, val ) { + + // Coalesce documents and windows + var win; + if ( jQuery.isWindow( elem ) ) { + win = elem; + } else if ( elem.nodeType === 9 ) { + win = elem.defaultView; + } + + if ( val === undefined ) { + return win ? win[ prop ] : elem[ method ]; + } + + if ( win ) { + win.scrollTo( + !top ? val : win.pageXOffset, + top ? val : win.pageYOffset + ); + + } else { + elem[ method ] = val; + } + }, method, val, arguments.length ); + }; +} ); + +// Support: Safari <=7 - 9.1, Chrome <=37 - 49 +// Add the top/left cssHooks using jQuery.fn.position +// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 +// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347 +// getComputedStyle returns percent when specified for top/left/bottom/right; +// rather than make the css module depend on the offset module, just check for it here +jQuery.each( [ "top", "left" ], function( i, prop ) { + jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition, + function( elem, computed ) { + if ( computed ) { + computed = curCSS( elem, prop ); + + // If curCSS returns percentage, fallback to offset + return rnumnonpx.test( computed ) ? + jQuery( elem ).position()[ prop ] + "px" : + computed; + } + } + ); +} ); + + +// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods +jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { + jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, + function( defaultExtra, funcName ) { + + // Margin is only for outerHeight, outerWidth + jQuery.fn[ funcName ] = function( margin, value ) { + var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), + extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); + + return access( this, function( elem, type, value ) { + var doc; + + if ( jQuery.isWindow( elem ) ) { + + // $( window ).outerWidth/Height return w/h including scrollbars (gh-1729) + return funcName.indexOf( "outer" ) === 0 ? + elem[ "inner" + name ] : + elem.document.documentElement[ "client" + name ]; + } + + // Get document width or height + if ( elem.nodeType === 9 ) { + doc = elem.documentElement; + + // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], + // whichever is greatest + return Math.max( + elem.body[ "scroll" + name ], doc[ "scroll" + name ], + elem.body[ "offset" + name ], doc[ "offset" + name ], + doc[ "client" + name ] + ); + } + + return value === undefined ? + + // Get width or height on the element, requesting but not forcing parseFloat + jQuery.css( elem, type, extra ) : + + // Set width or height on the element + jQuery.style( elem, type, value, extra ); + }, type, chainable ? margin : undefined, chainable ); + }; + } ); +} ); + + +jQuery.fn.extend( { + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length === 1 ? + this.off( selector, "**" ) : + this.off( types, selector || "**", fn ); + } +} ); + +jQuery.holdReady = function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } +}; +jQuery.isArray = Array.isArray; +jQuery.parseJSON = JSON.parse; +jQuery.nodeName = nodeName; + + + + +// Register as a named AMD module, since jQuery can be concatenated with other +// files that may use define, but not via a proper concatenation script that +// understands anonymous AMD modules. A named AMD is safest and most robust +// way to register. Lowercase jquery is used because AMD module names are +// derived from file names, and jQuery is normally delivered in a lowercase +// file name. Do this after creating the global so that if an AMD module wants +// to call noConflict to hide this version of jQuery, it will work. + +// Note that for maximum portability, libraries that are not jQuery should +// declare themselves as anonymous modules, and avoid setting a global if an +// AMD loader is present. jQuery is a special case. For more information, see +// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon + +if ( typeof define === "function" && define.amd ) { + define( "jquery", [], function() { + return jQuery; + } ); +} + + + + +var + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$; + +jQuery.noConflict = function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; +}; + +// Expose jQuery and $ identifiers, even in AMD +// (#7102#comment:10, https://github.com/jquery/jquery/pull/557) +// and CommonJS for browser emulators (#13566) +if ( !noGlobal ) { + window.jQuery = window.$ = jQuery; +} + + + + +return jQuery; +} ); diff --git a/refs/pull/405/merge/_static/jquery.js b/refs/pull/405/merge/_static/jquery.js new file mode 100644 index 00000000..644d35e2 --- /dev/null +++ b/refs/pull/405/merge/_static/jquery.js @@ -0,0 +1,4 @@ +/*! jQuery v3.2.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.2.1",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null==a?f.call(this):a<0?this[a+this.length]:this[a]},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c<b?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:h,sort:c.sort,splice:c.splice},r.extend=r.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||r.isFunction(g)||(g={}),h===i&&(g=this,h--);h<i;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(r.isPlainObject(d)||(e=Array.isArray(d)))?(e?(e=!1,f=c&&Array.isArray(c)?c:[]):f=c&&r.isPlainObject(c)?c:{},g[b]=r.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},r.extend({expando:"jQuery"+(q+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===r.type(a)},isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=r.type(a);return("number"===b||"string"===b)&&!isNaN(a-parseFloat(a))},isPlainObject:function(a){var b,c;return!(!a||"[object Object]"!==k.call(a))&&(!(b=e(a))||(c=l.call(b,"constructor")&&b.constructor,"function"==typeof c&&m.call(c)===n))},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?j[k.call(a)]||"object":typeof a},globalEval:function(a){p(a)},camelCase:function(a){return a.replace(t,"ms-").replace(u,v)},each:function(a,b){var c,d=0;if(w(a)){for(c=a.length;d<c;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(s,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(w(Object(a))?r.merge(c,"string"==typeof a?[a]:a):h.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:i.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;d<c;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;f<g;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,f=0,h=[];if(w(a))for(d=a.length;f<d;f++)e=b(a[f],f,c),null!=e&&h.push(e);else for(f in a)e=b(a[f],f,c),null!=e&&h.push(e);return g.apply([],h)},guid:1,proxy:function(a,b){var c,d,e;if("string"==typeof b&&(c=a[b],b=a,a=c),r.isFunction(a))return d=f.call(arguments,2),e=function(){return a.apply(b||this,d.concat(f.call(arguments)))},e.guid=a.guid=a.guid||r.guid++,e},now:Date.now,support:o}),"function"==typeof Symbol&&(r.fn[Symbol.iterator]=c[Symbol.iterator]),r.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){j["[object "+b+"]"]=b.toLowerCase()});function w(a){var b=!!a&&"length"in a&&a.length,c=r.type(a);return"function"!==c&&!r.isWindow(a)&&("array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",M="\\["+K+"*("+L+")(?:"+K+"*([*^$|!~]?=)"+K+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+L+"))|)"+K+"*\\]",N=":("+L+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+M+")*)|.*)\\)|)",O=new RegExp(K+"+","g"),P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0&&("form"in a||"label"in a)},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"form"in b?b.parentNode&&b.disabled===!1?"label"in b?"label"in b.parentNode?b.parentNode.disabled===a:b.disabled===a:b.isDisabled===a||b.isDisabled!==!a&&ea(b)===a:b.disabled===a:"label"in b&&b.disabled===a}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}}):(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c,d,e,f=b.getElementById(a);if(f){if(c=f.getAttributeNode("id"),c&&c.value===a)return[f];e=b.getElementsByName(a),d=0;while(f=e[d++])if(c=f.getAttributeNode("id"),c&&c.value===a)return[f]}return[]}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\r\\' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c<b;c+=2)a.push(c);return a}),odd:pa(function(a,b){for(var c=1;c<b;c+=2)a.push(c);return a}),lt:pa(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=ma(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=na(b);function ra(){}ra.prototype=d.filters=d.pseudos,d.setFilters=new ra,g=ga.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){c&&!(e=Q.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?ga.error(a):z(a,i).slice(0)};function sa(a){for(var b=0,c=a.length,d="";b<c;b++)d+=a[b].value;return d}function ta(a,b,c){var d=b.dir,e=b.next,f=e||d,g=c&&"parentNode"===f,h=x++;return b.first?function(b,c,e){while(b=b[d])if(1===b.nodeType||g)return a(b,c,e);return!1}:function(b,c,i){var j,k,l,m=[w,h];if(i){while(b=b[d])if((1===b.nodeType||g)&&a(b,c,i))return!0}else while(b=b[d])if(1===b.nodeType||g)if(l=b[u]||(b[u]={}),k=l[b.uniqueID]||(l[b.uniqueID]={}),e&&e===b.nodeName.toLowerCase())b=b[d]||b;else{if((j=k[f])&&j[0]===w&&j[1]===h)return m[2]=j[2];if(k[f]=m,m[2]=a(b,c,i))return!0}return!1}}function ua(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d<e;d++)ga(a,b[d],c);return c}function wa(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;h<i;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function xa(a,b,c,d,e,f){return d&&!d[u]&&(d=xa(d)),e&&!e[u]&&(e=xa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||va(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:wa(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=wa(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i<f;i++)if(c=d.relative[a[i].type])m=[ta(ua(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;e<f;e++)if(d.relative[a[e].type])break;return xa(i>1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i<e&&ya(a.slice(i,e)),e<f&&ya(a=a.slice(e)),e<f&&sa(a))}m.push(c)}return ua(m)}function za(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,c,e){var f,i,j,k,l,m="function"==typeof a&&a,n=!e&&g(a=m.selector||a);if(c=c||[],1===n.length){if(i=n[0]=n[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&9===b.nodeType&&p&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(_,aa),b)||[])[0],!b)return c;m&&(b=b.parentNode),a=a.slice(i.shift().value.length)}f=V.needsContext.test(a)?0:i.length;while(f--){if(j=i[f],d.relative[k=j.type])break;if((l=d.find[k])&&(e=l(j.matches[0].replace(_,aa),$.test(i[0].type)&&qa(b.parentNode)||b))){if(i.splice(f,1),a=e.length&&sa(i),!a)return G.apply(c,e),c;break}}}return(m||h(a,n))(e,b,!p,c,!b||$.test(a)&&qa(b.parentNode)||b),c},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext;function B(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()}var C=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,D=/^.[^:#\[\.,]*$/;function E(a,b,c){return r.isFunction(b)?r.grep(a,function(a,d){return!!b.call(a,d,a)!==c}):b.nodeType?r.grep(a,function(a){return a===b!==c}):"string"!=typeof b?r.grep(a,function(a){return i.call(b,a)>-1!==c}):D.test(b)?r.filter(b,a,c):(b=r.filter(b,a),r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType}))}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b<d;b++)if(r.contains(e[b],this))return!0}));for(c=this.pushStack([]),b=0;b<d;b++)r.find(a,e[b],c);return d>1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(E(this,a||[],!1))},not:function(a){return this.pushStack(E(this,a||[],!0))},is:function(a){return!!E(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var F,G=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,H=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||F,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:G.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),C.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};H.prototype=r.fn,F=r(d);var I=/^(?:parents|prev(?:Until|All))/,J={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a<c;a++)if(r.contains(this,b[a]))return!0})},closest:function(a,b){var c,d=0,e=this.length,f=[],g="string"!=typeof a&&r(a);if(!A.test(a))for(;d<e;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function K(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return K(a,"nextSibling")},prev:function(a){return K(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return B(a,"iframe")?a.contentDocument:(B(a,"template")&&(a=a.content||a),r.merge([],a.childNodes))}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(J[a]||r.uniqueSort(e),I.test(a)&&e.reverse()),this.pushStack(e)}});var L=/[^\x20\t\r\n\f]+/g;function M(a){var b={};return r.each(a.match(L)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?M(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=e||a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:"")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){r.each(b,function(b,c){r.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&"string"!==r.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return r.each(arguments,function(a,b){var c;while((c=r.inArray(b,f,c))>-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function N(a){return a}function O(a){throw a}function P(a,b,c,d){var e;try{a&&r.isFunction(e=a.promise)?e.call(a).done(b).fail(c):a&&r.isFunction(e=a.then)?e.call(a,b,c):b.apply(void 0,[a].slice(d))}catch(a){c.apply(void 0,[a])}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b<f)){if(a=d.apply(h,i),a===c.promise())throw new TypeError("Thenable self-resolution");j=a&&("object"==typeof a||"function"==typeof a)&&a.then,r.isFunction(j)?e?j.call(a,g(f,c,N,e),g(f,c,O,e)):(f++,j.call(a,g(f,c,N,e),g(f,c,O,e),g(f,c,N,c.notifyWith))):(d!==N&&(h=void 0,i=[a]),(e||c.resolveWith)(h,i))}},k=e?j:function(){try{j()}catch(a){r.Deferred.exceptionHook&&r.Deferred.exceptionHook(a,k.stackTrace),b+1>=f&&(d!==O&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:N,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:N)),c[2][3].add(g(0,a,r.isFunction(d)?d:O))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(P(a,g.done(h(c)).resolve,g.reject,!b),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)P(e[c],h(c),g.reject);return g.promise()}});var Q=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&Q.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var R=r.Deferred();r.fn.ready=function(a){return R.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||R.resolveWith(d,[r]))}}),r.ready.then=R.then;function S(){d.removeEventListener("DOMContentLoaded",S), +a.removeEventListener("load",S),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",S),a.addEventListener("load",S));var T=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)T(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h<i;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},U=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function V(){this.expando=r.expando+V.uid++}V.uid=1,V.prototype={cache:function(a){var b=a[this.expando];return b||(b={},U(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[r.camelCase(b)]=c;else for(d in b)e[r.camelCase(d)]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][r.camelCase(b)]},access:function(a,b,c){return void 0===b||b&&"string"==typeof b&&void 0===c?this.get(a,b):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d=a[this.expando];if(void 0!==d){if(void 0!==b){Array.isArray(b)?b=b.map(r.camelCase):(b=r.camelCase(b),b=b in d?[b]:b.match(L)||[]),c=b.length;while(c--)delete d[b[c]]}(void 0===b||r.isEmptyObject(d))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!r.isEmptyObject(b)}};var W=new V,X=new V,Y=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Z=/[A-Z]/g;function $(a){return"true"===a||"false"!==a&&("null"===a?null:a===+a+""?+a:Y.test(a)?JSON.parse(a):a)}function _(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Z,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c=$(c)}catch(e){}X.set(a,b,c)}else c=void 0;return c}r.extend({hasData:function(a){return X.hasData(a)||W.hasData(a)},data:function(a,b,c){return X.access(a,b,c)},removeData:function(a,b){X.remove(a,b)},_data:function(a,b,c){return W.access(a,b,c)},_removeData:function(a,b){W.remove(a,b)}}),r.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=X.get(f),1===f.nodeType&&!W.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=r.camelCase(d.slice(5)),_(f,d,e[d])));W.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){X.set(this,a)}):T(this,function(b){var c;if(f&&void 0===b){if(c=X.get(f,a),void 0!==c)return c;if(c=_(f,a),void 0!==c)return c}else this.each(function(){X.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){X.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=W.get(a,b),c&&(!d||Array.isArray(c)?d=W.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return W.get(a,c)||W.access(a,c,{empty:r.Callbacks("once memory").add(function(){W.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?r.queue(this[0],a):void 0===b?this:this.each(function(){var c=r.queue(this,a,b);r._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&r.dequeue(this,a)})},dequeue:function(a){return this.each(function(){r.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=r.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=W.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var aa=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,ba=new RegExp("^(?:([+-])=|)("+aa+")([a-z%]*)$","i"),ca=["Top","Right","Bottom","Left"],da=function(a,b){return a=b||a,"none"===a.style.display||""===a.style.display&&r.contains(a.ownerDocument,a)&&"none"===r.css(a,"display")},ea=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};function fa(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return r.css(a,b,"")},i=h(),j=c&&c[3]||(r.cssNumber[b]?"":"px"),k=(r.cssNumber[b]||"px"!==j&&+i)&&ba.exec(r.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,r.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var ga={};function ha(a){var b,c=a.ownerDocument,d=a.nodeName,e=ga[d];return e?e:(b=c.body.appendChild(c.createElement(d)),e=r.css(b,"display"),b.parentNode.removeChild(b),"none"===e&&(e="block"),ga[d]=e,e)}function ia(a,b){for(var c,d,e=[],f=0,g=a.length;f<g;f++)d=a[f],d.style&&(c=d.style.display,b?("none"===c&&(e[f]=W.get(d,"display")||null,e[f]||(d.style.display="")),""===d.style.display&&da(d)&&(e[f]=ha(d))):"none"!==c&&(e[f]="none",W.set(d,"display",c)));for(f=0;f<g;f++)null!=e[f]&&(a[f].style.display=e[f]);return a}r.fn.extend({show:function(){return ia(this,!0)},hide:function(){return ia(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){da(this)?r(this).show():r(this).hide()})}});var ja=/^(?:checkbox|radio)$/i,ka=/<([a-z][^\/\0>\x20\t\r\n\f]+)/i,la=/^$|\/(?:java|ecma)script/i,ma={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ma.optgroup=ma.option,ma.tbody=ma.tfoot=ma.colgroup=ma.caption=ma.thead,ma.th=ma.td;function na(a,b){var c;return c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[],void 0===b||b&&B(a,b)?r.merge([a],c):c}function oa(a,b){for(var c=0,d=a.length;c<d;c++)W.set(a[c],"globalEval",!b||W.get(b[c],"globalEval"))}var pa=/<|&#?\w+;/;function qa(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],n=0,o=a.length;n<o;n++)if(f=a[n],f||0===f)if("object"===r.type(f))r.merge(m,f.nodeType?[f]:f);else if(pa.test(f)){g=g||l.appendChild(b.createElement("div")),h=(ka.exec(f)||["",""])[1].toLowerCase(),i=ma[h]||ma._default,g.innerHTML=i[1]+r.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;r.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",n=0;while(f=m[n++])if(d&&r.inArray(f,d)>-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=na(l.appendChild(f),"script"),j&&oa(g),c){k=0;while(f=g[k++])la.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var ra=d.documentElement,sa=/^key/,ta=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ua=/^([^.]*)(?:\.(.+)|)/;function va(){return!0}function wa(){return!1}function xa(){try{return d.activeElement}catch(a){}}function ya(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ya(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=wa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(ra,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(L)||[""],j=b.length;while(j--)h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.hasData(a)&&W.get(a);if(q&&(i=q.events)){b=(b||"").match(L)||[""],j=b.length;while(j--)if(h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&W.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(W.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c<arguments.length;c++)i[c]=arguments[c];if(b.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,b)!==!1){h=r.event.handlers.call(this,b,j),c=0;while((f=h[c++])&&!b.isPropagationStopped()){b.currentTarget=f.elem,d=0;while((g=f.handlers[d++])&&!b.isImmediatePropagationStopped())b.rnamespace&&!b.rnamespace.test(g.namespace)||(b.handleObj=g,b.data=g.data,e=((r.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(b.result=e)===!1&&(b.preventDefault(),b.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,b),b.result}},handlers:function(a,b){var c,d,e,f,g,h=[],i=b.delegateCount,j=a.target;if(i&&j.nodeType&&!("click"===a.type&&a.button>=1))for(;j!==this;j=j.parentNode||this)if(1===j.nodeType&&("click"!==a.type||j.disabled!==!0)){for(f=[],g={},c=0;c<i;c++)d=b[c],e=d.selector+" ",void 0===g[e]&&(g[e]=d.needsContext?r(e,this).index(j)>-1:r.find(e,this,null,[j]).length),g[e]&&f.push(d);f.length&&h.push({elem:j,handlers:f})}return j=this,i<b.length&&h.push({elem:j,handlers:b.slice(i)}),h},addProp:function(a,b){Object.defineProperty(r.Event.prototype,a,{enumerable:!0,configurable:!0,get:r.isFunction(b)?function(){if(this.originalEvent)return b(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[a]},set:function(b){Object.defineProperty(this,a,{enumerable:!0,configurable:!0,writable:!0,value:b})}})},fix:function(a){return a[r.expando]?a:new r.Event(a)},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==xa()&&this.focus)return this.focus(),!1},delegateType:"focusin"},blur:{trigger:function(){if(this===xa()&&this.blur)return this.blur(),!1},delegateType:"focusout"},click:{trigger:function(){if("checkbox"===this.type&&this.click&&B(this,"input"))return this.click(),!1},_default:function(a){return B(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}}},r.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)},r.Event=function(a,b){return this instanceof r.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?va:wa,this.target=a.target&&3===a.target.nodeType?a.target.parentNode:a.target,this.currentTarget=a.currentTarget,this.relatedTarget=a.relatedTarget):this.type=a,b&&r.extend(this,b),this.timeStamp=a&&a.timeStamp||r.now(),void(this[r.expando]=!0)):new r.Event(a,b)},r.Event.prototype={constructor:r.Event,isDefaultPrevented:wa,isPropagationStopped:wa,isImmediatePropagationStopped:wa,isSimulated:!1,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=va,a&&!this.isSimulated&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=va,a&&!this.isSimulated&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=va,a&&!this.isSimulated&&a.stopImmediatePropagation(),this.stopPropagation()}},r.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(a){var b=a.button;return null==a.which&&sa.test(a.type)?null!=a.charCode?a.charCode:a.keyCode:!a.which&&void 0!==b&&ta.test(a.type)?1&b?1:2&b?3:4&b?2:0:a.which}},r.event.addProp),r.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){r.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return e&&(e===d||r.contains(d,e))||(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),r.fn.extend({on:function(a,b,c,d){return ya(this,a,b,c,d)},one:function(a,b,c,d){return ya(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,r(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return b!==!1&&"function"!=typeof b||(c=b,b=void 0),c===!1&&(c=wa),this.each(function(){r.event.remove(this,a,c,b)})}});var za=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,Aa=/<script|<style|<link/i,Ba=/checked\s*(?:[^=]|=\s*.checked.)/i,Ca=/^true\/(.*)/,Da=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function Ea(a,b){return B(a,"table")&&B(11!==b.nodeType?b:b.firstChild,"tr")?r(">tbody",a)[0]||a:a}function Fa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ga(a){var b=Ca.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ha(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(W.hasData(a)&&(f=W.access(a),g=W.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c<d;c++)r.event.add(b,e,j[e][c])}X.hasData(a)&&(h=X.access(a),i=r.extend({},h),X.set(b,i))}}function Ia(a,b){var c=b.nodeName.toLowerCase();"input"===c&&ja.test(a.type)?b.checked=a.checked:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}function Ja(a,b,c,d){b=g.apply([],b);var e,f,h,i,j,k,l=0,m=a.length,n=m-1,q=b[0],s=r.isFunction(q);if(s||m>1&&"string"==typeof q&&!o.checkClone&&Ba.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ja(f,b,c,d)});if(m&&(e=qa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(na(e,"script"),Fa),i=h.length;l<m;l++)j=e,l!==n&&(j=r.clone(j,!0,!0),i&&r.merge(h,na(j,"script"))),c.call(a[l],j,l);if(i)for(k=h[h.length-1].ownerDocument,r.map(h,Ga),l=0;l<i;l++)j=h[l],la.test(j.type||"")&&!W.access(j,"globalEval")&&r.contains(k,j)&&(j.src?r._evalUrl&&r._evalUrl(j.src):p(j.textContent.replace(Da,""),k))}return a}function Ka(a,b,c){for(var d,e=b?r.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||r.cleanData(na(d)),d.parentNode&&(c&&r.contains(d.ownerDocument,d)&&oa(na(d,"script")),d.parentNode.removeChild(d));return a}r.extend({htmlPrefilter:function(a){return a.replace(za,"<$1></$2>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=na(h),f=na(a),d=0,e=f.length;d<e;d++)Ia(f[d],g[d]);if(b)if(c)for(f=f||na(a),g=g||na(h),d=0,e=f.length;d<e;d++)Ha(f[d],g[d]);else Ha(a,h);return g=na(h,"script"),g.length>0&&oa(g,!i&&na(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(U(c)){if(b=c[W.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[W.expando]=void 0}c[X.expando]&&(c[X.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ka(this,a,!0)},remove:function(a){return Ka(this,a)},text:function(a){return T(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.appendChild(a)}})},prepend:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(na(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return T(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!Aa.test(a)&&!ma[(ka.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c<d;c++)b=this[c]||{},1===b.nodeType&&(r.cleanData(na(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ja(this,arguments,function(b){var c=this.parentNode;r.inArray(this,a)<0&&(r.cleanData(na(this)),c&&c.replaceChild(b,this))},a)}}),r.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){r.fn[a]=function(a){for(var c,d=[],e=r(a),f=e.length-1,g=0;g<=f;g++)c=g===f?this:this.clone(!0),r(e[g])[b](c),h.apply(d,c.get());return this.pushStack(d)}});var La=/^margin/,Ma=new RegExp("^("+aa+")(?!px)[a-z%]+$","i"),Na=function(b){var c=b.ownerDocument.defaultView;return c&&c.opener||(c=a),c.getComputedStyle(b)};!function(){function b(){if(i){i.style.cssText="box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",i.innerHTML="",ra.appendChild(h);var b=a.getComputedStyle(i);c="1%"!==b.top,g="2px"===b.marginLeft,e="4px"===b.width,i.style.marginRight="50%",f="4px"===b.marginRight,ra.removeChild(h),i=null}}var c,e,f,g,h=d.createElement("div"),i=d.createElement("div");i.style&&(i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",o.clearCloneStyle="content-box"===i.style.backgroundClip,h.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",h.appendChild(i),r.extend(o,{pixelPosition:function(){return b(),c},boxSizingReliable:function(){return b(),e},pixelMarginRight:function(){return b(),f},reliableMarginLeft:function(){return b(),g}}))}();function Oa(a,b,c){var d,e,f,g,h=a.style;return c=c||Na(a),c&&(g=c.getPropertyValue(b)||c[b],""!==g||r.contains(a.ownerDocument,a)||(g=r.style(a,b)),!o.pixelMarginRight()&&Ma.test(g)&&La.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function Pa(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Qa=/^(none|table(?!-c[ea]).+)/,Ra=/^--/,Sa={position:"absolute",visibility:"hidden",display:"block"},Ta={letterSpacing:"0",fontWeight:"400"},Ua=["Webkit","Moz","ms"],Va=d.createElement("div").style;function Wa(a){if(a in Va)return a;var b=a[0].toUpperCase()+a.slice(1),c=Ua.length;while(c--)if(a=Ua[c]+b,a in Va)return a}function Xa(a){var b=r.cssProps[a];return b||(b=r.cssProps[a]=Wa(a)||a),b}function Ya(a,b,c){var d=ba.exec(b);return d?Math.max(0,d[2]-(c||0))+(d[3]||"px"):b}function Za(a,b,c,d,e){var f,g=0;for(f=c===(d?"border":"content")?4:"width"===b?1:0;f<4;f+=2)"margin"===c&&(g+=r.css(a,c+ca[f],!0,e)),d?("content"===c&&(g-=r.css(a,"padding"+ca[f],!0,e)),"margin"!==c&&(g-=r.css(a,"border"+ca[f]+"Width",!0,e))):(g+=r.css(a,"padding"+ca[f],!0,e),"padding"!==c&&(g+=r.css(a,"border"+ca[f]+"Width",!0,e)));return g}function $a(a,b,c){var d,e=Na(a),f=Oa(a,b,e),g="border-box"===r.css(a,"boxSizing",!1,e);return Ma.test(f)?f:(d=g&&(o.boxSizingReliable()||f===a.style[b]),"auto"===f&&(f=a["offset"+b[0].toUpperCase()+b.slice(1)]),f=parseFloat(f)||0,f+Za(a,b,c||(g?"border":"content"),d,e)+"px")}r.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Oa(a,"opacity");return""===c?"1":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=r.camelCase(b),i=Ra.test(b),j=a.style;return i||(b=Xa(h)),g=r.cssHooks[b]||r.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:j[b]:(f=typeof c,"string"===f&&(e=ba.exec(c))&&e[1]&&(c=fa(a,b,e),f="number"),null!=c&&c===c&&("number"===f&&(c+=e&&e[3]||(r.cssNumber[h]?"":"px")),o.clearCloneStyle||""!==c||0!==b.indexOf("background")||(j[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i?j.setProperty(b,c):j[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=r.camelCase(b),i=Ra.test(b);return i||(b=Xa(h)),g=r.cssHooks[b]||r.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=Oa(a,b,d)),"normal"===e&&b in Ta&&(e=Ta[b]),""===c||c?(f=parseFloat(e),c===!0||isFinite(f)?f||0:e):e}}),r.each(["height","width"],function(a,b){r.cssHooks[b]={get:function(a,c,d){if(c)return!Qa.test(r.css(a,"display"))||a.getClientRects().length&&a.getBoundingClientRect().width?$a(a,b,d):ea(a,Sa,function(){return $a(a,b,d)})},set:function(a,c,d){var e,f=d&&Na(a),g=d&&Za(a,b,d,"border-box"===r.css(a,"boxSizing",!1,f),f);return g&&(e=ba.exec(c))&&"px"!==(e[3]||"px")&&(a.style[b]=c,c=r.css(a,b)),Ya(a,c,g)}}}),r.cssHooks.marginLeft=Pa(o.reliableMarginLeft,function(a,b){if(b)return(parseFloat(Oa(a,"marginLeft"))||a.getBoundingClientRect().left-ea(a,{marginLeft:0},function(){return a.getBoundingClientRect().left}))+"px"}),r.each({margin:"",padding:"",border:"Width"},function(a,b){r.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];d<4;d++)e[a+ca[d]+b]=f[d]||f[d-2]||f[0];return e}},La.test(a)||(r.cssHooks[a+b].set=Ya)}),r.fn.extend({css:function(a,b){return T(this,function(a,b,c){var d,e,f={},g=0;if(Array.isArray(b)){for(d=Na(a),e=b.length;g<e;g++)f[b[g]]=r.css(a,b[g],!1,d);return f}return void 0!==c?r.style(a,b,c):r.css(a,b)},a,b,arguments.length>1)}});function _a(a,b,c,d,e){return new _a.prototype.init(a,b,c,d,e)}r.Tween=_a,_a.prototype={constructor:_a,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=_a.propHooks[this.prop];return a&&a.get?a.get(this):_a.propHooks._default.get(this)},run:function(a){var b,c=_a.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):_a.propHooks._default.set(this),this}},_a.prototype.init.prototype=_a.prototype,_a.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},_a.propHooks.scrollTop=_a.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=_a.prototype.init,r.fx.step={};var ab,bb,cb=/^(?:toggle|show|hide)$/,db=/queueHooks$/;function eb(){bb&&(d.hidden===!1&&a.requestAnimationFrame?a.requestAnimationFrame(eb):a.setTimeout(eb,r.fx.interval),r.fx.tick())}function fb(){return a.setTimeout(function(){ab=void 0}),ab=r.now()}function gb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=ca[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function hb(a,b,c){for(var d,e=(kb.tweeners[b]||[]).concat(kb.tweeners["*"]),f=0,g=e.length;f<g;f++)if(d=e[f].call(c,b,a))return d}function ib(a,b,c){var d,e,f,g,h,i,j,k,l="width"in b||"height"in b,m=this,n={},o=a.style,p=a.nodeType&&da(a),q=W.get(a,"fxshow");c.queue||(g=r._queueHooks(a,"fx"),null==g.unqueued&&(g.unqueued=0,h=g.empty.fire,g.empty.fire=function(){g.unqueued||h()}),g.unqueued++,m.always(function(){m.always(function(){g.unqueued--,r.queue(a,"fx").length||g.empty.fire()})}));for(d in b)if(e=b[d],cb.test(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}n[d]=q&&q[d]||r.style(a,d)}if(i=!r.isEmptyObject(b),i||!r.isEmptyObject(n)){l&&1===a.nodeType&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=q&&q.display,null==j&&(j=W.get(a,"display")),k=r.css(a,"display"),"none"===k&&(j?k=j:(ia([a],!0),j=a.style.display||j,k=r.css(a,"display"),ia([a]))),("inline"===k||"inline-block"===k&&null!=j)&&"none"===r.css(a,"float")&&(i||(m.done(function(){o.display=j}),null==j&&(k=o.display,j="none"===k?"":k)),o.display="inline-block")),c.overflow&&(o.overflow="hidden",m.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]})),i=!1;for(d in n)i||(q?"hidden"in q&&(p=q.hidden):q=W.access(a,"fxshow",{display:j}),f&&(q.hidden=!p),p&&ia([a],!0),m.done(function(){p||ia([a]),W.remove(a,"fxshow");for(d in n)r.style(a,d,n[d])})),i=hb(p?q[d]:0,d,m),d in q||(q[d]=i.start,p&&(i.end=i.start,i.start=0))}}function jb(a,b){var c,d,e,f,g;for(c in a)if(d=r.camelCase(c),e=b[d],f=a[c],Array.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=r.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kb(a,b,c){var d,e,f=0,g=kb.prefilters.length,h=r.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=ab||fb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;g<i;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),f<1&&i?c:(i||h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:r.extend({},b),opts:r.extend(!0,{specialEasing:{},easing:r.easing._default},c),originalProperties:b,originalOptions:c,startTime:ab||fb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=r.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;c<d;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jb(k,j.opts.specialEasing);f<g;f++)if(d=kb.prefilters[f].call(j,a,k,j.opts))return r.isFunction(d.stop)&&(r._queueHooks(j.elem,j.opts.queue).stop=r.proxy(d.stop,d)),d;return r.map(k,hb,j),r.isFunction(j.opts.start)&&j.opts.start.call(a,j),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always),r.fx.timer(r.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j}r.Animation=r.extend(kb,{tweeners:{"*":[function(a,b){var c=this.createTween(a,b);return fa(c.elem,a,ba.exec(b),c),c}]},tweener:function(a,b){r.isFunction(a)?(b=a,a=["*"]):a=a.match(L);for(var c,d=0,e=a.length;d<e;d++)c=a[d],kb.tweeners[c]=kb.tweeners[c]||[],kb.tweeners[c].unshift(b)},prefilters:[ib],prefilter:function(a,b){b?kb.prefilters.unshift(a):kb.prefilters.push(a)}}),r.speed=function(a,b,c){var d=a&&"object"==typeof a?r.extend({},a):{complete:c||!c&&b||r.isFunction(a)&&a,duration:a,easing:c&&b||b&&!r.isFunction(b)&&b};return r.fx.off?d.duration=0:"number"!=typeof d.duration&&(d.duration in r.fx.speeds?d.duration=r.fx.speeds[d.duration]:d.duration=r.fx.speeds._default),null!=d.queue&&d.queue!==!0||(d.queue="fx"),d.old=d.complete,d.complete=function(){r.isFunction(d.old)&&d.old.call(this),d.queue&&r.dequeue(this,d.queue)},d},r.fn.extend({fadeTo:function(a,b,c,d){return this.filter(da).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=r.isEmptyObject(a),f=r.speed(b,c,d),g=function(){var b=kb(this,r.extend({},a),f);(e||W.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=r.timers,g=W.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&db.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));!b&&c||r.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=W.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=r.timers,g=d?d.length:0;for(c.finish=!0,r.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;b<g;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),r.each(["toggle","show","hide"],function(a,b){var c=r.fn[b];r.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gb(b,!0),a,d,e)}}),r.each({slideDown:gb("show"),slideUp:gb("hide"),slideToggle:gb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){r.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),r.timers=[],r.fx.tick=function(){var a,b=0,c=r.timers;for(ab=r.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||r.fx.stop(),ab=void 0},r.fx.timer=function(a){r.timers.push(a),r.fx.start()},r.fx.interval=13,r.fx.start=function(){bb||(bb=!0,eb())},r.fx.stop=function(){bb=null},r.fx.speeds={slow:600,fast:200,_default:400},r.fn.delay=function(b,c){return b=r.fx?r.fx.speeds[b]||b:b,c=c||"fx",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a=d.createElement("input"),b=d.createElement("select"),c=b.appendChild(d.createElement("option"));a.type="checkbox",o.checkOn=""!==a.value,o.optSelected=c.selected,a=d.createElement("input"),a.value="t",a.type="radio",o.radioValue="t"===a.value}();var lb,mb=r.expr.attrHandle;r.fn.extend({attr:function(a,b){return T(this,r.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?lb:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b), +null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&B(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(L);if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),lb={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=mb[b]||r.find.attr;mb[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=mb[g],mb[g]=e,e=null!=c(a,b,d)?g:null,mb[g]=f),e}});var nb=/^(?:input|select|textarea|button)$/i,ob=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return T(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):nb.test(a.nodeName)||ob.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});function pb(a){var b=a.match(L)||[];return b.join(" ")}function qb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,qb(this)))});if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,qb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,qb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(L)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=qb(this),b&&W.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":W.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+pb(qb(c))+" ").indexOf(b)>-1)return!0;return!1}});var rb=/\r/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":Array.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(rb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:pb(r.text(a))}},select:{get:function(a){var b,c,d,e=a.options,f=a.selectedIndex,g="select-one"===a.type,h=g?null:[],i=g?f+1:e.length;for(d=f<0?i:g?f:0;d<i;d++)if(c=e[d],(c.selected||d===f)&&!c.disabled&&(!c.parentNode.disabled||!B(c.parentNode,"optgroup"))){if(b=r(c).val(),g)return b;h.push(b)}return h},set:function(a,b){var c,d,e=a.options,f=r.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=r.inArray(r.valHooks.option.get(d),f)>-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(Array.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var sb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!sb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,sb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(W.get(h,"events")||{})[b.type]&&W.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&U(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!U(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=W.access(d,b);e||d.addEventListener(a,c,!0),W.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=W.access(d,b)-1;e?W.access(d,b,e):(d.removeEventListener(a,c,!0),W.remove(d,b))}}});var tb=a.location,ub=r.now(),vb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var wb=/\[\]$/,xb=/\r?\n/g,yb=/^(?:submit|button|image|reset|file)$/i,zb=/^(?:input|select|textarea|keygen)/i;function Ab(a,b,c,d){var e;if(Array.isArray(b))r.each(b,function(b,e){c||wb.test(a)?d(a,e):Ab(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)Ab(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(Array.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)Ab(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&zb.test(this.nodeName)&&!yb.test(a)&&(this.checked||!ja.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:Array.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(xb,"\r\n")}}):{name:b.name,value:c.replace(xb,"\r\n")}}).get()}});var Bb=/%20/g,Cb=/#.*$/,Db=/([?&])_=[^&]*/,Eb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Fb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Gb=/^(?:GET|HEAD)$/,Hb=/^\/\//,Ib={},Jb={},Kb="*/".concat("*"),Lb=d.createElement("a");Lb.href=tb.href;function Mb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(L)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nb(a,b,c,d){var e={},f=a===Jb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Ob(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Pb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Qb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:tb.href,type:"GET",isLocal:Fb.test(tb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Ob(Ob(a,r.ajaxSettings),b):Ob(r.ajaxSettings,a)},ajaxPrefilter:Mb(Ib),ajaxTransport:Mb(Jb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Eb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||tb.href)+"").replace(Hb,tb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(L)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Lb.protocol+"//"+Lb.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Nb(Ib,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Gb.test(o.type),f=o.url.replace(Cb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(Bb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(vb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Db,"$1"),n=(vb.test(f)?"&":"?")+"_="+ub++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Kb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Nb(Jb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Pb(o,y,d)),v=Qb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Rb={0:200,1223:204},Sb=r.ajaxSettings.xhr();o.cors=!!Sb&&"withCredentials"in Sb,o.ajax=Sb=!!Sb,r.ajaxTransport(function(b){var c,d;if(o.cors||Sb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Rb[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r("<script>").prop({charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&f("error"===a.type?404:200,a.type)}),d.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Tb=[],Ub=/(=)\?(?=&|$)|\?\?/;r.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Tb.pop()||r.expando+"_"+ub++;return this[a]=!0,a}}),r.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Ub.test(b.url)?"url":"string"==typeof b.data&&0===(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ub.test(b.data)&&"data");if(h||"jsonp"===b.dataTypes[0])return e=b.jsonpCallback=r.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Ub,"$1"+e):b.jsonp!==!1&&(b.url+=(vb.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||r.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){void 0===f?r(a).removeProp(e):a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Tb.push(e)),g&&r.isFunction(f)&&f(g[0]),g=f=void 0}),"script"}),o.createHTMLDocument=function(){var a=d.implementation.createHTMLDocument("").body;return a.innerHTML="<form></form><form></form>",2===a.childNodes.length}(),r.parseHTML=function(a,b,c){if("string"!=typeof a)return[];"boolean"==typeof b&&(c=b,b=!1);var e,f,g;return b||(o.createHTMLDocument?(b=d.implementation.createHTMLDocument(""),e=b.createElement("base"),e.href=d.location.href,b.head.appendChild(e)):b=d),f=C.exec(a),g=!c&&[],f?[b.createElement(f[1])]:(f=qa([a],b,g),g&&g.length&&r(g).remove(),r.merge([],f.childNodes))},r.fn.load=function(a,b,c){var d,e,f,g=this,h=a.indexOf(" ");return h>-1&&(d=pb(a.slice(h)),a=a.slice(0,h)),r.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&r.ajax({url:a,type:e||"GET",dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?r("<div>").append(r.parseHTML(a)).find(d):a)}).always(c&&function(a,b){g.each(function(){c.apply(this,f||[a.responseText,b,a])})}),this},r.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){r.fn[b]=function(a){return this.on(b,a)}}),r.expr.pseudos.animated=function(a){return r.grep(r.timers,function(b){return a===b.elem}).length},r.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=r.css(a,"position"),l=r(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=r.css(a,"top"),i=r.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),r.isFunction(b)&&(b=b.call(a,c,r.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},r.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){r.offset.setOffset(this,a,b)});var b,c,d,e,f=this[0];if(f)return f.getClientRects().length?(d=f.getBoundingClientRect(),b=f.ownerDocument,c=b.documentElement,e=b.defaultView,{top:d.top+e.pageYOffset-c.clientTop,left:d.left+e.pageXOffset-c.clientLeft}):{top:0,left:0}},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===r.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),B(a[0],"html")||(d=a.offset()),d={top:d.top+r.css(a[0],"borderTopWidth",!0),left:d.left+r.css(a[0],"borderLeftWidth",!0)}),{top:b.top-d.top-r.css(c,"marginTop",!0),left:b.left-d.left-r.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&"static"===r.css(a,"position"))a=a.offsetParent;return a||ra})}}),r.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c="pageYOffset"===b;r.fn[a]=function(d){return T(this,function(a,d,e){var f;return r.isWindow(a)?f=a:9===a.nodeType&&(f=a.defaultView),void 0===e?f?f[b]:a[d]:void(f?f.scrollTo(c?f.pageXOffset:e,c?e:f.pageYOffset):a[d]=e)},a,d,arguments.length)}}),r.each(["top","left"],function(a,b){r.cssHooks[b]=Pa(o.pixelPosition,function(a,c){if(c)return c=Oa(a,b),Ma.test(c)?r(a).position()[b]+"px":c})}),r.each({Height:"height",Width:"width"},function(a,b){r.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){r.fn[d]=function(e,f){var g=arguments.length&&(c||"boolean"!=typeof e),h=c||(e===!0||f===!0?"margin":"border");return T(this,function(b,c,e){var f;return r.isWindow(b)?0===d.indexOf("outer")?b["inner"+a]:b.document.documentElement["client"+a]:9===b.nodeType?(f=b.documentElement,Math.max(b.body["scroll"+a],f["scroll"+a],b.body["offset"+a],f["offset"+a],f["client"+a])):void 0===e?r.css(b,c,h):r.style(b,c,e,h)},b,g?e:void 0,g)}})}),r.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}}),r.holdReady=function(a){a?r.readyWait++:r.ready(!0)},r.isArray=Array.isArray,r.parseJSON=JSON.parse,r.nodeName=B,"function"==typeof define&&define.amd&&define("jquery",[],function(){return r});var Vb=a.jQuery,Wb=a.$;return r.noConflict=function(b){return a.$===r&&(a.$=Wb),b&&a.jQuery===r&&(a.jQuery=Vb),r},b||(a.jQuery=a.$=r),r}); diff --git a/refs/pull/405/merge/_static/js/badge_only.js b/refs/pull/405/merge/_static/js/badge_only.js new file mode 100644 index 00000000..526d7234 --- /dev/null +++ b/refs/pull/405/merge/_static/js/badge_only.js @@ -0,0 +1 @@ +!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}}); \ No newline at end of file diff --git a/refs/pull/405/merge/_static/js/html5shiv-printshiv.min.js b/refs/pull/405/merge/_static/js/html5shiv-printshiv.min.js new file mode 100644 index 00000000..2b43bd06 --- /dev/null +++ b/refs/pull/405/merge/_static/js/html5shiv-printshiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3-pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/refs/pull/405/merge/_static/js/html5shiv.min.js b/refs/pull/405/merge/_static/js/html5shiv.min.js new file mode 100644 index 00000000..cd1c674f --- /dev/null +++ b/refs/pull/405/merge/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/refs/pull/405/merge/_static/js/theme.js b/refs/pull/405/merge/_static/js/theme.js new file mode 100644 index 00000000..1fddb6ee --- /dev/null +++ b/refs/pull/405/merge/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("<div class='wy-table-responsive'></div>"),n("table.docutils.footnote").wrap("<div class='wy-table-responsive footnote'></div>"),n("table.docutils.citation").wrap("<div class='wy-table-responsive citation'></div>"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n('<button class="toctree-expand" title="Open/close menu"></button>'),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t<e.length&&!window.requestAnimationFrame;++t)window.requestAnimationFrame=window[e[t]+"RequestAnimationFrame"],window.cancelAnimationFrame=window[e[t]+"CancelAnimationFrame"]||window[e[t]+"CancelRequestAnimationFrame"];window.requestAnimationFrame||(window.requestAnimationFrame=function(e,t){var i=(new Date).getTime(),o=Math.max(0,16-(i-n)),r=window.setTimeout((function(){e(i+o)}),o);return n=i+o,r}),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(n){clearTimeout(n)})}()}).call(window)},function(n,e){n.exports=jQuery},function(n,e,t){}]); \ No newline at end of file diff --git a/refs/pull/405/merge/_static/minus.png b/refs/pull/405/merge/_static/minus.png new file mode 100644 index 00000000..d96755fd Binary files /dev/null and b/refs/pull/405/merge/_static/minus.png differ diff --git a/refs/pull/405/merge/_static/plus.png b/refs/pull/405/merge/_static/plus.png new file mode 100644 index 00000000..7107cec9 Binary files /dev/null and b/refs/pull/405/merge/_static/plus.png differ diff --git a/refs/pull/405/merge/_static/pygments.css b/refs/pull/405/merge/_static/pygments.css new file mode 100644 index 00000000..20c4814d --- /dev/null +++ b/refs/pull/405/merge/_static/pygments.css @@ -0,0 +1,69 @@ +.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #333333 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #208050 } /* Literal.Number.Bin */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e } /* Name.Function.Magic */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/refs/pull/405/merge/_static/searchtools.js b/refs/pull/405/merge/_static/searchtools.js new file mode 100644 index 00000000..41b83367 --- /dev/null +++ b/refs/pull/405/merge/_static/searchtools.js @@ -0,0 +1,761 @@ +/* + * searchtools.js_t + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + + +/* Non-minified version JS is _stemmer.js if file is provided */ +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + + + +/** + * Simple result scoring code. + */ +var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [filename, title, anchor, descr, score] + // and returns the new score. + /* + score: function(result) { + return result[4]; + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: {0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5}, // used to be unimportantResults + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + // query found in terms + term: 5 +}; + + + + + +var splitChars = (function() { + var result = {}; + var singles = [96, 180, 187, 191, 215, 247, 749, 885, 903, 907, 909, 930, 1014, 1648, + 1748, 1809, 2416, 2473, 2481, 2526, 2601, 2609, 2612, 2615, 2653, 2702, + 2706, 2729, 2737, 2740, 2857, 2865, 2868, 2910, 2928, 2948, 2961, 2971, + 2973, 3085, 3089, 3113, 3124, 3213, 3217, 3241, 3252, 3295, 3341, 3345, + 3369, 3506, 3516, 3633, 3715, 3721, 3736, 3744, 3748, 3750, 3756, 3761, + 3781, 3912, 4239, 4347, 4681, 4695, 4697, 4745, 4785, 4799, 4801, 4823, + 4881, 5760, 5901, 5997, 6313, 7405, 8024, 8026, 8028, 8030, 8117, 8125, + 8133, 8181, 8468, 8485, 8487, 8489, 8494, 8527, 11311, 11359, 11687, 11695, + 11703, 11711, 11719, 11727, 11735, 12448, 12539, 43010, 43014, 43019, 43587, + 43696, 43713, 64286, 64297, 64311, 64317, 64319, 64322, 64325, 65141]; + var i, j, start, end; + for (i = 0; i < singles.length; i++) { + result[singles[i]] = true; + } + var ranges = [[0, 47], [58, 64], [91, 94], [123, 169], [171, 177], [182, 184], [706, 709], + [722, 735], [741, 747], [751, 879], [888, 889], [894, 901], [1154, 1161], + [1318, 1328], [1367, 1368], [1370, 1376], [1416, 1487], [1515, 1519], [1523, 1568], + [1611, 1631], [1642, 1645], [1750, 1764], [1767, 1773], [1789, 1790], [1792, 1807], + [1840, 1868], [1958, 1968], [1970, 1983], [2027, 2035], [2038, 2041], [2043, 2047], + [2070, 2073], [2075, 2083], [2085, 2087], [2089, 2307], [2362, 2364], [2366, 2383], + [2385, 2391], [2402, 2405], [2419, 2424], [2432, 2436], [2445, 2446], [2449, 2450], + [2483, 2485], [2490, 2492], [2494, 2509], [2511, 2523], [2530, 2533], [2546, 2547], + [2554, 2564], [2571, 2574], [2577, 2578], [2618, 2648], [2655, 2661], [2672, 2673], + [2677, 2692], [2746, 2748], [2750, 2767], [2769, 2783], [2786, 2789], [2800, 2820], + [2829, 2830], [2833, 2834], [2874, 2876], [2878, 2907], [2914, 2917], [2930, 2946], + [2955, 2957], [2966, 2968], [2976, 2978], [2981, 2983], [2987, 2989], [3002, 3023], + [3025, 3045], [3059, 3076], [3130, 3132], [3134, 3159], [3162, 3167], [3170, 3173], + [3184, 3191], [3199, 3204], [3258, 3260], [3262, 3293], [3298, 3301], [3312, 3332], + [3386, 3388], [3390, 3423], [3426, 3429], [3446, 3449], [3456, 3460], [3479, 3481], + [3518, 3519], [3527, 3584], [3636, 3647], [3655, 3663], [3674, 3712], [3717, 3718], + [3723, 3724], [3726, 3731], [3752, 3753], [3764, 3772], [3774, 3775], [3783, 3791], + [3802, 3803], [3806, 3839], [3841, 3871], [3892, 3903], [3949, 3975], [3980, 4095], + [4139, 4158], [4170, 4175], [4182, 4185], [4190, 4192], [4194, 4196], [4199, 4205], + [4209, 4212], [4226, 4237], [4250, 4255], [4294, 4303], [4349, 4351], [4686, 4687], + [4702, 4703], [4750, 4751], [4790, 4791], [4806, 4807], [4886, 4887], [4955, 4968], + [4989, 4991], [5008, 5023], [5109, 5120], [5741, 5742], [5787, 5791], [5867, 5869], + [5873, 5887], [5906, 5919], [5938, 5951], [5970, 5983], [6001, 6015], [6068, 6102], + [6104, 6107], [6109, 6111], [6122, 6127], [6138, 6159], [6170, 6175], [6264, 6271], + [6315, 6319], [6390, 6399], [6429, 6469], [6510, 6511], [6517, 6527], [6572, 6592], + [6600, 6607], [6619, 6655], [6679, 6687], [6741, 6783], [6794, 6799], [6810, 6822], + [6824, 6916], [6964, 6980], [6988, 6991], [7002, 7042], [7073, 7085], [7098, 7167], + [7204, 7231], [7242, 7244], [7294, 7400], [7410, 7423], [7616, 7679], [7958, 7959], + [7966, 7967], [8006, 8007], [8014, 8015], [8062, 8063], [8127, 8129], [8141, 8143], + [8148, 8149], [8156, 8159], [8173, 8177], [8189, 8303], [8306, 8307], [8314, 8318], + [8330, 8335], [8341, 8449], [8451, 8454], [8456, 8457], [8470, 8472], [8478, 8483], + [8506, 8507], [8512, 8516], [8522, 8525], [8586, 9311], [9372, 9449], [9472, 10101], + [10132, 11263], [11493, 11498], [11503, 11516], [11518, 11519], [11558, 11567], + [11622, 11630], [11632, 11647], [11671, 11679], [11743, 11822], [11824, 12292], + [12296, 12320], [12330, 12336], [12342, 12343], [12349, 12352], [12439, 12444], + [12544, 12548], [12590, 12592], [12687, 12689], [12694, 12703], [12728, 12783], + [12800, 12831], [12842, 12880], [12896, 12927], [12938, 12976], [12992, 13311], + [19894, 19967], [40908, 40959], [42125, 42191], [42238, 42239], [42509, 42511], + [42540, 42559], [42592, 42593], [42607, 42622], [42648, 42655], [42736, 42774], + [42784, 42785], [42889, 42890], [42893, 43002], [43043, 43055], [43062, 43071], + [43124, 43137], [43188, 43215], [43226, 43249], [43256, 43258], [43260, 43263], + [43302, 43311], [43335, 43359], [43389, 43395], [43443, 43470], [43482, 43519], + [43561, 43583], [43596, 43599], [43610, 43615], [43639, 43641], [43643, 43647], + [43698, 43700], [43703, 43704], [43710, 43711], [43715, 43738], [43742, 43967], + [44003, 44015], [44026, 44031], [55204, 55215], [55239, 55242], [55292, 55295], + [57344, 63743], [64046, 64047], [64110, 64111], [64218, 64255], [64263, 64274], + [64280, 64284], [64434, 64466], [64830, 64847], [64912, 64913], [64968, 65007], + [65020, 65135], [65277, 65295], [65306, 65312], [65339, 65344], [65371, 65381], + [65471, 65473], [65480, 65481], [65488, 65489], [65496, 65497]]; + for (i = 0; i < ranges.length; i++) { + start = ranges[i][0]; + end = ranges[i][1]; + for (j = start; j <= end; j++) { + result[j] = true; + } + } + return result; +})(); + +function splitQuery(query) { + var result = []; + var start = -1; + for (var i = 0; i < query.length; i++) { + if (splitChars[query.charCodeAt(i)]) { + if (start !== -1) { + result.push(query.slice(start, i)); + start = -1; + } + } else if (start === -1) { + start = i; + } + } + if (start !== -1) { + result.push(query.slice(start)); + } + return result; +} + + + + +/** + * Search Module + */ +var Search = { + + _index : null, + _queued_query : null, + _pulse_status : -1, + + init : function() { + var params = $.getQueryParameters(); + if (params.q) { + var query = params.q[0]; + $('input[name="q"]')[0].value = query; + this.performSearch(query); + } + }, + + loadIndex : function(url) { + $.ajax({type: "GET", url: url, data: null, + dataType: "script", cache: true, + complete: function(jqxhr, textstatus) { + if (textstatus != "success") { + document.getElementById("searchindexloader").src = url; + } + }}); + }, + + setIndex : function(index) { + var q; + this._index = index; + if ((q = this._queued_query) !== null) { + this._queued_query = null; + Search.query(q); + } + }, + + hasIndex : function() { + return this._index !== null; + }, + + deferQuery : function(query) { + this._queued_query = query; + }, + + stopPulse : function() { + this._pulse_status = 0; + }, + + startPulse : function() { + if (this._pulse_status >= 0) + return; + function pulse() { + var i; + Search._pulse_status = (Search._pulse_status + 1) % 4; + var dotString = ''; + for (i = 0; i < Search._pulse_status; i++) + dotString += '.'; + Search.dots.text(dotString); + if (Search._pulse_status > -1) + window.setTimeout(pulse, 500); + } + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch : function(query) { + // create the required interface elements + this.out = $('#search-results'); + this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out); + this.dots = $('<span></span>').appendTo(this.title); + this.status = $('<p style="display: none"></p>').appendTo(this.out); + this.output = $('<ul class="search"/>').appendTo(this.out); + + $('#search-progress').text(_('Preparing search...')); + this.startPulse(); + + // index already loaded, the browser was quick! + if (this.hasIndex()) + this.query(query); + else + this.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query : function(query) { + var i; + var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"]; + + // stem the searchterms and add them to the correct list + var stemmer = new Stemmer(); + var searchterms = []; + var excluded = []; + var hlterms = []; + var tmp = splitQuery(query); + var objectterms = []; + for (i = 0; i < tmp.length; i++) { + if (tmp[i] !== "") { + objectterms.push(tmp[i].toLowerCase()); + } + + if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i].match(/^\d+$/) || + tmp[i] === "") { + // skip this "word" + continue; + } + // stem the word + var word = stemmer.stemWord(tmp[i].toLowerCase()); + // prevent stemmer from cutting word smaller than two chars + if(word.length < 3 && tmp[i].length >= 3) { + word = tmp[i]; + } + var toAppend; + // select the correct list + if (word[0] == '-') { + toAppend = excluded; + word = word.substr(1); + } + else { + toAppend = searchterms; + hlterms.push(tmp[i].toLowerCase()); + } + // only add if not already in the list + if (!$u.contains(toAppend, word)) + toAppend.push(word); + } + var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" ")); + + // console.debug('SEARCH: searching for:'); + // console.info('required: ', searchterms); + // console.info('excluded: ', excluded); + + // prepare search + var terms = this._index.terms; + var titleterms = this._index.titleterms; + + // array of [filename, title, anchor, descr, score] + var results = []; + $('#search-progress').empty(); + + // lookup as object + for (i = 0; i < objectterms.length; i++) { + var others = [].concat(objectterms.slice(0, i), + objectterms.slice(i+1, objectterms.length)); + results = results.concat(this.performObjectSearch(objectterms[i], others)); + } + + // lookup as search terms in fulltext + results = results.concat(this.performTermsSearch(searchterms, excluded, terms, titleterms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) { + for (i = 0; i < results.length; i++) + results[i][4] = Scorer.score(results[i]); + } + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort(function(a, b) { + var left = a[4]; + var right = b[4]; + if (left > right) { + return 1; + } else if (left < right) { + return -1; + } else { + // same score: sort alphabetically + left = a[1].toLowerCase(); + right = b[1].toLowerCase(); + return (left > right) ? -1 : ((left < right) ? 1 : 0); + } + }); + + // for debugging + //Search.lastresults = results.slice(); // a copy + //console.info('search results:', Search.lastresults); + + // print the results + var resultCount = results.length; + function displayNextItem() { + // results left, load the summary and display it + if (results.length) { + var item = results.pop(); + var listItem = $('<li style="display:none"></li>'); + if (DOCUMENTATION_OPTIONS.FILE_SUFFIX === '') { + // dirhtml builder + var dirname = item[0] + '/'; + if (dirname.match(/\/index\/$/)) { + dirname = dirname.substring(0, dirname.length-6); + } else if (dirname == 'index/') { + dirname = ''; + } + listItem.append($('<a/>').attr('href', + DOCUMENTATION_OPTIONS.URL_ROOT + dirname + + highlightstring + item[2]).html(item[1])); + } else { + // normal html builders + listItem.append($('<a/>').attr('href', + item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX + + highlightstring + item[2]).html(item[1])); + } + if (item[3]) { + listItem.append($('<span> (' + item[3] + ')</span>')); + Search.output.append(listItem); + listItem.slideDown(5, function() { + displayNextItem(); + }); + } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) { + var suffix = DOCUMENTATION_OPTIONS.SOURCELINK_SUFFIX; + if (suffix === undefined) { + suffix = '.txt'; + } + $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[5] + (item[5].slice(-suffix.length) === suffix ? '' : suffix), + dataType: "text", + complete: function(jqxhr, textstatus) { + var data = jqxhr.responseText; + if (data !== '' && data !== undefined) { + listItem.append(Search.makeSearchSummary(data, searchterms, hlterms)); + } + Search.output.append(listItem); + listItem.slideDown(5, function() { + displayNextItem(); + }); + }}); + } else { + // no source available, just display title + Search.output.append(listItem); + listItem.slideDown(5, function() { + displayNextItem(); + }); + } + } + // search finished, update title and status message + else { + Search.stopPulse(); + Search.title.text(_('Search Results')); + if (!resultCount) + Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.')); + else + Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount)); + Search.status.fadeIn(500); + } + } + displayNextItem(); + }, + + /** + * search for object names + */ + performObjectSearch : function(object, otherterms) { + var filenames = this._index.filenames; + var docnames = this._index.docnames; + var objects = this._index.objects; + var objnames = this._index.objnames; + var titles = this._index.titles; + + var i; + var results = []; + + for (var prefix in objects) { + for (var name in objects[prefix]) { + var fullname = (prefix ? prefix + '.' : '') + name; + if (fullname.toLowerCase().indexOf(object) > -1) { + var score = 0; + var parts = fullname.split('.'); + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullname == object || parts[parts.length - 1] == object) { + score += Scorer.objNameMatch; + // matches in last name + } else if (parts[parts.length - 1].indexOf(object) > -1) { + score += Scorer.objPartialMatch; + } + var match = objects[prefix][name]; + var objname = objnames[match[1]][2]; + var title = titles[match[0]]; + // If more than one term searched for, we require other words to be + // found in the name/title/description + if (otherterms.length > 0) { + var haystack = (prefix + ' ' + name + ' ' + + objname + ' ' + title).toLowerCase(); + var allfound = true; + for (i = 0; i < otherterms.length; i++) { + if (haystack.indexOf(otherterms[i]) == -1) { + allfound = false; + break; + } + } + if (!allfound) { + continue; + } + } + var descr = objname + _(', in ') + title; + + var anchor = match[3]; + if (anchor === '') + anchor = fullname; + else if (anchor == '-') + anchor = objnames[match[1]][1] + '-' + fullname; + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) { + score += Scorer.objPrio[match[2]]; + } else { + score += Scorer.objPrioDefault; + } + results.push([docnames[match[0]], fullname, '#'+anchor, descr, score, filenames[match[0]]]); + } + } + } + + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch : function(searchterms, excluded, terms, titleterms) { + var docnames = this._index.docnames; + var filenames = this._index.filenames; + var titles = this._index.titles; + + var i, j, file; + var fileMap = {}; + var scoreMap = {}; + var results = []; + + // perform the search on the required terms + for (i = 0; i < searchterms.length; i++) { + var word = searchterms[i]; + var files = []; + var _o = [ + {files: terms[word], score: Scorer.term}, + {files: titleterms[word], score: Scorer.title} + ]; + + // no match but word was a required one + if ($u.every(_o, function(o){return o.files === undefined;})) { + break; + } + // found search word in contents + $u.each(_o, function(o) { + var _files = o.files; + if (_files === undefined) + return + + if (_files.length === undefined) + _files = [_files]; + files = files.concat(_files); + + // set score for the word in each file to Scorer.term + for (j = 0; j < _files.length; j++) { + file = _files[j]; + if (!(file in scoreMap)) + scoreMap[file] = {} + scoreMap[file][word] = o.score; + } + }); + + // create the mapping + for (j = 0; j < files.length; j++) { + file = files[j]; + if (file in fileMap) + fileMap[file].push(word); + else + fileMap[file] = [word]; + } + } + + // now check if the files don't contain excluded terms + for (file in fileMap) { + var valid = true; + + // check if all requirements are matched + if (fileMap[file].length != searchterms.length) + continue; + + // ensure that none of the excluded terms is in the search result + for (i = 0; i < excluded.length; i++) { + if (terms[excluded[i]] == file || + titleterms[excluded[i]] == file || + $u.contains(terms[excluded[i]] || [], file) || + $u.contains(titleterms[excluded[i]] || [], file)) { + valid = false; + break; + } + } + + // if we have still a valid result we can add it to the result list + if (valid) { + // select one (max) score for the file. + // for better ranking, we should calculate ranking by using words statistics like basic tf-idf... + var score = $u.max($u.map(fileMap[file], function(w){return scoreMap[file][w]})); + results.push([docnames[file], titles[file], '', null, score, filenames[file]]); + } + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words, hlwords is the list of normal, unstemmed + * words. the first one is used to find the occurrence, the + * latter for highlighting it. + */ + makeSearchSummary : function(text, keywords, hlwords) { + var textLower = text.toLowerCase(); + var start = 0; + $.each(keywords, function() { + var i = textLower.indexOf(this.toLowerCase()); + if (i > -1) + start = i; + }); + start = Math.max(start - 120, 0); + var excerpt = ((start > 0) ? '...' : '') + + $.trim(text.substr(start, 240)) + + ((start + 240 - text.length) ? '...' : ''); + var rv = $('<div class="context"></div>').text(excerpt); + $.each(hlwords, function() { + rv = rv.highlightText(this, 'highlighted'); + }); + return rv; + } +}; + +$(document).ready(function() { + Search.init(); +}); \ No newline at end of file diff --git a/refs/pull/405/merge/_static/single.css b/refs/pull/405/merge/_static/single.css new file mode 100644 index 00000000..ca0451fc --- /dev/null +++ b/refs/pull/405/merge/_static/single.css @@ -0,0 +1,6 @@ +@import url(slides.css); + +.slides > article.level-2 > h2 { + position: static; + margin-top: 0; +} diff --git a/refs/pull/405/merge/_static/slides.css b/refs/pull/405/merge/_static/slides.css new file mode 100644 index 00000000..03fce601 --- /dev/null +++ b/refs/pull/405/merge/_static/slides.css @@ -0,0 +1,54 @@ +img.fill { + position: absolute; + left: 0; + top: 0; + min-width: 100%; + min-height: 100%; + + border-radius: 10px; + -o-border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + + z-index: -1; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink { + visibility: visible; +} + +div.figure p.caption { + position: absolute; + left: 0; + bottom: 0; + font-size: 0.5em; +} + +.slide-no { + position: absolute; + bottom: 1ex; + right: 1em; + font-size: 66%; +} + +.slide-footer { + position: absolute; + bottom: 1ex; + left: 1em; + font-size: 66%; +} + +div.admonition.note { + visibility: hidden; + display: none; +} diff --git a/refs/pull/405/merge/_static/slides.js b/refs/pull/405/merge/_static/slides.js new file mode 100644 index 00000000..8eb49782 --- /dev/null +++ b/refs/pull/405/merge/_static/slides.js @@ -0,0 +1,547 @@ +/* + + Slide Presentation Javascript + (consumers should include commons.js as well) + + ----- + + Based on Google HTML5 slides template + + Original Authors: Luke Mahé (code) + Marcin Wichary (code and design) + + Dominic Mazzoni (browser compatibility) + Charles Chen (ChromeVox support) + + URL: http://code.google.com/p/html5slides/ + +*/ + +var SlideDeck = ( + function() { + +var +curSlide, +slide_console; + +/* Slide movement */ + +function getSlideEl(no) { + if ((no < 0) || (no >= slideEls.length)) { + return null; + } else { + return slideEls[no]; + } +}; + +function updateSlideClass(slideNo, className) { + var el = getSlideEl(slideNo); + + if (!el) { + return; + } + + if (className) { + el.classList.add(className); + } + + for (var i in SLIDE_CLASSES) { + if (className != SLIDE_CLASSES[i]) { + el.classList.remove(SLIDE_CLASSES[i]); + } + } +}; + + +function updateSlides() { + for (var i = 0; i < slideEls.length; i++) { + switch (i) { + case curSlide - 2: + updateSlideClass(i, 'far-past'); + break; + case curSlide - 1: + updateSlideClass(i, 'past'); + break; + case curSlide: + updateSlideClass(i, 'current'); + break; + case curSlide + 1: + updateSlideClass(i, 'next'); + break; + case curSlide + 2: + updateSlideClass(i, 'far-next'); + break; + default: + updateSlideClass(i); + break; + } + } + + triggerLeaveEvent(curSlide - 1); + triggerEnterEvent(curSlide); + + window.setTimeout(function() { + // Hide after the slide + disableSlideFrames(curSlide - 2); + }, 301); + + enableSlideFrames(curSlide - 1); + enableSlideFrames(curSlide + 2); + + if (isChromeVoxActive()) { + speakAndSyncToNode(slideEls[curSlide]); + } + + updateHash(); + + // notifyListeners( + // {command: 'cur_slide', + // content: curSlide, + // prev_slide: curSlide > 0 ? getSlideEl(curSlide - 1).outerHTML : '', + // slide: getSlideEl(curSlide).outerHTML, + // next_slide: curSlide < slideEls.length - 1 ? getSlideEl(curSlide + 1).outerHTML : '' + // } + // ); + +}; + +function buildNextItem() { + var toBuild = slideEls[curSlide].querySelectorAll('.to-build'); + + if (!toBuild.length) { + return false; + } + + toBuild[0].classList.remove('to-build'); + + if (isChromeVoxActive()) { + speakAndSyncToNode(toBuild[0]); + } + + return true; +}; + + +function prevSlide() { + if (slidesContainer.classList.contains(TABLE_CLASS)) return; + + if (curSlide > 0) { + curSlide--; + + updateSlides(); + } +}; + +function nextSlide() { + if (slidesContainer.classList.contains(TABLE_CLASS)) return; + + if (buildNextItem()) { + return; + } + + if (curSlide < slideEls.length - 1) { + curSlide++; + + updateSlides(); + } +}; + +function showSlide(e) { + + if (!slidesContainer.classList.contains(TABLE_CLASS)) return; + + // toggle table class + toggleView(); + + // set curSlide + if (e) { + for (i = 0; i < slideEls.length; i++) { + if (slideEls[i].contains(e.target)) { + curSlide = i; + break; + } + } + } + + // update slide classes + updateSlides(); +}; + +function toggleView() { + for (var i = 0; i < slideEls.length; i++) { + updateSlideClass(i); + }; + + if (slidesContainer.classList.contains(TABLE_CLASS)) { + // leaving table mode + updateSlides(); + } + + slidesContainer.classList.toggle(TABLE_CLASS); + $(document).trigger('slidesSized'); +}; + + +/* Slide events */ + +function triggerEnterEvent(no) { + var el = getSlideEl(no); + if (!el) { + return; + } + + var onEnter = el.getAttribute('onslideenter'); + if (onEnter) { + new Function(onEnter).call(el); + } + + var evt = document.createEvent('Event'); + evt.initEvent('slideenter', true, true); + evt.slideNumber = no + 1; // Make it readable + + el.dispatchEvent(evt); +}; + +function triggerLeaveEvent(no) { + var el = getSlideEl(no); + if (!el) { + return; + } + + var onLeave = el.getAttribute('onslideleave'); + if (onLeave) { + new Function(onLeave).call(el); + } + + var evt = document.createEvent('Event'); + evt.initEvent('slideleave', true, true); + evt.slideNumber = no + 1; // Make it readable + + el.dispatchEvent(evt); +}; + +/* Touch events */ + +function handleTouchStart(event) { + if (event.touches.length == 1) { + touchDX = 0; + touchDY = 0; + + touchStartX = event.touches[0].pageX; + touchStartY = event.touches[0].pageY; + + document.body.addEventListener('touchmove', handleTouchMove, true); + document.body.addEventListener('touchend', handleTouchEnd, true); + } +}; + +function handleTouchMove(event) { + if (event.touches.length > 1) { + cancelTouch(); + } else { + touchDX = event.touches[0].pageX - touchStartX; + touchDY = event.touches[0].pageY - touchStartY; + } +}; + +function handleTouchEnd(event) { + var dx = Math.abs(touchDX); + var dy = Math.abs(touchDY); + + if ((dx > PM_TOUCH_SENSITIVITY) && (dy < (dx * 2 / 3))) { + if (touchDX > 0) { + prevSlide(); + } else { + nextSlide(); + } + } + + cancelTouch(); +}; + +function cancelTouch() { + document.body.removeEventListener('touchmove', handleTouchMove, true); + document.body.removeEventListener('touchend', handleTouchEnd, true); +}; + +/* Preloading frames */ + +function disableSlideFrames(no) { + var el = getSlideEl(no); + if (!el) { + return; + } + + var frames = el.getElementsByTagName('iframe'); + for (var i = 0, frame; frame = frames[i]; i++) { + disableFrame(frame); + } +}; + +function enableSlideFrames(no) { + var el = getSlideEl(no); + if (!el) { + return; + } + + var frames = el.getElementsByTagName('iframe'); + for (var i = 0, frame; frame = frames[i]; i++) { + enableFrame(frame); + } +}; + +function disableFrame(frame) { + frame.src = 'about:blank'; +}; + +function enableFrame(frame) { + var src = frame._src; + + if (frame.src != src && src != 'about:blank') { + frame.src = src; + } +}; + +function setupFrames() { + var frames = document.querySelectorAll('iframe'); + for (var i = 0, frame; frame = frames[i]; i++) { + frame._src = frame.src; + disableFrame(frame); + } + + enableSlideFrames(curSlide); + enableSlideFrames(curSlide + 1); + enableSlideFrames(curSlide + 2); +}; + +function setupInteraction() { + /* Clicking and tapping */ + + var el = document.createElement('div'); + el.className = 'slide-area'; + el.id = 'prev-slide-area'; + el.addEventListener('click', prevSlide, false); + document.querySelector('section.slides').appendChild(el); + + var el = document.createElement('div'); + el.className = 'slide-area'; + el.id = 'next-slide-area'; + el.addEventListener('click', nextSlide, false); + document.querySelector('section.slides').appendChild(el); + + /* Swiping */ + + document.body.addEventListener('touchstart', handleTouchStart, false); + + /* Clicking Slides */ + for (i = 0; i < slideEls.length; i++) { + slideEls[i].addEventListener('click', showSlide, false); + } + +} + +/* ChromeVox support */ + +function isChromeVoxActive() { + if (typeof(cvox) == 'undefined') { + return false; + } else { + return true; + } +}; + +function speakAndSyncToNode(node) { + if (!isChromeVoxActive()) { + return; + } + + cvox.ChromeVox.navigationManager.switchToStrategy( + cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM, 0, true); + cvox.ChromeVox.navigationManager.syncToNode(node); + cvox.ChromeVoxUserCommands.finishNavCommand(''); + var target = node; + while (target.firstChild) { + target = target.firstChild; + } + cvox.ChromeVox.navigationManager.syncToNode(target); +}; + +function speakNextItem() { + if (!isChromeVoxActive()) { + return; + } + + cvox.ChromeVox.navigationManager.switchToStrategy( + cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM, 0, true); + cvox.ChromeVox.navigationManager.next(true); + if (!cvox.DomUtil.isDescendantOfNode( + cvox.ChromeVox.navigationManager.getCurrentNode(), slideEls[curSlide])){ + var target = slideEls[curSlide]; + while (target.firstChild) { + target = target.firstChild; + } + cvox.ChromeVox.navigationManager.syncToNode(target); + cvox.ChromeVox.navigationManager.next(true); + } + cvox.ChromeVoxUserCommands.finishNavCommand(''); +}; + +function speakPrevItem() { + if (!isChromeVoxActive()) { + return; + } + + cvox.ChromeVox.navigationManager.switchToStrategy( + cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM, 0, true); + cvox.ChromeVox.navigationManager.previous(true); + if (!cvox.DomUtil.isDescendantOfNode( + cvox.ChromeVox.navigationManager.getCurrentNode(), slideEls[curSlide])){ + var target = slideEls[curSlide]; + while (target.lastChild){ + target = target.lastChild; + } + cvox.ChromeVox.navigationManager.syncToNode(target); + cvox.ChromeVox.navigationManager.previous(true); + } + cvox.ChromeVoxUserCommands.finishNavCommand(''); +}; + +/* Hash functions */ + +function findSlideById(title_id) { + // Return the 1-base index of the Slide with id ``title_id`` + // + // The index must be 1-based, as it's passed to code which assumes + // it was specified as the location fragment. + + for (var i = 0; i < slideEls.length; i++) { + if (slideEls.item(i).id == title_id) { + return i + 1; + } + } + + // no match on a slide, perhaps it's an explicit reference? + var + target_link = document.querySelector("span[id='" + title_id + "']"), + // XXX this is pretty strict, may need to be more flexible in the future + slide = (target_link && target_link.parentNode); + + if (slide && slide.tagName == 'ARTICLE') { + return findSlideById(slide.id); + } + + return false; + +}; + +function getCurSlideFromHash() { + var slideNo = Number(location.hash.substr(1)); + + if (isNaN(slideNo)) { + // must be a section title reference + slideNo = findSlideById(location.hash.substr(1)); + } + + if (slideNo) { + curSlide = slideNo - 1; + } else { + curSlide = 0; + } +}; + +function updateHash() { + location.replace('#' + (curSlide + 1)); +}; + +/* Event listeners */ + + + + +function addEventListeners() { + +}; + +/* Initialization */ + +function addGeneralStyle() { + var el = document.createElement('meta'); + el.name = 'viewport'; + el.content = 'width=1100,height=750'; + document.querySelector('head').appendChild(el); + + var el = document.createElement('meta'); + el.name = 'apple-mobile-web-app-capable'; + el.content = 'yes'; + document.querySelector('head').appendChild(el); +}; + +function makeBuildLists() { + for (var i = curSlide, slide; slide = slideEls[i]; i++) { + var items = slide.querySelectorAll('.build > *'); + for (var j = 0, item; item = items[j]; j++) { + if (item.classList) { + item.classList.add('to-build'); + } + } + } +}; + +function handleDomLoaded() { + slidesContainer = document.querySelector('section.slides'); + slideEls = document.querySelectorAll(SLIDES_SELECTOR); + + getCurSlideFromHash(); + setupFrames(); + + addGeneralStyle(); + addEventListeners(); + + updateSlides(); + + setupInteraction(); + makeBuildLists(); + + document.body.classList.add('loaded'); + $(document).trigger('slidesSized'); +}; + + + var + + getLocation = function () { + return curSlide; + }, + + setLocation = function (slide) { + curSlide = slide; + updateSlides(); + }, + + getLength = function () { + return slideEls.length; + }, + + init = function () { + document.addEventListener('DOMContentLoaded', handleDomLoaded, false); + }; + + + init(); + + return { + curSlide: getLocation, + location: getLocation, + setLocation: setLocation, + + toggleView: toggleView, + + length: getLength, + + getSlideEl: getSlideEl, + + nextSlide: nextSlide, + prevSlide: prevSlide + }; + + }()); diff --git a/refs/pull/405/merge/_static/styles.css b/refs/pull/405/merge/_static/styles.css new file mode 100644 index 00000000..b8d1b367 --- /dev/null +++ b/refs/pull/405/merge/_static/styles.css @@ -0,0 +1,723 @@ +@import url(fonts/stylesheet.css); + +/* + Google HTML5 slides template + + Authors: Luke Mahé (code) + Marcin Wichary (code and design) + + Dominic Mazzoni (browser compatibility) + Charles Chen (ChromeVox support) + + URL: http://code.google.com/p/html5slides/ +*/ + +/* Framework */ + +html { + height: 100%; +} + +body { + margin: 0; + padding: 0; + + display: block !important; + + height: 100%; + min-height: 740px; + + overflow-x: hidden; + overflow-y: auto; + + background: rgb(215, 215, 215); + background: -o-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190)); + background: -moz-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190)); + background: -webkit-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190)); + background: -webkit-gradient(radial, 50% 50%, 0, 50% 50%, 500, from(rgb(240, 240, 240)), to(rgb(190, 190, 190))); + + -webkit-font-smoothing: antialiased; +} + +.slides { + width: 100%; + height: 100%; + left: 0; + + position: absolute; + + -webkit-transform: translate3d(0, 0, 0); +} + +.slides > article { + display: block; + + position: absolute; + overflow: hidden; + + width: 900px; + height: 700px; + + left: 50%; + top: 50%; + + margin-left: -450px; + margin-top: -350px; + + padding: 40px 60px; + + box-sizing: border-box; + -o-box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + + border-radius: 10px; + -o-border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + + background-color: white; + + box-shadow: 0 2px 6px rgba(0, 0, 0, .1); + border: 1px solid rgba(0, 0, 0, .3); + + transition: transform .3s ease-out; + -o-transition: -o-transform .3s ease-out; + -moz-transition: -moz-transform .3s ease-out; + -webkit-transition: -webkit-transform .3s ease-out; +} +.slides.layout-widescreen > article { + margin-left: -550px; + width: 1100px; +} +.slides.layout-faux-widescreen > article { + margin-left: -550px; + width: 1100px; + + padding: 40px 160px; +} + +.slides.layout-widescreen > article:not(.nobackground):not(.biglogo), +.slides.layout-faux-widescreen > article:not(.nobackground):not(.biglogo) { + background-position-x: 0, 840px; +} + +.slides > article.appear { + transition: none; + display: none; +} + +.slides > article.fade-in { + transition: opacity 0.2s; +} + +.slides > article.fade-in.current { + z-index: 100; +} + +.slides .handout { + display: none; +} + +.slides.table { + font-size: 15px; + padding: 10px; +} + +.slides.table > .slide-area { + display: none; +} + +.slides.table > article:hover { + -moz-box-shadow: 0px 0px 20px yellow; + -webkit-box-shadow: 0px 0px 20px yellow; + box-shadow: 0px 0px 20px yellow; + border: 2px; +} + +.slides.table > article { + display: block; + float: left; + position: relative; + overflow: hidden; + + width: 450px; + height: 350px; + + left: 0; + top: 0; + + margin: 10px; + + padding: 20px 30px; + + box-sizing: border-box; + -o-box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + + border-radius: 10px; + -o-border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + + box-shadow: 0 2px 6px rgba(0, 0, 0, .1); + border: 1px solid rgba(0, 0, 0, .3); + + /* transform: scale(0.5); */ + /* -webkit-transform: scale(0.5); */ + transition: width height .3s ease-out; + -o-transition: -o-transform .3s ease-out; + -moz-transition: -moz-transform .3s ease-out; + -webkit-transition: width height .3s ease-out; +} + +.slides.table > article, +.slides.table > article.next, +.slides.table > article.far-past, +.slides.table > article.past, +.slides.table > article.current, +.slides.table > article.far-next { + display: block; + transform: translate(0px); + -o-transform: translate(0px); + -moz-transform: translate(0px); + -webkit-transform: translate(0px); +} + +.slides.table > article .to-build { + opacity: 100; +} + +/* Clickable/tappable areas */ + +.slide-area { + z-index: 1000; + + position: absolute; + left: 0; + top: 0; + width: 150px; + height: 700px; + + left: 50%; + top: 50%; + + cursor: pointer; + margin-top: -350px; + + tap-highlight-color: transparent; + -o-tap-highlight-color: transparent; + -moz-tap-highlight-color: transparent; + -webkit-tap-highlight-color: transparent; +} +#prev-slide-area { + margin-left: -550px; +} +#next-slide-area { + margin-left: 400px; +} +.slides.layout-widescreen #prev-slide-area, +.slides.layout-faux-widescreen #prev-slide-area { + margin-left: -650px; +} +.slides.layout-widescreen #next-slide-area, +.slides.layout-faux-widescreen #next-slide-area { + margin-left: 500px; +} + +/* Slides */ + +.slides > article { + display: none; +} +.slides > article.far-past { + display: block; + transform: translate(-2040px); + -o-transform: translate(-2040px); + -moz-transform: translate(-2040px); + -webkit-transform: translate3d(-2040px, 0, 0); +} +.slides > article.past { + display: block; + transform: translate(-1020px); + -o-transform: translate(-1020px); + -moz-transform: translate(-1020px); + -webkit-transform: translate3d(-1020px, 0, 0); +} +.slides > article.current { + display: block; + opacity: 1; + transform: translate(0); + -o-transform: translate(0); + -moz-transform: translate(0); + -webkit-transform: translate3d(0, 0, 0); +} +.slides > article.next { + display: block; + transform: translate(1020px); + -o-transform: translate(1020px); + -moz-transform: translate(1020px); + -webkit-transform: translate3d(1020px, 0, 0); +} +.slides > article.far-next { + display: block; + transform: translate(2040px); + -o-transform: translate(2040px); + -moz-transform: translate(2040px); + -webkit-transform: translate3d(2040px, 0, 0); +} + +.slides.layout-widescreen > article.far-past, +.slides.layout-faux-widescreen > article.far-past { + display: block; + transform: translate(-2260px); + -o-transform: translate(-2260px); + -moz-transform: translate(-2260px); + -webkit-transform: translate3d(-2260px, 0, 0); +} +.slides.layout-widescreen > article.past, +.slides.layout-faux-widescreen > article.past { + display: block; + transform: translate(-1130px); + -o-transform: translate(-1130px); + -moz-transform: translate(-1130px); + -webkit-transform: translate3d(-1130px, 0, 0); +} +.slides.layout-widescreen > article.current, +.slides.layout-faux-widescreen > article.current { + display: block; + transform: translate(0); + -o-transform: translate(0); + -moz-transform: translate(0); + -webkit-transform: translate3d(0, 0, 0); +} +.slides.layout-widescreen > article.next, +.slides.layout-faux-widescreen > article.next { + display: block; + transform: translate(1130px); + -o-transform: translate(1130px); + -moz-transform: translate(1130px); + -webkit-transform: translate3d(1130px, 0, 0); +} +.slides.layout-widescreen > article.far-next, +.slides.layout-faux-widescreen > article.far-next { + display: block; + transform: translate(2260px); + -o-transform: translate(2260px); + -moz-transform: translate(2260px); + -webkit-transform: translate3d(2260px, 0, 0); +} + +.slides > article.fade-in.next, +.slides > article.fade-in.far-past, +.slides > article.fade-in.past, +.slides > article.fade-in.far-next { + opacity: 0; + transform: translate(0px); + -o-transform: translate(0px); + -moz-transform: translate(0px); + -webkit-transform: translate(0px); +} + +.slides > article.appear.next, +.slides > article.appear.far-past, +.slides > article.appear.past, +.slides > article.appear.far-next { + display: none; + transform: translate(0px); + -o-transform: translate(0px); + -moz-transform: translate(0px); + -webkit-transform: translate(0px); +} + + +/* Styles for slides */ + +.slides { + font-size: 30px; +} + +.slides > article { + font-family: 'Open Sans', Arial, sans-serif; + + color: rgb(102, 102, 102); + text-shadow: 0 1px 1px rgba(0, 0, 0, .1); + + font-size: 1em; + line-height: 1.2em; + + letter-spacing: -1px; +} + +b { + font-weight: 600; +} + +.blue { + color: rgb(0, 102, 204); +} +.yellow { + color: rgb(255, 211, 25); +} +.green { + color: rgb(0, 138, 53); +} +.red { + color: rgb(255, 0, 0); +} +.black { + color: black; +} +.white { + color: white; +} + +a { + color: rgb(0, 102, 204); +} +a:visited { + color: rgba(0, 102, 204, .75); +} +a:hover { + color: black; +} + +p { + margin: 0; + padding: 0; + + margin-top: 20px; +} +p:first-child { + margin-top: 0; +} + +h1 { + font-size: 2em; + line-height: 1em; + + padding: 0; + margin: 0; + margin-top: 200px; + padding-right: 40px; + + font-weight: 600; + + letter-spacing: -3px; + + color: rgb(51, 51, 51); +} + +h2 { + font-size: 1.5em; + line-height: 1em; + + padding: 0; + margin: 0; + margin-top: 465px; + padding-right: 40px; + /* position: absolute; */ + /* bottom: 150px; */ + + font-weight: 600; + + letter-spacing: -2px; + + color: rgb(51, 51, 51); +} + +h3 { + font-size: 1em; + line-height: 1.2em; + + padding: 0; + margin: 0; + padding-right: 40px; + + font-weight: 600; + + letter-spacing: -1px; + + color: rgb(51, 51, 51); +} + +article.fill h3 { + background: rgba(255, 255, 255, .75); + padding-top: .2em; + padding-bottom: .3em; + margin-top: -.2em; + margin-left: -60px; + padding-left: 60px; + margin-right: -60px; + padding-right: 60px; +} + +ul { + list-style: none; + margin: 0; + padding: 0; + + margin-top: 40px; + + margin-left: .75em; +} +ul ul { + margin-top: .5em; +} +li { + padding: 0; + margin: 0; + + margin-bottom: .5em; +} +ul li::before { + content: '·'; + + width: .75em; + margin-left: -.75em; + + position: absolute; +} + +pre { + font-family: 'Droid Sans Mono', 'Courier New', monospace; + + font-size: 0.66em; + line-height: 1.4em; + padding: 5px 10px; + + letter-spacing: -1px; + + margin-top: 40px; + margin-bottom: 40px; + + color: black; + background: rgb(240, 240, 240); + border: 1px solid rgb(224, 224, 224); + box-shadow: inset 0 2px 6px rgba(0, 0, 0, .1); + + overflow: hidden; +} + +code { + font-size: 95%; + font-family: 'Droid Sans Mono', 'Courier New', monospace; + + color: black; +} + +iframe { + width: 100%; + + height: 620px; + + background: white; + border: 1px solid rgb(192, 192, 192); + margin: -1px; + /*box-shadow: inset 0 2px 6px rgba(0, 0, 0, .1);*/ +} + +h3 + iframe { + margin-top: 40px; + height: 540px; +} + +article.fill iframe { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + + border: 0; + margin: 0; + + border-radius: 10px; + -o-border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + + z-index: -1; +} + +article.fill img { + position: absolute; + left: 0; + top: 0; + min-width: 100%; + min-height: 100%; + + border-radius: 10px; + -o-border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + + z-index: -1; +} +img.centered { + margin: 0 auto; + display: block; +} + +table { + width: 100%; + border-collapse: collapse; + margin-top: 40px; +} +th { + font-weight: 600; + text-align: left; +} +td, +th { + border: 1px solid rgb(224, 224, 224); + padding: 5px 10px; + vertical-align: top; +} + +.source { + position: absolute; + left: 60px; + top: 644px; + padding-right: 175px; + + font-size: 0.5em; + letter-spacing: 0; + line-height: 18px; +} + +q { + display: block; + font-size: 2em; + line-height: 72px; + + margin-left: 20px; + + margin-top: 100px; + margin-right: 150px; +} +q::before { + content: '“'; + + position: absolute; + display: inline-block; + margin-left: -2.1em; + width: 2em; + text-align: right; + + font-size: 3em; + color: rgb(192, 192, 192); +} +q::after { + content: '”'; + + position: absolute; + margin-left: .1em; + + font-size: 3em; + color: rgb(192, 192, 192); +} +div.author { + text-align: right; + font-size: 1.33em; + + margin-top: 20px; + margin-right: 150px; +} +div.author::before { + content: '—'; +} + +/* Size variants */ + +article.smaller p, +article.smaller ul { + font-size: 0.66em; + line-height: 1.2em; + letter-spacing: 0; +} +article.smaller table { + font-size: 0.66em; + line-height: 1.2em; + letter-spacing: 0; +} +article.smaller pre { + font-size: 0.5em; + line-height: 1.33em; + letter-spacing: 0; +} +article.smaller q { + font-size: 1.33em; + line-height: 1.2em; +} +article.smaller q::before, +article.smaller q::after { + font-size: 2em; +} + +/* Builds */ + +.build > * { + transition: opacity 0.5s ease-in-out 0.2s; + -o-transition: opacity 0.5s ease-in-out 0.2s; + -moz-transition: opacity 0.5s ease-in-out 0.2s; + -webkit-transition: opacity 0.5s ease-in-out 0.2s; +} + +.to-build { + opacity: 0; +} + +/* Pretty print */ + +.prettyprint .str, /* string content */ +.prettyprint .atv { /* a markup attribute value */ + color: rgb(0, 138, 53); +} +.prettyprint .kwd, /* a keyword */ +.prettyprint .tag { /* a markup tag name */ + color: rgb(0, 102, 204); +} +.prettyprint .com { /* a comment */ + color: rgb(127, 127, 127); + font-style: italic; +} +.prettyprint .lit { /* a literal value */ + color: rgb(127, 0, 0); +} +.prettyprint .pun, /* punctuation, lisp open bracket, lisp close bracket */ +.prettyprint .opn, +.prettyprint .clo { + color: rgb(127, 127, 127); +} +.prettyprint .typ, /* a type name */ +.prettyprint .atn, /* a markup attribute name */ +.prettyprint .dec, +.prettyprint .var { /* a declaration; a variable name */ + color: rgb(127, 0, 127); +} + +@media print { + + .slides > article, + .slides > article.far-past, + .slides > article.past, + .slides > article.next, + .slides > article.far-next { + + position: static; + overflow: hidden; + display: block !important; + + margin: auto; + page-break-after: always; + page-break-inside: avoid; + + transform: none; + -o-transform: none; + -moz-transform: none; + -webkit-transform: none; + } + +} diff --git a/refs/pull/405/merge/_static/sync.js b/refs/pull/405/merge/_static/sync.js new file mode 100644 index 00000000..8319161b --- /dev/null +++ b/refs/pull/405/merge/_static/sync.js @@ -0,0 +1,129 @@ +var SlideSync = ( + function() { + + var + slides, + slide_listeners = [], + + showConsole = function(e) { + slide_console = window.open( + DOCUMENTATION_OPTIONS.URL_ROOT + 'console.html', + 'console', + "menubar=no,location=no,resizable=yes,scrollbars=yes,status=yes"); + }, + + nextSlide = function() { + slides.nextSlide(); + + sendCommand('nextSlide'); + sendCurSlide(); + }, + + prevSlide = function() { + slides.prevSlide(); + + sendCommand('prevSlide'); + sendCurSlide(); + }, + + sendCurSlide = function() { + + var curSlide = slides.curSlide(); + + notifyListeners( + {command: 'cur_slide', + content: curSlide, + prev_slide: curSlide > 0 ? slides.getSlideEl(curSlide - 1).outerHTML : '', + slide: slides.getSlideEl(curSlide).outerHTML, + next_slide: curSlide < slides.length() - 1 ? slides.getSlideEl(curSlide + 1).outerHTML : '' + } + ); + + }, + + notifyListeners = function (message) { + + for (var i = 0; i < slide_listeners.length; i++) { + slide_listeners[i].postMessage(message, '*'); + } + + }, + + sendCommand = function(command) { + return sendMessage({'command':command}); + }, + + sendMessage = function(message) { + notifyListeners(message); + }, + + handleMessage = function(message, source) { + + console.log(message); + + switch (message.command) { + + case 'register': + slide_listeners.push(source); + sendMessage( + {command: 'num_slides', + content: slideEls.length + } + ); + break; + + case 'nextSlide': + slides.nextSlide(); + break; + + case 'prevSlide': + slides.prevSlide(); + break; + + }; + + sendCurSlide(); + + }, + + onKeyDown = function (event) { + + switch (event.keyCode) { + + case 84: // t + slides.toggleView && slides.toggleView(); + break; + + case 67: // c + showConsole(); + break; + } + }, + + init = function(slidedeck) { + slides = slidedeck; + + // attach event handlers + document.addEventListener('keydown', onKeyDown, false); + window.addEventListener( + 'message', + function(e) { + return handleMessage(e.data, e.source); + }, false); + + }; + + + return { + init: init, + showConsole: showConsole, + + nextSlide: nextSlide, + prevSlide: prevSlide, + + handleMessage: handleMessage, + sendMessage: sendMessage, + sendCommand: sendCommand + }; + + }()); \ No newline at end of file diff --git a/refs/pull/405/merge/_static/theme.css b/refs/pull/405/merge/_static/theme.css new file mode 100644 index 00000000..ba0589f0 --- /dev/null +++ b/refs/pull/405/merge/_static/theme.css @@ -0,0 +1,3 @@ +a.headerlink { + display: none; +} \ No newline at end of file diff --git a/refs/pull/405/merge/_static/theme_overrides.css b/refs/pull/405/merge/_static/theme_overrides.css new file mode 100644 index 00000000..a0052bd1 --- /dev/null +++ b/refs/pull/405/merge/_static/theme_overrides.css @@ -0,0 +1,149 @@ +/* -*- coding: utf-8; mode: css -*- + * + * Sphinx HTML theme customization: read the doc + * + */ + +/* Improve contrast and increase size for easier reading. */ + +body { + font-family: serif; + color: black; + font-size: 100%; +} + +h1, h2, .rst-content .toctree-wrapper p.caption, h3, h4, h5, h6, legend { + font-family: sans-serif; +} + +.wy-menu-vertical li.current a { + color: #505050; +} + +.wy-menu-vertical li.on a, .wy-menu-vertical li.current > a { + color: #303030; +} + +div[class^="highlight"] pre { + font-family: monospace; + color: black; + font-size: 100%; +} + +.wy-menu-vertical { + font-family: sans-serif; +} + +.c { + font-style: normal; +} + +p { + font-size: 100%; +} + +/* Interim: Code-blocks with line nos - lines and line numbers don't line up. + * see: https://github.com/rtfd/sphinx_rtd_theme/issues/419 + */ + +div[class^="highlight"] pre { + line-height: normal; +} +.rst-content .highlight > pre { + line-height: normal; +} + +/* Keep fields from being strangely far apart due to inheirited table CSS. */ +.rst-content table.field-list th.field-name { + padding-top: 1px; + padding-bottom: 1px; +} +.rst-content table.field-list td.field-body { + padding-top: 1px; + padding-bottom: 1px; +} + +@media screen { + + /* content column + * + * RTD theme's default is 800px as max width for the content, but we have + * tables with tons of columns, which need the full width of the view-port. + */ + + .wy-nav-content{max-width: none; } + + /* table: + * + * - Sequences of whitespace should collapse into a single whitespace. + * - make the overflow auto (scrollbar if needed) + * - align caption "left" ("center" is unsuitable on vast tables) + */ + + .wy-table-responsive table td { white-space: normal; } + .wy-table-responsive { overflow: auto; } + .rst-content table.docutils caption { text-align: left; font-size: 100%; } + + /* captions: + * + * - captions should have 100% (not 85%) font size + * - hide the permalink symbol as long as link is not hovered + */ + + .toc-title { + font-size: 150%; + font-weight: bold; + } + + caption, .wy-table caption, .rst-content table.field-list caption { + font-size: 100%; + } + caption a.headerlink { opacity: 0; } + caption a.headerlink:hover { opacity: 1; } + + /* Menu selection and keystrokes */ + + span.menuselection { + color: blue; + font-family: "Courier New", Courier, monospace + } + + code.kbd, code.kbd span { + color: white; + background-color: darkblue; + font-weight: bold; + font-family: "Courier New", Courier, monospace + } + + /* fix bottom margin of lists items */ + + .rst-content .section ul li:last-child, .rst-content .section ul li p:last-child { + margin-bottom: 12px; + } + + /* inline literal: drop the borderbox, padding and red color */ + + code, .rst-content tt, .rst-content code { + color: inherit; + border: none; + padding: unset; + background: inherit; + font-size: 85%; + } + + .rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal { + color: inherit; + } +} + +/* scrollable code blocks in slides */ +div[class^="highlight"] pre { + font-size: 45%; + max-height: 500px; + overflow-y: scroll; +} + +/* disable scroll in docs */ +.rst-content .highlight > pre { + max-height: none; +} diff --git a/refs/pull/405/merge/_static/underscore-1.3.1.js b/refs/pull/405/merge/_static/underscore-1.3.1.js new file mode 100644 index 00000000..208d4cd8 --- /dev/null +++ b/refs/pull/405/merge/_static/underscore-1.3.1.js @@ -0,0 +1,999 @@ +// Underscore.js 1.3.1 +// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore is freely distributable under the MIT license. +// Portions of Underscore are inspired or borrowed from Prototype, +// Oliver Steele's Functional, and John Resig's Micro-Templating. +// For all details and documentation: +// http://documentcloud.github.com/underscore + +(function() { + + // Baseline setup + // -------------- + + // Establish the root object, `window` in the browser, or `global` on the server. + var root = this; + + // Save the previous value of the `_` variable. + var previousUnderscore = root._; + + // Establish the object that gets returned to break out of a loop iteration. + var breaker = {}; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; + + // Create quick reference variables for speed access to core prototypes. + var slice = ArrayProto.slice, + unshift = ArrayProto.unshift, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. + var + nativeForEach = ArrayProto.forEach, + nativeMap = ArrayProto.map, + nativeReduce = ArrayProto.reduce, + nativeReduceRight = ArrayProto.reduceRight, + nativeFilter = ArrayProto.filter, + nativeEvery = ArrayProto.every, + nativeSome = ArrayProto.some, + nativeIndexOf = ArrayProto.indexOf, + nativeLastIndexOf = ArrayProto.lastIndexOf, + nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeBind = FuncProto.bind; + + // Create a safe reference to the Underscore object for use below. + var _ = function(obj) { return new wrapper(obj); }; + + // Export the Underscore object for **Node.js**, with + // backwards-compatibility for the old `require()` API. If we're in + // the browser, add `_` as a global object via a string identifier, + // for Closure Compiler "advanced" mode. + if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = _; + } + exports._ = _; + } else { + root['_'] = _; + } + + // Current version. + _.VERSION = '1.3.1'; + + // Collection Functions + // -------------------- + + // The cornerstone, an `each` implementation, aka `forEach`. + // Handles objects with the built-in `forEach`, arrays, and raw objects. + // Delegates to **ECMAScript 5**'s native `forEach` if available. + var each = _.each = _.forEach = function(obj, iterator, context) { + if (obj == null) return; + if (nativeForEach && obj.forEach === nativeForEach) { + obj.forEach(iterator, context); + } else if (obj.length === +obj.length) { + for (var i = 0, l = obj.length; i < l; i++) { + if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return; + } + } else { + for (var key in obj) { + if (_.has(obj, key)) { + if (iterator.call(context, obj[key], key, obj) === breaker) return; + } + } + } + }; + + // Return the results of applying the iterator to each element. + // Delegates to **ECMAScript 5**'s native `map` if available. + _.map = _.collect = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); + each(obj, function(value, index, list) { + results[results.length] = iterator.call(context, value, index, list); + }); + if (obj.length === +obj.length) results.length = obj.length; + return results; + }; + + // **Reduce** builds up a single result from a list of values, aka `inject`, + // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. + _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { + var initial = arguments.length > 2; + if (obj == null) obj = []; + if (nativeReduce && obj.reduce === nativeReduce) { + if (context) iterator = _.bind(iterator, context); + return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); + } + each(obj, function(value, index, list) { + if (!initial) { + memo = value; + initial = true; + } else { + memo = iterator.call(context, memo, value, index, list); + } + }); + if (!initial) throw new TypeError('Reduce of empty array with no initial value'); + return memo; + }; + + // The right-associative version of reduce, also known as `foldr`. + // Delegates to **ECMAScript 5**'s native `reduceRight` if available. + _.reduceRight = _.foldr = function(obj, iterator, memo, context) { + var initial = arguments.length > 2; + if (obj == null) obj = []; + if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { + if (context) iterator = _.bind(iterator, context); + return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); + } + var reversed = _.toArray(obj).reverse(); + if (context && !initial) iterator = _.bind(iterator, context); + return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator); + }; + + // Return the first value which passes a truth test. Aliased as `detect`. + _.find = _.detect = function(obj, iterator, context) { + var result; + any(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) { + result = value; + return true; + } + }); + return result; + }; + + // Return all the elements that pass a truth test. + // Delegates to **ECMAScript 5**'s native `filter` if available. + // Aliased as `select`. + _.filter = _.select = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); + each(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) results[results.length] = value; + }); + return results; + }; + + // Return all the elements for which a truth test fails. + _.reject = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + each(obj, function(value, index, list) { + if (!iterator.call(context, value, index, list)) results[results.length] = value; + }); + return results; + }; + + // Determine whether all of the elements match a truth test. + // Delegates to **ECMAScript 5**'s native `every` if available. + // Aliased as `all`. + _.every = _.all = function(obj, iterator, context) { + var result = true; + if (obj == null) return result; + if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); + each(obj, function(value, index, list) { + if (!(result = result && iterator.call(context, value, index, list))) return breaker; + }); + return result; + }; + + // Determine if at least one element in the object matches a truth test. + // Delegates to **ECMAScript 5**'s native `some` if available. + // Aliased as `any`. + var any = _.some = _.any = function(obj, iterator, context) { + iterator || (iterator = _.identity); + var result = false; + if (obj == null) return result; + if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); + each(obj, function(value, index, list) { + if (result || (result = iterator.call(context, value, index, list))) return breaker; + }); + return !!result; + }; + + // Determine if a given value is included in the array or object using `===`. + // Aliased as `contains`. + _.include = _.contains = function(obj, target) { + var found = false; + if (obj == null) return found; + if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; + found = any(obj, function(value) { + return value === target; + }); + return found; + }; + + // Invoke a method (with arguments) on every item in a collection. + _.invoke = function(obj, method) { + var args = slice.call(arguments, 2); + return _.map(obj, function(value) { + return (_.isFunction(method) ? method || value : value[method]).apply(value, args); + }); + }; + + // Convenience version of a common use case of `map`: fetching a property. + _.pluck = function(obj, key) { + return _.map(obj, function(value){ return value[key]; }); + }; + + // Return the maximum element or (element-based computation). + _.max = function(obj, iterator, context) { + if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj); + if (!iterator && _.isEmpty(obj)) return -Infinity; + var result = {computed : -Infinity}; + each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + computed >= result.computed && (result = {value : value, computed : computed}); + }); + return result.value; + }; + + // Return the minimum element (or element-based computation). + _.min = function(obj, iterator, context) { + if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj); + if (!iterator && _.isEmpty(obj)) return Infinity; + var result = {computed : Infinity}; + each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + computed < result.computed && (result = {value : value, computed : computed}); + }); + return result.value; + }; + + // Shuffle an array. + _.shuffle = function(obj) { + var shuffled = [], rand; + each(obj, function(value, index, list) { + if (index == 0) { + shuffled[0] = value; + } else { + rand = Math.floor(Math.random() * (index + 1)); + shuffled[index] = shuffled[rand]; + shuffled[rand] = value; + } + }); + return shuffled; + }; + + // Sort the object's values by a criterion produced by an iterator. + _.sortBy = function(obj, iterator, context) { + return _.pluck(_.map(obj, function(value, index, list) { + return { + value : value, + criteria : iterator.call(context, value, index, list) + }; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }), 'value'); + }; + + // Groups the object's values by a criterion. Pass either a string attribute + // to group by, or a function that returns the criterion. + _.groupBy = function(obj, val) { + var result = {}; + var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; }; + each(obj, function(value, index) { + var key = iterator(value, index); + (result[key] || (result[key] = [])).push(value); + }); + return result; + }; + + // Use a comparator function to figure out at what index an object should + // be inserted so as to maintain order. Uses binary search. + _.sortedIndex = function(array, obj, iterator) { + iterator || (iterator = _.identity); + var low = 0, high = array.length; + while (low < high) { + var mid = (low + high) >> 1; + iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid; + } + return low; + }; + + // Safely convert anything iterable into a real, live array. + _.toArray = function(iterable) { + if (!iterable) return []; + if (iterable.toArray) return iterable.toArray(); + if (_.isArray(iterable)) return slice.call(iterable); + if (_.isArguments(iterable)) return slice.call(iterable); + return _.values(iterable); + }; + + // Return the number of elements in an object. + _.size = function(obj) { + return _.toArray(obj).length; + }; + + // Array Functions + // --------------- + + // Get the first element of an array. Passing **n** will return the first N + // values in the array. Aliased as `head`. The **guard** check allows it to work + // with `_.map`. + _.first = _.head = function(array, n, guard) { + return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; + }; + + // Returns everything but the last entry of the array. Especcialy useful on + // the arguments object. Passing **n** will return all the values in + // the array, excluding the last N. The **guard** check allows it to work with + // `_.map`. + _.initial = function(array, n, guard) { + return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); + }; + + // Get the last element of an array. Passing **n** will return the last N + // values in the array. The **guard** check allows it to work with `_.map`. + _.last = function(array, n, guard) { + if ((n != null) && !guard) { + return slice.call(array, Math.max(array.length - n, 0)); + } else { + return array[array.length - 1]; + } + }; + + // Returns everything but the first entry of the array. Aliased as `tail`. + // Especially useful on the arguments object. Passing an **index** will return + // the rest of the values in the array from that index onward. The **guard** + // check allows it to work with `_.map`. + _.rest = _.tail = function(array, index, guard) { + return slice.call(array, (index == null) || guard ? 1 : index); + }; + + // Trim out all falsy values from an array. + _.compact = function(array) { + return _.filter(array, function(value){ return !!value; }); + }; + + // Return a completely flattened version of an array. + _.flatten = function(array, shallow) { + return _.reduce(array, function(memo, value) { + if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value)); + memo[memo.length] = value; + return memo; + }, []); + }; + + // Return a version of the array that does not contain the specified value(s). + _.without = function(array) { + return _.difference(array, slice.call(arguments, 1)); + }; + + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + // Aliased as `unique`. + _.uniq = _.unique = function(array, isSorted, iterator) { + var initial = iterator ? _.map(array, iterator) : array; + var result = []; + _.reduce(initial, function(memo, el, i) { + if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) { + memo[memo.length] = el; + result[result.length] = array[i]; + } + return memo; + }, []); + return result; + }; + + // Produce an array that contains the union: each distinct element from all of + // the passed-in arrays. + _.union = function() { + return _.uniq(_.flatten(arguments, true)); + }; + + // Produce an array that contains every item shared between all the + // passed-in arrays. (Aliased as "intersect" for back-compat.) + _.intersection = _.intersect = function(array) { + var rest = slice.call(arguments, 1); + return _.filter(_.uniq(array), function(item) { + return _.every(rest, function(other) { + return _.indexOf(other, item) >= 0; + }); + }); + }; + + // Take the difference between one array and a number of other arrays. + // Only the elements present in just the first array will remain. + _.difference = function(array) { + var rest = _.flatten(slice.call(arguments, 1)); + return _.filter(array, function(value){ return !_.include(rest, value); }); + }; + + // Zip together multiple lists into a single array -- elements that share + // an index go together. + _.zip = function() { + var args = slice.call(arguments); + var length = _.max(_.pluck(args, 'length')); + var results = new Array(length); + for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i); + return results; + }; + + // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), + // we need this function. Return the position of the first occurrence of an + // item in an array, or -1 if the item is not included in the array. + // Delegates to **ECMAScript 5**'s native `indexOf` if available. + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + _.indexOf = function(array, item, isSorted) { + if (array == null) return -1; + var i, l; + if (isSorted) { + i = _.sortedIndex(array, item); + return array[i] === item ? i : -1; + } + if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item); + for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i; + return -1; + }; + + // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. + _.lastIndexOf = function(array, item) { + if (array == null) return -1; + if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item); + var i = array.length; + while (i--) if (i in array && array[i] === item) return i; + return -1; + }; + + // Generate an integer Array containing an arithmetic progression. A port of + // the native Python `range()` function. See + // [the Python documentation](http://docs.python.org/library/functions.html#range). + _.range = function(start, stop, step) { + if (arguments.length <= 1) { + stop = start || 0; + start = 0; + } + step = arguments[2] || 1; + + var len = Math.max(Math.ceil((stop - start) / step), 0); + var idx = 0; + var range = new Array(len); + + while(idx < len) { + range[idx++] = start; + start += step; + } + + return range; + }; + + // Function (ahem) Functions + // ------------------ + + // Reusable constructor function for prototype setting. + var ctor = function(){}; + + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). Binding with arguments is also known as `curry`. + // Delegates to **ECMAScript 5**'s native `Function.bind` if available. + // We check for `func.bind` first, to fail fast when `func` is undefined. + _.bind = function bind(func, context) { + var bound, args; + if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + if (!_.isFunction(func)) throw new TypeError; + args = slice.call(arguments, 2); + return bound = function() { + if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); + ctor.prototype = func.prototype; + var self = new ctor; + var result = func.apply(self, args.concat(slice.call(arguments))); + if (Object(result) === result) return result; + return self; + }; + }; + + // Bind all of an object's methods to that object. Useful for ensuring that + // all callbacks defined on an object belong to it. + _.bindAll = function(obj) { + var funcs = slice.call(arguments, 1); + if (funcs.length == 0) funcs = _.functions(obj); + each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); + return obj; + }; + + // Memoize an expensive function by storing its results. + _.memoize = function(func, hasher) { + var memo = {}; + hasher || (hasher = _.identity); + return function() { + var key = hasher.apply(this, arguments); + return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); + }; + }; + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + _.delay = function(func, wait) { + var args = slice.call(arguments, 2); + return setTimeout(function(){ return func.apply(func, args); }, wait); + }; + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + _.defer = function(func) { + return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); + }; + + // Returns a function, that, when invoked, will only be triggered at most once + // during a given window of time. + _.throttle = function(func, wait) { + var context, args, timeout, throttling, more; + var whenDone = _.debounce(function(){ more = throttling = false; }, wait); + return function() { + context = this; args = arguments; + var later = function() { + timeout = null; + if (more) func.apply(context, args); + whenDone(); + }; + if (!timeout) timeout = setTimeout(later, wait); + if (throttling) { + more = true; + } else { + func.apply(context, args); + } + whenDone(); + throttling = true; + }; + }; + + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. + _.debounce = function(func, wait) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + func.apply(context, args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }; + + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + _.once = function(func) { + var ran = false, memo; + return function() { + if (ran) return memo; + ran = true; + return memo = func.apply(this, arguments); + }; + }; + + // Returns the first function passed as an argument to the second, + // allowing you to adjust arguments, run code before and after, and + // conditionally execute the original function. + _.wrap = function(func, wrapper) { + return function() { + var args = [func].concat(slice.call(arguments, 0)); + return wrapper.apply(this, args); + }; + }; + + // Returns a function that is the composition of a list of functions, each + // consuming the return value of the function that follows. + _.compose = function() { + var funcs = arguments; + return function() { + var args = arguments; + for (var i = funcs.length - 1; i >= 0; i--) { + args = [funcs[i].apply(this, args)]; + } + return args[0]; + }; + }; + + // Returns a function that will only be executed after being called N times. + _.after = function(times, func) { + if (times <= 0) return func(); + return function() { + if (--times < 1) { return func.apply(this, arguments); } + }; + }; + + // Object Functions + // ---------------- + + // Retrieve the names of an object's properties. + // Delegates to **ECMAScript 5**'s native `Object.keys` + _.keys = nativeKeys || function(obj) { + if (obj !== Object(obj)) throw new TypeError('Invalid object'); + var keys = []; + for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; + return keys; + }; + + // Retrieve the values of an object's properties. + _.values = function(obj) { + return _.map(obj, _.identity); + }; + + // Return a sorted list of the function names available on the object. + // Aliased as `methods` + _.functions = _.methods = function(obj) { + var names = []; + for (var key in obj) { + if (_.isFunction(obj[key])) names.push(key); + } + return names.sort(); + }; + + // Extend a given object with all the properties in passed-in object(s). + _.extend = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + obj[prop] = source[prop]; + } + }); + return obj; + }; + + // Fill in a given object with default properties. + _.defaults = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + if (obj[prop] == null) obj[prop] = source[prop]; + } + }); + return obj; + }; + + // Create a (shallow-cloned) duplicate of an object. + _.clone = function(obj) { + if (!_.isObject(obj)) return obj; + return _.isArray(obj) ? obj.slice() : _.extend({}, obj); + }; + + // Invokes interceptor with the obj, and then returns obj. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. + _.tap = function(obj, interceptor) { + interceptor(obj); + return obj; + }; + + // Internal recursive comparison function. + function eq(a, b, stack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal. + if (a === b) return a !== 0 || 1 / a == 1 / b; + // A strict comparison is necessary because `null == undefined`. + if (a == null || b == null) return a === b; + // Unwrap any wrapped objects. + if (a._chain) a = a._wrapped; + if (b._chain) b = b._wrapped; + // Invoke a custom `isEqual` method if one is provided. + if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b); + if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a); + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className != toString.call(b)) return false; + switch (className) { + // Strings, numbers, dates, and booleans are compared by value. + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + return a == String(b); + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for + // other numeric values. + return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + return +a == +b; + // RegExps are compared by their source patterns and flags. + case '[object RegExp]': + return a.source == b.source && + a.global == b.global && + a.multiline == b.multiline && + a.ignoreCase == b.ignoreCase; + } + if (typeof a != 'object' || typeof b != 'object') return false; + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. + var length = stack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (stack[length] == a) return true; + } + // Add the first object to the stack of traversed objects. + stack.push(a); + var size = 0, result = true; + // Recursively compare objects and arrays. + if (className == '[object Array]') { + // Compare array lengths to determine if a deep comparison is necessary. + size = a.length; + result = size == b.length; + if (result) { + // Deep compare the contents, ignoring non-numeric properties. + while (size--) { + // Ensure commutative equality for sparse arrays. + if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break; + } + } + } else { + // Objects with different constructors are not equivalent. + if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false; + // Deep compare objects. + for (var key in a) { + if (_.has(a, key)) { + // Count the expected number of properties. + size++; + // Deep compare each member. + if (!(result = _.has(b, key) && eq(a[key], b[key], stack))) break; + } + } + // Ensure that both objects contain the same number of properties. + if (result) { + for (key in b) { + if (_.has(b, key) && !(size--)) break; + } + result = !size; + } + } + // Remove the first object from the stack of traversed objects. + stack.pop(); + return result; + } + + // Perform a deep comparison to check if two objects are equal. + _.isEqual = function(a, b) { + return eq(a, b, []); + }; + + // Is a given array, string, or object empty? + // An "empty" object has no enumerable own-properties. + _.isEmpty = function(obj) { + if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; + for (var key in obj) if (_.has(obj, key)) return false; + return true; + }; + + // Is a given value a DOM element? + _.isElement = function(obj) { + return !!(obj && obj.nodeType == 1); + }; + + // Is a given value an array? + // Delegates to ECMA5's native Array.isArray + _.isArray = nativeIsArray || function(obj) { + return toString.call(obj) == '[object Array]'; + }; + + // Is a given variable an object? + _.isObject = function(obj) { + return obj === Object(obj); + }; + + // Is a given variable an arguments object? + _.isArguments = function(obj) { + return toString.call(obj) == '[object Arguments]'; + }; + if (!_.isArguments(arguments)) { + _.isArguments = function(obj) { + return !!(obj && _.has(obj, 'callee')); + }; + } + + // Is a given value a function? + _.isFunction = function(obj) { + return toString.call(obj) == '[object Function]'; + }; + + // Is a given value a string? + _.isString = function(obj) { + return toString.call(obj) == '[object String]'; + }; + + // Is a given value a number? + _.isNumber = function(obj) { + return toString.call(obj) == '[object Number]'; + }; + + // Is the given value `NaN`? + _.isNaN = function(obj) { + // `NaN` is the only value for which `===` is not reflexive. + return obj !== obj; + }; + + // Is a given value a boolean? + _.isBoolean = function(obj) { + return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; + }; + + // Is a given value a date? + _.isDate = function(obj) { + return toString.call(obj) == '[object Date]'; + }; + + // Is the given value a regular expression? + _.isRegExp = function(obj) { + return toString.call(obj) == '[object RegExp]'; + }; + + // Is a given value equal to null? + _.isNull = function(obj) { + return obj === null; + }; + + // Is a given variable undefined? + _.isUndefined = function(obj) { + return obj === void 0; + }; + + // Has own property? + _.has = function(obj, key) { + return hasOwnProperty.call(obj, key); + }; + + // Utility Functions + // ----------------- + + // Run Underscore.js in *noConflict* mode, returning the `_` variable to its + // previous owner. Returns a reference to the Underscore object. + _.noConflict = function() { + root._ = previousUnderscore; + return this; + }; + + // Keep the identity function around for default iterators. + _.identity = function(value) { + return value; + }; + + // Run a function **n** times. + _.times = function (n, iterator, context) { + for (var i = 0; i < n; i++) iterator.call(context, i); + }; + + // Escape a string for HTML interpolation. + _.escape = function(string) { + return (''+string).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g,'/'); + }; + + // Add your own custom functions to the Underscore object, ensuring that + // they're correctly added to the OOP wrapper as well. + _.mixin = function(obj) { + each(_.functions(obj), function(name){ + addToWrapper(name, _[name] = obj[name]); + }); + }; + + // Generate a unique integer id (unique within the entire client session). + // Useful for temporary DOM ids. + var idCounter = 0; + _.uniqueId = function(prefix) { + var id = idCounter++; + return prefix ? prefix + id : id; + }; + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /.^/; + + // Within an interpolation, evaluation, or escaping, remove HTML escaping + // that had been previously added. + var unescape = function(code) { + return code.replace(/\\\\/g, '\\').replace(/\\'/g, "'"); + }; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(str, data) { + var c = _.templateSettings; + var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' + + 'with(obj||{}){__p.push(\'' + + str.replace(/\\/g, '\\\\') + .replace(/'/g, "\\'") + .replace(c.escape || noMatch, function(match, code) { + return "',_.escape(" + unescape(code) + "),'"; + }) + .replace(c.interpolate || noMatch, function(match, code) { + return "'," + unescape(code) + ",'"; + }) + .replace(c.evaluate || noMatch, function(match, code) { + return "');" + unescape(code).replace(/[\r\n\t]/g, ' ') + ";__p.push('"; + }) + .replace(/\r/g, '\\r') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + + "');}return __p.join('');"; + var func = new Function('obj', '_', tmpl); + if (data) return func(data, _); + return function(data) { + return func.call(this, data, _); + }; + }; + + // Add a "chain" function, which will delegate to the wrapper. + _.chain = function(obj) { + return _(obj).chain(); + }; + + // The OOP Wrapper + // --------------- + + // If Underscore is called as a function, it returns a wrapped object that + // can be used OO-style. This wrapper holds altered versions of all the + // underscore functions. Wrapped objects may be chained. + var wrapper = function(obj) { this._wrapped = obj; }; + + // Expose `wrapper.prototype` as `_.prototype` + _.prototype = wrapper.prototype; + + // Helper function to continue chaining intermediate results. + var result = function(obj, chain) { + return chain ? _(obj).chain() : obj; + }; + + // A method to easily add functions to the OOP wrapper. + var addToWrapper = function(name, func) { + wrapper.prototype[name] = function() { + var args = slice.call(arguments); + unshift.call(args, this._wrapped); + return result(func.apply(_, args), this._chain); + }; + }; + + // Add all of the Underscore functions to the wrapper object. + _.mixin(_); + + // Add all mutator Array functions to the wrapper. + each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + wrapper.prototype[name] = function() { + var wrapped = this._wrapped; + method.apply(wrapped, arguments); + var length = wrapped.length; + if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0]; + return result(wrapped, this._chain); + }; + }); + + // Add all accessor Array functions to the wrapper. + each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + wrapper.prototype[name] = function() { + return result(method.apply(this._wrapped, arguments), this._chain); + }; + }); + + // Start chaining a wrapped Underscore object. + wrapper.prototype.chain = function() { + this._chain = true; + return this; + }; + + // Extracts the result from a wrapped and chained object. + wrapper.prototype.value = function() { + return this._wrapped; + }; + +}).call(this); diff --git a/refs/pull/405/merge/_static/underscore.js b/refs/pull/405/merge/_static/underscore.js new file mode 100644 index 00000000..5b55f32b --- /dev/null +++ b/refs/pull/405/merge/_static/underscore.js @@ -0,0 +1,31 @@ +// Underscore.js 1.3.1 +// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore is freely distributable under the MIT license. +// Portions of Underscore are inspired or borrowed from Prototype, +// Oliver Steele's Functional, and John Resig's Micro-Templating. +// For all details and documentation: +// http://documentcloud.github.com/underscore +(function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source== +c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c, +h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var j=b.each= +b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===n)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===n)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(x&&a.map===x)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a== +null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect= +function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e= +e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck= +function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&(e={value:a,computed:b})}); +return e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){f==0?b[0]=a:(d=Math.floor(Math.random()*(f+1)),b[f]=b[d],b[d]=a)});return b};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,g){return{value:a,criteria:c.call(d,a,b,g)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c<d?-1:c>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a, +c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:a.toArray?a.toArray():b.isArray(a)?i.call(a):b.isArguments(a)?i.call(a):b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest= +b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,g,h){if(0==h||(c===true?b.last(d)!=g:!b.include(d,g)))d[d.length]=g,e[e.length]=a[h];return d},[]); +return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c, +d){if(a==null)return-1;var e;if(d)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(p&&a.indexOf===p)return a.indexOf(c);for(d=0,e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(D&&a.lastIndexOf===D)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d;return g}; +var F=function(){};b.bind=function(a,c){var d,e;if(a.bind===s&&s)return s.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));F.prototype=a.prototype;var b=new F,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a, +c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i=b.debounce(function(){h=g=false},c);return function(){d=this;e=arguments;var b;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);i()},c));g?h=true: +a.apply(d,e);i();g=true}};b.debounce=function(a,b){var d;return function(){var e=this,f=arguments;clearTimeout(d);d=setTimeout(function(){d=null;a.apply(e,f)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}}; +b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments, +1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)}; +b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"}; +b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a), +function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+ +u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]= +function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain= +true;return this};m.prototype.value=function(){return this._wrapped}}).call(this); diff --git a/refs/pull/405/merge/_static/up-pressed.png b/refs/pull/405/merge/_static/up-pressed.png new file mode 100644 index 00000000..acee3b68 Binary files /dev/null and b/refs/pull/405/merge/_static/up-pressed.png differ diff --git a/refs/pull/405/merge/_static/up.png b/refs/pull/405/merge/_static/up.png new file mode 100644 index 00000000..2a940a7d Binary files /dev/null and b/refs/pull/405/merge/_static/up.png differ diff --git a/refs/pull/405/merge/_static/websupport.js b/refs/pull/405/merge/_static/websupport.js new file mode 100644 index 00000000..79b18e38 --- /dev/null +++ b/refs/pull/405/merge/_static/websupport.js @@ -0,0 +1,808 @@ +/* + * websupport.js + * ~~~~~~~~~~~~~ + * + * sphinx.websupport utilities for all documentation. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +(function($) { + $.fn.autogrow = function() { + return this.each(function() { + var textarea = this; + + $.fn.autogrow.resize(textarea); + + $(textarea) + .focus(function() { + textarea.interval = setInterval(function() { + $.fn.autogrow.resize(textarea); + }, 500); + }) + .blur(function() { + clearInterval(textarea.interval); + }); + }); + }; + + $.fn.autogrow.resize = function(textarea) { + var lineHeight = parseInt($(textarea).css('line-height'), 10); + var lines = textarea.value.split('\n'); + var columns = textarea.cols; + var lineCount = 0; + $.each(lines, function() { + lineCount += Math.ceil(this.length / columns) || 1; + }); + var height = lineHeight * (lineCount + 1); + $(textarea).css('height', height); + }; +})(jQuery); + +(function($) { + var comp, by; + + function init() { + initEvents(); + initComparator(); + } + + function initEvents() { + $(document).on("click", 'a.comment-close', function(event) { + event.preventDefault(); + hide($(this).attr('id').substring(2)); + }); + $(document).on("click", 'a.vote', function(event) { + event.preventDefault(); + handleVote($(this)); + }); + $(document).on("click", 'a.reply', function(event) { + event.preventDefault(); + openReply($(this).attr('id').substring(2)); + }); + $(document).on("click", 'a.close-reply', function(event) { + event.preventDefault(); + closeReply($(this).attr('id').substring(2)); + }); + $(document).on("click", 'a.sort-option', function(event) { + event.preventDefault(); + handleReSort($(this)); + }); + $(document).on("click", 'a.show-proposal', function(event) { + event.preventDefault(); + showProposal($(this).attr('id').substring(2)); + }); + $(document).on("click", 'a.hide-proposal', function(event) { + event.preventDefault(); + hideProposal($(this).attr('id').substring(2)); + }); + $(document).on("click", 'a.show-propose-change', function(event) { + event.preventDefault(); + showProposeChange($(this).attr('id').substring(2)); + }); + $(document).on("click", 'a.hide-propose-change', function(event) { + event.preventDefault(); + hideProposeChange($(this).attr('id').substring(2)); + }); + $(document).on("click", 'a.accept-comment', function(event) { + event.preventDefault(); + acceptComment($(this).attr('id').substring(2)); + }); + $(document).on("click", 'a.delete-comment', function(event) { + event.preventDefault(); + deleteComment($(this).attr('id').substring(2)); + }); + $(document).on("click", 'a.comment-markup', function(event) { + event.preventDefault(); + toggleCommentMarkupBox($(this).attr('id').substring(2)); + }); + } + + /** + * Set comp, which is a comparator function used for sorting and + * inserting comments into the list. + */ + function setComparator() { + // If the first three letters are "asc", sort in ascending order + // and remove the prefix. + if (by.substring(0,3) == 'asc') { + var i = by.substring(3); + comp = function(a, b) { return a[i] - b[i]; }; + } else { + // Otherwise sort in descending order. + comp = function(a, b) { return b[by] - a[by]; }; + } + + // Reset link styles and format the selected sort option. + $('a.sel').attr('href', '#').removeClass('sel'); + $('a.by' + by).removeAttr('href').addClass('sel'); + } + + /** + * Create a comp function. If the user has preferences stored in + * the sortBy cookie, use those, otherwise use the default. + */ + function initComparator() { + by = 'rating'; // Default to sort by rating. + // If the sortBy cookie is set, use that instead. + if (document.cookie.length > 0) { + var start = document.cookie.indexOf('sortBy='); + if (start != -1) { + start = start + 7; + var end = document.cookie.indexOf(";", start); + if (end == -1) { + end = document.cookie.length; + by = unescape(document.cookie.substring(start, end)); + } + } + } + setComparator(); + } + + /** + * Show a comment div. + */ + function show(id) { + $('#ao' + id).hide(); + $('#ah' + id).show(); + var context = $.extend({id: id}, opts); + var popup = $(renderTemplate(popupTemplate, context)).hide(); + popup.find('textarea[name="proposal"]').hide(); + popup.find('a.by' + by).addClass('sel'); + var form = popup.find('#cf' + id); + form.submit(function(event) { + event.preventDefault(); + addComment(form); + }); + $('#s' + id).after(popup); + popup.slideDown('fast', function() { + getComments(id); + }); + } + + /** + * Hide a comment div. + */ + function hide(id) { + $('#ah' + id).hide(); + $('#ao' + id).show(); + var div = $('#sc' + id); + div.slideUp('fast', function() { + div.remove(); + }); + } + + /** + * Perform an ajax request to get comments for a node + * and insert the comments into the comments tree. + */ + function getComments(id) { + $.ajax({ + type: 'GET', + url: opts.getCommentsURL, + data: {node: id}, + success: function(data, textStatus, request) { + var ul = $('#cl' + id); + var speed = 100; + $('#cf' + id) + .find('textarea[name="proposal"]') + .data('source', data.source); + + if (data.comments.length === 0) { + ul.html('<li>No comments yet.</li>'); + ul.data('empty', true); + } else { + // If there are comments, sort them and put them in the list. + var comments = sortComments(data.comments); + speed = data.comments.length * 100; + appendComments(comments, ul); + ul.data('empty', false); + } + $('#cn' + id).slideUp(speed + 200); + ul.slideDown(speed); + }, + error: function(request, textStatus, error) { + showError('Oops, there was a problem retrieving the comments.'); + }, + dataType: 'json' + }); + } + + /** + * Add a comment via ajax and insert the comment into the comment tree. + */ + function addComment(form) { + var node_id = form.find('input[name="node"]').val(); + var parent_id = form.find('input[name="parent"]').val(); + var text = form.find('textarea[name="comment"]').val(); + var proposal = form.find('textarea[name="proposal"]').val(); + + if (text == '') { + showError('Please enter a comment.'); + return; + } + + // Disable the form that is being submitted. + form.find('textarea,input').attr('disabled', 'disabled'); + + // Send the comment to the server. + $.ajax({ + type: "POST", + url: opts.addCommentURL, + dataType: 'json', + data: { + node: node_id, + parent: parent_id, + text: text, + proposal: proposal + }, + success: function(data, textStatus, error) { + // Reset the form. + if (node_id) { + hideProposeChange(node_id); + } + form.find('textarea') + .val('') + .add(form.find('input')) + .removeAttr('disabled'); + var ul = $('#cl' + (node_id || parent_id)); + if (ul.data('empty')) { + $(ul).empty(); + ul.data('empty', false); + } + insertComment(data.comment); + var ao = $('#ao' + node_id); + ao.find('img').attr({'src': opts.commentBrightImage}); + if (node_id) { + // if this was a "root" comment, remove the commenting box + // (the user can get it back by reopening the comment popup) + $('#ca' + node_id).slideUp(); + } + }, + error: function(request, textStatus, error) { + form.find('textarea,input').removeAttr('disabled'); + showError('Oops, there was a problem adding the comment.'); + } + }); + } + + /** + * Recursively append comments to the main comment list and children + * lists, creating the comment tree. + */ + function appendComments(comments, ul) { + $.each(comments, function() { + var div = createCommentDiv(this); + ul.append($(document.createElement('li')).html(div)); + appendComments(this.children, div.find('ul.comment-children')); + // To avoid stagnating data, don't store the comments children in data. + this.children = null; + div.data('comment', this); + }); + } + + /** + * After adding a new comment, it must be inserted in the correct + * location in the comment tree. + */ + function insertComment(comment) { + var div = createCommentDiv(comment); + + // To avoid stagnating data, don't store the comments children in data. + comment.children = null; + div.data('comment', comment); + + var ul = $('#cl' + (comment.node || comment.parent)); + var siblings = getChildren(ul); + + var li = $(document.createElement('li')); + li.hide(); + + // Determine where in the parents children list to insert this comment. + for(i=0; i < siblings.length; i++) { + if (comp(comment, siblings[i]) <= 0) { + $('#cd' + siblings[i].id) + .parent() + .before(li.html(div)); + li.slideDown('fast'); + return; + } + } + + // If we get here, this comment rates lower than all the others, + // or it is the only comment in the list. + ul.append(li.html(div)); + li.slideDown('fast'); + } + + function acceptComment(id) { + $.ajax({ + type: 'POST', + url: opts.acceptCommentURL, + data: {id: id}, + success: function(data, textStatus, request) { + $('#cm' + id).fadeOut('fast'); + $('#cd' + id).removeClass('moderate'); + }, + error: function(request, textStatus, error) { + showError('Oops, there was a problem accepting the comment.'); + } + }); + } + + function deleteComment(id) { + $.ajax({ + type: 'POST', + url: opts.deleteCommentURL, + data: {id: id}, + success: function(data, textStatus, request) { + var div = $('#cd' + id); + if (data == 'delete') { + // Moderator mode: remove the comment and all children immediately + div.slideUp('fast', function() { + div.remove(); + }); + return; + } + // User mode: only mark the comment as deleted + div + .find('span.user-id:first') + .text('[deleted]').end() + .find('div.comment-text:first') + .text('[deleted]').end() + .find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id + + ', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id) + .remove(); + var comment = div.data('comment'); + comment.username = '[deleted]'; + comment.text = '[deleted]'; + div.data('comment', comment); + }, + error: function(request, textStatus, error) { + showError('Oops, there was a problem deleting the comment.'); + } + }); + } + + function showProposal(id) { + $('#sp' + id).hide(); + $('#hp' + id).show(); + $('#pr' + id).slideDown('fast'); + } + + function hideProposal(id) { + $('#hp' + id).hide(); + $('#sp' + id).show(); + $('#pr' + id).slideUp('fast'); + } + + function showProposeChange(id) { + $('#pc' + id).hide(); + $('#hc' + id).show(); + var textarea = $('#pt' + id); + textarea.val(textarea.data('source')); + $.fn.autogrow.resize(textarea[0]); + textarea.slideDown('fast'); + } + + function hideProposeChange(id) { + $('#hc' + id).hide(); + $('#pc' + id).show(); + var textarea = $('#pt' + id); + textarea.val('').removeAttr('disabled'); + textarea.slideUp('fast'); + } + + function toggleCommentMarkupBox(id) { + $('#mb' + id).toggle(); + } + + /** Handle when the user clicks on a sort by link. */ + function handleReSort(link) { + var classes = link.attr('class').split(/\s+/); + for (var i=0; i<classes.length; i++) { + if (classes[i] != 'sort-option') { + by = classes[i].substring(2); + } + } + setComparator(); + // Save/update the sortBy cookie. + var expiration = new Date(); + expiration.setDate(expiration.getDate() + 365); + document.cookie= 'sortBy=' + escape(by) + + ';expires=' + expiration.toUTCString(); + $('ul.comment-ul').each(function(index, ul) { + var comments = getChildren($(ul), true); + comments = sortComments(comments); + appendComments(comments, $(ul).empty()); + }); + } + + /** + * Function to process a vote when a user clicks an arrow. + */ + function handleVote(link) { + if (!opts.voting) { + showError("You'll need to login to vote."); + return; + } + + var id = link.attr('id'); + if (!id) { + // Didn't click on one of the voting arrows. + return; + } + // If it is an unvote, the new vote value is 0, + // Otherwise it's 1 for an upvote, or -1 for a downvote. + var value = 0; + if (id.charAt(1) != 'u') { + value = id.charAt(0) == 'u' ? 1 : -1; + } + // The data to be sent to the server. + var d = { + comment_id: id.substring(2), + value: value + }; + + // Swap the vote and unvote links. + link.hide(); + $('#' + id.charAt(0) + (id.charAt(1) == 'u' ? 'v' : 'u') + d.comment_id) + .show(); + + // The div the comment is displayed in. + var div = $('div#cd' + d.comment_id); + var data = div.data('comment'); + + // If this is not an unvote, and the other vote arrow has + // already been pressed, unpress it. + if ((d.value !== 0) && (data.vote === d.value * -1)) { + $('#' + (d.value == 1 ? 'd' : 'u') + 'u' + d.comment_id).hide(); + $('#' + (d.value == 1 ? 'd' : 'u') + 'v' + d.comment_id).show(); + } + + // Update the comments rating in the local data. + data.rating += (data.vote === 0) ? d.value : (d.value - data.vote); + data.vote = d.value; + div.data('comment', data); + + // Change the rating text. + div.find('.rating:first') + .text(data.rating + ' point' + (data.rating == 1 ? '' : 's')); + + // Send the vote information to the server. + $.ajax({ + type: "POST", + url: opts.processVoteURL, + data: d, + error: function(request, textStatus, error) { + showError('Oops, there was a problem casting that vote.'); + } + }); + } + + /** + * Open a reply form used to reply to an existing comment. + */ + function openReply(id) { + // Swap out the reply link for the hide link + $('#rl' + id).hide(); + $('#cr' + id).show(); + + // Add the reply li to the children ul. + var div = $(renderTemplate(replyTemplate, {id: id})).hide(); + $('#cl' + id) + .prepend(div) + // Setup the submit handler for the reply form. + .find('#rf' + id) + .submit(function(event) { + event.preventDefault(); + addComment($('#rf' + id)); + closeReply(id); + }) + .find('input[type=button]') + .click(function() { + closeReply(id); + }); + div.slideDown('fast', function() { + $('#rf' + id).find('textarea').focus(); + }); + } + + /** + * Close the reply form opened with openReply. + */ + function closeReply(id) { + // Remove the reply div from the DOM. + $('#rd' + id).slideUp('fast', function() { + $(this).remove(); + }); + + // Swap out the hide link for the reply link + $('#cr' + id).hide(); + $('#rl' + id).show(); + } + + /** + * Recursively sort a tree of comments using the comp comparator. + */ + function sortComments(comments) { + comments.sort(comp); + $.each(comments, function() { + this.children = sortComments(this.children); + }); + return comments; + } + + /** + * Get the children comments from a ul. If recursive is true, + * recursively include childrens' children. + */ + function getChildren(ul, recursive) { + var children = []; + ul.children().children("[id^='cd']") + .each(function() { + var comment = $(this).data('comment'); + if (recursive) + comment.children = getChildren($(this).find('#cl' + comment.id), true); + children.push(comment); + }); + return children; + } + + /** Create a div to display a comment in. */ + function createCommentDiv(comment) { + if (!comment.displayed && !opts.moderator) { + return $('<div class="moderate">Thank you! Your comment will show up ' + + 'once it is has been approved by a moderator.</div>'); + } + // Prettify the comment rating. + comment.pretty_rating = comment.rating + ' point' + + (comment.rating == 1 ? '' : 's'); + // Make a class (for displaying not yet moderated comments differently) + comment.css_class = comment.displayed ? '' : ' moderate'; + // Create a div for this comment. + var context = $.extend({}, opts, comment); + var div = $(renderTemplate(commentTemplate, context)); + + // If the user has voted on this comment, highlight the correct arrow. + if (comment.vote) { + var direction = (comment.vote == 1) ? 'u' : 'd'; + div.find('#' + direction + 'v' + comment.id).hide(); + div.find('#' + direction + 'u' + comment.id).show(); + } + + if (opts.moderator || comment.text != '[deleted]') { + div.find('a.reply').show(); + if (comment.proposal_diff) + div.find('#sp' + comment.id).show(); + if (opts.moderator && !comment.displayed) + div.find('#cm' + comment.id).show(); + if (opts.moderator || (opts.username == comment.username)) + div.find('#dc' + comment.id).show(); + } + return div; + } + + /** + * A simple template renderer. Placeholders such as <%id%> are replaced + * by context['id'] with items being escaped. Placeholders such as <#id#> + * are not escaped. + */ + function renderTemplate(template, context) { + var esc = $(document.createElement('div')); + + function handle(ph, escape) { + var cur = context; + $.each(ph.split('.'), function() { + cur = cur[this]; + }); + return escape ? esc.text(cur || "").html() : cur; + } + + return template.replace(/<([%#])([\w\.]*)\1>/g, function() { + return handle(arguments[2], arguments[1] == '%' ? true : false); + }); + } + + /** Flash an error message briefly. */ + function showError(message) { + $(document.createElement('div')).attr({'class': 'popup-error'}) + .append($(document.createElement('div')) + .attr({'class': 'error-message'}).text(message)) + .appendTo('body') + .fadeIn("slow") + .delay(2000) + .fadeOut("slow"); + } + + /** Add a link the user uses to open the comments popup. */ + $.fn.comment = function() { + return this.each(function() { + var id = $(this).attr('id').substring(1); + var count = COMMENT_METADATA[id]; + var title = count + ' comment' + (count == 1 ? '' : 's'); + var image = count > 0 ? opts.commentBrightImage : opts.commentImage; + var addcls = count == 0 ? ' nocomment' : ''; + $(this) + .append( + $(document.createElement('a')).attr({ + href: '#', + 'class': 'sphinx-comment-open' + addcls, + id: 'ao' + id + }) + .append($(document.createElement('img')).attr({ + src: image, + alt: 'comment', + title: title + })) + .click(function(event) { + event.preventDefault(); + show($(this).attr('id').substring(2)); + }) + ) + .append( + $(document.createElement('a')).attr({ + href: '#', + 'class': 'sphinx-comment-close hidden', + id: 'ah' + id + }) + .append($(document.createElement('img')).attr({ + src: opts.closeCommentImage, + alt: 'close', + title: 'close' + })) + .click(function(event) { + event.preventDefault(); + hide($(this).attr('id').substring(2)); + }) + ); + }); + }; + + var opts = { + processVoteURL: '/_process_vote', + addCommentURL: '/_add_comment', + getCommentsURL: '/_get_comments', + acceptCommentURL: '/_accept_comment', + deleteCommentURL: '/_delete_comment', + commentImage: '/static/_static/comment.png', + closeCommentImage: '/static/_static/comment-close.png', + loadingImage: '/static/_static/ajax-loader.gif', + commentBrightImage: '/static/_static/comment-bright.png', + upArrow: '/static/_static/up.png', + downArrow: '/static/_static/down.png', + upArrowPressed: '/static/_static/up-pressed.png', + downArrowPressed: '/static/_static/down-pressed.png', + voting: false, + moderator: false + }; + + if (typeof COMMENT_OPTIONS != "undefined") { + opts = jQuery.extend(opts, COMMENT_OPTIONS); + } + + var popupTemplate = '\ + <div class="sphinx-comments" id="sc<%id%>">\ + <p class="sort-options">\ + Sort by:\ + <a href="#" class="sort-option byrating">best rated</a>\ + <a href="#" class="sort-option byascage">newest</a>\ + <a href="#" class="sort-option byage">oldest</a>\ + </p>\ + <div class="comment-header">Comments</div>\ + <div class="comment-loading" id="cn<%id%>">\ + loading comments... <img src="<%loadingImage%>" alt="" /></div>\ + <ul id="cl<%id%>" class="comment-ul"></ul>\ + <div id="ca<%id%>">\ + <p class="add-a-comment">Add a comment\ + (<a href="#" class="comment-markup" id="ab<%id%>">markup</a>):</p>\ + <div class="comment-markup-box" id="mb<%id%>">\ + reStructured text markup: <i>*emph*</i>, <b>**strong**</b>, \ + <code>``code``</code>, \ + code blocks: <code>::</code> and an indented block after blank line</div>\ + <form method="post" id="cf<%id%>" class="comment-form" action="">\ + <textarea name="comment" cols="80"></textarea>\ + <p class="propose-button">\ + <a href="#" id="pc<%id%>" class="show-propose-change">\ + Propose a change ▹\ + </a>\ + <a href="#" id="hc<%id%>" class="hide-propose-change">\ + Propose a change ▿\ + </a>\ + </p>\ + <textarea name="proposal" id="pt<%id%>" cols="80"\ + spellcheck="false"></textarea>\ + <input type="submit" value="Add comment" />\ + <input type="hidden" name="node" value="<%id%>" />\ + <input type="hidden" name="parent" value="" />\ + </form>\ + </div>\ + </div>'; + + var commentTemplate = '\ + <div id="cd<%id%>" class="sphinx-comment<%css_class%>">\ + <div class="vote">\ + <div class="arrow">\ + <a href="#" id="uv<%id%>" class="vote" title="vote up">\ + <img src="<%upArrow%>" />\ + </a>\ + <a href="#" id="uu<%id%>" class="un vote" title="vote up">\ + <img src="<%upArrowPressed%>" />\ + </a>\ + </div>\ + <div class="arrow">\ + <a href="#" id="dv<%id%>" class="vote" title="vote down">\ + <img src="<%downArrow%>" id="da<%id%>" />\ + </a>\ + <a href="#" id="du<%id%>" class="un vote" title="vote down">\ + <img src="<%downArrowPressed%>" />\ + </a>\ + </div>\ + </div>\ + <div class="comment-content">\ + <p class="tagline comment">\ + <span class="user-id"><%username%></span>\ + <span class="rating"><%pretty_rating%></span>\ + <span class="delta"><%time.delta%></span>\ + </p>\ + <div class="comment-text comment"><#text#></div>\ + <p class="comment-opts comment">\ + <a href="#" class="reply hidden" id="rl<%id%>">reply ▹</a>\ + <a href="#" class="close-reply" id="cr<%id%>">reply ▿</a>\ + <a href="#" id="sp<%id%>" class="show-proposal">proposal ▹</a>\ + <a href="#" id="hp<%id%>" class="hide-proposal">proposal ▿</a>\ + <a href="#" id="dc<%id%>" class="delete-comment hidden">delete</a>\ + <span id="cm<%id%>" class="moderation hidden">\ + <a href="#" id="ac<%id%>" class="accept-comment">accept</a>\ + </span>\ + </p>\ + <pre class="proposal" id="pr<%id%>">\ +<#proposal_diff#>\ + </pre>\ + <ul class="comment-children" id="cl<%id%>"></ul>\ + </div>\ + <div class="clearleft"></div>\ + </div>\ + </div>'; + + var replyTemplate = '\ + <li>\ + <div class="reply-div" id="rd<%id%>">\ + <form id="rf<%id%>">\ + <textarea name="comment" cols="80"></textarea>\ + <input type="submit" value="Add reply" />\ + <input type="button" value="Cancel" />\ + <input type="hidden" name="parent" value="<%id%>" />\ + <input type="hidden" name="node" value="" />\ + </form>\ + </div>\ + </li>'; + + $(document).ready(function() { + init(); + }); +})(jQuery); + +$(document).ready(function() { + // add comment anchors for all paragraphs that are commentable + $('.sphinx-has-comment').comment(); + + // highlight search words in search results + $("div.context").each(function() { + var params = $.getQueryParameters(); + var terms = (params.q) ? params.q[0].split(/\s+/) : []; + var result = $(this); + $.each(terms, function() { + result.highlightText(this.toLowerCase(), 'highlighted'); + }); + }); + + // directly open comment window if requested + var anchor = document.location.hash; + if (anchor.substring(0, 9) == '#comment-') { + $('#ao' + anchor.substring(9)).click(); + document.location.hash = '#s' + anchor.substring(9); + } +}); diff --git a/refs/pull/405/merge/genindex.html b/refs/pull/405/merge/genindex.html new file mode 100644 index 00000000..cbbad364 --- /dev/null +++ b/refs/pull/405/merge/genindex.html @@ -0,0 +1,159 @@ + +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Index — The Linux Kernel documentation</title><link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'./', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="_static/jquery.js"></script> + <script src="_static/underscore.js"></script> + <script src="_static/doctools.js"></script> + <script src="_static/asciinema-player.js"></script> + <script src="_static/js/theme.js"></script> + <link rel="index" title="Index" href="#" /> + <link rel="search" title="Search" href="search.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Index</li> + <li class="wy-breadcrumbs-aside"> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + +<h1 id="index">Index</h1> + +<div class="genindex-jumpbox"> + +</div> + + + </div> + </div> + <footer> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/index.html b/refs/pull/405/merge/index.html new file mode 100644 index 00000000..813082ed --- /dev/null +++ b/refs/pull/405/merge/index.html @@ -0,0 +1,1960 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Linux Kernel Teaching — The Linux Kernel documentation</title><link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'./', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="_static/jquery.js"></script> + <script src="_static/underscore.js"></script> + <script src="_static/doctools.js"></script> + <script src="_static/asciinema-player.js"></script> + <script src="_static/js/theme.js"></script> + <link rel="index" title="Index" href="genindex.html" /> + <link rel="search" title="Search" href="search.html" /> + <link rel="next" title="Operating Systems 2" href="so2/index.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="#" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="#">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="#" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Linux Kernel Teaching</li> + <li class="wy-breadcrumbs-aside"> + <a href="_sources/index.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="linux-kernel-teaching"> +<h1>Linux Kernel Teaching<a class="headerlink" href="#linux-kernel-teaching" title="Permalink to this headline">¶</a></h1> +<p>This is a collection of lectures and labs Linux kernel topics. The +lectures focus on theoretical and Linux kernel exploration.</p> +<p>The labs focus on device drivers topics and they resemble "howto" +style documentation. Each topic has two parts:</p> +<ul class="simple"> +<li>a walk-through the topic which contains an overview, the main +abstractions, simple examples and pointers to APIs</li> +<li>a hands-on part which contains a few exercises that should be +resolved by the student; to focus on the topic at hand, the student +is presented with a starting coding skeleton and with in-depth tips +on how to solve the exercises</li> +</ul> +<p>This content is based on the <a class="reference external" href="http://ocw.cs.pub.ro/courses/so2">Operatings Systems 2</a> course from the Computer Science +and Engineering Department, the Faculty of Automatic Control and +Computers, University POLITEHNICA of Bucharest.</p> +<p>You can get the latest version at <a class="reference external" href="http://github.com/linux-kernel-labs">http://github.com/linux-kernel-labs</a>.</p> +<p>To get started build the documentation from the sources after +installing docker-compose on you host:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">cd</span> <span class="n">tools</span><span class="o">/</span><span class="n">labs</span> <span class="o">&&</span> <span class="n">make</span> <span class="n">docker</span><span class="o">-</span><span class="n">docs</span> +</pre></div> +</div> +<p>then point your browser at <strong>Documentation/output/labs/index.html</strong>.</p> +<p>Alternatively, you can build directly on the host (see +tools/labs/docs/Dockerfile for dependencies):</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">cd</span> <span class="n">tools</span><span class="o">/</span><span class="n">labs</span> <span class="o">&&</span> <span class="n">make</span> <span class="n">docs</span> +</pre></div> +</div> +<div class="toctree-wrapper compound"> +<ul> +<li class="toctree-l1"><a class="reference internal" href="so2/index.html">Operating Systems 2</a><ul> +<li class="toctree-l2"><a class="reference internal" href="so2/grading.html">SO2 - General Rules and Grading</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/grading.html#general-rules">General Rules</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/grading.html#laboratory">1. Laboratory</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/grading.html#final-deadline-for-submitting-assignments">2. Final deadline for submitting assignments</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/grading.html#assignment-presentations">3. Assignment Presentations</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/grading.html#rules-on-assignments">4. Rules on Assignments</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/grading.html#penalties-for-plagiarized-assignments">5. Penalties for Plagiarized Assignments</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/grading.html#retake-grade-increase">6. Retake/Grade Increase</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/grading.html#class-redo">7. Class Redo</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/grading.html#grading">Grading</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/grading.html#lectures-3-points">1. Lectures (3 points)</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/grading.html#laboratory-2-points">2. Laboratory (2 points)</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/grading.html#assignments-5-points-extra">3. Assignments (5 points + Extra)</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lec1-intro.html#echipa">Echipa</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec1-intro.html#pozitionare-curs">Poziționare curs</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec1-intro.html#resurse">Resurse</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec1-intro.html#comunitate">Comunitate</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec1-intro.html#notare">Notare</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec1-intro.html#obiectivele-cursului">Obiectivele cursului</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec1-intro.html#obiectivele-laboratorului-si-a-temelor">Obiectivele laboratorului si a temelor</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec1-intro.html#cursuri-necesare">Cursuri necesare</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec1-intro.html#despre-curs">Despre curs</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec1-intro.html#lista-cursuri">Lista cursuri</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec1-intro.html#despre-laborator">Despre laborator</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec1-intro.html#despre-teme">Despre teme</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec1-intro.html#lista-teme">Lista teme</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec1-intro.html#bibliografie-curs">Bibliografie curs</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec1-intro.html#bibliografie-laborator">Bibliografie laborator</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec1-intro.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec1-intro.html#basic-operating-systems-terms-and-concepts">Basic operating systems terms and concepts</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#user-vs-kernel">User vs Kernel</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#typical-operating-system-architecture">Typical operating system architecture</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#monolithic-kernel">Monolithic kernel</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#micro-kernel">Micro kernel</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#micro-kernels-vs-monolithic-kernels">Micro-kernels vs monolithic kernels</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#address-space">Address space</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#user-and-kernel-sharing-the-virtual-address-space">User and kernel sharing the virtual address space</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#execution-contexts">Execution contexts</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#multi-tasking">Multi-tasking</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#preemptive-kernel">Preemptive kernel</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#pageable-kernel-memory">Pageable kernel memory</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#kernel-stack">Kernel stack</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#portability">Portability</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#asymmetric-multiprocessing-asmp">Asymmetric MultiProcessing (ASMP)</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#symmetric-multiprocessing-smp">Symmetric MultiProcessing (SMP)</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#cpu-scalability">CPU Scalability</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec1-intro.html#overview-of-the-linux-kernel">Overview of the Linux kernel</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#linux-development-model">Linux development model</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#maintainer-hierarchy">Maintainer hierarchy</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#linux-source-code-layout">Linux source code layout</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec1-intro.html#linux-kernel-architecture">Linux kernel architecture</a><ul> +<li class="toctree-l5"><a class="reference internal" href="so2/lec1-intro.html#arch">arch</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lec1-intro.html#device-drivers">Device drivers</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lec1-intro.html#process-management">Process management</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lec1-intro.html#memory-management">Memory management</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lec1-intro.html#block-i-o-management">Block I/O management</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lec1-intro.html#virtual-filesystem-switch">Virtual Filesystem Switch</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lec1-intro.html#networking-stack">Networking stack</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lec1-intro.html#linux-security-modules">Linux Security Modules</a></li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lec2-syscalls.html">SO2 Lecture 02 - System calls</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lec2-syscalls.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec2-syscalls.html#linux-system-calls-implementation">Linux system calls implementation</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec2-syscalls.html#system-call-table">System call table</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec2-syscalls.html#system-call-parameters-handling">System call parameters handling</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec2-syscalls.html#virtual-dynamic-shared-object-vdso">Virtual Dynamic Shared Object (VDSO)</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec2-syscalls.html#accessing-user-space-from-system-calls">Accessing user space from system calls</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lec3-processes.html">SO2 Lecture 03 - Processes</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lec3-processes.html#lecture-objectives">Lecture objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec3-processes.html#processes-and-threads">Processes and threads</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec3-processes.html#overview-of-process-resources">Overview of process resources</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec3-processes.html#struct-task-struct"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code></a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec3-processes.html#inspecting-task-struct">Inspecting task_struct</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec3-processes.html#quiz-inspect-a-task-to-determine-opened-files">Quiz: Inspect a task to determine opened files</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec3-processes.html#threads">Threads</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec3-processes.html#the-clone-system-call">The clone system call</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec3-processes.html#namespaces-and-containers">Namespaces and "containers"</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec3-processes.html#accessing-the-current-process">Accessing the current process</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec3-processes.html#quiz-previous-implementation-for-current-x86">Quiz: previous implementation for current (x86)</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec3-processes.html#context-switching">Context switching</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec3-processes.html#quiz-context-switch">Quiz: context switch</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec3-processes.html#blocking-and-waking-up-tasks">Blocking and waking up tasks</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec3-processes.html#task-states">Task states</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec3-processes.html#blocking-the-current-thread">Blocking the current thread</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec3-processes.html#waking-up-a-task">Waking up a task</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec3-processes.html#preempting-tasks">Preempting tasks</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec3-processes.html#non-preemptive-kernel">Non preemptive kernel</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec3-processes.html#preemptive-kernel">Preemptive kernel</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec3-processes.html#process-context">Process context</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec3-processes.html#kernel-threads">Kernel threads</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec3-processes.html#using-gdb-scripts-for-kernel-inspection">Using gdb scripts for kernel inspection</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec3-processes.html#quiz-kernel-gdb-scripts">Quiz: Kernel gdb scripts</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lec4-interrupts.html#lecture-objectives">Lecture objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec4-interrupts.html#what-is-an-interrupt">What is an interrupt?</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#exceptions">Exceptions</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#quiz-interrupt-terminology">Quiz: interrupt terminology</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec4-interrupts.html#hardware-concepts">Hardware Concepts</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#programmable-interrupt-controller">Programmable Interrupt Controller</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#interrupt-controllers-in-smp-systems">Interrupt controllers in SMP systems</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#interrupt-control">Interrupt Control</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#interrupt-priorities">Interrupt priorities</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#quiz-hardware-concepts">Quiz: hardware concepts</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec4-interrupts.html#interrupt-handling-on-the-x86-architecture">Interrupt handling on the x86 architecture</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#interrupt-descriptor-table">Interrupt Descriptor Table</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#interrupt-handler-address">Interrupt handler address</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#stack-of-interrupt-handler">Stack of interrupt handler</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#handling-an-interrupt-request">Handling an interrupt request</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#returning-from-an-interrupt-handler">Returning from an interrupt handler</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#inspecting-the-x86-interrupt-handling">Inspecting the x86 interrupt handling</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#quiz-x86-interrupt-handling">Quiz: x86 interrupt handling</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec4-interrupts.html#interrupt-handling-in-linux">Interrupt handling in Linux</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#nested-interrupts-and-exceptions">Nested interrupts and exceptions</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#interrupt-context">Interrupt context</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#deferrable-actions">Deferrable actions</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#soft-irqs">Soft IRQs</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#packet-flood-example">Packet flood example</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#tasklets">Tasklets</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#workqueues">Workqueues</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#timers">Timers</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#deferrable-actions-summary">Deferrable actions summary</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec4-interrupts.html#quiz-linux-interrupt-handling">Quiz: Linux interrupt handling</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lec5-smp.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec5-smp.html#synchronization-basics">Synchronization basics</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec5-smp.html#linux-kernel-concurrency-sources">Linux kernel concurrency sources</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec5-smp.html#atomic-operations">Atomic operations</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec5-smp.html#disabling-preemption-interrupts">Disabling preemption (interrupts)</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec5-smp.html#spin-locks">Spin Locks</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec5-smp.html#cache-coherency-in-multi-processor-systems">Cache coherency in multi-processor systems</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec5-smp.html#optimized-spin-locks">Optimized spin locks</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec5-smp.html#process-and-interrupt-context-synchronization">Process and Interrupt Context Synchronization</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec5-smp.html#mutexes">Mutexes</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec5-smp.html#per-cpu-data">Per CPU data</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec5-smp.html#memory-ordering-and-barriers">Memory Ordering and Barriers</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec5-smp.html#read-copy-update-rcu">Read Copy Update (RCU)</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lec6-address-space.html">SO2 Lecture 06 - Address Space</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lec6-address-space.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec6-address-space.html#x86-mmu">x86 MMU</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec6-address-space.html#selectors">Selectors</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec6-address-space.html#segment-descriptor">Segment descriptor</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec6-address-space.html#segmentation-in-linux">Segmentation in Linux</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec6-address-space.html#inspecting-selectors-and-segments">Inspecting selectors and segments</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec6-address-space.html#x86-paging">x86 Paging</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec6-address-space.html#page-tables">Page tables</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec6-address-space.html#linux-paging">Linux paging</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec6-address-space.html#translation-look-aside-buffer">Translation Look-aside Buffer</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec6-address-space.html#linux-address-space">Linux address space</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec6-address-space.html#address-space-options-for-32bit-systems">Address space options for 32bit systems</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec6-address-space.html#linear-mappings">Linear mappings</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec6-address-space.html#highmem">Highmem</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec6-address-space.html#fixed-mapped-linear-addresses">Fixed-mapped linear addresses</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec6-address-space.html#temporary-mappings">Temporary mappings</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec6-address-space.html#permanent-mappings">Permanent mappings</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lec7-memory-management.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec7-memory-management.html#physical-memory-management">Physical Memory Management</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec7-memory-management.html#memory-zones">Memory zones</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec7-memory-management.html#non-uniform-memory-access">Non-Uniform Memory Access</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec7-memory-management.html#page-allocation">Page allocation</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec7-memory-management.html#small-allocations">Small allocations</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec7-memory-management.html#virtual-memory-management">Virtual memory management</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec7-memory-management.html#fault-page-handling">Fault page handling</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lec8-filesystems.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec8-filesystems.html#filesystem-abstractions">Filesystem Abstractions</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec8-filesystems.html#filesystem-operations">Filesystem Operations</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec8-filesystems.html#mounting-a-filesystem">Mounting a filesystem</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec8-filesystems.html#opening-a-file">Opening a file</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec8-filesystems.html#querying-file-attributes">Querying file attributes</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec8-filesystems.html#reading-data-from-a-file">Reading data from a file</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec8-filesystems.html#writing-data-to-a-file">Writing data to a file</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec8-filesystems.html#closing-a-file">Closing a file</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec8-filesystems.html#directories">Directories</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec8-filesystems.html#creating-a-file">Creating a file</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec8-filesystems.html#deleting-a-file">Deleting a file</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec8-filesystems.html#linux-virtual-file-system">Linux Virtual File System</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec8-filesystems.html#superblock-operations">Superblock Operations</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec8-filesystems.html#inode-operations">Inode Operations</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec8-filesystems.html#the-inode-cache">The Inode Cache</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec8-filesystems.html#the-dentry-cache">The Dentry Cache</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec8-filesystems.html#the-page-cache">The Page Cache</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lec9-debugging.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec9-debugging.html#decoding-an-oops-panic">Decoding an oops/panic</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec9-debugging.html#decoding-an-oops">Decoding an oops</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec9-debugging.html#addr2line">addr2line</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec9-debugging.html#objdump">objdump</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec9-debugging.html#gdb">gdb</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec9-debugging.html#kernel-panic">Kernel panic</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec9-debugging.html#list-debugging">List debugging</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec9-debugging.html#memory-debugging">Memory debugging</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec9-debugging.html#slab-debugging">Slab debugging</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec9-debugging.html#debug-pagealloc">DEBUG_PAGEALLOC</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec9-debugging.html#kasan">KASan</a><ul> +<li class="toctree-l5"><a class="reference internal" href="so2/lec9-debugging.html#kasan-vs-debug-pagealloc">KASan vs DEBUG_PAGEALLOC</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lec9-debugging.html#kasan-vs-slub-debug">KASan vs SLUB_DEBUG</a></li> +</ul> +</li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec9-debugging.html#kmemleak">Kmemleak</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec9-debugging.html#lockdep-checker">Lockdep checker</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec9-debugging.html#perf">perf</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec9-debugging.html#other-tools">Other tools</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lec10-networking.html">SO2 Lecture 10 - Networking</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lec10-networking.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec10-networking.html#network-management-overview">Network Management Overview</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec10-networking.html#sockets-implementation-overview">Sockets Implementation Overview</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec10-networking.html#sockets-families-and-protocols">Sockets Families and Protocols</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec10-networking.html#example-udp-send">Example: UDP send</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec10-networking.html#network-processing-phases">Network processing phases</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec10-networking.html#packet-routing">Packet Routing</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec10-networking.html#routing-table-s">Routing Table(s)</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec10-networking.html#routing-policy-database">Routing Policy Database</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec10-networking.html#routing-table-processing">Routing table processing</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec10-networking.html#forwarding-information-database">Forwarding Information Database</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec10-networking.html#netfilter">Netfilter</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec10-networking.html#network-packets-skbs-struct-sk-buff">Network packets / skbs (struct sk_buff)</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec10-networking.html#network-device">Network Device</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec10-networking.html#hardware-and-software-acceleration-techniques">Hardware and Software Acceleration Techniques</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lec11-arch.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec11-arch.html#overview-of-the-arch-layer">Overview of the arch layer</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec11-arch.html#boot-strap">Boot strap</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec11-arch.html#boot-strap-1">Boot strap</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec11-arch.html#memory-setup">Memory setup</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec11-arch.html#mmu-management">MMU management</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec11-arch.html#thread-management">Thread Management</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec11-arch.html#time-management">Time Management</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec11-arch.html#irqs-and-exception-management">IRQs and exception management</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec11-arch.html#system-calls">System calls</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec11-arch.html#platform-drivers">Platform Drivers</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec11-arch.html#machine-specific-code">Machine specific code</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec11-arch.html#overview-of-the-boot-process">Overview of the boot process</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lec12-virtualization.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec12-virtualization.html#emulation-basics">Emulation basics</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec12-virtualization.html#virtualization-basics">Virtualization basics</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec12-virtualization.html#classic-virtualization">Classic virtualization</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec12-virtualization.html#software-virtualization">Software virtualization</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec12-virtualization.html#mmu-virtualization">MMU virtualization</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec12-virtualization.html#shadow-page-tables">Shadow page tables</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec12-virtualization.html#lazy-shadow-sync">Lazy shadow sync</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec12-virtualization.html#i-o-emulation">I/O emulation</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec12-virtualization.html#paravirtualization">Paravirtualization</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec12-virtualization.html#intel-vt-x">Intel VT-x</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec12-virtualization.html#virtual-machine-control-structure">Virtual Machine Control Structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec12-virtualization.html#vm-entry-exit">VM entry & exit</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lec12-virtualization.html#vm-execution-control-fields">VM execution control fields</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec12-virtualization.html#extend-page-tables">Extend Page Tables</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lec12-virtualization.html#vpid">VPID</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec12-virtualization.html#i-o-virtualization">I/O virtualization</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec12-virtualization.html#qemu">qemu</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec12-virtualization.html#kvm">KVM</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec12-virtualization.html#type-1-vs-type-2-hypervisors">Type 1 vs Type 2 Hypervisors</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lec12-virtualization.html#xen">Xen</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lab1-intro.html">SO2 Lab 01 - Introduction</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lab1-intro.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab1-intro.html#about-this-laboratory">About this laboratory</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab1-intro.html#references">References</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab1-intro.html#documentation">Documentation</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab1-intro.html#kernel-modules-overview">Kernel Modules Overview</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab1-intro.html#an-example-of-a-kernel-module">An example of a kernel module</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab1-intro.html#compiling-kernel-modules">Compiling kernel modules</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab1-intro.html#loading-unloading-a-kernel-module">Loading/unloading a kernel module</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab1-intro.html#kernel-module-debugging">Kernel Module Debugging</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#objdump">objdump</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#addr2line">addr2line</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#minicom">minicom</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#netconsole">netconsole</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#printk-debugging">Printk debugging</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#dynamic-debugging">Dynamic debugging</a><ul> +<li class="toctree-l5"><a class="reference internal" href="so2/lab1-intro.html#dyndbg-options">Dyndbg Options</a></li> +</ul> +</li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#kdb-kernel-debugger">KDB: Kernel debugger</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab1-intro.html#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#remarks">Remarks</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#kernel-module">1. Kernel module</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#printk">2. Printk</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#error">3. Error</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#sub-modules">4. Sub-modules</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#kernel-oops-1">5. Kernel oops</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#module-parameters">6. Module parameters</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#proc-info-1">7. Proc info</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab1-intro.html#good-to-know-1">Good to know</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab1-intro.html#source-code-navigation">Source code navigation</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#cscope">cscope</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#clangd">clangd</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#kscope">Kscope</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#lxr-cross-reference">LXR Cross-Reference</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#sourceweb">SourceWeb</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab1-intro.html#kernel-debugging">Kernel Debugging</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#gdb-linux">gdb (Linux)</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab1-intro.html#getting-a-stack-trace">Getting a stack trace</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lab2-kernel-api.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab2-kernel-api.html#overview">Overview</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab2-kernel-api.html#accessing-memory">Accessing memory</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab2-kernel-api.html#contexts-of-execution">Contexts of execution</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab2-kernel-api.html#locking">Locking</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab2-kernel-api.html#preemptivity">Preemptivity</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab2-kernel-api.html#linux-kernel-api">Linux Kernel API</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab2-kernel-api.html#convention-indicating-errors">Convention indicating errors</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab2-kernel-api.html#strings-of-characters">Strings of characters</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab2-kernel-api.html#printk">printk</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab2-kernel-api.html#memory-allocation">Memory allocation</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab2-kernel-api.html#lists">lists</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab2-kernel-api.html#spinlock">Spinlock</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab2-kernel-api.html#mutex">mutex</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab2-kernel-api.html#atomic-variables-1">Atomic variables</a><ul> +<li class="toctree-l5"><a class="reference internal" href="so2/lab2-kernel-api.html#use-of-atomic-variables">Use of atomic variables</a></li> +</ul> +</li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab2-kernel-api.html#atomic-bitwise-operations">Atomic bitwise operations</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab2-kernel-api.html#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab2-kernel-api.html#intro">0. Intro</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab2-kernel-api.html#memory-allocation-in-linux-kernel">1. Memory allocation in Linux kernel</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab2-kernel-api.html#sleeping-in-atomic-context">2. Sleeping in atomic context</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab2-kernel-api.html#working-with-kernel-memory">3. Working with kernel memory</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab2-kernel-api.html#working-with-kernel-lists">4. Working with kernel lists</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab2-kernel-api.html#working-with-kernel-lists-for-process-handling">5. Working with kernel lists for process handling</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab2-kernel-api.html#synchronizing-list-work">6. Synchronizing list work</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab2-kernel-api.html#test-module-calling-in-our-list-module">7. Test module calling in our list module</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lab3-device-drivers.html#laboratory-objectives">Laboratory objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab3-device-drivers.html#overview">Overview</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab3-device-drivers.html#majors-and-minors">Majors and minors</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab3-device-drivers.html#data-structures-for-a-character-device">Data structures for a character device</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab3-device-drivers.html#struct-file-operations"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code></a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab3-device-drivers.html#inode-and-file-structures"><code class="docutils literal"><span class="pre">inode</span></code> and <code class="docutils literal"><span class="pre">file</span></code> structures</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab3-device-drivers.html#implementation-of-operations">Implementation of operations</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab3-device-drivers.html#registration-and-unregistration-of-character-devices">Registration and unregistration of character devices</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab3-device-drivers.html#access-to-the-address-space-of-the-process">Access to the address space of the process</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab3-device-drivers.html#open-and-release">Open and release</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab3-device-drivers.html#read-and-write">Read and write</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab3-device-drivers.html#ioctl-1">ioctl</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab3-device-drivers.html#waiting-queues">Waiting queues</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab3-device-drivers.html#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab3-device-drivers.html#intro">0. Intro</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab3-device-drivers.html#register-unregister">1. Register/unregister</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab3-device-drivers.html#register-an-already-registered-major">2. Register an already registered major</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab3-device-drivers.html#open-and-close">3. Open and close</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab3-device-drivers.html#access-restriction">4. Access restriction</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab3-device-drivers.html#read-operation">5. Read operation</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab3-device-drivers.html#write-operation">6. Write operation</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab3-device-drivers.html#ioctl-operation">7. ioctl operation</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab3-device-drivers.html#extra-exercises">Extra Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab3-device-drivers.html#ioctl-with-messaging">Ioctl with messaging</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab3-device-drivers.html#ioctl-with-waiting-queues">Ioctl with waiting queues</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab3-device-drivers.html#o-nonblock-implementation">O_NONBLOCK implementation</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lab4-interrupts.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab4-interrupts.html#background-information">Background information</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab4-interrupts.html#accessing-the-hardware">Accessing the hardware</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#request-access-to-i-o-ports">Request access to I/O ports</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#accessing-i-o-ports">Accessing I/O ports</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#accessing-i-o-ports-from-userspace">5. Accessing I/O ports from userspace</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab4-interrupts.html#interrupt-handling">Interrupt handling</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#requesting-an-interrupt">Requesting an interrupt</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#implementing-an-interrupt-handler">Implementing an interrupt handler</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#locking">Locking</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#interrupt-statistics">Interrupt statistics</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab4-interrupts.html#further-reading">Further reading</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#serial-port">Serial Port</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#parallel-port">Parallel port</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#keyboard-controller">Keyboard controller</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#linux-device-drivers">Linux device drivers</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab4-interrupts.html#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#intro">0. Intro</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#keyboard-driver">Keyboard driver</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#request-the-i-o-ports">1. Request the I/O ports</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#interrupt-handling-routine">2. Interrupt handling routine</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#store-ascii-keys-to-buffer">3. Store ASCII keys to buffer</a><ul> +<li class="toctree-l5"><a class="reference internal" href="so2/lab4-interrupts.html#reading-the-data-register">Reading the data register</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lab4-interrupts.html#interpreting-the-scancode">Interpreting the scancode</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lab4-interrupts.html#store-characters-to-the-buffer">Store characters to the buffer</a></li> +</ul> +</li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#reading-the-buffer">4. Reading the buffer</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#reset-the-buffer">5. Reset the buffer</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab4-interrupts.html#extra-exercises">Extra Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab4-interrupts.html#kfifo">1. kfifo</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lab5-deferred-work.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab5-deferred-work.html#background-information">Background information</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab5-deferred-work.html#softirqs">Softirqs</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab5-deferred-work.html#tasklets">Tasklets</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab5-deferred-work.html#timers">Timers</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab5-deferred-work.html#locking">Locking</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab5-deferred-work.html#workqueues">Workqueues</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab5-deferred-work.html#kernel-threads">Kernel threads</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab5-deferred-work.html#further-reading">Further reading</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab5-deferred-work.html#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab5-deferred-work.html#intro">0. Intro</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab5-deferred-work.html#timer">1.Timer</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab5-deferred-work.html#periodic-timer">2. Periodic timer</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab5-deferred-work.html#timer-control-using-ioctl">3. Timer control using ioctl</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab5-deferred-work.html#blocking-operations">4. Blocking operations</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab5-deferred-work.html#workqueues-1">5. Workqueues</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab5-deferred-work.html#kernel-thread">6. Kernel thread</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab5-deferred-work.html#buffer-shared-between-timer-and-process">7. Buffer shared between timer and process</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lab6-memory-mapping.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab6-memory-mapping.html#overview">Overview</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab6-memory-mapping.html#structures-used-for-memory-mapping">Structures used for memory mapping</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab6-memory-mapping.html#struct-page"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code></a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab6-memory-mapping.html#struct-vm-area-struct"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code></a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab6-memory-mapping.html#struct-mm-struct"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code></a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab6-memory-mapping.html#device-driver-memory-mapping">Device driver memory mapping</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab6-memory-mapping.html#further-reading">Further reading</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab6-memory-mapping.html#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab6-memory-mapping.html#mapping-contiguous-physical-memory-to-userspace">1. Mapping contiguous physical memory to userspace</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab6-memory-mapping.html#mapping-non-contiguous-physical-memory-to-userspace">2. Mapping non-contiguous physical memory to userspace</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab6-memory-mapping.html#read-write-operations-in-mapped-memory">3. Read / write operations in mapped memory</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab6-memory-mapping.html#display-memory-mapped-in-procfs">4. Display memory mapped in procfs</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lab7-block-device-drivers.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab7-block-device-drivers.html#overview">Overview</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab7-block-device-drivers.html#register-a-block-i-o-device">Register a block I/O device</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab7-block-device-drivers.html#register-a-disk">Register a disk</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab7-block-device-drivers.html#struct-gendisk-structure"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab7-block-device-drivers.html#struct-block-device-operations-structure"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">block_device_operations</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab7-block-device-drivers.html#request-queues-multi-queue-block-layer">Request Queues - Multi-Queue Block Layer</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#software-staging-queues">Software staging queues</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#hardware-dispatch-queues">Hardware dispatch queues</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#tag-sets">Tag sets</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#create-and-delete-a-request-queue">Create and delete a request queue</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#useful-functions-for-processing-request-queues">Useful functions for processing request queues</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab7-block-device-drivers.html#requests-for-block-devices">Requests for block devices</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#create-a-request">Create a request</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#process-a-request">Process a request</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab7-block-device-drivers.html#struct-bio-structure"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#create-a-struct-bio-structure">Create a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#submit-a-struct-bio-structure">Submit a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#wait-for-the-completion-of-a-struct-bio-structure">Wait for the completion of a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#initialize-a-struct-bio-structure">Initialize a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#how-to-use-the-content-of-a-struct-bio-structure">How to use the content of a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#free-a-struct-bio-structure">Free a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#set-up-a-request-queue-at-struct-bio-level">Set up a request queue at <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> level</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab7-block-device-drivers.html#further-reading">Further reading</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab7-block-device-drivers.html#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#intro">0. Intro</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#block-device">1. Block device</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#disk-registration">2. Disk registration</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#ram-disk">3. RAM disk</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#read-data-from-the-disk">4. Read data from the disk</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#write-data-to-the-disk">5. Write data to the disk</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab7-block-device-drivers.html#processing-requests-from-the-request-queue-at-struct-bio-level">6. Processing requests from the request queue at <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> level</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lab8-filesystems-part1.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab8-filesystems-part1.html#virtual-filesystem-vfs">Virtual Filesystem (VFS)</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab8-filesystems-part1.html#the-general-file-system-model">The general file system model</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab8-filesystems-part1.html#superblock">superblock</a><ul> +<li class="toctree-l5"><a class="reference internal" href="so2/lab8-filesystems-part1.html#localization">Localization:</a></li> +</ul> +</li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab8-filesystems-part1.html#inode">inode</a><ul> +<li class="toctree-l5"><a class="reference internal" href="so2/lab8-filesystems-part1.html#localization-1">Localization:</a></li> +</ul> +</li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab8-filesystems-part1.html#file">file</a><ul> +<li class="toctree-l5"><a class="reference internal" href="so2/lab8-filesystems-part1.html#localization-2">Localization:</a></li> +</ul> +</li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab8-filesystems-part1.html#dentry">dentry</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab8-filesystems-part1.html#register-and-unregister-filesystems">Register and unregister filesystems</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab8-filesystems-part1.html#functions-mount-kill-sb">Functions mount, kill_sb</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab8-filesystems-part1.html#superblock-in-vfs">Superblock in VFS</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab8-filesystems-part1.html#the-struct-super-block-structure">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab8-filesystems-part1.html#superblock-operations">Superblock operations</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab8-filesystems-part1.html#the-fill-super-function">The <code class="docutils literal"><span class="pre">fill_super()</span></code> function</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab8-filesystems-part1.html#buffer-cache">Buffer cache</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab8-filesystems-part1.html#functions-and-useful-macros">Functions and useful macros</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab8-filesystems-part1.html#further-reading">Further reading</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab8-filesystems-part1.html#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab8-filesystems-part1.html#myfs">myfs</a><ul> +<li class="toctree-l5"><a class="reference internal" href="so2/lab8-filesystems-part1.html#register-and-unregister-the-myfs-file-system">1. Register and unregister the myfs file system</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lab8-filesystems-part1.html#completing-myfs-superblock">2. Completing myfs superblock</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lab8-filesystems-part1.html#initialize-myfs-root-inode">3. Initialize myfs root inode</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lab8-filesystems-part1.html#test-myfs-mount-and-unmount">4. Test myfs mount and unmount</a></li> +</ul> +</li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab8-filesystems-part1.html#minfs">minfs</a><ul> +<li class="toctree-l5"><a class="reference internal" href="so2/lab8-filesystems-part1.html#registering-and-unregistering-the-minfs-file-system">1. Registering and unregistering the minfs file system</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lab8-filesystems-part1.html#completing-minfs-superblock">2. Completing minfs superblock</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lab8-filesystems-part1.html#creating-and-destroying-minfs-inodes">3. Creating and destroying minfs inodes</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lab8-filesystems-part1.html#initialize-minfs-root-inode">4. Initialize minfs root inode</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lab8-filesystems-part1.html#testing-of-minfs-mount-and-unmount">5. Testing of minfs mount and unmount</a></li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lab9-filesystems-part2.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab9-filesystems-part2.html#inode">Inode</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab9-filesystems-part2.html#the-inode-structure">The inode structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab9-filesystems-part2.html#inode-operations">Inode operations</a><ul> +<li class="toctree-l5"><a class="reference internal" href="so2/lab9-filesystems-part2.html#getting-an-inode">Getting an inode</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lab9-filesystems-part2.html#superoperations">Superoperations</a></li> +<li class="toctree-l5"><a class="reference internal" href="so2/lab9-filesystems-part2.html#inode-operations-1">inode_operations</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab9-filesystems-part2.html#the-file-structure">The file structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab9-filesystems-part2.html#regular-files-inodes">Regular files inodes</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab9-filesystems-part2.html#regular-files-inode-operations">Regular files inode operations</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab9-filesystems-part2.html#address-space-operations">Address space operations</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab9-filesystems-part2.html#dentry-structure">Dentry structure</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab9-filesystems-part2.html#dentry-operations">Dentry operations</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab9-filesystems-part2.html#directory-inodes-operations">Directory inodes operations</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab9-filesystems-part2.html#creating-an-inode">Creating an inode</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab9-filesystems-part2.html#creating-a-directory">Creating a directory</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab9-filesystems-part2.html#creating-a-link">Creating a link</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab9-filesystems-part2.html#creating-a-symbolic-link">Creating a symbolic link</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab9-filesystems-part2.html#deleting-a-link">Deleting a link</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab9-filesystems-part2.html#deleting-a-directory">Deleting a directory</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab9-filesystems-part2.html#searching-for-an-inode-in-a-directory">Searching for an inode in a directory</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab9-filesystems-part2.html#iterating-through-entries-in-a-directory">Iterating through entries in a directory</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab9-filesystems-part2.html#bitmap-operations">Bitmap operations</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab9-filesystems-part2.html#further-reading">Further reading</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab9-filesystems-part2.html#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab9-filesystems-part2.html#myfs">myfs</a><ul> +<li class="toctree-l5"><a class="reference internal" href="so2/lab9-filesystems-part2.html#directory-operations">1. Directory operations</a><ul> +<li class="toctree-l6"><a class="reference internal" href="so2/lab9-filesystems-part2.html#testing">Testing</a></li> +</ul> +</li> +<li class="toctree-l5"><a class="reference internal" href="so2/lab9-filesystems-part2.html#file-operations">2. File operations</a><ul> +<li class="toctree-l6"><a class="reference internal" href="so2/lab9-filesystems-part2.html#testing-1">Testing</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab9-filesystems-part2.html#minfs">minfs</a><ul> +<li class="toctree-l5"><a class="reference internal" href="so2/lab9-filesystems-part2.html#iterate-operation">1. Iterate operation</a><ul> +<li class="toctree-l6"><a class="reference internal" href="so2/lab9-filesystems-part2.html#testing-2">Testing</a></li> +</ul> +</li> +<li class="toctree-l5"><a class="reference internal" href="so2/lab9-filesystems-part2.html#lookup-operation">2. Lookup operation</a><ul> +<li class="toctree-l6"><a class="reference internal" href="so2/lab9-filesystems-part2.html#testing-3">Testing</a></li> +</ul> +</li> +<li class="toctree-l5"><a class="reference internal" href="so2/lab9-filesystems-part2.html#create-operation">3. Create operation</a><ul> +<li class="toctree-l6"><a class="reference internal" href="so2/lab9-filesystems-part2.html#testing-4">Testing</a></li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lab10-networking.html">SO2 Lab 10 - Networking</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lab10-networking.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab10-networking.html#overview">Overview</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab10-networking.html#networking-in-user-space">Networking in user space</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab10-networking.html#linux-networking">Linux networking</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab10-networking.html#the-struct-socket-structure">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> structure</a><ul> +<li class="toctree-l5"><a class="reference internal" href="so2/lab10-networking.html#operations-on-the-socket-structure">Operations on the socket structure</a><ul> +<li class="toctree-l6"><a class="reference internal" href="so2/lab10-networking.html#creation">Creation</a></li> +<li class="toctree-l6"><a class="reference internal" href="so2/lab10-networking.html#closing">Closing</a></li> +<li class="toctree-l6"><a class="reference internal" href="so2/lab10-networking.html#sending-receiving-messages">Sending/receiving messages</a></li> +</ul> +</li> +<li class="toctree-l5"><a class="reference internal" href="so2/lab10-networking.html#the-struct-socket-fields">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> fields</a><ul> +<li class="toctree-l6"><a class="reference internal" href="so2/lab10-networking.html#the-struct-proto-ops-structure">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">proto_ops</span></code> structure</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab10-networking.html#the-struct-sock-structure">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">sock</span></code> structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab10-networking.html#the-struct-sk-buff-structure">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">sk_buff</span></code> structure</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab10-networking.html#conversions-1">Conversions</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab10-networking.html#netfilter-1">netfilter</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab10-networking.html#netcat">netcat</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab10-networking.html#further-reading">Further reading</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab10-networking.html#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab10-networking.html#displaying-packets-in-kernel-space">1. Displaying packets in kernel space</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab10-networking.html#filtering-by-destination-address">2. Filtering by destination address</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab10-networking.html#listening-on-a-tcp-socket">3. Listening on a TCP socket</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab10-networking.html#accepting-connections-in-kernel-space">4. Accepting connections in kernel space</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab10-networking.html#udp-socket-sender">5. UDP socket sender</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lab11-arm-kernel-development.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab11-arm-kernel-development.html#system-on-a-chip">System on a Chip</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab11-arm-kernel-development.html#board-support-package">Board Support package</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab11-arm-kernel-development.html#toolchain">Toolchain</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab11-arm-kernel-development.html#compiling-the-linux-kernel-on-arm">Compiling the Linux kernel on ARM</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab11-arm-kernel-development.html#linux-kernel-image">Linux kernel image</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab11-arm-kernel-development.html#rootfs">Rootfs</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab11-arm-kernel-development.html#device-tree">Device tree</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab11-arm-kernel-development.html#qemu">Qemu</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab11-arm-kernel-development.html#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab11-arm-kernel-development.html#intro">0. Intro</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab11-arm-kernel-development.html#boot">1. Boot</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab11-arm-kernel-development.html#cpu-information">2. CPU information</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab11-arm-kernel-development.html#i-o-memory">3. I/O memory</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab11-arm-kernel-development.html#hello-world">4. Hello World</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab11-arm-kernel-development.html#simple-device">5. Simple device</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/lab12-kernel-profiling.html#lab-objectives">Lab Objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab12-kernel-profiling.html#overview">Overview</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab12-kernel-profiling.html#profiling-tools">Profiling Tools</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab12-kernel-profiling.html#perf">perf</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab12-kernel-profiling.html#ps">ps</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab12-kernel-profiling.html#time">time</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab12-kernel-profiling.html#top">top</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab12-kernel-profiling.html#profiling-methodology">Profiling Methodology</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab12-kernel-profiling.html#exercises">Exercises</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/lab12-kernel-profiling.html#demo-profiling-i-o-problems">0. Demo: Profiling I/O Problems</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/lab12-kernel-profiling.html#investigating-reduced-responsiveness">1. Investigating Reduced Responsiveness</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab12-kernel-profiling.html#launching-new-threads">2. Launching New Threads</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab12-kernel-profiling.html#tuning-cp">3. Tuning <code class="docutils literal"><span class="pre">cp</span></code></a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab12-kernel-profiling.html#i-o-latency">4. I/O Latency</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/lab12-kernel-profiling.html#bad-elf">5. Bad ELF</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/assign-collaboration.html">Collaboration</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/assign-collaboration.html#use-github-gitlab">1. Use Github / Gitlab</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign-collaboration.html#start-with-a-skeleton-for-the-assignment">2. Start with a skeleton for the assignment</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign-collaboration.html#add-a-commit-for-each-individual-change">3. Add a commit for each individual change</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign-collaboration.html#split-the-work-inside-the-team">4. Split the work inside the team</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign-collaboration.html#do-reviews">5. Do reviews</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign-collaboration.html#merge-the-work">6. Merge the work</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/assign0-kernel-api.html">Assignment 0 - Kernel API</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/assign0-kernel-api.html#assignment-s-objectives">Assignment's Objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign0-kernel-api.html#statement">Statement</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign0-kernel-api.html#testing">Testing</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign0-kernel-api.html#quickstart">QuickStart</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/assign0-kernel-api.html#tips">Tips</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/assign0-kernel-api.html#penalties">Penalties</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/assign0-kernel-api.html#submitting-the-assigment">Submitting the assigment</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign0-kernel-api.html#resources">Resources</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign0-kernel-api.html#questions">Questions</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/assign1-kprobe-based-tracer.html#assignment-s-objectives">Assignment's Objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign1-kprobe-based-tracer.html#statement">Statement</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/assign1-kprobe-based-tracer.html#implementation-details">Implementation details</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign1-kprobe-based-tracer.html#testing">Testing</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign1-kprobe-based-tracer.html#quickstart">QuickStart</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/assign1-kprobe-based-tracer.html#tips">Tips</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/assign1-kprobe-based-tracer.html#penalties">Penalties</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/assign1-kprobe-based-tracer.html#submitting-the-assigment">Submitting the assigment</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign1-kprobe-based-tracer.html#resources">Resources</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign1-kprobe-based-tracer.html#questions">Questions</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/assign2-driver-uart.html">Assignment 2 - Driver UART</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/assign2-driver-uart.html#assignment-s-objectives">Assignment's Objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign2-driver-uart.html#statement">Statement</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/assign2-driver-uart.html#buffers-scheme">Buffers Scheme</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign2-driver-uart.html#implementation-details">Implementation Details</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign2-driver-uart.html#testing">Testing</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign2-driver-uart.html#quickstart">QuickStart</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/assign2-driver-uart.html#tips">Tips</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/assign2-driver-uart.html#penalties">Penalties</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/assign2-driver-uart.html#submitting-the-assigment">Submitting the assigment</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign2-driver-uart.html#resources">Resources</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign2-driver-uart.html#questions">Questions</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/assign3-software-raid.html">Assignment 3 - Software RAID</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/assign3-software-raid.html#assignment-s-objectives">Assignment's Objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign3-software-raid.html#statement">Statement</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/assign3-software-raid.html#important-to-know">Important to know</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign3-software-raid.html#implementation-details">Implementation Details</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign3-software-raid.html#testing">Testing</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign3-software-raid.html#quickstart">QuickStart</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/assign3-software-raid.html#tips">Tips</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/assign3-software-raid.html#penalties">Penalties</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/assign3-software-raid.html#submitting-the-assigment">Submitting the assigment</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign3-software-raid.html#resources">Resources</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign3-software-raid.html#questions">Questions</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/assign4-transport-protocol.html#assignment-s-objectives">Assignment's Objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign4-transport-protocol.html#statement">Statement</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign4-transport-protocol.html#implementation-details">Implementation Details</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/assign4-transport-protocol.html#sample-protocol-implementations">Sample Protocol Implementations</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign4-transport-protocol.html#testing">Testing</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/assign4-transport-protocol.html#tcpdump">tcpdump</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign4-transport-protocol.html#quickstart">QuickStart</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/assign4-transport-protocol.html#tips">Tips</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/assign4-transport-protocol.html#penalties">Penalties</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/assign4-transport-protocol.html#submitting-the-assigment">Submitting the assigment</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign4-transport-protocol.html#resources">Resources</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign4-transport-protocol.html#questions">Questions</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="so2/assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a><ul> +<li class="toctree-l3"><a class="reference internal" href="so2/assign7-kvm-vmm.html#i-virtual-machine-manager">I. Virtual Machine Manager</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/assign7-kvm-vmm.html#initialize-the-vmm">1. Initialize the VMM</a><ul> +<li class="toctree-l5"><a class="reference internal" href="so2/assign7-kvm-vmm.html#initialize-a-virtual-cpu">2. Initialize a virtual CPU</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign7-kvm-vmm.html#running-the-vm">Running the VM</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/assign7-kvm-vmm.html#setup-real-mode">Setup real mode</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/assign7-kvm-vmm.html#setup-long-mode">Setup long mode</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/assign7-kvm-vmm.html#running">Running</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/assign7-kvm-vmm.html#guest-code">Guest code</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/assign7-kvm-vmm.html#controller-queues">Controller queues</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/assign7-kvm-vmm.html#device-structures">Device structures</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign7-kvm-vmm.html#using-the-skeleton">Using the skeleton</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign7-kvm-vmm.html#debugging">Debugging</a></li> +<li class="toctree-l3"><a class="reference internal" href="so2/assign7-kvm-vmm.html#tasks">Tasks</a><ul> +<li class="toctree-l4"><a class="reference internal" href="so2/assign7-kvm-vmm.html#submitting-the-assigment">Submitting the assigment</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/assign7-kvm-vmm.html#tips">Tips</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/assign7-kvm-vmm.html#penalties">Penalties</a></li> +<li class="toctree-l4"><a class="reference internal" href="so2/assign7-kvm-vmm.html#tldr">TLDR</a></li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +</ul> +</div> +<div class="toctree-wrapper compound"> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="lectures/intro.html">Introduction</a><ul> +<li class="toctree-l2"><a class="reference internal" href="lectures/intro.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/intro.html#basic-operating-systems-terms-and-concepts">Basic operating systems terms and concepts</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#user-vs-kernel">User vs Kernel</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#typical-operating-system-architecture">Typical operating system architecture</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#monolithic-kernel">Monolithic kernel</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#micro-kernel">Micro kernel</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#micro-kernels-vs-monolithic-kernels">Micro-kernels vs monolithic kernels</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#address-space">Address space</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#user-and-kernel-sharing-the-virtual-address-space">User and kernel sharing the virtual address space</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#execution-contexts">Execution contexts</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#multi-tasking">Multi-tasking</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#preemptive-kernel">Preemptive kernel</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#pageable-kernel-memory">Pageable kernel memory</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#kernel-stack">Kernel stack</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#portability">Portability</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#asymmetric-multiprocessing-asmp">Asymmetric MultiProcessing (ASMP)</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#symmetric-multiprocessing-smp">Symmetric MultiProcessing (SMP)</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#cpu-scalability">CPU Scalability</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/intro.html#overview-of-the-linux-kernel">Overview of the Linux kernel</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#linux-development-model">Linux development model</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#maintainer-hierarchy">Maintainer hierarchy</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#linux-source-code-layout">Linux source code layout</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/intro.html#linux-kernel-architecture">Linux kernel architecture</a><ul> +<li class="toctree-l4"><a class="reference internal" href="lectures/intro.html#arch">arch</a></li> +<li class="toctree-l4"><a class="reference internal" href="lectures/intro.html#device-drivers">Device drivers</a></li> +<li class="toctree-l4"><a class="reference internal" href="lectures/intro.html#process-management">Process management</a></li> +<li class="toctree-l4"><a class="reference internal" href="lectures/intro.html#memory-management">Memory management</a></li> +<li class="toctree-l4"><a class="reference internal" href="lectures/intro.html#block-i-o-management">Block I/O management</a></li> +<li class="toctree-l4"><a class="reference internal" href="lectures/intro.html#virtual-filesystem-switch">Virtual Filesystem Switch</a></li> +<li class="toctree-l4"><a class="reference internal" href="lectures/intro.html#networking-stack">Networking stack</a></li> +<li class="toctree-l4"><a class="reference internal" href="lectures/intro.html#linux-security-modules">Linux Security Modules</a></li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="lectures/syscalls.html">System Calls</a><ul> +<li class="toctree-l2"><a class="reference internal" href="lectures/syscalls.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/syscalls.html#linux-system-calls-implementation">Linux system calls implementation</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/syscalls.html#system-call-table">System call table</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/syscalls.html#system-call-parameters-handling">System call parameters handling</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/syscalls.html#virtual-dynamic-shared-object-vdso">Virtual Dynamic Shared Object (VDSO)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/syscalls.html#accessing-user-space-from-system-calls">Accessing user space from system calls</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="lectures/processes.html">Processes</a><ul> +<li class="toctree-l2"><a class="reference internal" href="lectures/processes.html#lecture-objectives">Lecture objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/processes.html#processes-and-threads">Processes and threads</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/processes.html#overview-of-process-resources">Overview of process resources</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/processes.html#struct-task-struct"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code></a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/processes.html#inspecting-task-struct">Inspecting task_struct</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/processes.html#quiz-inspect-a-task-to-determine-opened-files">Quiz: Inspect a task to determine opened files</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/processes.html#threads">Threads</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/processes.html#the-clone-system-call">The clone system call</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/processes.html#namespaces-and-containers">Namespaces and "containers"</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/processes.html#accessing-the-current-process">Accessing the current process</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/processes.html#quiz-previous-implementation-for-current-x86">Quiz: previous implementation for current (x86)</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/processes.html#context-switching">Context switching</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/processes.html#quiz-context-switch">Quiz: context switch</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/processes.html#blocking-and-waking-up-tasks">Blocking and waking up tasks</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/processes.html#task-states">Task states</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/processes.html#blocking-the-current-thread">Blocking the current thread</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/processes.html#waking-up-a-task">Waking up a task</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/processes.html#preempting-tasks">Preempting tasks</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/processes.html#non-preemptive-kernel">Non preemptive kernel</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/processes.html#preemptive-kernel">Preemptive kernel</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/processes.html#process-context">Process context</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/processes.html#kernel-threads">Kernel threads</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/processes.html#using-gdb-scripts-for-kernel-inspection">Using gdb scripts for kernel inspection</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/processes.html#quiz-kernel-gdb-scripts">Quiz: Kernel gdb scripts</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="lectures/interrupts.html">Interrupts</a><ul> +<li class="toctree-l2"><a class="reference internal" href="lectures/interrupts.html#lecture-objectives">Lecture objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/interrupts.html#what-is-an-interrupt">What is an interrupt?</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#exceptions">Exceptions</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#quiz-interrupt-terminology">Quiz: interrupt terminology</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/interrupts.html#hardware-concepts">Hardware Concepts</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#programmable-interrupt-controller">Programmable Interrupt Controller</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#interrupt-controllers-in-smp-systems">Interrupt controllers in SMP systems</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#interrupt-control">Interrupt Control</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#interrupt-priorities">Interrupt priorities</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#quiz-hardware-concepts">Quiz: hardware concepts</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/interrupts.html#interrupt-handling-on-the-x86-architecture">Interrupt handling on the x86 architecture</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#interrupt-descriptor-table">Interrupt Descriptor Table</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#interrupt-handler-address">Interrupt handler address</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#stack-of-interrupt-handler">Stack of interrupt handler</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#handling-an-interrupt-request">Handling an interrupt request</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#returning-from-an-interrupt-handler">Returning from an interrupt handler</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#inspecting-the-x86-interrupt-handling">Inspecting the x86 interrupt handling</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#quiz-x86-interrupt-handling">Quiz: x86 interrupt handling</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/interrupts.html#interrupt-handling-in-linux">Interrupt handling in Linux</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#nested-interrupts-and-exceptions">Nested interrupts and exceptions</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#interrupt-context">Interrupt context</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#deferrable-actions">Deferrable actions</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#soft-irqs">Soft IRQs</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#packet-flood-example">Packet flood example</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#tasklets">Tasklets</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#workqueues">Workqueues</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#timers">Timers</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#deferrable-actions-summary">Deferrable actions summary</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/interrupts.html#quiz-linux-interrupt-handling">Quiz: Linux interrupt handling</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="lectures/smp.html">Symmetric Multi-Processing</a><ul> +<li class="toctree-l2"><a class="reference internal" href="lectures/smp.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/smp.html#synchronization-basics">Synchronization basics</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/smp.html#linux-kernel-concurrency-sources">Linux kernel concurrency sources</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/smp.html#atomic-operations">Atomic operations</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/smp.html#disabling-preemption-interrupts">Disabling preemption (interrupts)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/smp.html#spin-locks">Spin Locks</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/smp.html#cache-coherency-in-multi-processor-systems">Cache coherency in multi-processor systems</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/smp.html#optimized-spin-locks">Optimized spin locks</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/smp.html#process-and-interrupt-context-synchronization">Process and Interrupt Context Synchronization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/smp.html#mutexes">Mutexes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/smp.html#per-cpu-data">Per CPU data</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/smp.html#memory-ordering-and-barriers">Memory Ordering and Barriers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/smp.html#read-copy-update-rcu">Read Copy Update (RCU)</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="lectures/address-space.html">Address Space</a><ul> +<li class="toctree-l2"><a class="reference internal" href="lectures/address-space.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/address-space.html#x86-mmu">x86 MMU</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/address-space.html#selectors">Selectors</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/address-space.html#segment-descriptor">Segment descriptor</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/address-space.html#segmentation-in-linux">Segmentation in Linux</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/address-space.html#inspecting-selectors-and-segments">Inspecting selectors and segments</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/address-space.html#x86-paging">x86 Paging</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/address-space.html#page-tables">Page tables</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/address-space.html#linux-paging">Linux paging</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/address-space.html#translation-look-aside-buffer">Translation Look-aside Buffer</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/address-space.html#linux-address-space">Linux address space</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/address-space.html#address-space-options-for-32bit-systems">Address space options for 32bit systems</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/address-space.html#linear-mappings">Linear mappings</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/address-space.html#highmem">Highmem</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/address-space.html#fixed-mapped-linear-addresses">Fixed-mapped linear addresses</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/address-space.html#temporary-mappings">Temporary mappings</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/address-space.html#permanent-mappings">Permanent mappings</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="lectures/memory-management.html">Memory Management</a><ul> +<li class="toctree-l2"><a class="reference internal" href="lectures/memory-management.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/memory-management.html#physical-memory-management">Physical Memory Management</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/memory-management.html#memory-zones">Memory zones</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/memory-management.html#non-uniform-memory-access">Non-Uniform Memory Access</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/memory-management.html#page-allocation">Page allocation</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/memory-management.html#small-allocations">Small allocations</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/memory-management.html#virtual-memory-management">Virtual memory management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/memory-management.html#fault-page-handling">Fault page handling</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="lectures/fs.html">Filesystem Management</a><ul> +<li class="toctree-l2"><a class="reference internal" href="lectures/fs.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/fs.html#filesystem-abstractions">Filesystem Abstractions</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/fs.html#filesystem-operations">Filesystem Operations</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/fs.html#mounting-a-filesystem">Mounting a filesystem</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/fs.html#opening-a-file">Opening a file</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/fs.html#querying-file-attributes">Querying file attributes</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/fs.html#reading-data-from-a-file">Reading data from a file</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/fs.html#writing-data-to-a-file">Writing data to a file</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/fs.html#closing-a-file">Closing a file</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/fs.html#directories">Directories</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/fs.html#creating-a-file">Creating a file</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/fs.html#deleting-a-file">Deleting a file</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/fs.html#linux-virtual-file-system">Linux Virtual File System</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/fs.html#superblock-operations">Superblock Operations</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/fs.html#inode-operations">Inode Operations</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/fs.html#the-inode-cache">The Inode Cache</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/fs.html#the-dentry-cache">The Dentry Cache</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/fs.html#the-page-cache">The Page Cache</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="lectures/debugging.html">Debugging</a><ul> +<li class="toctree-l2"><a class="reference internal" href="lectures/debugging.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/debugging.html#decoding-an-oops-panic">Decoding an oops/panic</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/debugging.html#decoding-an-oops">Decoding an oops</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/debugging.html#addr2line">addr2line</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/debugging.html#objdump">objdump</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/debugging.html#gdb">gdb</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/debugging.html#kernel-panic">Kernel panic</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/debugging.html#list-debugging">List debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/debugging.html#memory-debugging">Memory debugging</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/debugging.html#slab-debugging">Slab debugging</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/debugging.html#debug-pagealloc">DEBUG_PAGEALLOC</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/debugging.html#kasan">KASan</a><ul> +<li class="toctree-l4"><a class="reference internal" href="lectures/debugging.html#kasan-vs-debug-pagealloc">KASan vs DEBUG_PAGEALLOC</a></li> +<li class="toctree-l4"><a class="reference internal" href="lectures/debugging.html#kasan-vs-slub-debug">KASan vs SLUB_DEBUG</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="lectures/debugging.html#kmemleak">Kmemleak</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/debugging.html#lockdep-checker">Lockdep checker</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/debugging.html#perf">perf</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/debugging.html#other-tools">Other tools</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="lectures/networking.html">Network Management</a><ul> +<li class="toctree-l2"><a class="reference internal" href="lectures/networking.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/networking.html#network-management-overview">Network Management Overview</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/networking.html#sockets-implementation-overview">Sockets Implementation Overview</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/networking.html#sockets-families-and-protocols">Sockets Families and Protocols</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/networking.html#example-udp-send">Example: UDP send</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/networking.html#network-processing-phases">Network processing phases</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/networking.html#packet-routing">Packet Routing</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/networking.html#routing-table-s">Routing Table(s)</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/networking.html#routing-policy-database">Routing Policy Database</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/networking.html#routing-table-processing">Routing table processing</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/networking.html#forwarding-information-database">Forwarding Information Database</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/networking.html#netfilter">Netfilter</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/networking.html#network-packets-skbs-struct-sk-buff">Network packets / skbs (struct sk_buff)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/networking.html#network-device">Network Device</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/networking.html#hardware-and-software-acceleration-techniques">Hardware and Software Acceleration Techniques</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="lectures/arch.html">Architecture Layer</a><ul> +<li class="toctree-l2"><a class="reference internal" href="lectures/arch.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/arch.html#overview-of-the-arch-layer">Overview of the arch layer</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/arch.html#boot-strap">Boot strap</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/arch.html#boot-strap-1">Boot strap</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/arch.html#memory-setup">Memory setup</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/arch.html#mmu-management">MMU management</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/arch.html#thread-management">Thread Management</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/arch.html#time-management">Time Management</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/arch.html#irqs-and-exception-management">IRQs and exception management</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/arch.html#system-calls">System calls</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/arch.html#platform-drivers">Platform Drivers</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/arch.html#machine-specific-code">Machine specific code</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/arch.html#overview-of-the-boot-process">Overview of the boot process</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="lectures/virt.html">Virtualization</a><ul> +<li class="toctree-l2"><a class="reference internal" href="lectures/virt.html#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/virt.html#emulation-basics">Emulation basics</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/virt.html#virtualization-basics">Virtualization basics</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/virt.html#classic-virtualization">Classic virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/virt.html#software-virtualization">Software virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/virt.html#mmu-virtualization">MMU virtualization</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/virt.html#shadow-page-tables">Shadow page tables</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/virt.html#lazy-shadow-sync">Lazy shadow sync</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/virt.html#i-o-emulation">I/O emulation</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/virt.html#paravirtualization">Paravirtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/virt.html#intel-vt-x">Intel VT-x</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/virt.html#virtual-machine-control-structure">Virtual Machine Control Structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/virt.html#vm-entry-exit">VM entry & exit</a></li> +<li class="toctree-l3"><a class="reference internal" href="lectures/virt.html#vm-execution-control-fields">VM execution control fields</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/virt.html#extend-page-tables">Extend Page Tables</a><ul> +<li class="toctree-l3"><a class="reference internal" href="lectures/virt.html#vpid">VPID</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lectures/virt.html#i-o-virtualization">I/O virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/virt.html#qemu">qemu</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/virt.html#kvm">KVM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/virt.html#type-1-vs-type-2-hypervisors">Type 1 vs Type 2 Hypervisors</a></li> +<li class="toctree-l2"><a class="reference internal" href="lectures/virt.html#xen">Xen</a></li> +</ul> +</li> +</ul> +</div> +<div class="toctree-wrapper compound"> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/introduction.html">Introduction</a><ul> +<li class="toctree-l2"><a class="reference internal" href="labs/introduction.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/introduction.html#keywords">Keywords</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/introduction.html#about-this-laboratory">About this laboratory</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/introduction.html#references">References</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/introduction.html#source-code-navigation">Source code navigation</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/introduction.html#cscope">cscope</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/introduction.html#clangd">clangd</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/introduction.html#kscope">Kscope</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/introduction.html#lxr-cross-reference">LXR Cross-Reference</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/introduction.html#sourceweb">SourceWeb</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/introduction.html#kernel-debugging">Kernel Debugging</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/introduction.html#gdb-linux">gdb (Linux)</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/introduction.html#getting-a-stack-trace">Getting a stack trace</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/introduction.html#documentation">Documentation</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/introduction.html#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/introduction.html#remarks">Remarks</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/introduction.html#booting-the-virtual-machine">Booting the virtual machine</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/introduction.html#adding-and-using-a-virtual-disk">Adding and using a virtual disk</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/introduction.html#gdb-and-qemu">GDB and QEMU</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/introduction.html#gdb-spelunking">4. GDB spelunking</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/introduction.html#cscope-spelunking">5. Cscope spelunking</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="labs/kernel_modules.html">Kernel modules</a><ul> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_modules.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_modules.html#kernel-modules-overview">Kernel Modules Overview</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_modules.html#an-example-of-a-kernel-module">An example of a kernel module</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_modules.html#compiling-kernel-modules">Compiling kernel modules</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_modules.html#loading-unloading-a-kernel-module">Loading/unloading a kernel module</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_modules.html#kernel-module-debugging">Kernel Module Debugging</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#objdump">objdump</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#addr2line">addr2line</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#minicom">minicom</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#netconsole">netconsole</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#printk-debugging">Printk debugging</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#dynamic-debugging">Dynamic debugging</a><ul> +<li class="toctree-l4"><a class="reference internal" href="labs/kernel_modules.html#dyndbg-options">Dyndbg Options</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#kdb-kernel-debugger">KDB: Kernel debugger</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_modules.html#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#intro">0. Intro</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#kernel-module">1. Kernel module</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#printk">2. Printk</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#error">3. Error</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#sub-modules">4. Sub-modules</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#kernel-oops-1">5. Kernel oops</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#module-parameters">6. Module parameters</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#proc-info-1">7. Proc info</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_modules.html#extra-exercises">Extra Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#kdb">1. KDB</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#ps-module">2. PS Module</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#memory-info">3. Memory Info</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#dynamic-debugging-1">4. Dynamic Debugging</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_modules.html#dynamic-debugging-during-initialization">5. Dynamic Debugging During Initialization</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="labs/kernel_api.html">Kernel API</a><ul> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_api.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_api.html#overview">Overview</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_api.html#accessing-memory">Accessing memory</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_api.html#contexts-of-execution">Contexts of execution</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_api.html#locking">Locking</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_api.html#preemptivity">Preemptivity</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_api.html#linux-kernel-api">Linux Kernel API</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_api.html#convention-indicating-errors">Convention indicating errors</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_api.html#strings-of-characters">Strings of characters</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_api.html#printk">printk</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_api.html#memory-allocation">Memory allocation</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_api.html#lists">lists</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_api.html#spinlock">Spinlock</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_api.html#mutex">mutex</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_api.html#atomic-variables-1">Atomic variables</a><ul> +<li class="toctree-l4"><a class="reference internal" href="labs/kernel_api.html#use-of-atomic-variables">Use of atomic variables</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_api.html#atomic-bitwise-operations">Atomic bitwise operations</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_api.html#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_api.html#intro">0. Intro</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_api.html#memory-allocation-in-linux-kernel">1. Memory allocation in Linux kernel</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_api.html#sleeping-in-atomic-context">2. Sleeping in atomic context</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_api.html#working-with-kernel-memory">3. Working with kernel memory</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_api.html#working-with-kernel-lists">4. Working with kernel lists</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_api.html#working-with-kernel-lists-for-process-handling">5. Working with kernel lists for process handling</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_api.html#synchronizing-list-work">6. Synchronizing list work</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_api.html#test-module-calling-in-our-list-module">7. Test module calling in our list module</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="labs/device_drivers.html">Character device drivers</a><ul> +<li class="toctree-l2"><a class="reference internal" href="labs/device_drivers.html#laboratory-objectives">Laboratory objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/device_drivers.html#overview">Overview</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/device_drivers.html#majors-and-minors">Majors and minors</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/device_drivers.html#data-structures-for-a-character-device">Data structures for a character device</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/device_drivers.html#struct-file-operations"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code></a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_drivers.html#inode-and-file-structures"><code class="docutils literal"><span class="pre">inode</span></code> and <code class="docutils literal"><span class="pre">file</span></code> structures</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/device_drivers.html#implementation-of-operations">Implementation of operations</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/device_drivers.html#registration-and-unregistration-of-character-devices">Registration and unregistration of character devices</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/device_drivers.html#access-to-the-address-space-of-the-process">Access to the address space of the process</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/device_drivers.html#open-and-release">Open and release</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/device_drivers.html#read-and-write">Read and write</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/device_drivers.html#ioctl-1">ioctl</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/device_drivers.html#waiting-queues">Waiting queues</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/device_drivers.html#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/device_drivers.html#intro">0. Intro</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_drivers.html#register-unregister">1. Register/unregister</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_drivers.html#register-an-already-registered-major">2. Register an already registered major</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_drivers.html#open-and-close">3. Open and close</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_drivers.html#access-restriction">4. Access restriction</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_drivers.html#read-operation">5. Read operation</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_drivers.html#write-operation">6. Write operation</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_drivers.html#ioctl-operation">7. ioctl operation</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/device_drivers.html#extra-exercises">Extra Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/device_drivers.html#ioctl-with-messaging">Ioctl with messaging</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_drivers.html#ioctl-with-waiting-queues">Ioctl with waiting queues</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_drivers.html#o-nonblock-implementation">O_NONBLOCK implementation</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="labs/interrupts.html">I/O access and Interrupts</a><ul> +<li class="toctree-l2"><a class="reference internal" href="labs/interrupts.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/interrupts.html#background-information">Background information</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/interrupts.html#accessing-the-hardware">Accessing the hardware</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#request-access-to-i-o-ports">Request access to I/O ports</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#accessing-i-o-ports">Accessing I/O ports</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#accessing-i-o-ports-from-userspace">5. Accessing I/O ports from userspace</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/interrupts.html#interrupt-handling">Interrupt handling</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#requesting-an-interrupt">Requesting an interrupt</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#implementing-an-interrupt-handler">Implementing an interrupt handler</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#locking">Locking</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#interrupt-statistics">Interrupt statistics</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/interrupts.html#further-reading">Further reading</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#serial-port">Serial Port</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#parallel-port">Parallel port</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#keyboard-controller">Keyboard controller</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#linux-device-drivers">Linux device drivers</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/interrupts.html#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#intro">0. Intro</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#keyboard-driver">Keyboard driver</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#request-the-i-o-ports">1. Request the I/O ports</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#interrupt-handling-routine">2. Interrupt handling routine</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#store-ascii-keys-to-buffer">3. Store ASCII keys to buffer</a><ul> +<li class="toctree-l4"><a class="reference internal" href="labs/interrupts.html#reading-the-data-register">Reading the data register</a></li> +<li class="toctree-l4"><a class="reference internal" href="labs/interrupts.html#interpreting-the-scancode">Interpreting the scancode</a></li> +<li class="toctree-l4"><a class="reference internal" href="labs/interrupts.html#store-characters-to-the-buffer">Store characters to the buffer</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#reading-the-buffer">4. Reading the buffer</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#reset-the-buffer">5. Reset the buffer</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/interrupts.html#extra-exercises">Extra Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/interrupts.html#kfifo">1. kfifo</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="labs/deferred_work.html">Deferred work</a><ul> +<li class="toctree-l2"><a class="reference internal" href="labs/deferred_work.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/deferred_work.html#background-information">Background information</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/deferred_work.html#softirqs">Softirqs</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/deferred_work.html#tasklets">Tasklets</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/deferred_work.html#timers">Timers</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/deferred_work.html#locking">Locking</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/deferred_work.html#workqueues">Workqueues</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/deferred_work.html#kernel-threads">Kernel threads</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/deferred_work.html#further-reading">Further reading</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/deferred_work.html#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/deferred_work.html#intro">0. Intro</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/deferred_work.html#timer">1.Timer</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/deferred_work.html#periodic-timer">2. Periodic timer</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/deferred_work.html#timer-control-using-ioctl">3. Timer control using ioctl</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/deferred_work.html#blocking-operations">4. Blocking operations</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/deferred_work.html#workqueues-1">5. Workqueues</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/deferred_work.html#kernel-thread">6. Kernel thread</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/deferred_work.html#buffer-shared-between-timer-and-process">7. Buffer shared between timer and process</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="labs/block_device_drivers.html">Block Device Drivers</a><ul> +<li class="toctree-l2"><a class="reference internal" href="labs/block_device_drivers.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/block_device_drivers.html#overview">Overview</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/block_device_drivers.html#register-a-block-i-o-device">Register a block I/O device</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/block_device_drivers.html#register-a-disk">Register a disk</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/block_device_drivers.html#struct-gendisk-structure"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> structure</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/block_device_drivers.html#struct-block-device-operations-structure"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">block_device_operations</span></code> structure</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/block_device_drivers.html#request-queues-multi-queue-block-layer">Request Queues - Multi-Queue Block Layer</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#software-staging-queues">Software staging queues</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#hardware-dispatch-queues">Hardware dispatch queues</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#tag-sets">Tag sets</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#create-and-delete-a-request-queue">Create and delete a request queue</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#useful-functions-for-processing-request-queues">Useful functions for processing request queues</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/block_device_drivers.html#requests-for-block-devices">Requests for block devices</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#create-a-request">Create a request</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#process-a-request">Process a request</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/block_device_drivers.html#struct-bio-structure"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#create-a-struct-bio-structure">Create a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#submit-a-struct-bio-structure">Submit a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#wait-for-the-completion-of-a-struct-bio-structure">Wait for the completion of a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#initialize-a-struct-bio-structure">Initialize a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#how-to-use-the-content-of-a-struct-bio-structure">How to use the content of a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#free-a-struct-bio-structure">Free a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#set-up-a-request-queue-at-struct-bio-level">Set up a request queue at <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> level</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/block_device_drivers.html#further-reading">Further reading</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/block_device_drivers.html#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#intro">0. Intro</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#block-device">1. Block device</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#disk-registration">2. Disk registration</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#ram-disk">3. RAM disk</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#read-data-from-the-disk">4. Read data from the disk</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#write-data-to-the-disk">5. Write data to the disk</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/block_device_drivers.html#processing-requests-from-the-request-queue-at-struct-bio-level">6. Processing requests from the request queue at <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> level</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="labs/filesystems_part1.html">File system drivers (Part 1)</a><ul> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part1.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part1.html#virtual-filesystem-vfs">Virtual Filesystem (VFS)</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part1.html#the-general-file-system-model">The general file system model</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part1.html#superblock">superblock</a><ul> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part1.html#localization">Localization:</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part1.html#inode">inode</a><ul> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part1.html#localization-1">Localization:</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part1.html#file">file</a><ul> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part1.html#localization-2">Localization:</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part1.html#dentry">dentry</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part1.html#register-and-unregister-filesystems">Register and unregister filesystems</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part1.html#functions-mount-kill-sb">Functions mount, kill_sb</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part1.html#superblock-in-vfs">Superblock in VFS</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part1.html#the-struct-super-block-structure">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part1.html#superblock-operations">Superblock operations</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part1.html#the-fill-super-function">The <code class="docutils literal"><span class="pre">fill_super()</span></code> function</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part1.html#buffer-cache">Buffer cache</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part1.html#functions-and-useful-macros">Functions and useful macros</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part1.html#further-reading">Further reading</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part1.html#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part1.html#myfs">myfs</a><ul> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part1.html#register-and-unregister-the-myfs-file-system">1. Register and unregister the myfs file system</a></li> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part1.html#completing-myfs-superblock">2. Completing myfs superblock</a></li> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part1.html#initialize-myfs-root-inode">3. Initialize myfs root inode</a></li> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part1.html#test-myfs-mount-and-unmount">4. Test myfs mount and unmount</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part1.html#minfs">minfs</a><ul> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part1.html#registering-and-unregistering-the-minfs-file-system">1. Registering and unregistering the minfs file system</a></li> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part1.html#completing-minfs-superblock">2. Completing minfs superblock</a></li> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part1.html#creating-and-destroying-minfs-inodes">3. Creating and destroying minfs inodes</a></li> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part1.html#initialize-minfs-root-inode">4. Initialize minfs root inode</a></li> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part1.html#testing-of-minfs-mount-and-unmount">5. Testing of minfs mount and unmount</a></li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="labs/filesystems_part2.html">File system drivers (Part 2)</a><ul> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part2.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part2.html#inode">Inode</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part2.html#the-inode-structure">The inode structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part2.html#inode-operations">Inode operations</a><ul> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part2.html#getting-an-inode">Getting an inode</a></li> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part2.html#superoperations">Superoperations</a></li> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part2.html#inode-operations-1">inode_operations</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part2.html#the-file-structure">The file structure</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part2.html#regular-files-inodes">Regular files inodes</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part2.html#regular-files-inode-operations">Regular files inode operations</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part2.html#address-space-operations">Address space operations</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part2.html#dentry-structure">Dentry structure</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part2.html#dentry-operations">Dentry operations</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part2.html#directory-inodes-operations">Directory inodes operations</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part2.html#creating-an-inode">Creating an inode</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part2.html#creating-a-directory">Creating a directory</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part2.html#creating-a-link">Creating a link</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part2.html#creating-a-symbolic-link">Creating a symbolic link</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part2.html#deleting-a-link">Deleting a link</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part2.html#deleting-a-directory">Deleting a directory</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part2.html#searching-for-an-inode-in-a-directory">Searching for an inode in a directory</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part2.html#iterating-through-entries-in-a-directory">Iterating through entries in a directory</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part2.html#bitmap-operations">Bitmap operations</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part2.html#further-reading">Further reading</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/filesystems_part2.html#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part2.html#myfs">myfs</a><ul> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part2.html#directory-operations">1. Directory operations</a><ul> +<li class="toctree-l5"><a class="reference internal" href="labs/filesystems_part2.html#testing">Testing</a></li> +</ul> +</li> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part2.html#file-operations">2. File operations</a><ul> +<li class="toctree-l5"><a class="reference internal" href="labs/filesystems_part2.html#testing-1">Testing</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="labs/filesystems_part2.html#minfs">minfs</a><ul> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part2.html#iterate-operation">1. Iterate operation</a><ul> +<li class="toctree-l5"><a class="reference internal" href="labs/filesystems_part2.html#testing-2">Testing</a></li> +</ul> +</li> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part2.html#lookup-operation">2. Lookup operation</a><ul> +<li class="toctree-l5"><a class="reference internal" href="labs/filesystems_part2.html#testing-3">Testing</a></li> +</ul> +</li> +<li class="toctree-l4"><a class="reference internal" href="labs/filesystems_part2.html#create-operation">3. Create operation</a><ul> +<li class="toctree-l5"><a class="reference internal" href="labs/filesystems_part2.html#testing-4">Testing</a></li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="labs/networking.html">Networking</a><ul> +<li class="toctree-l2"><a class="reference internal" href="labs/networking.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/networking.html#overview">Overview</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/networking.html#networking-in-user-space">Networking in user space</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/networking.html#linux-networking">Linux networking</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/networking.html#the-struct-socket-structure">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> structure</a><ul> +<li class="toctree-l4"><a class="reference internal" href="labs/networking.html#operations-on-the-socket-structure">Operations on the socket structure</a><ul> +<li class="toctree-l5"><a class="reference internal" href="labs/networking.html#creation">Creation</a></li> +<li class="toctree-l5"><a class="reference internal" href="labs/networking.html#closing">Closing</a></li> +<li class="toctree-l5"><a class="reference internal" href="labs/networking.html#sending-receiving-messages">Sending/receiving messages</a></li> +</ul> +</li> +<li class="toctree-l4"><a class="reference internal" href="labs/networking.html#the-struct-socket-fields">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> fields</a><ul> +<li class="toctree-l5"><a class="reference internal" href="labs/networking.html#the-struct-proto-ops-structure">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">proto_ops</span></code> structure</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="labs/networking.html#the-struct-sock-structure">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">sock</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/networking.html#the-struct-sk-buff-structure">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">sk_buff</span></code> structure</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/networking.html#conversions-1">Conversions</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/networking.html#netfilter-1">netfilter</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/networking.html#netcat">netcat</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/networking.html#further-reading">Further reading</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/networking.html#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/networking.html#displaying-packets-in-kernel-space">1. Displaying packets in kernel space</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/networking.html#filtering-by-destination-address">2. Filtering by destination address</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/networking.html#listening-on-a-tcp-socket">3. Listening on a TCP socket</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/networking.html#accepting-connections-in-kernel-space">4. Accepting connections in kernel space</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/networking.html#udp-socket-sender">5. UDP socket sender</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="labs/arm_kernel_development.html">Kernel Development on ARM</a><ul> +<li class="toctree-l2"><a class="reference internal" href="labs/arm_kernel_development.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/arm_kernel_development.html#system-on-a-chip">System on a Chip</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/arm_kernel_development.html#board-support-package">Board Support package</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/arm_kernel_development.html#toolchain">Toolchain</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/arm_kernel_development.html#compiling-the-linux-kernel-on-arm">Compiling the Linux kernel on ARM</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/arm_kernel_development.html#linux-kernel-image">Linux kernel image</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/arm_kernel_development.html#rootfs">Rootfs</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/arm_kernel_development.html#device-tree">Device tree</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/arm_kernel_development.html#qemu">Qemu</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/arm_kernel_development.html#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/arm_kernel_development.html#intro">0. Intro</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/arm_kernel_development.html#boot">1. Boot</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/arm_kernel_development.html#cpu-information">2. CPU information</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/arm_kernel_development.html#i-o-memory">3. I/O memory</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/arm_kernel_development.html#hello-world">4. Hello World</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/arm_kernel_development.html#simple-device">5. Simple device</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="labs/memory_mapping.html">Memory mapping</a><ul> +<li class="toctree-l2"><a class="reference internal" href="labs/memory_mapping.html#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/memory_mapping.html#overview">Overview</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/memory_mapping.html#structures-used-for-memory-mapping">Structures used for memory mapping</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/memory_mapping.html#struct-page"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code></a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/memory_mapping.html#struct-vm-area-struct"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code></a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/memory_mapping.html#struct-mm-struct"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code></a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/memory_mapping.html#device-driver-memory-mapping">Device driver memory mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/memory_mapping.html#further-reading">Further reading</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/memory_mapping.html#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/memory_mapping.html#mapping-contiguous-physical-memory-to-userspace">1. Mapping contiguous physical memory to userspace</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/memory_mapping.html#mapping-non-contiguous-physical-memory-to-userspace">2. Mapping non-contiguous physical memory to userspace</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/memory_mapping.html#read-write-operations-in-mapped-memory">3. Read / write operations in mapped memory</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/memory_mapping.html#display-memory-mapped-in-procfs">4. Display memory mapped in procfs</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="labs/device_model.html">Linux Device Model</a><ul> +<li class="toctree-l2"><a class="reference internal" href="labs/device_model.html#overview">Overview</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/device_model.html#sysfs">sysfs</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/device_model.html#basic-structures-in-linux-devices">Basic Structures in Linux Devices</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#the-kobject-structure">The kobject structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#buses">Buses</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#devices">Devices</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#drivers">Drivers</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#classes">Classes</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#hotplug">Hotplug</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/device_model.html#plug-and-play">Plug and Play</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#pnp-bus">PNP bus</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#pnp-operations">PNP operations</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#adding-a-driver">Adding a driver</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#removing-a-driver">Removing a driver</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#adding-a-new-device">Adding a new device</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#removing-a-device">Removing a device</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/device_model.html#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#intro">0. Intro</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#bus-implementation">1. Bus implementation</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#add-type-and-version-device-attributes">2. Add type and version device attributes</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#add-del-and-add-bus-attributes">3. Add del and add bus attributes</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#register-the-bex-misc-driver">4. Register the bex misc driver</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#register-misc-device-in-the-bex-misc-probe-function">5. Register misc device in the bex_misc probe function</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/device_model.html#monitor-uevent-notifications">6. Monitor uevent notifications</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="labs/kernel_profiling.html">Kernel Profiling</a><ul> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_profiling.html#lab-objectives">Lab Objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_profiling.html#overview">Overview</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_profiling.html#profiling-tools">Profiling Tools</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_profiling.html#perf">perf</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_profiling.html#ps">ps</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_profiling.html#time">time</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_profiling.html#top">top</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_profiling.html#profiling-methodology">Profiling Methodology</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_profiling.html#exercises">Exercises</a></li> +<li class="toctree-l2"><a class="reference internal" href="labs/kernel_profiling.html#demo-profiling-i-o-problems">0. Demo: Profiling I/O Problems</a><ul> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_profiling.html#investigating-reduced-responsiveness">1. Investigating Reduced Responsiveness</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_profiling.html#launching-new-threads">2. Launching New Threads</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_profiling.html#tuning-cp">3. Tuning <code class="docutils literal"><span class="pre">cp</span></code></a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_profiling.html#i-o-latency">4. I/O Latency</a></li> +<li class="toctree-l3"><a class="reference internal" href="labs/kernel_profiling.html#bad-elf">5. Bad ELF</a></li> +</ul> +</li> +</ul> +</li> +</ul> +</div> +<div class="toctree-wrapper compound"> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="info/vm.html#virtual-machine-setup">Virtual Machine Setup</a><ul> +<li class="toctree-l2"><a class="reference internal" href="info/vm.html#starting-the-virtual-machine">Starting the Virtual Machine</a></li> +<li class="toctree-l2"><a class="reference internal" href="info/vm.html#connecting-to-the-virtual-machine">Connecting to the Virtual Machine</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="info/extra-vm.html">Customizing the Virtual Machine Setup</a><ul> +<li class="toctree-l2"><a class="reference internal" href="info/extra-vm.html#connect-to-the-virtual-machine-via-ssh">Connect to the Virtual Machine via SSH</a></li> +<li class="toctree-l2"><a class="reference internal" href="info/extra-vm.html#connecting-a-debugger-to-the-virtual-machine-kernel">Connecting a Debugger to the Virtual Machine Kernel</a></li> +<li class="toctree-l2"><a class="reference internal" href="info/extra-vm.html#rebuild-the-kernel-image">Rebuild the Kernel Image</a></li> +<li class="toctree-l2"><a class="reference internal" href="info/extra-vm.html#using-docker-containers">Using Docker containers</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="info/contributing.html">Contributing to linux-kernel-labs</a><ul> +<li class="toctree-l2"><a class="reference internal" href="info/contributing.html#repository-structure">Repository structure</a></li> +<li class="toctree-l2"><a class="reference internal" href="info/contributing.html#building-the-documentation">Building the documentation</a></li> +<li class="toctree-l2"><a class="reference internal" href="info/contributing.html#creating-a-contribution">Creating a contribution</a><ul> +<li class="toctree-l3"><a class="reference internal" href="info/contributing.html#forking-the-repository">Forking the repository</a></li> +<li class="toctree-l3"><a class="reference internal" href="info/contributing.html#creating-a-pull-request">Creating a pull request</a></li> +<li class="toctree-l3"><a class="reference internal" href="info/contributing.html#making-changes-to-a-pull-request">Making changes to a Pull Request</a></li> +</ul> +</li> +</ul> +</li> +</ul> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="so2/index.html" class="btn btn-neutral float-right" title="Operating Systems 2" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/info/contributing.html b/refs/pull/405/merge/info/contributing.html new file mode 100644 index 00000000..0fea866c --- /dev/null +++ b/refs/pull/405/merge/info/contributing.html @@ -0,0 +1,379 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Contributing to linux-kernel-labs — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="prev" title="Customizing the Virtual Machine Setup" href="extra-vm.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Contributing to linux-kernel-labs</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#repository-structure">Repository structure</a></li> +<li class="toctree-l2"><a class="reference internal" href="#building-the-documentation">Building the documentation</a></li> +<li class="toctree-l2"><a class="reference internal" href="#creating-a-contribution">Creating a contribution</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#forking-the-repository">Forking the repository</a></li> +<li class="toctree-l3"><a class="reference internal" href="#creating-a-pull-request">Creating a pull request</a></li> +<li class="toctree-l3"><a class="reference internal" href="#making-changes-to-a-pull-request">Making changes to a Pull Request</a></li> +</ul> +</li> +</ul> +</li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Contributing to linux-kernel-labs</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/info/contributing.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="contributing-to-linux-kernel-labs"> +<h1>Contributing to linux-kernel-labs<a class="headerlink" href="#contributing-to-linux-kernel-labs" title="Permalink to this headline">¶</a></h1> +<p><code class="docutils literal"><span class="pre">linux-kernel-labs</span></code> is an open platform. +You can help it get better by contributing to the documentation, exercises or +the infrastructure. +All contributions are welcome, no matter if they are just fixes for typos or +new sections in the documentation.</p> +<p>All information required for making a contribution can be found in the +<a class="reference external" href="https://github.com/linux-kernel-labs/linux">linux-kernel-labs Linux repo</a>. +In order to change anything, you need to create a Pull Request (<code class="docutils literal"><span class="pre">PR</span></code>) +from your own fork to this repository. +The PR will be reviewed by the members of the team and will be merged once +any potential issue is fixed.</p> +<div class="section" id="repository-structure"> +<h2>Repository structure<a class="headerlink" href="#repository-structure" title="Permalink to this headline">¶</a></h2> +<p>The <a class="reference external" href="https://github.com/linux-kernel-labs/linux">linux-kernel-labs repo</a> is +a fork of the Linux kernel repo, with the following additions:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">/tools/labs</span></code>: contains the labs and the <a class="reference internal" href="vm.html#vm-link"><span class="std std-ref">virtual machine (VM) infrastructure</span></a><ul> +<li><code class="docutils literal"><span class="pre">tools/labs/templates</span></code>: contains the skeletons sources</li> +<li><code class="docutils literal"><span class="pre">tools/labs/qemu</span></code>: contains the qemu VM configuration</li> +</ul> +</li> +<li><code class="docutils literal"><span class="pre">/Documentation/teaching</span></code>: contains the sources used to generate this +documentation</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="building-the-documentation"> +<h2>Building the documentation<a class="headerlink" href="#building-the-documentation" title="Permalink to this headline">¶</a></h2> +<p>To build the documentation, navigate to <code class="docutils literal"><span class="pre">tools/labs</span></code> and run the following +command:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>make docs +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The command should install all the required packages. +In some cases, installing the packages or building the documentation might +fail, because of broken dependencies versions.</p> +<p>Instead of struggling to fix the dependencies, the simplest way to build +the documentation is using a <a class="reference external" href="https://www.docker.com/">Docker</a>. +First, install <code class="docutils literal"><span class="pre">docker</span></code> and <code class="docutils literal"><span class="pre">docker-compose</span></code> on your host, and then run:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>make docker-docs +</pre></div> +</div> +<p class="last">The first run might take some time, but subsequent builds will be faster.</p> +</div> +</div> +<div class="section" id="creating-a-contribution"> +<h2>Creating a contribution<a class="headerlink" href="#creating-a-contribution" title="Permalink to this headline">¶</a></h2> +<div class="section" id="forking-the-repository"> +<h3>Forking the repository<a class="headerlink" href="#forking-the-repository" title="Permalink to this headline">¶</a></h3> +<ol class="arabic"> +<li><p class="first">If you haven't done it already, clone the +<a class="reference external" href="https://github.com/linux-kernel-labs/linux">linux-kernel-labs repo</a> +repository locally:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ mkdir -p ~/src +$ git clone git@github.com:linux-kernel-labs/linux.git ~/src/linux +</pre></div> +</div> +</li> +<li><p class="first">Go to <a class="reference external" href="https://github.com/linux-kernel-labs/linux">https://github.com/linux-kernel-labs/linux</a>, make sure you are logged +in and click <code class="docutils literal"><span class="pre">Fork</span></code> in the top right of the page.</p> +</li> +<li><p class="first">Add the forked repo as a new remote to the local repo:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ git remote add my_fork git@github.com:<your_username>/linux.git +</pre></div> +</div> +</li> +</ol> +<p>Now, you can push to your fork by using <code class="docutils literal"><span class="pre">my_fork</span></code> instead of <code class="docutils literal"><span class="pre">origin</span></code> +(e.g. <code class="docutils literal"><span class="pre">git</span> <span class="pre">push</span> <span class="pre">my_fork</span> <span class="pre">master</span></code>).</p> +</div> +<div class="section" id="creating-a-pull-request"> +<h3>Creating a pull request<a class="headerlink" href="#creating-a-pull-request" title="Permalink to this headline">¶</a></h3> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p class="last">Pull requests must be created from their own branches, which are started from +<code class="docutils literal"><span class="pre">master</span></code>.</p> +</div> +<ol class="arabic simple"> +<li>Go to the master branch and make sure you have no local changes:</li> +</ol> +<blockquote> +<div><div class="highlight-bash"><div class="highlight"><pre><span></span>student@eg106:~/src/linux$ git checkout master +student@eg106:~/src/linux$ git status +On branch master +Your branch is up-to-date with <span class="s1">'origin/master'</span>. +nothing to commit, working directory clean +</pre></div> +</div> +</div></blockquote> +<ol class="arabic simple" start="2"> +<li>Make sure the local master branch is up-to-date with linux-kernel-labs:</li> +</ol> +<blockquote> +<div><div class="highlight-bash"><div class="highlight"><pre><span></span>student@eg106:~/src/linux$ git pull origin master +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>You can also push the latest master to your forked repo:</p> +<div class="last highlight-bash"><div class="highlight"><pre><span></span>student@eg106:~/src/linux$ git push my_fork master +</pre></div> +</div> +</div> +</div></blockquote> +<ol class="arabic simple" start="3"> +<li>Create a new branch for your change:</li> +</ol> +<blockquote> +<div><div class="highlight-bash"><div class="highlight"><pre><span></span>student@eg106:~/src/linux$ git checkout -b <your_branch_name> +</pre></div> +</div> +</div></blockquote> +<ol class="arabic simple" start="4"> +<li>Make some changes and commit them. In this example, we are going to change +<code class="docutils literal"><span class="pre">Documentation/teaching/index.rst</span></code>:</li> +</ol> +<blockquote> +<div><div class="highlight-bash"><div class="highlight"><pre><span></span>student@eg106:~/src/linux$ vim Documentation/teaching/index.rst +student@eg106:~/src/linux$ git add Documentation/teaching/index.rst +student@eg106:~/src/linux$ git commit -m <span class="s2">"<commit message>"</span> +</pre></div> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>The commit message must include a relevant description of your change +and the location of the changed component.</p> +<p>Examples:</p> +<blockquote class="last"> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">documentation:</span> <span class="pre">index:</span> <span class="pre">Fix</span> <span class="pre">typo</span> <span class="pre">in</span> <span class="pre">the</span> <span class="pre">first</span> <span class="pre">section</span></code></li> +<li><code class="docutils literal"><span class="pre">labs:</span> <span class="pre">block_devices:</span> <span class="pre">Change</span> <span class="pre">printk</span> <span class="pre">log</span> <span class="pre">level</span></code></li> +</ul> +</div></blockquote> +</div> +</div></blockquote> +<ol class="arabic simple" start="5"> +<li>Push the local branch to your forked repository:</li> +</ol> +<blockquote> +<div><div class="highlight-bash"><div class="highlight"><pre><span></span>student@eg106:~/src/linux$ git push my_fork <your_branch_name> +</pre></div> +</div> +</div></blockquote> +<ol class="arabic simple" start="6"> +<li>Open the Pull Request</li> +</ol> +<blockquote> +<div><ul class="simple"> +<li>Go to <a class="reference external" href="https://github.com">https://github.com</a> and open your forked repository page</li> +<li>Click <code class="docutils literal"><span class="pre">New</span> <span class="pre">pull</span> <span class="pre">request</span></code>.</li> +<li>Make sure base repository (left side) is <code class="docutils literal"><span class="pre">linux-kernel-labs/linux</span></code> and the +base is master.</li> +<li>Make sure the head repository (right side) is your forked repo and the +compare branch is your pushed branch.</li> +<li>Click <code class="docutils literal"><span class="pre">Create</span> <span class="pre">pull</span> <span class="pre">request</span></code>.</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="making-changes-to-a-pull-request"> +<h3>Making changes to a Pull Request<a class="headerlink" href="#making-changes-to-a-pull-request" title="Permalink to this headline">¶</a></h3> +<p>After receiving feedback for your changes, you might need to update the Pull +Request. +Your goal is to do a new push on the same branch. For this, follow the next steps:</p> +<ol class="arabic simple"> +<li>Make sure your branch is still up to date with the <code class="docutils literal"><span class="pre">linux-kernel-labs</span></code> repo +<code class="docutils literal"><span class="pre">master</span></code> branch.</li> +</ol> +<blockquote> +<div><div class="highlight-bash"><div class="highlight"><pre><span></span>student@eg106:~/src/linux$ git fetch origin master +student@eg106:~/src/linux$ git rebase FETCH_HEAD +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>If you are getting conflicts, it means that someone else modified the same +files/lines as you and already merged the changes since you opened the +Pull Request.</p> +<p class="last">In this case, you will need to fix the conflicts by editing the +conflicting files manually (run <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code> to see these files). +After fixing the conflicts, add them using <code class="docutils literal"><span class="pre">git</span> <span class="pre">add</span></code> and then run +<code class="docutils literal"><span class="pre">git</span> <span class="pre">rebase</span> <span class="pre">--continue</span></code>.</p> +</div> +</div></blockquote> +<ol class="arabic simple" start="2"> +<li>Apply the changes to your local files</li> +<li>Commit the changes. We want all the changes to be in the same commit, so +we will amend the changes to the initial commit.</li> +</ol> +<blockquote> +<div><div class="highlight-bash"><div class="highlight"><pre><span></span>student@eg106:~/src/linux$ git add Documentation/teaching/index.rst +student@eg106:~/src/linux$ git commit --amend +</pre></div> +</div> +</div></blockquote> +<ol class="arabic simple" start="4"> +<li>Force-push the updated commit:</li> +</ol> +<blockquote> +<div><div class="highlight-bash"><div class="highlight"><pre><span></span>student@eg106:~/src/linux$ git push my_fork <your_branch_name> -f +</pre></div> +</div> +<p>After this step, the Pull Request is updated. It is now up to the +linux-kernel-labs team to review the pull request and integrate your +contributions in the main project.</p> +</div></blockquote> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="extra-vm.html" class="btn btn-neutral float-left" title="Customizing the Virtual Machine Setup" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/info/extra-vm.html b/refs/pull/405/merge/info/extra-vm.html new file mode 100644 index 00000000..763ca8c0 --- /dev/null +++ b/refs/pull/405/merge/info/extra-vm.html @@ -0,0 +1,306 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Customizing the Virtual Machine Setup — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Contributing to linux-kernel-labs" href="contributing.html" /> + <link rel="prev" title="Recommended Setup" href="vm.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Customizing the Virtual Machine Setup</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#connect-to-the-virtual-machine-via-ssh">Connect to the Virtual Machine via SSH</a></li> +<li class="toctree-l2"><a class="reference internal" href="#connecting-a-debugger-to-the-virtual-machine-kernel">Connecting a Debugger to the Virtual Machine Kernel</a></li> +<li class="toctree-l2"><a class="reference internal" href="#rebuild-the-kernel-image">Rebuild the Kernel Image</a></li> +<li class="toctree-l2"><a class="reference internal" href="#using-docker-containers">Using Docker containers</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Customizing the Virtual Machine Setup</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/info/extra-vm.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="customizing-the-virtual-machine-setup"> +<h1>Customizing the Virtual Machine Setup<a class="headerlink" href="#customizing-the-virtual-machine-setup" title="Permalink to this headline">¶</a></h1> +<div class="section" id="connect-to-the-virtual-machine-via-ssh"> +<h2>Connect to the Virtual Machine via SSH<a class="headerlink" href="#connect-to-the-virtual-machine-via-ssh" title="Permalink to this headline">¶</a></h2> +<p>The default Yocto image for the QEMU virtual machine +(<code class="docutils literal"><span class="pre">core-image-minimal-qemu</span></code>) provides the minimal functionality to run the +kernel and kernel modules. For extra features, such as an SSH connection, +a more complete image is required, such as <code class="docutils literal"><span class="pre">core-image-sato-dev-qemu</span></code>.</p> +<p>To use the new image, update the <code class="docutils literal"><span class="pre">YOCTO_IMAGE</span></code> variable in +<code class="docutils literal"><span class="pre">tools/labs/qemu/Makefile</span></code>:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span><span class="nv">YOCTO_IMAGE</span> <span class="o">=</span> core-image-sato-qemu<span class="k">$(</span>ARCH<span class="k">)</span>.ext4 +</pre></div> +</div> +<p>When you start the virtual machine the first time using <code class="docutils literal"><span class="pre">make</span> <span class="pre">boot</span></code> with the +new image configuration, it will download the image and then boot the virtual +machine. The image is larger (around 400MB) than the minimal image so expect +some time for the download.</p> +<p>You then enter the virtual machine via <code class="docutils literal"><span class="pre">minicom</span></code>, determine the IP address of +the <code class="docutils literal"><span class="pre">eth0</span></code> interface an then you can connect to the virtual machine via SSH:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>$ minicom -D serial.pts +Poky (Yocto Project Reference Distro) 2.3 qemux86 /dev/hvc0 + +qemux86 login: root +root@qemux86:~# ip a s +1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 + inet 127.0.0.1/8 scope host lo + valid_lft forever preferred_lft forever + inet6 ::1/128 scope host + valid_lft forever preferred_lft forever +2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000 + link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff + inet 172.213.0.18/24 brd 172.213.0.255 scope global eth0 + valid_lft forever preferred_lft forever + inet6 fe80::5054:ff:fe12:3456/64 scope link + valid_lft forever preferred_lft forever +3: sit0@NONE: <NOARP> mtu 1480 qdisc noop qlen 1000 + link/sit 0.0.0.0 brd 0.0.0.0 + +$ ssh -l root 172.213.0.18 +The authenticity of host '172.213.0.18 (172.213.0.18)' can't be established. +RSA key fingerprint is SHA256:JUWUcD7LdvURNcamoPePMhqEjFFtUNLAqO+TtzUiv5k. +Are you sure you want to continue connecting (yes/no)? yes +Warning: Permanently added '172.213.0.18' (RSA) to the list of known hosts. +root@qemux86:~# uname -a +Linux qemux86 4.19.0+ #3 SMP Sat Apr 4 22:45:18 EEST 2020 i686 GNU/Linux +</pre></div> +</div> +</div> +<div class="section" id="connecting-a-debugger-to-the-virtual-machine-kernel"> +<h2>Connecting a Debugger to the Virtual Machine Kernel<a class="headerlink" href="#connecting-a-debugger-to-the-virtual-machine-kernel" title="Permalink to this headline">¶</a></h2> +<p>You can use GDB to connect to the running virtual machine kernel and inspect +the state of the kernel. You run <code class="docutils literal"><span class="pre">make</span> <span class="pre">gdb</span></code> in <code class="docutils literal"><span class="pre">tools/labs/</span></code>:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>.../linux/tools/labs$ make gdb +ln -fs /home/tavi/src/linux/vmlinux vmlinux +gdb -ex <span class="s2">"target remote localhost:1234"</span> vmlinux +GNU gdb <span class="o">(</span>Ubuntu <span class="m">7</span>.11.1-0ubuntu1~16.04<span class="o">)</span> <span class="m">7</span>.11.1 +Copyright <span class="o">(</span>C<span class="o">)</span> <span class="m">2016</span> Free Software Foundation, Inc. +License GPLv3+: GNU GPL version <span class="m">3</span> or later <http://gnu.org/licenses/gpl.html> +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. Type <span class="s2">"show copying"</span> +and <span class="s2">"show warranty"</span> <span class="k">for</span> details. +This GDB was configured as <span class="s2">"x86_64-linux-gnu"</span>. +Type <span class="s2">"show configuration"</span> <span class="k">for</span> configuration details. +For bug reporting instructions, please see: +<http://www.gnu.org/software/gdb/bugs/>. +Find the GDB manual and other documentation resources online at: +<http://www.gnu.org/software/gdb/documentation/>. +For help, <span class="nb">type</span> <span class="s2">"help"</span>. +Type <span class="s2">"apropos word"</span> to search <span class="k">for</span> commands related to <span class="s2">"word"</span>... +Reading symbols from vmlinux...done. +Remote debugging using localhost:1234 +0xc13cf2f2 in native_safe_halt <span class="o">()</span> at ./arch/x86/include/asm/irqflags.h:53 +53asm volatile<span class="o">(</span><span class="s2">"sti; hlt"</span>: : :<span class="s2">"memory"</span><span class="o">)</span><span class="p">;</span> +<span class="o">(</span>gdb<span class="o">)</span> bt +<span class="c1">#0 0xc13cf2f2 in native_safe_halt () at ./arch/x86/include/asm/irqflags.h:53</span> +<span class="c1">#1 arch_safe_halt () at ./arch/x86/include/asm/irqflags.h:95</span> +<span class="c1">#2 default_idle () at arch/x86/kernel/process.c:341</span> +<span class="c1">#3 0xc101f136 in arch_cpu_idle () at arch/x86/kernel/process.c:332</span> +<span class="c1">#4 0xc106a6dd in cpuidle_idle_call () at kernel/sched/idle.c:156</span> +<span class="c1">#5 do_idle () at kernel/sched/idle.c:245</span> +<span class="c1">#6 0xc106a8c5 in cpu_startup_entry (state=<optimized out>)</span> +at kernel/sched/idle.c:350 +<span class="c1">#7 0xc13cb14a in rest_init () at init/main.c:415</span> +<span class="c1">#8 0xc1507a7a in start_kernel () at init/main.c:679</span> +<span class="c1">#9 0xc10001da in startup_32_smp () at arch/x86/kernel/head_32.S:368</span> +<span class="c1">#10 0x00000000 in ?? ()</span> +<span class="o">(</span>gdb<span class="o">)</span> +</pre></div> +</div> +</div> +<div class="section" id="rebuild-the-kernel-image"> +<h2>Rebuild the Kernel Image<a class="headerlink" href="#rebuild-the-kernel-image" title="Permalink to this headline">¶</a></h2> +<p>The kernel image is built the first time the VM is started. To rebuild the +kernel remove the kernel image file defined by the <code class="docutils literal"><span class="pre">ZIMAGE</span></code> variable in +<code class="docutils literal"><span class="pre">tools/labs/qemu/Makefile</span></code>:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span><span class="nv">ZIMAGE</span> <span class="o">=</span> <span class="k">$(</span>KDIR<span class="k">)</span>/arch/<span class="k">$(</span>ARCH<span class="k">)</span>/boot/<span class="k">$(</span>b<span class="k">)</span>zImage +</pre></div> +</div> +<p>Typically the full path of the kernel is <code class="docutils literal"><span class="pre">arch/x86/boot/bzImage</span></code>.</p> +<p>Once removed the kernel image is rebuild by using:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>~/src/linux/tools/labs$ make zImage +</pre></div> +</div> +<p>or simply starting the virtual machine</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>~/src/linux/tools/labs$ make boot +</pre></div> +</div> +</div> +<div class="section" id="using-docker-containers"> +<h2>Using Docker containers<a class="headerlink" href="#using-docker-containers" title="Permalink to this headline">¶</a></h2> +<p>If your setup doesn't allow the installation of the packages required for the +laboratory setup, you can build and run a container that has all the setup +already prepared for the virtual machine environment.</p> +<p>In order to run the containerized setup, you need to install the following +packages:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">docker</span></code></li> +<li><code class="docutils literal"><span class="pre">docker-compose</span></code></li> +</ul> +<p>In order to run the container infrastructure run the following command in the +<code class="docutils literal"><span class="pre">tools/labs/</span></code> directory:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>sergiu@local:~/src/linux/tools/labs$ make docker-kernel +... +ubuntu@so2:~$ +</pre></div> +</div> +<p>The first time you run the command above, it will take a long time, because you +will have to build the container environment and install the required +applications.</p> +<p>Every time you run the <code class="docutils literal"><span class="pre">make</span> <span class="pre">docker-kernel</span></code> command, another shell will +connect to the container. This will allow you to work with multiple tabs.</p> +<p>All the commands that you would use in the regular environment can be used in +the containerized environment.</p> +<p>The linux repository is mounted in the <code class="docutils literal"><span class="pre">/linux</span></code> directory. All changes +you will make here will also be seen on your local instance.</p> +<p>In order to stop the container use the following command:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>make stop-docker-kernel +</pre></div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="vm.html" class="btn btn-neutral float-left" title="Recommended Setup" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="contributing.html" class="btn btn-neutral float-right" title="Contributing to linux-kernel-labs" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/info/vm.html b/refs/pull/405/merge/info/vm.html new file mode 100644 index 00000000..b44fdf42 --- /dev/null +++ b/refs/pull/405/merge/info/vm.html @@ -0,0 +1,283 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Recommended Setup — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Customizing the Virtual Machine Setup" href="extra-vm.html" /> + <link rel="prev" title="Kernel Profiling" href="../labs/kernel_profiling.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul class="current"> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="#virtual-machine-setup">Virtual Machine Setup</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#starting-the-virtual-machine">Starting the Virtual Machine</a></li> +<li class="toctree-l2"><a class="reference internal" href="#connecting-to-the-virtual-machine">Connecting to the Virtual Machine</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Recommended Setup</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/info/vm.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="recommended-setup"> +<span id="vm-link"></span><h1>Recommended Setup<a class="headerlink" href="#recommended-setup" title="Permalink to this headline">¶</a></h1> +<p>The simplest way to achieve a functional setup is to follow the steps listed in <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repo</a>.</p> +</div> +<div class="section" id="virtual-machine-setup"> +<h1>Virtual Machine Setup<a class="headerlink" href="#virtual-machine-setup" title="Permalink to this headline">¶</a></h1> +<p>Practice work is designed to run on a QEMU based virtual machine. Kernel code +is developed and built on the host machine and then deployed and run on the +virtual machine.</p> +<p>In order to run and use the virtual machine the following packages are required +on a Debian/Ubuntu system:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">flex</span></code></li> +<li><code class="docutils literal"><span class="pre">bison</span></code></li> +<li><code class="docutils literal"><span class="pre">build-essential</span></code></li> +<li><code class="docutils literal"><span class="pre">gcc-multilib</span></code></li> +<li><code class="docutils literal"><span class="pre">libncurses5-dev</span></code></li> +<li><code class="docutils literal"><span class="pre">qemu-system-x86</span></code></li> +<li><code class="docutils literal"><span class="pre">qemu-system-arm</span></code></li> +<li><code class="docutils literal"><span class="pre">python3</span></code></li> +<li><code class="docutils literal"><span class="pre">minicom</span></code></li> +</ul> +<p>The <code class="docutils literal"><span class="pre">kvm</span></code> package is not strictly required, but will make the virtual machine +faster by using KVM support (with the <code class="docutils literal"><span class="pre">-enable-kvm</span></code> option to QEMU). If <code class="docutils literal"><span class="pre">kvm</span></code> +is absent, the virtual machine will still run (albeit slower) using emulation.</p> +<p>The virtual machine setup uses prebuild Yocto images that it downloads and a +kernel image that it builds itself. The following images are supported:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">core-image-minimal-qemu</span></code></li> +<li><code class="docutils literal"><span class="pre">core-image-minimal-dev-qemu</span></code></li> +<li><code class="docutils literal"><span class="pre">core-image-sato-dev-qemu</span></code></li> +<li><code class="docutils literal"><span class="pre">core-image-sato-qemu</span></code></li> +<li><code class="docutils literal"><span class="pre">core-image-sato-sdk-qemu</span></code></li> +</ul> +<p>By default, <code class="docutils literal"><span class="pre">core-image-minimal-qemu</span></code> it used. This setting can be changed by +updating the <code class="docutils literal"><span class="pre">YOCTO_IMAGE</span></code> variable in <code class="docutils literal"><span class="pre">tools/labs/qemu/Makefile</span></code>.</p> +<div class="section" id="starting-the-virtual-machine"> +<h2>Starting the Virtual Machine<a class="headerlink" href="#starting-the-virtual-machine" title="Permalink to this headline">¶</a></h2> +<p>You start the virtual machine in the <code class="docutils literal"><span class="pre">tools/labs/</span></code> folder by running <code class="docutils literal"><span class="pre">make</span> +<span class="pre">boot</span></code>:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>.../linux/tools/labs$ make boot +</pre></div> +</div> +<p>The first run of the <code class="docutils literal"><span class="pre">make</span> <span class="pre">boot</span></code> command will compile the kernel image and it +will take longer. Subsequent runs will only start the QEMU virtual machine, +with verbose output provided:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>.../linux/tools/labs$ make boot +mkdir /tmp/tmp.7rWv63E9Wf +sudo mount -t ext4 -o loop core-image-minimal-qemux86.ext4 /tmp/tmp.7rWv63E9Wf +sudo make -C /home/razvan/school/so2/linux.git modules_install <span class="nv">INSTALL_MOD_PATH</span><span class="o">=</span>/tmp/tmp.7rWv63E9Wf +make: Entering directory <span class="s1">'/home/razvan/school/so2/linux.git'</span> + INSTALL crypto/crypto_engine.ko + INSTALL drivers/crypto/virtio/virtio_crypto.ko + INSTALL drivers/net/netconsole.ko + DEPMOD <span class="m">4</span>.19.0+ +make: Leaving directory <span class="s1">'/home/razvan/school/so2/linux.git'</span> +sudo umount /tmp/tmp.7rWv63E9Wf +rmdir /tmp/tmp.7rWv63E9Wf +sleep <span class="m">1</span> <span class="o">&&</span> touch .modinst +qemu/create_net.sh tap0 + +dnsmasq: failed to create listening socket <span class="k">for</span> <span class="m">172</span>.213.0.1: Address already in use +qemu/create_net.sh tap1 + +dnsmasq: failed to create listening socket <span class="k">for</span> <span class="m">127</span>.0.0.1: Address already in use +/home/razvan/school/so2/linux.git/tools/labs/templates/assignments/6-e100/nttcp -v -i <span class="p">&</span> +nttcp-l: nttcp, version <span class="m">1</span>.47 +nttcp-l: running in inetd mode on port <span class="m">5037</span> - ignoring options beside -v and -p +bind: Address already in use +nttcp-l: service-socket: bind:: Address already in use, <span class="nv">errno</span><span class="o">=</span><span class="m">98</span> +<span class="nv">ARCH</span><span class="o">=</span>x86 qemu/qemu.sh -kernel /home/razvan/school/so2/linux.git/arch/x86/boot/bzImage -device virtio-serial -chardev pty,id<span class="o">=</span>virtiocon0 -device virtconsole,chardev<span class="o">=</span>virtiocon0 -serial pipe:pipe1 -serial pipe:pipe2 -netdev tap,id<span class="o">=</span>tap0,ifname<span class="o">=</span>tap0,script<span class="o">=</span>no,downscript<span class="o">=</span>no -net nic,netdev<span class="o">=</span>tap0,model<span class="o">=</span>virtio -netdev tap,id<span class="o">=</span>tap1,ifname<span class="o">=</span>tap1,script<span class="o">=</span>no,downscript<span class="o">=</span>no -net nic,netdev<span class="o">=</span>tap1,model<span class="o">=</span>i82559er -drive <span class="nv">file</span><span class="o">=</span>core-image-minimal-qemux86.ext4,if<span class="o">=</span>virtio,format<span class="o">=</span>raw -drive <span class="nv">file</span><span class="o">=</span>disk1.img,if<span class="o">=</span>virtio,format<span class="o">=</span>raw -drive <span class="nv">file</span><span class="o">=</span>disk2.img,if<span class="o">=</span>virtio,format<span class="o">=</span>raw --append <span class="s2">"root=/dev/vda loglevel=15 console=hvc0"</span> --display none -s +qemu-system-i386: -chardev pty,id<span class="o">=</span>virtiocon0: char device redirected to /dev/pts/68 <span class="o">(</span>label virtiocon0<span class="o">)</span> +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">To show the QEMU console use</p> +</div> +<div class="highlight-shell"><div class="highlight"><pre><span></span>.../linux/tools/labs$ <span class="nv">QEMU_DISPLAY</span><span class="o">=</span>gtk make boot + + This will show the VGA output and will also give + access to the standard keyboard. +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The virtual machine setup scripts and configuration files are located +in <code class="docutils literal"><span class="pre">tools/labs/qemu/</span></code>.</p> +</div> +</div> +<div class="section" id="connecting-to-the-virtual-machine"> +<span id="vm-interaction-link"></span><h2>Connecting to the Virtual Machine<a class="headerlink" href="#connecting-to-the-virtual-machine" title="Permalink to this headline">¶</a></h2> +<p>Once the virtual machine is started you can connect to it on the serial port. A +symbolic link named <code class="docutils literal"><span class="pre">serial.pts</span></code> is created to the emulated serial port +device:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>.../linux/tools/labs$ ls -l serial.pts +lrwxrwxrwx <span class="m">1</span> razvan razvan <span class="m">11</span> Apr <span class="m">1</span> <span class="m">08</span>:03 serial.pts -> /dev/pts/68 +</pre></div> +</div> +<p>On the host you use the <code class="docutils literal"><span class="pre">minicom</span></code> command to connect to the virtual machine +via the <code class="docutils literal"><span class="pre">serial.pts</span></code> link:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>.../linux/tools/labs$ minicom -D serial.pts +<span class="o">[</span>...<span class="o">]</span> +Poky <span class="o">(</span>Yocto Project Reference Distro<span class="o">)</span> <span class="m">2</span>.3 qemux86 /dev/hvc0 + +qemux86 login: root +root@qemux86:~# +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">When you connect to the virtual machine, simply enter <code class="docutils literal"><span class="pre">root</span></code> at the +login prompt and you will get a root console, no password required.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">You exit <code class="docutils literal"><span class="pre">minicom</span></code> by pressing <code class="docutils literal"><span class="pre">Ctrl+a</span></code> and then <code class="docutils literal"><span class="pre">x</span></code>. You will +get a confirmation prompt and then you will exit <code class="docutils literal"><span class="pre">minicom</span></code>.</p> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../labs/kernel_profiling.html" class="btn btn-neutral float-left" title="Kernel Profiling" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="extra-vm.html" class="btn btn-neutral float-right" title="Customizing the Virtual Machine Setup" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/labs/arm_kernel_development.html b/refs/pull/405/merge/labs/arm_kernel_development.html new file mode 100644 index 00000000..1d08441e --- /dev/null +++ b/refs/pull/405/merge/labs/arm_kernel_development.html @@ -0,0 +1,586 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Kernel Development on ARM — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Memory mapping" href="memory_mapping.html" /> + <link rel="prev" title="Networking" href="networking.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Networking</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Kernel Development on ARM</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="#system-on-a-chip">System on a Chip</a></li> +<li class="toctree-l2"><a class="reference internal" href="#board-support-package">Board Support package</a></li> +<li class="toctree-l2"><a class="reference internal" href="#toolchain">Toolchain</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#compiling-the-linux-kernel-on-arm">Compiling the Linux kernel on ARM</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#linux-kernel-image">Linux kernel image</a></li> +<li class="toctree-l2"><a class="reference internal" href="#rootfs">Rootfs</a></li> +<li class="toctree-l2"><a class="reference internal" href="#device-tree">Device tree</a></li> +<li class="toctree-l2"><a class="reference internal" href="#qemu">Qemu</a></li> +<li class="toctree-l2"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#intro">0. Intro</a></li> +<li class="toctree-l3"><a class="reference internal" href="#boot">1. Boot</a></li> +<li class="toctree-l3"><a class="reference internal" href="#cpu-information">2. CPU information</a></li> +<li class="toctree-l3"><a class="reference internal" href="#i-o-memory">3. I/O memory</a></li> +<li class="toctree-l3"><a class="reference internal" href="#hello-world">4. Hello World</a></li> +<li class="toctree-l3"><a class="reference internal" href="#simple-device">5. Simple device</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Kernel Development on ARM</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/labs/arm_kernel_development.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="kernel-development-on-arm"> +<h1>Kernel Development on ARM<a class="headerlink" href="#kernel-development-on-arm" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>get a feeling of what System on a Chip (SoC) means</li> +<li>get familiar with embedded world using ARM as a supported architecture</li> +<li>understand what a Board Support Package means (BSP)</li> +<li>compile and boot an ARM kernel with Qemu using i.MX6UL platform as an example</li> +<li>get familiar with hardware description using Device Trees</li> +</ul> +</div> +<div class="section" id="system-on-a-chip"> +<h2>System on a Chip<a class="headerlink" href="#system-on-a-chip" title="Permalink to this headline">¶</a></h2> +<p>A System on a Chip (<strong>SoC</strong>) is an integrated circuit (<strong>IC</strong>) that integrates an entire system onto it. The components +that can be usually found on an SoC include a central processing unit (<strong>CPU</strong>), memory, input/output ports, storage devices +together with more sophisticated modules like audio digital interfaces, neural processing units (<strong>NPU</strong>) or graphical +processing units (<strong>GPU</strong>).</p> +<dl class="docutils"> +<dt>SoCs can be used in various applications most common are:</dt> +<dd><ul class="first last simple"> +<li>consumer electronics (TV sets, mobile phones, video game consoles)</li> +<li>industrial computers (medical imaging, etc)</li> +<li>automotive</li> +<li>home appliances</li> +</ul> +</dd> +</dl> +<p>The leading architecture for SoCs is <strong>ARM</strong>. Worth mentioning here is that there are also x86-based SoCs platforms. Another thing +we need to keep an eye on is <strong>RISC-V</strong> an open standard instruction set architecture.</p> +<p>A simplified view of an <strong>ARM</strong> platform is shown in the image below:</p> +<img alt="../_images/schematic.png" class="align-center" src="../_images/schematic.png" /> +<p>We will refer as a reference platform at NXP's <a class="reference external" href="imx6ul">i.MX6UL</a> platform, but in general all SoC's contain the following building blocks:</p> +<blockquote> +<div><blockquote> +<div><ul class="simple"> +<li>one or more CPU cores</li> +<li>a system bus</li> +<li>clock and reset module<ul> +<li>PLL</li> +<li>OSC</li> +<li>reset controller</li> +</ul> +</li> +</ul> +</div></blockquote> +<ul class="simple"> +<li>interrupt controller</li> +<li>timers</li> +<li>memory controller</li> +<li>peripheral controllers<ul> +<li><a class="reference external" href="https://en.wikipedia.org/wiki/I%C2%B2C">I2C</a></li> +<li><a class="reference external" href="https://en.wikipedia.org/wiki/Serial_Peripheral_Interface">SPI</a></li> +<li><a class="reference external" href="https://en.wikipedia.org/wiki/General-purpose_input/output">GPIO</a></li> +<li><a class="reference external" href="https://en.wikipedia.org/wiki/Network_interface_controller">Ethernet</a> (for network)</li> +<li><a class="reference external" href="https://en.wikipedia.org/wiki/MultiMediaCard">uSDHC</a> (for storage)</li> +<li>USB</li> +<li><a class="reference external" href="https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter">UART</a></li> +<li><a class="reference external" href="https://en.wikipedia.org/wiki/I%C2%B2S">I2S</a> (for sound)</li> +<li>eLCDIF (for LCD Panel)</li> +</ul> +</li> +</ul> +</div></blockquote> +<p>Here is the complete block diagram for i.MX6UL platform:</p> +<a class="reference internal image-reference" href="https://www.nxp.com/assets/images/en/block-diagrams/IMX6UL-BD.jpg"><img alt="IMX6UL-BD" class="align-center" src="https://www.nxp.com/assets/images/en/block-diagrams/IMX6UL-BD.jpg" style="width: 60%;" /></a> +<p>i.MX6UL Evaluation Kit board looks like this:</p> +<a class="reference internal image-reference" href="https://www.compulab.com/wp-content/gallery/sbc-imx6ul/compulab_sbc-imx6ul_single-board-computer.jpg"><img alt="imx6ul-evk" class="align-center" src="https://www.compulab.com/wp-content/gallery/sbc-imx6ul/compulab_sbc-imx6ul_single-board-computer.jpg" style="width: 60%;" /></a> +<p>Other popular SoC boards:</p> +<blockquote> +<div><ul class="simple"> +<li><a class="reference external" href="https://en.wikipedia.org/wiki/Raspberry_Pi">Broadcom Raspberry Pi</a></li> +<li><a class="reference external" href="https://en.wikipedia.org/wiki/BeagleBoard">Texas Instruments Beagle board</a></li> +<li><a class="reference external" href="https://wiki.odroid.com/odroid-xu4/odroid-xu4">Odroid Xu4</a></li> +<li><a class="reference external" href="https://developer.nvidia.com/embedded/jetson-nano-developer-kit">Nvidia Jetson Nano</a></li> +</ul> +</div></blockquote> +</div> +<div class="section" id="board-support-package"> +<h2>Board Support package<a class="headerlink" href="#board-support-package" title="Permalink to this headline">¶</a></h2> +<p>A board support package (<strong>BSP</strong>) is the minimal set of software packages that allow to demonstrate the capabilities of a certain hardware platform. This includes:</p> +<blockquote> +<div><ul class="simple"> +<li>toolchain</li> +<li>bootloader</li> +<li>Linux kernel image, device tree files and drivers</li> +<li>root filesystem</li> +</ul> +</div></blockquote> +<p>Semiconductor manufacturers usually provide a <strong>BSP</strong> together with an evaluation board. BSP is typically bundled using <a class="reference external" href="https://www.yoctoproject.org/">Yocto</a></p> +</div> +<div class="section" id="toolchain"> +<h2>Toolchain<a class="headerlink" href="#toolchain" title="Permalink to this headline">¶</a></h2> +<p>Because our development machines are mostly x86-based we need a cross compiler that can produce executable +code for ARM platform.</p> +<p>We can build our own cross compiler from scratch using <a class="reference external" href="https://crosstool-ng.github.io/">https://crosstool-ng.github.io/</a> or we can install one</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf <span class="c1"># for arm32</span> +$ sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu <span class="c1"># for arm64</span> +</pre></div> +</div> +<p>There are several of toolchain binaries depending on the configuration:</p> +<blockquote> +<div><ul class="simple"> +<li>With "arm-eabi-gcc" you have the Linux system C library which will make calls into the kernel IOCTLs, e.g. for allocating memory pages to the process.</li> +<li>With "arm-eabi-none-gcc" you are running on platform which doesn't have an operating system at all - so the C library is different to cope with that.</li> +</ul> +</div></blockquote> +<div class="section" id="compiling-the-linux-kernel-on-arm"> +<h3>Compiling the Linux kernel on ARM<a class="headerlink" href="#compiling-the-linux-kernel-on-arm" title="Permalink to this headline">¶</a></h3> +<p>Compile the kernel for 32bit ARM boards:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># select defconfig based on your platform</span> +$ <span class="nv">ARCH</span><span class="o">=</span>arm <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabihf- make imx_v6_v7_defconfig +<span class="c1"># compile the kernel</span> +$ <span class="nv">ARCH</span><span class="o">=</span>arm <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabihf- make -j8 +</pre></div> +</div> +<p>Compile the kernel for 64bit ARM boards:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># for 64bit ARM there is a single config for all supported boards</span> +$ <span class="nv">ARCH</span><span class="o">=</span>arm <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabihf- make defconfig +<span class="c1"># compile the kernel</span> +$ <span class="nv">ARCH</span><span class="o">=</span>arm64 <span class="nv">CROSS_COMPILE</span><span class="o">=</span>aarch64-linux-gnu- make -j8 +</pre></div> +</div> +</div> +</div> +<div class="section" id="linux-kernel-image"> +<h2>Linux kernel image<a class="headerlink" href="#linux-kernel-image" title="Permalink to this headline">¶</a></h2> +<p>The kernel image binary is named <code class="docutils literal"><span class="pre">vmlinux</span></code> and it can be found in the root of the kernel tree. Compressed image used for booting can be found under:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">arch/arm/boot/Image</span></code>, for arm32</li> +<li><code class="docutils literal"><span class="pre">arch/arm64/boot/Image</span></code>, for arm64</li> +</ul> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ file vmlinux + vmlinux: ELF <span class="m">32</span>-bit LSB executable, ARM, EABI5 version <span class="m">1</span> <span class="o">(</span>SYSV<span class="o">)</span>, statically linked, not stripped + +$ file vmlinux + vmlinux: ELF <span class="m">64</span>-bit LSB shared object, ARM aarch64, version <span class="m">1</span> <span class="o">(</span>SYSV<span class="o">)</span>, statically linked, not stripped +</pre></div> +</div> +</div> +<div class="section" id="rootfs"> +<h2>Rootfs<a class="headerlink" href="#rootfs" title="Permalink to this headline">¶</a></h2> +<p>The root filesystem (<code class="docutils literal"><span class="pre">rootfs</span></code>) is the filesystem mounted at the top of files hierarchy (<code class="docutils literal"><span class="pre">/</span></code>). It should contain at least +the critical files allowing the system to boot to a shell.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>root@so2$ tree -d -L <span class="m">2</span> +├── bin +├── boot +├── dev +├── etc +├── home +│ └── root +├── lib +│ └── udev +├── mnt +├── proc +├── sbin +│ └── init +├── sys +├── usr +│ ├── bin +│ ├── include +│ ├── lib +└── var +</pre></div> +</div> +<p>As for <code class="docutils literal"><span class="pre">x86</span></code> we will make use of Yocto rootfs images. In order to download an <code class="docutils literal"><span class="pre">ext4</span></code> rootfs image for <code class="docutils literal"><span class="pre">arm32</span></code> one needs to run:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nb">cd</span> tools/labs/ +$ <span class="nv">ARCH</span><span class="o">=</span>arm make core-image-minimal-qemuarm.ext4 +</pre></div> +</div> +</div> +<div class="section" id="device-tree"> +<h2>Device tree<a class="headerlink" href="#device-tree" title="Permalink to this headline">¶</a></h2> +<p>Device tree (<strong>DT</strong>) is a tree structure used to describe the hardware devices in a system. Each node in the tree describes a device hence it is called <strong>device node</strong>. DT was introduced +to provide a way to discover non-discoverable hardware (e.g a device on an I2C bus). This information was previously stored inside the source code for the Linux kernel. This meant that +each time we needed to modify a node for a device the kernel needed to be recompiled. This no longer holds true as device tree and kernel image are separate binaries now.</p> +<p>Device trees are stored inside device tree sources (<em>.dts</em>) and compiled into device tree blobs (<em>.dtb</em>).</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># compile dtbs</span> +$ make dtbs + +<span class="c1"># location for DT sources on arm32</span> +$ ls arch/arm/boot/dts/ + imx6ul-14x14-evk.dtb imx6ull-14x14-evk.dtb bcm2835-rpi-a-plus.dts + +<span class="c1"># location for DT source on arm64</span> +$ ls arch/arm64/boot/dts/<vendor> + imx8mm-evk.dts imx8mp-evk.dts +</pre></div> +</div> +<p>The following image is a represantation of a simple device tree, describing board type, cpu and memory.</p> +<img alt="../_images/dts_node.png" class="align-center" src="../_images/dts_node.png" /> +<p>Notice that a device tree node can be defined using <code class="docutils literal"><span class="pre">label:</span> <span class="pre">name@address</span></code>:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">label</span></code>, is an identifier used to reference the node from other places</li> +<li><code class="docutils literal"><span class="pre">name</span></code>, node identifier</li> +<li><code class="docutils literal"><span class="pre">address</span></code>, used to differentiate nodes with the same name.</li> +</ul> +</div></blockquote> +<p>A node might contain several properties arranged in the <code class="docutils literal"><span class="pre">name</span> <span class="pre">=</span> <span class="pre">value</span></code> format. The name is a string +and the value can be bytes, strings, array of strings.</p> +<p>Here is an example:</p> +<div class="code c highlight-none"><div class="highlight"><pre><span></span>/ { + node@0 { + empty-property; + string-property = "string value"; + string-list-property = "string value 1", "string value 2"; + int-list-property = <value1 value2>; + + child-node@0 { + child-empty-property; + child-string-property = "string value"; + child-node-reference = <&child-node1>; + }; + + child-node1: child-node@1 { + child-empty-property; + child-string-property = "string value"; + }; + }; +}; +</pre></div> +</div> +</div> +<div class="section" id="qemu"> +<h2>Qemu<a class="headerlink" href="#qemu" title="Permalink to this headline">¶</a></h2> +<p>We will use <code class="docutils literal"><span class="pre">qemu-system-arm</span></code> to boot 32bit ARM platforms. Although, this can be installed from official distro repos, for example:</p> +<div class="code bash highlight-none"><div class="highlight"><pre><span></span>sudo apt-get install -y qemu-system-arm +</pre></div> +</div> +<p>We strongly recommend using latest version of <code class="docutils literal"><span class="pre">qemu-system-arm</span></code> build from sources:</p> +<div class="code bash highlight-none"><div class="highlight"><pre><span></span>$ git clone https://gitlab.com/qemu-project/qemu.git +$ ./configure --target-list=arm-softmmu --disable-docs +$ make -j8 +$ ./build/qemu-system-arm +</pre></div> +</div> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is arm_kernel_development. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/arm_kernel_development/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>The rules for working with the virtual machine for <code class="docutils literal"><span class="pre">ARM</span></code> are modified as follows</p> +<div class="last highlight-shell"><div class="highlight"><pre><span></span><span class="c1"># modules build</span> +tools/labs $ <span class="nv">ARCH</span><span class="o">=</span>arm <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabihf- make build +<span class="c1"># modules copy</span> +tools/labs $ <span class="nv">ARCH</span><span class="o">=</span>arm make copy +<span class="c1"># kernel build</span> +$ <span class="nv">ARCH</span><span class="o">=</span>arm <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabihf- make -j8 +</pre></div> +</div> +</div> +<div class="section" id="intro"> +<h3>0. Intro<a class="headerlink" href="#intro" title="Permalink to this headline">¶</a></h3> +<p>Inspect the following locations in the Linux kernel code and identify platforms and vendors using +ARM architecture:</p> +<blockquote> +<div><ul class="simple"> +<li>32-bit: <code class="docutils literal"><span class="pre">arch/arm/boot/dts</span></code></li> +<li>64-bit: <code class="docutils literal"><span class="pre">arch/arm64/boot/dts</span></code></li> +</ul> +</div></blockquote> +<p>Use <code class="docutils literal"><span class="pre">qemu</span></code> and look at the supported platforms:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>../qemu/build/arm-softmmu/qemu-system-arm -M ? +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">We used our own compiled version of <code class="docutils literal"><span class="pre">Qemu</span></code> for <code class="docutils literal"><span class="pre">arm32</span></code>. See <a class="reference internal" href="#qemu">Qemu</a> section for more details.</p> +</div> +</div> +<div class="section" id="boot"> +<h3>1. Boot<a class="headerlink" href="#boot" title="Permalink to this headline">¶</a></h3> +<p>Use <code class="docutils literal"><span class="pre">qemu</span></code> to boot <code class="docutils literal"><span class="pre">i.MX6UL</span></code> platform. In order to boot, we first need to compile the kernel. +Review <a class="reference internal" href="#compiling-the-linux-kernel-on-arm">Compiling the Linux kernel on ARM</a> section.</p> +<p>Successful compilation will result in the following binaries:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">arch/arm/boot/Image</span></code>, kernel image compiled for ARM</li> +<li><code class="docutils literal"><span class="pre">arch/arm/boot/dts/imx6ul-14x14-evk.dtb</span></code>, device tree blob for <code class="docutils literal"><span class="pre">i.MX6UL</span></code> board</li> +</ul> +</div></blockquote> +<p>Review <a class="reference internal" href="#rootfs">Rootfs</a> section and download <code class="docutils literal"><span class="pre">core-image-minimal-qemuarm.ext4</span></code> rootfs. +Run <code class="docutils literal"><span class="pre">qemu</span></code> using then following command:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>../qemu/build/arm-softmmu/qemu-system-arm -M mcimx6ul-evk -cpu cortex-a7 -m 512M <span class="se">\</span> + -kernel arch/arm/boot/zImage -nographic -dtb arch/arm/boot/dts/imx6ul-14x14-evk.dtb <span class="se">\</span> + -append <span class="s2">"root=/dev/mmcblk0 rw console=ttymxc0 loglevel=8 earlycon printk"</span> -sd tools/labs/core-image-minimal-qemuarm.ext4 +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">LCDIF and ASRC devices are not well supported with <code class="docutils literal"><span class="pre">Qemu</span></code>. Remove them from compilation.</p> +</div> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nv">ARCH</span><span class="o">=</span>arm <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabihf- make menuconfig +<span class="c1"># set FSL_ASRC=n and DRM_MXSFB=n</span> +$ <span class="nv">ARCH</span><span class="o">=</span>arm <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabihf- make -j8 +</pre></div> +</div> +<p>Once the kernel is booted check kernel version and cpu info:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ cat /proc/cpuinfo +$ cat /proc/version +</pre></div> +</div> +</div> +<div class="section" id="cpu-information"> +<h3>2. CPU information<a class="headerlink" href="#cpu-information" title="Permalink to this headline">¶</a></h3> +<p>Inspect the CPU configuration for <code class="docutils literal"><span class="pre">NXP</span> <span class="pre">i.MX6UL</span></code> board. Start with <code class="docutils literal"><span class="pre">arch/arm/boot/dts/imx6ul-14x14-evk.dts</span></code>.</p> +<blockquote> +<div><ul class="simple"> +<li>find <code class="docutils literal"><span class="pre">cpu@0</span></code> device tree node and look for <code class="docutils literal"><span class="pre">operating-points</span></code> property.</li> +<li>read the maximum and minimum operating frequency the processor can run</li> +</ul> +<blockquote> +<div><div class="code bash highlight-none"><div class="highlight"><pre><span></span>$ cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq +$ cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq +</pre></div> +</div> +</div></blockquote> +</div></blockquote> +</div> +<div class="section" id="i-o-memory"> +<h3>3. I/O memory<a class="headerlink" href="#i-o-memory" title="Permalink to this headline">¶</a></h3> +<p>Inspect I/O space configuration for <code class="docutils literal"><span class="pre">NXP</span> <span class="pre">i.MX6UL</span></code> board. Start with <code class="docutils literal"><span class="pre">arch/arm/boot/dts/imx6ul-14x14-evk.dts</span></code> and identify each device mentioned below.</p> +<div class="code bash highlight-none"><div class="highlight"><pre><span></span>$ cat /proc/iomem + 00900000-0091ffff : 900000.sram sram@900000 + 0209c000-0209ffff : 209c000.gpio gpio@209c000 + 021a0000-021a3fff : 21a0000.i2c i2c@21a0000 + 80000000-9fffffff : System RAM +</pre></div> +</div> +<p>Identify device tree nodes corresponding to:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">System</span> <span class="pre">RAM</span></code>, look for <code class="docutils literal"><span class="pre">memory@80000000</span></code> node in <code class="docutils literal"><span class="pre">arch/arm/boot/dts/imx6ul-14x14-evk.dtsi</span></code>. What's the size of the System RAM?</li> +<li><code class="docutils literal"><span class="pre">GPIO1</span></code>, look for <code class="docutils literal"><span class="pre">gpio@209c000</span></code> node in <code class="docutils literal"><span class="pre">arch/arm/boot/dts/imx6ul.dtsi</span></code>. What's the size of the I/O space for this device?</li> +<li><code class="docutils literal"><span class="pre">I2C1</span></code>, look for <code class="docutils literal"><span class="pre">i2c@21a0000</span></code> node in <code class="docutils literal"><span class="pre">arch/arm/boot/dts/imx6ul.dtsi</span></code>. What's the size of the I/O spaces for this device?</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="hello-world"> +<h3>4. Hello World<a class="headerlink" href="#hello-world" title="Permalink to this headline">¶</a></h3> +<p>Implement a simple kernel module that prints a message at load/unload time. Compile it and load it on <code class="docutils literal"><span class="pre">i.MX6UL</span></code> emulated platform.</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span><span class="c1"># modules build</span> +tools/labs $ <span class="nv">ARCH</span><span class="o">=</span>arm <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabihf- make build +<span class="c1"># modules copy</span> +tools/labs $ <span class="nv">ARCH</span><span class="o">=</span>arm make copy +<span class="c1"># kernel build</span> +$ <span class="nv">ARCH</span><span class="o">=</span>arm <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabihf- make -j8 +</pre></div> +</div> +</div> +<div class="section" id="simple-device"> +<h3>5. Simple device<a class="headerlink" href="#simple-device" title="Permalink to this headline">¶</a></h3> +<p>Implement a driver for a simple platform device. Find <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">1</span></code> and notice how <code class="docutils literal"><span class="pre">simple_driver</span></code> is declared and register as a platform driver. +Follow <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">2</span></code> and add the <code class="docutils literal"><span class="pre">so2,simple-device-v1</span></code> and <code class="docutils literal"><span class="pre">so2,simple-device-v2</span></code> compatible strings in the simple_device_ids array.</p> +<p>Create two device tree nodes in <code class="docutils literal"><span class="pre">arch/arm/boot/dts/imx6ul.dtsi</span></code> under <code class="docutils literal"><span class="pre">soc</span></code> node with compatible strings <code class="docutils literal"><span class="pre">so2,simple-device-v1</span></code> and +<code class="docutils literal"><span class="pre">so2,simple-device-v2</span></code> respectively. Then notice the behavior when loading <code class="docutils literal"><span class="pre">simple_driver</span></code> module.</p> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="networking.html" class="btn btn-neutral float-left" title="Networking" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="memory_mapping.html" class="btn btn-neutral float-right" title="Memory mapping" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/labs/block_device_drivers.html b/refs/pull/405/merge/labs/block_device_drivers.html new file mode 100644 index 00000000..98333214 --- /dev/null +++ b/refs/pull/405/merge/labs/block_device_drivers.html @@ -0,0 +1,1362 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Block Device Drivers — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="File system drivers (Part 1)" href="filesystems_part1.html" /> + <link rel="prev" title="Deferred work" href="deferred_work.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="deferred_work.html">Deferred work</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Block Device Drivers</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="#overview">Overview</a></li> +<li class="toctree-l2"><a class="reference internal" href="#register-a-block-i-o-device">Register a block I/O device</a></li> +<li class="toctree-l2"><a class="reference internal" href="#register-a-disk">Register a disk</a></li> +<li class="toctree-l2"><a class="reference internal" href="#struct-gendisk-structure"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> structure</a></li> +<li class="toctree-l2"><a class="reference internal" href="#struct-block-device-operations-structure"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">block_device_operations</span></code> structure</a></li> +<li class="toctree-l2"><a class="reference internal" href="#request-queues-multi-queue-block-layer">Request Queues - Multi-Queue Block Layer</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#software-staging-queues">Software staging queues</a></li> +<li class="toctree-l3"><a class="reference internal" href="#hardware-dispatch-queues">Hardware dispatch queues</a></li> +<li class="toctree-l3"><a class="reference internal" href="#tag-sets">Tag sets</a></li> +<li class="toctree-l3"><a class="reference internal" href="#create-and-delete-a-request-queue">Create and delete a request queue</a></li> +<li class="toctree-l3"><a class="reference internal" href="#useful-functions-for-processing-request-queues">Useful functions for processing request queues</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#requests-for-block-devices">Requests for block devices</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#create-a-request">Create a request</a></li> +<li class="toctree-l3"><a class="reference internal" href="#process-a-request">Process a request</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#struct-bio-structure"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#create-a-struct-bio-structure">Create a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="#submit-a-struct-bio-structure">Submit a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="#wait-for-the-completion-of-a-struct-bio-structure">Wait for the completion of a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="#initialize-a-struct-bio-structure">Initialize a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="#how-to-use-the-content-of-a-struct-bio-structure">How to use the content of a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="#free-a-struct-bio-structure">Free a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="#set-up-a-request-queue-at-struct-bio-level">Set up a request queue at <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> level</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#further-reading">Further reading</a></li> +<li class="toctree-l2"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#intro">0. Intro</a></li> +<li class="toctree-l3"><a class="reference internal" href="#block-device">1. Block device</a></li> +<li class="toctree-l3"><a class="reference internal" href="#disk-registration">2. Disk registration</a></li> +<li class="toctree-l3"><a class="reference internal" href="#ram-disk">3. RAM disk</a></li> +<li class="toctree-l3"><a class="reference internal" href="#read-data-from-the-disk">4. Read data from the disk</a></li> +<li class="toctree-l3"><a class="reference internal" href="#write-data-to-the-disk">5. Write data to the disk</a></li> +<li class="toctree-l3"><a class="reference internal" href="#processing-requests-from-the-request-queue-at-struct-bio-level">6. Processing requests from the request queue at <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> level</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Block Device Drivers</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/labs/block_device_drivers.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="block-device-drivers"> +<h1>Block Device Drivers<a class="headerlink" href="#block-device-drivers" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<blockquote> +<div><ul class="simple"> +<li>acquiring knowledge about the behavior of the I/O subsystem on Linux</li> +<li>hands-on activities in structures and functions of block devices</li> +<li>acquiring basic skills for utilizing the API for block devices, by solving +exercises</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="overview"> +<h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline">¶</a></h2> +<p>Block devices are characterized by random access to data organized in fixed-size +blocks. Examples of such devices are hard drives, CD-ROM drives, RAM disks, etc. +The speed of block devices is generally much higher than the speed of character +devices, and their performance is also important. This is why the Linux kernel +handles differently these 2 types of devices (it uses a specialized API).</p> +<p>Working with block devices is therefore more complicated than working with +character devices. Character devices have a single current position, while block +devices must be able to move to any position in the device to provide random +access to data. To simplify work with block devices, the Linux kernel provides +an entire subsystem called the block I/O (or block layer) subsystem.</p> +<p>From the kernel perspective, the smallest logical unit of addressing is the +block. Although the physical device can be addressed at sector level, the kernel +performs all disk operations using blocks. Since the smallest unit of physical +addressing is the sector, the size of the block must be a multiple of the size +of the sector. Additionally, the block size must be a power of 2 and can not +exceed the size of a page. The size of the block may vary depending on the file +system used, the most common values being 512 bytes, 1 kilobytes and 4 +kilobytes.</p> +</div> +<div class="section" id="register-a-block-i-o-device"> +<h2>Register a block I/O device<a class="headerlink" href="#register-a-block-i-o-device" title="Permalink to this headline">¶</a></h2> +<p>To register a block I/O device, function <code class="xref c c-func docutils literal"><span class="pre">register_blkdev()</span></code> is used. +To deregister a block I/O device, function <code class="xref c c-func docutils literal"><span class="pre">unregister_blkdev()</span></code> is +used.</p> +<p>Starting with version 4.9 of the Linux kernel, the call to +<code class="xref c c-func docutils literal"><span class="pre">register_blkdev()</span></code> is optional. The only operations performed by this +function are the dynamic allocation of a major (if the major argument is 0 when +calling the function) and creating an entry in <code class="file docutils literal"><span class="pre">/proc/devices</span></code>. In +future kernel versions it may be removed; however, most drivers still call it.</p> +<p>Usually, the call to the register function is performed in the module +initialization function, and the call to the deregister function is performed in +the module exit function. A typical scenario is presented below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> + +<span class="cp">#define MY_BLOCK_MAJOR 240</span> +<span class="cp">#define MY_BLKDEV_NAME "mybdev"</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_block_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">status</span><span class="p">;</span> + + <span class="n">status</span> <span class="o">=</span> <span class="n">register_blkdev</span><span class="p">(</span><span class="n">MY_BLOCK_MAJOR</span><span class="p">,</span> <span class="n">MY_BLKDEV_NAME</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">status</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="n">printk</span><span class="p">(</span><span class="n">KERN_ERR</span> <span class="s">"unable to register mybdev block device</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EBUSY</span><span class="p">;</span> + <span class="p">}</span> + <span class="c1">//...</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">my_block_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="c1">//...</span> + <span class="n">unregister_blkdev</span><span class="p">(</span><span class="n">MY_BLOCK_MAJOR</span><span class="p">,</span> <span class="n">MY_BLKDEV_NAME</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="register-a-disk"> +<h2>Register a disk<a class="headerlink" href="#register-a-disk" title="Permalink to this headline">¶</a></h2> +<p>Although the <code class="xref c c-func docutils literal"><span class="pre">register_blkdev()</span></code> function obtains a major, it does not +provide a device (disk) to the system. For creating and using block devices +(disks), a specialized interface defined in <code class="file docutils literal"><span class="pre">linux/genhd.h</span></code> is used.</p> +<p>The useful functions defined in <code class="file docutils literal"><span class="pre">linux/genhd.h</span></code> are to register /allocate +a disk, add it to the system, and de-register /unmount the disk.</p> +<p>The <code class="xref c c-func docutils literal"><span class="pre">alloc_disk()</span></code> function is used to allocate a disk, and the +<code class="xref c c-func docutils literal"><span class="pre">del_gendisk()</span></code> function is used to deallocate it. Adding the disk to the +system is done using the <code class="xref c c-func docutils literal"><span class="pre">add_disk()</span></code> function.</p> +<p>The <code class="xref c c-func docutils literal"><span class="pre">alloc_disk()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">add_disk()</span></code> functions are typically used in +the module initialization function, and the <code class="xref c c-func docutils literal"><span class="pre">del_gendisk()</span></code> function in +the module exit function.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/genhd.h></span><span class="cp"></span> + +<span class="cp">#define MY_BLOCK_MINORS 1</span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">my_block_dev</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">gendisk</span> <span class="o">*</span><span class="n">gd</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">}</span> <span class="n">dev</span><span class="p">;</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">create_block_device</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_block_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">dev</span><span class="o">-></span><span class="n">gd</span> <span class="o">=</span> <span class="n">alloc_disk</span><span class="p">(</span><span class="n">MY_BLOCK_MINORS</span><span class="p">);</span> + <span class="c1">//...</span> + <span class="n">add_disk</span><span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_block_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="c1">//...</span> + <span class="n">create_block_device</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">delete_block_device</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_block_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="p">)</span> + <span class="n">del_gendisk</span><span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="p">);</span> + <span class="c1">//...</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">my_block_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">delete_block_device</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="p">);</span> + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>As with character devices, it is recommended to use <code class="xref c c-type docutils literal"><span class="pre">my_block_dev</span></code> +structure to store important elements describing the block device.</p> +<p>Note that immediately after calling the <code class="xref c c-func docutils literal"><span class="pre">add_disk()</span></code> function (actually +even during the call), the disk is active and its methods can be called at any +time. As a result, this function should not be called before the driver is fully +initialized and ready to respond to requests for the registered disk.</p> +<p>It can be noticed that the basic structure in working with block devices (disks) +is the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> structure.</p> +<p>After a call to <code class="xref c c-func docutils literal"><span class="pre">del_gendisk()</span></code>, the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> structure +may continue to exist (and the device operations may still be called) if there +are still users (an open operation was called on the device but the associated +release operation has not been called). One solution is to keep the number of +users of the device and call the <code class="xref c c-func docutils literal"><span class="pre">del_gendisk()</span></code> function only when there +are no users left of the device.</p> +</div> +<div class="section" id="struct-gendisk-structure"> +<h2><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> structure<a class="headerlink" href="#struct-gendisk-structure" title="Permalink to this headline">¶</a></h2> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> structure stores information about a disk. As +stated above, such a structure is obtained from the <code class="xref c c-func docutils literal"><span class="pre">alloc_disk()</span></code> call +and its fields must be filled before it is sent to the <code class="xref c c-func docutils literal"><span class="pre">add_disk()</span></code> +function.</p> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> structure has the following important fields:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-member docutils literal"><span class="pre">major</span></code>, <code class="xref c c-member docutils literal"><span class="pre">first_minor</span></code>, <code class="xref c c-member docutils literal"><span class="pre">minor</span></code>, describing +the identifiers used by the disk; a disk must have at least one minor; if +the disk allows the partitioning operation, a minor must be allocated for +each possible partition</li> +<li><code class="xref c c-member docutils literal"><span class="pre">disk_name</span></code>, which represents the disk name as it appears in +<code class="file docutils literal"><span class="pre">/proc/partitions</span></code> and in sysfs (<code class="file docutils literal"><span class="pre">/sys/block</span></code>)</li> +<li><code class="xref c c-member docutils literal"><span class="pre">fops</span></code>, representing operations associated with the disk</li> +<li><code class="xref c c-member docutils literal"><span class="pre">queue</span></code>, which represents the queue of requests</li> +<li><code class="xref c c-member docutils literal"><span class="pre">capacity</span></code>, which is disk capacity in 512 byte sectors; +it is initialized using the <code class="xref c c-func docutils literal"><span class="pre">set_capacity()</span></code> function</li> +<li><code class="xref c c-member docutils literal"><span class="pre">private_data</span></code>, which is a pointer to private data</li> +</ul> +</div></blockquote> +<p>An example of filling a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> structure is presented below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/genhd.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/blkdev.h></span><span class="cp"></span> + +<span class="cp">#define NR_SECTORS 1024</span> + +<span class="cp">#define KERNEL_SECTOR_SIZE 512</span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">my_block_dev</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="n">spinlock_t</span> <span class="n">lock</span><span class="p">;</span> <span class="cm">/* For mutual exclusion */</span> + <span class="k">struct</span> <span class="n">request_queue</span> <span class="o">*</span><span class="n">queue</span><span class="p">;</span> <span class="cm">/* The device request queue */</span> + <span class="k">struct</span> <span class="n">gendisk</span> <span class="o">*</span><span class="n">gd</span><span class="p">;</span> <span class="cm">/* The gendisk structure */</span> + <span class="c1">//...</span> +<span class="p">}</span> <span class="n">dev</span><span class="p">;</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">create_block_device</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_block_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span> +<span class="p">{</span> + <span class="p">...</span> + <span class="cm">/* Initialize the gendisk structure */</span> + <span class="n">dev</span><span class="o">-></span><span class="n">gd</span> <span class="o">=</span> <span class="n">alloc_disk</span><span class="p">(</span><span class="n">MY_BLOCK_MINORS</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="p">)</span> <span class="p">{</span> + <span class="n">printk</span> <span class="p">(</span><span class="n">KERN_NOTICE</span> <span class="s">"alloc_disk failure</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="k">return</span> <span class="o">-</span><span class="n">ENOMEM</span><span class="p">;</span> + <span class="p">}</span> + + <span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="o">-></span><span class="n">major</span> <span class="o">=</span> <span class="n">MY_BLOCK_MAJOR</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="o">-></span><span class="n">first_minor</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="o">-></span><span class="n">fops</span> <span class="o">=</span> <span class="o">&</span><span class="n">my_block_ops</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="o">-></span><span class="n">queue</span> <span class="o">=</span> <span class="n">dev</span><span class="o">-></span><span class="n">queue</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="o">-></span><span class="n">private_data</span> <span class="o">=</span> <span class="n">dev</span><span class="p">;</span> + <span class="n">snprintf</span> <span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="o">-></span><span class="n">disk_name</span><span class="p">,</span> <span class="mi">32</span><span class="p">,</span> <span class="s">"myblock"</span><span class="p">);</span> + <span class="n">set_capacity</span><span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="p">,</span> <span class="n">NR_SECTORS</span><span class="p">);</span> + + <span class="n">add_disk</span><span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_block_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">status</span><span class="p">;</span> + <span class="c1">//...</span> + <span class="n">status</span> <span class="o">=</span> <span class="n">create_block_device</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">status</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">return</span> <span class="n">status</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">delete_block_device</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_block_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="p">)</span> <span class="p">{</span> + <span class="n">del_gendisk</span><span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="p">);</span> + <span class="p">}</span> + <span class="c1">//...</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">my_block_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">delete_block_device</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="p">);</span> + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>As stated before, the kernel considers a disk as a vector of 512 byte sectors. +In reality, the devices may have a different size of the sector. To work with +these devices, the kernel needs to be informed about the real size of a sector, +and for all operations the necessary conversions must be made.</p> +<p>To inform the kernel about the device sector size, a parameter of the request +queue must be set just after the request queue is allocated, using the +<code class="xref c c-func docutils literal"><span class="pre">blk_queue_logical_block_size()</span></code> function. All requests generated by the +kernel will be multiple of this sector size and will be aligned accordingly. +However, communication between the device and the driver will still be performed +in sectors of 512 bytes in size, so conversion should be done each time (an +example of such conversion is when calling the <code class="xref c c-func docutils literal"><span class="pre">set_capacity()</span></code> function +in the code above).</p> +</div> +<div class="section" id="struct-block-device-operations-structure"> +<h2><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">block_device_operations</span></code> structure<a class="headerlink" href="#struct-block-device-operations-structure" title="Permalink to this headline">¶</a></h2> +<p>Just as for a character device, operations in <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code> +should be completed, so for a block device, the operations in +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">block_device_operations</span></code> should be completed. The association +of operations is done through the <code class="xref c c-member docutils literal"><span class="pre">fops</span></code> field in the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> +structure.</p> +<p>Some of the fields of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">block_device_operations</span></code> structure +are presented below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">block_device_operations</span> <span class="p">{</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">open</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">block_device</span> <span class="o">*</span><span class="p">,</span> <span class="n">fmode_t</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">release</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">gendisk</span> <span class="o">*</span><span class="p">,</span> <span class="n">fmode_t</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">locked_ioctl</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">block_device</span> <span class="o">*</span><span class="p">,</span> <span class="n">fmode_t</span><span class="p">,</span> <span class="kt">unsigned</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">ioctl</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">block_device</span> <span class="o">*</span><span class="p">,</span> <span class="n">fmode_t</span><span class="p">,</span> <span class="kt">unsigned</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">compat_ioctl</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">block_device</span> <span class="o">*</span><span class="p">,</span> <span class="n">fmode_t</span><span class="p">,</span> <span class="kt">unsigned</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">direct_access</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">block_device</span> <span class="o">*</span><span class="p">,</span> <span class="n">sector_t</span><span class="p">,</span> + <span class="kt">void</span> <span class="o">**</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">media_changed</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">gendisk</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">revalidate_disk</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">gendisk</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">getgeo</span><span class="p">)(</span><span class="k">struct</span> <span class="n">block_device</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">hd_geometry</span> <span class="o">*</span><span class="p">);</span> + <span class="n">blk_qc_t</span> <span class="p">(</span><span class="o">*</span><span class="n">submit_bio</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">bio</span> <span class="o">*</span><span class="n">bio</span><span class="p">);</span> + <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">owner</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p><code class="xref c c-func docutils literal"><span class="pre">open()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">release()</span></code> operations are called directly from user +space by utilities that may perform the following tasks: partitioning, file +system creation, file system verification. In a <code class="xref c c-func docutils literal"><span class="pre">mount()</span></code> operation, the +<code class="xref c c-func docutils literal"><span class="pre">open()</span></code> function is called directly from the kernel space, the file +descriptor being stored by the kernel. A driver for a block device can not +differentiate between <code class="xref c c-func docutils literal"><span class="pre">open()</span></code> calls performed from user space and kernel +space.</p> +<p>An example of how to use these two functions is given below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/genhd.h></span><span class="cp"></span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">my_block_dev</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">gendisk</span> <span class="o">*</span> <span class="n">gd</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">}</span> <span class="n">dev</span><span class="p">;</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_block_open</span><span class="p">(</span><span class="k">struct</span> <span class="n">block_device</span> <span class="o">*</span><span class="n">bdev</span><span class="p">,</span> <span class="n">fmode_t</span> <span class="n">mode</span><span class="p">)</span> +<span class="p">{</span> + <span class="c1">//...</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_block_release</span><span class="p">(</span><span class="k">struct</span> <span class="n">gendisk</span> <span class="o">*</span><span class="n">gd</span><span class="p">,</span> <span class="n">fmode_t</span> <span class="n">mode</span><span class="p">)</span> +<span class="p">{</span> + <span class="c1">//...</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">struct</span> <span class="n">block_device_operations</span> <span class="n">my_block_ops</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">owner</span> <span class="o">=</span> <span class="n">THIS_MODULE</span><span class="p">,</span> + <span class="p">.</span><span class="n">open</span> <span class="o">=</span> <span class="n">my_block_open</span><span class="p">,</span> + <span class="p">.</span><span class="n">release</span> <span class="o">=</span> <span class="n">my_block_release</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">create_block_device</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_block_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span> +<span class="p">{</span> + <span class="c1">//....</span> + <span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="o">-></span><span class="n">fops</span> <span class="o">=</span> <span class="o">&</span><span class="n">my_block_ops</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="o">-></span><span class="n">private_data</span> <span class="o">=</span> <span class="n">dev</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Please notice that there are no read or write operations. These operations are +performed by the <code class="xref c c-func docutils literal"><span class="pre">request()</span></code> function associated with the request queue +of the disk.</p> +</div> +<div class="section" id="request-queues-multi-queue-block-layer"> +<h2>Request Queues - Multi-Queue Block Layer<a class="headerlink" href="#request-queues-multi-queue-block-layer" title="Permalink to this headline">¶</a></h2> +<p>Drivers for block devices use queues to store the block I/O requests that will +be processed. A request queue is represented by the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request_queue</span></code> structure. The request queue is made up of a +double-linked list of requests and their associated control information. The +requests are added to the queue by higher-level kernel code (for example, file +systems).</p> +<p>The block device driver associates each queue with a handling function, which +will be called for each request in the queue +(the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code> structure).</p> +<p>In earlier version of the Linux kernel, each device driver had associated one or +more request queues (<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request_queue</span></code>), where any client could add +requests, while also being able to reorder them. +The problem with this approach is that it requires a per-queue lock, making it +inefficient in distributed systems.</p> +<p>The <a class="reference external" href="https://www.kernel.org/doc/html/latest/block/blk-mq.html">Multi-Queue Block Queing Mechanism</a> +solves this issue by splitting the device driver queue in two parts:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Software staging queues</li> +<li>Hardware dispatch queues</li> +</ol> +</div></blockquote> +<div class="section" id="software-staging-queues"> +<h3>Software staging queues<a class="headerlink" href="#software-staging-queues" title="Permalink to this headline">¶</a></h3> +<p>The staging queues hold requests from the clients before sending them to the +block device driver. To prevent the waiting for a per-queue lock, a staging +queue is allocated for each CPU or node. A software queue is associated to +only one hardware queue.</p> +<p>While in this queue, the requests can be merged or reordered, according to an +I/O Scheduler, in order to maximize performance. This means that only the +requests coming from the same CPU or node can be optimized.</p> +<p>Staging queues are usually not used by the block device drivers, but only +internally by the I/O subsystem to optimize requests before sending them to the +device drivers.</p> +</div> +<div class="section" id="hardware-dispatch-queues"> +<h3>Hardware dispatch queues<a class="headerlink" href="#hardware-dispatch-queues" title="Permalink to this headline">¶</a></h3> +<p>The hardware queues (<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">blk_mq_hw_ctx</span></code>) are used to send the +requests from the staging queues to the block device driver. +Once in this queue, the requests can't be merged or reordered.</p> +<p>Depending on the underlying hardware, a block device driver can create multiple +hardware queues in order to improve parallelism and maximize performance.</p> +</div> +<div class="section" id="tag-sets"> +<h3>Tag sets<a class="headerlink" href="#tag-sets" title="Permalink to this headline">¶</a></h3> +<p>A block device driver can accept a request before the previous one is completed. +As a consequence, the upper layers need a way to know when a request is +completed. For this, a "tag" is added to each request upon submission and sent +back using a completion notification after the request is completed.</p> +<p>The tags are part of a tag set (<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">blk_mq_tag_set</span></code>), which is +unique to a device. +The tag set structure is allocated and initialized before the request queues +and also stores some of the queues properties.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">blk_mq_tag_set</span> <span class="p">{</span> + <span class="p">...</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">blk_mq_ops</span> <span class="o">*</span><span class="n">ops</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">nr_hw_queues</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">queue_depth</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">cmd_size</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">numa_node</span><span class="p">;</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">driver_data</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">blk_mq_tags</span> <span class="o">**</span><span class="n">tags</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="n">tag_list</span><span class="p">;</span> + <span class="p">...</span> +<span class="p">};</span> +</pre></div> +</div> +<p>Some of the fields in <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">blk_mq_tag_set</span></code> are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">ops</span></code> - Queue operations, most notably the request handling function.</li> +<li><code class="docutils literal"><span class="pre">nr_hw_queues</span></code> - The number of hardware queues allocated for the device</li> +<li><code class="docutils literal"><span class="pre">queue_depth</span></code> - Hardware queues size</li> +<li><code class="docutils literal"><span class="pre">cmd_size</span></code> - Number of extra bytes allocated at the end of the device, to +be used by the block device driver, if needed.</li> +<li><code class="docutils literal"><span class="pre">numa_node</span></code> - In NUMA systems, the index of the node the storage device is +connected to.</li> +<li><code class="docutils literal"><span class="pre">driver_data</span></code> - Data private to the driver, if needed.</li> +<li><code class="docutils literal"><span class="pre">tags</span></code> - Pointer to an array of <code class="docutils literal"><span class="pre">nr_hw_queues</span></code> tag sets.</li> +<li><code class="docutils literal"><span class="pre">tag_list</span></code> - List of request queues using this tag set.</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="create-and-delete-a-request-queue"> +<h3>Create and delete a request queue<a class="headerlink" href="#create-and-delete-a-request-queue" title="Permalink to this headline">¶</a></h3> +<p>Request queues are created using the <code class="xref c c-func docutils literal"><span class="pre">blk_mq_init_queue()</span></code> function and +are deleted using <code class="xref c c-func docutils literal"><span class="pre">blk_cleanup_queue()</span></code>. The first function creates both +the hardware and the software queues and initializes their structures.</p> +<p>Queue properties, including the number of hardware queues, their capacity and +request handling function are configured using the <code class="xref c c-type docutils literal"><span class="pre">blk_mq_tag_set</span></code> +structure, as described above.</p> +<p>An example of using these functions is as follows:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/genhd.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/blkdev.h></span><span class="cp"></span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">my_block_dev</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">blk_mq_tag_set</span> <span class="n">tag_set</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">request_queue</span> <span class="o">*</span><span class="n">queue</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">}</span> <span class="n">dev</span><span class="p">;</span> + +<span class="k">static</span> <span class="n">blk_status_t</span> <span class="nf">my_block_request</span><span class="p">(</span><span class="k">struct</span> <span class="n">blk_mq_hw_ctx</span> <span class="o">*</span><span class="n">hctx</span><span class="p">,</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">blk_mq_queue_data</span> <span class="o">*</span><span class="n">bd</span><span class="p">)</span> +<span class="c1">//...</span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">blk_mq_ops</span> <span class="n">my_queue_ops</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">queue_rq</span> <span class="o">=</span> <span class="n">my_block_request</span><span class="p">,</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">create_block_device</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_block_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span> +<span class="p">{</span> + <span class="cm">/* Initialize tag set. */</span> + <span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">.</span><span class="n">ops</span> <span class="o">=</span> <span class="o">&</span><span class="n">my_queue_ops</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">.</span><span class="n">nr_hw_queues</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">.</span><span class="n">queue_depth</span> <span class="o">=</span> <span class="mi">128</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">.</span><span class="n">numa_node</span> <span class="o">=</span> <span class="n">NUMA_NO_NODE</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">.</span><span class="n">cmd_size</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">.</span><span class="n">flags</span> <span class="o">=</span> <span class="n">BLK_MQ_F_SHOULD_MERGE</span><span class="p">;</span> + <span class="n">err</span> <span class="o">=</span> <span class="n">blk_mq_alloc_tag_set</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span><span class="p">)</span> <span class="p">{</span> + <span class="k">goto</span> <span class="n">out_err</span><span class="p">;</span> + <span class="p">}</span> + + <span class="cm">/* Allocate queue. */</span> + <span class="n">dev</span><span class="o">-></span><span class="n">queue</span> <span class="o">=</span> <span class="n">blk_mq_init_queue</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">IS_ERR</span><span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">queue</span><span class="p">))</span> <span class="p">{</span> + <span class="k">goto</span> <span class="n">out_blk_init</span><span class="p">;</span> + <span class="p">}</span> + + <span class="n">blk_queue_logical_block_size</span><span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">queue</span><span class="p">,</span> <span class="n">KERNEL_SECTOR_SIZE</span><span class="p">);</span> + + <span class="cm">/* Assign private data to queue structure. */</span> + <span class="n">dev</span><span class="o">-></span><span class="n">queue</span><span class="o">-></span><span class="n">queuedata</span> <span class="o">=</span> <span class="n">dev</span><span class="p">;</span> + <span class="c1">//...</span> + +<span class="nl">out_blk_init</span><span class="p">:</span> + <span class="n">blk_mq_free_tag_set</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">);</span> +<span class="nl">out_err</span><span class="p">:</span> + <span class="k">return</span> <span class="o">-</span><span class="n">ENOMEM</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_block_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">status</span><span class="p">;</span> + <span class="c1">//...</span> + <span class="n">status</span> <span class="o">=</span> <span class="n">create_block_device</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">status</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">return</span> <span class="n">status</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">delete_block_device</span><span class="p">(</span><span class="k">struct</span> <span class="n">block_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span> +<span class="p">{</span> + <span class="c1">//...</span> + <span class="n">blk_cleanup_queue</span><span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">queue</span><span class="p">);</span> + <span class="n">blk_mq_free_tag_set</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">my_block_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">delete_block_device</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="p">);</span> + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>After initializing the tag set structure, the tag lists are allocated using the +<code class="xref c c-func docutils literal"><span class="pre">blk_mq_alloc_tag_set()</span></code> function. +The pointer to the function which will process the requests +(<code class="xref c c-func docutils literal"><span class="pre">my_block_request()</span></code>) is filled in the <code class="docutils literal"><span class="pre">my_queue_ops</span></code> structure and +then the pointer to this structure is added to the tag set.</p> +<p>The queue is created using the <code class="xref c c-func docutils literal"><span class="pre">blk_mq_init_queue()</span></code> function, based on +the information added in the tag set.</p> +<p>As part of the request queue initialization, you can configure the +<code class="xref c c-member docutils literal"><span class="pre">queuedata</span></code> field, which is equivalent to the <code class="xref c c-member docutils literal"><span class="pre">private_data</span></code> +field in other structures.</p> +</div> +<div class="section" id="useful-functions-for-processing-request-queues"> +<h3>Useful functions for processing request queues<a class="headerlink" href="#useful-functions-for-processing-request-queues" title="Permalink to this headline">¶</a></h3> +<p>The <code class="docutils literal"><span class="pre">queue_rq</span></code> function from <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">blk_mq_ops</span></code> is used to handle +requests for working with the block device. +This function is the equivalent of read and write functions encountered on +character devices. The function receives the requests for the device as +arguments and can use various functions for processing them.</p> +<p>The functions used to process the requests in the handler are described below:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">blk_mq_start_request()</span></code> - must be called before starting processing +a request;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">blk_mq_requeue_request()</span></code> - to re-send the request in the queue;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">blk_mq_end_request()</span></code> - to end request processing and notify the +upper layers.</li> +</ul> +</div></blockquote> +</div> +</div> +<div class="section" id="requests-for-block-devices"> +<h2>Requests for block devices<a class="headerlink" href="#requests-for-block-devices" title="Permalink to this headline">¶</a></h2> +<p>A request for a block device is described by <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code> +structure.</p> +<p>The fields of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code> structure include:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-member docutils literal"><span class="pre">cmd_flags</span></code>: a series of flags including direction (reading or +writing); to find out the direction, the macrodefinition +<code class="xref c c-macro docutils literal"><span class="pre">rq_data_dir</span></code> is used, which returns 0 for a read request and 1 +for a write request on the device;</li> +<li><code class="xref c c-member docutils literal"><span class="pre">__sector</span></code>: the first sector of the transfer request; if the +device sector has a different size, the appropriate conversion should be +done. To access this field, use the <code class="xref c c-macro docutils literal"><span class="pre">blk_rq_pos</span></code> macro;</li> +<li><code class="xref c c-member docutils literal"><span class="pre">__data_len</span></code>: the total number of bytes to be transferred; to +access this field the <code class="xref c c-macro docutils literal"><span class="pre">blk_rq_bytes</span></code> macro is used;</li> +<li>generally, data from the current <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> will be +transferred; the data size is obtained using the +<code class="xref c c-macro docutils literal"><span class="pre">blk_rq_cur_bytes</span></code> macro;</li> +<li><code class="xref c c-member docutils literal"><span class="pre">bio</span></code>, a dynamic list of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structures that +is a set of buffers associated to the request; this field is accessed by +macrodefinition <code class="xref c c-macro docutils literal"><span class="pre">rq_for_each_segment</span></code> if there are multiple +buffers, or by <code class="xref c c-macro docutils literal"><span class="pre">bio_data</span></code> macrodefinition in case there is only +one associated buffer;</li> +</ul> +</div></blockquote> +<p>We will discuss more about the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure and its +associated operations in the <span class="xref std std-ref">bio_structure</span> section.</p> +<div class="section" id="create-a-request"> +<h3>Create a request<a class="headerlink" href="#create-a-request" title="Permalink to this headline">¶</a></h3> +<p>Read /write requests are created by code layers superior to the kernel I/O +subsystem. Typically, the subsystem that creates requests for block devices is +the file management subsystem. The I/O subsystem acts as an interface between +the file management subsystem and the block device driver. The main operations +under the responsibility of the I/O subsystem are adding requests to the queue +of the specific block device and sorting and merging requests according to +performance considerations.</p> +</div> +<div class="section" id="process-a-request"> +<h3>Process a request<a class="headerlink" href="#process-a-request" title="Permalink to this headline">¶</a></h3> +<p>The central part of a block device driver is the request handling function +(<code class="docutils literal"><span class="pre">queue_rq</span></code>). In previous examples, the function that fulfilled this role was +<code class="xref c c-func docutils literal"><span class="pre">my_block_request()</span></code>. As stated in the +<a class="reference internal" href="#create-and-delete-a-request-queue">Create and delete a request queue</a> section, this function is associated to the +driver when creating the tag set structure.</p> +<p>This function is called when the kernel considers that the driver should process +I/O requests. The function must start processing the requests from the queue, +but it is not mandatory to finish them, as requests may be finished by other +parts of the driver.</p> +<p>The request function runs in an atomic context and must follow the rules for +atomic code (it does not need to call functions that can cause sleep, etc.).</p> +<p>Calling the function that processes the requests is asynchronous relative +to the actions of any userspace process and no assumptions about the process +in which the respective function is running should be made. Also, it should not +be assumed that the buffer provided by a request is from kernel space or user +space, any operation that accesses the userspace being erroneous.</p> +<p>One of the simplest request handling function is presented below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">blk_status_t</span> <span class="nf">my_block_request</span><span class="p">(</span><span class="k">struct</span> <span class="n">blk_mq_hw_ctx</span> <span class="o">*</span><span class="n">hctx</span><span class="p">,</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">blk_mq_queue_data</span> <span class="o">*</span><span class="n">bd</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">request</span> <span class="o">*</span><span class="n">rq</span> <span class="o">=</span> <span class="n">bd</span><span class="o">-></span><span class="n">rq</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">my_block_dev</span> <span class="o">*</span><span class="n">dev</span> <span class="o">=</span> <span class="n">q</span><span class="o">-></span><span class="n">queuedata</span><span class="p">;</span> + + <span class="n">blk_mq_start_request</span><span class="p">(</span><span class="n">rq</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">blk_rq_is_passthrough</span><span class="p">(</span><span class="n">rq</span><span class="p">))</span> <span class="p">{</span> + <span class="n">printk</span> <span class="p">(</span><span class="n">KERN_NOTICE</span> <span class="s">"Skip non-fs request</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="n">blk_mq_end_request</span><span class="p">(</span><span class="n">rq</span><span class="p">,</span> <span class="n">BLK_STS_IOERR</span><span class="p">);</span> + <span class="k">goto</span> <span class="n">out</span><span class="p">;</span> + <span class="p">}</span> + + <span class="cm">/* do work */</span> + <span class="p">...</span> + + <span class="n">blk_mq_end_request</span><span class="p">(</span><span class="n">rq</span><span class="p">,</span> <span class="n">BLK_STS_OK</span><span class="p">);</span> + +<span class="nl">out</span><span class="p">:</span> + <span class="k">return</span> <span class="n">BLK_STS_OK</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The <code class="xref c c-func docutils literal"><span class="pre">my_block_request()</span></code> function performs the following operations:</p> +<blockquote> +<div><ul class="simple"> +<li>Get a pointer to the request structure from the <code class="docutils literal"><span class="pre">bd</span></code> argument and start +its processing using the <code class="xref c c-func docutils literal"><span class="pre">blk_mq_start_request()</span></code> function.</li> +<li>A block device can receive calls which do not transfer data blocks (e.g. +low level operations on the disk, instructions referring to special ways of +accessing the device). Most drivers do not know how to handle these +requests and return an error.</li> +<li>To return an error, <code class="xref c c-func docutils literal"><span class="pre">blk_mq_end_request()</span></code> function is called, +<code class="docutils literal"><span class="pre">BLK_STS_IOERR</span></code> being the second argument.</li> +<li>The request is processed according to the needs of the associated device.</li> +<li>The request ends. In this case, <code class="xref c c-func docutils literal"><span class="pre">blk_mq_end_request()</span></code> function is +called in order to complete the request.</li> +</ul> +</div></blockquote> +</div> +</div> +<div class="section" id="struct-bio-structure"> +<h2><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure<a class="headerlink" href="#struct-bio-structure" title="Permalink to this headline">¶</a></h2> +<p>Each <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code> structure is an I/O block request, but may come +from combining more independent requests from a higher level. The sectors to be +transferred for a request can be scattered into the main memory but they always +correspond to a set of consecutive sectors on the device. The request is +represented as a series of segments, each corresponding to a buffer in memory. +The kernel can combine requests that refer to adjacent sectors but will not +combine write requests with read requests into a single +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code> structure.</p> +<p>A <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code> structure is implemented as a linked list of +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structures together with information that allows the +driver to retain its current position while processing the request.</p> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure is a low-level description of a portion of +a block I/O request.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">bio</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">gendisk</span> <span class="o">*</span><span class="n">bi_disk</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">bi_opf</span><span class="p">;</span> <span class="cm">/* bottom bits req flags, top bits REQ_OP. Use accessors. */</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">bio_vec</span> <span class="o">*</span><span class="n">bi_io_vec</span><span class="p">;</span> <span class="cm">/* the actual vec list */</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">bvec_iter</span> <span class="n">bi_iter</span><span class="p">;</span> + <span class="o">/</span><span class="p">...</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">bi_private</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">};</span> +</pre></div> +</div> +<p>In turn, the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure contains a <code class="xref c c-member docutils literal"><span class="pre">bi_io_vec</span></code> +vector of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio_vec</span></code> structures. It consists of the individual +pages in the physical memory to be transferred, the offset within the page and +the size of the buffer. To iterate through a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure, +we need to iterate through the vector of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio_vec</span></code> and transfer +the data from every physical page. To simplify vector iteration, the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bvec_iter</span></code> structure is used. This structure maintains +information about how many buffers and sectors were consumed during the +iteration. The request type is encoded in the <code class="xref c c-member docutils literal"><span class="pre">bi_opf</span></code> field; to +determine it, use the <code class="xref c c-func docutils literal"><span class="pre">bio_data_dir()</span></code> function.</p> +<div class="section" id="create-a-struct-bio-structure"> +<h3>Create a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure<a class="headerlink" href="#create-a-struct-bio-structure" title="Permalink to this headline">¶</a></h3> +<p>Two functions can be used to create a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">bio_alloc()</span></code>: allocates space for a new structure; the structure +must be initialized;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">bio_clone()</span></code>: makes a copy of an existing <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> +structure; the newly obtained structure is initialized with the values of +the cloned structure fields; the buffers are shared with the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure that has been cloned so that access to the +buffers has to be done carefully to avoid access to the same memory area +from the two clones;</li> +</ul> +</div></blockquote> +<p>Both functions return a new <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure.</p> +</div> +<div class="section" id="submit-a-struct-bio-structure"> +<h3>Submit a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure<a class="headerlink" href="#submit-a-struct-bio-structure" title="Permalink to this headline">¶</a></h3> +<p>Usually, a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure is created by the higher levels of +the kernel (usually the file system). A structure thus created is then +transmitted to the I/O subsystem that gathers more <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> +structures into a request.</p> +<p>For submitting a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure to the associated I/O device +driver, the <code class="xref c c-func docutils literal"><span class="pre">submit_bio()</span></code> function is used. The function receives as +argument an initialized <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure that will be added to +a request from the request queue of an I/O device. From that queue, it can be +processed by the I/O device driver using a specialized function.</p> +</div> +<div class="section" id="wait-for-the-completion-of-a-struct-bio-structure"> +<span id="bio-completion"></span><h3>Wait for the completion of a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure<a class="headerlink" href="#wait-for-the-completion-of-a-struct-bio-structure" title="Permalink to this headline">¶</a></h3> +<p>Submitting a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure to a driver has the effect of +adding it to a request from the request queue from where it will be further +processed. Thus, when the <code class="xref c c-func docutils literal"><span class="pre">submit_bio()</span></code> function returns, it is not +guaranteed that the processing of the structure has finished. If you want to +wait for the processing of the request to be finished, use the +<code class="xref c c-func docutils literal"><span class="pre">submit_bio_wait()</span></code> function.</p> +<p>To be notified when the processing of a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure ends +(when we do not use <code class="xref c c-func docutils literal"><span class="pre">submit_bio_wait()</span></code> function), the +<code class="xref c c-member docutils literal"><span class="pre">bi_end_io</span></code> field of the structure should be used. This field +specifies the function that will be called at the end of the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure processing. You can use the +<code class="xref c c-member docutils literal"><span class="pre">bi_private</span></code> field of the structure to pass information to the +function.</p> +</div> +<div class="section" id="initialize-a-struct-bio-structure"> +<h3>Initialize a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure<a class="headerlink" href="#initialize-a-struct-bio-structure" title="Permalink to this headline">¶</a></h3> +<p>Once a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure has been allocated and before being +transmitted, it must be initialized.</p> +<p>Initializing the structure involves filling in its important fields. As +mentioned above, the <code class="xref c c-member docutils literal"><span class="pre">bi_end_io</span></code> field is used to specify the function +called when the processing of the structure is finished. The +<code class="xref c c-member docutils literal"><span class="pre">bi_private</span></code> field is used to store useful data that can be accessed +in the function pointed by <code class="xref c c-member docutils literal"><span class="pre">bi_end_io</span></code>.</p> +<p>The <code class="xref c c-member docutils literal"><span class="pre">bi_opf</span></code> field specifies the type of operation.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">bio</span> <span class="o">*</span><span class="n">bio</span> <span class="o">=</span> <span class="n">bio_alloc</span><span class="p">(</span><span class="n">GFP_NOIO</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> +<span class="c1">//...</span> +<span class="n">bio</span><span class="o">-></span><span class="n">bi_disk</span> <span class="o">=</span> <span class="n">bdev</span><span class="o">-></span><span class="n">bd_disk</span><span class="p">;</span> +<span class="n">bio</span><span class="o">-></span><span class="n">bi_iter</span><span class="p">.</span><span class="n">bi_sector</span> <span class="o">=</span> <span class="n">sector</span><span class="p">;</span> +<span class="n">bio</span><span class="o">-></span><span class="n">bi_opf</span> <span class="o">=</span> <span class="n">REQ_OP_READ</span><span class="p">;</span> +<span class="n">bio_add_page</span><span class="p">(</span><span class="n">bio</span><span class="p">,</span> <span class="n">page</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="n">offset</span><span class="p">);</span> +<span class="c1">//...</span> +</pre></div> +</div> +<p>In the code snippet above we specified the block device to which we sent the +following: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure, startup sector, operation +(<code class="xref c c-data docutils literal"><span class="pre">REQ_OP_READ</span></code> or <code class="xref c c-data docutils literal"><span class="pre">REQ_OP_WRITE</span></code>) and content. The content of a +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure is a buffer described by: a physical page, +the offset in the page and the size of the bufer. A page can be assigned using +the <code class="xref c c-func docutils literal"><span class="pre">alloc_page()</span></code> call.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The <code class="xref c c-data docutils literal"><span class="pre">size</span></code> field of the <code class="xref c c-func docutils literal"><span class="pre">bio_add_page()</span></code> call must be +a multiple of the device sector size.</p> +</div> +</div> +<div class="section" id="how-to-use-the-content-of-a-struct-bio-structure"> +<span id="bio-content"></span><h3>How to use the content of a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure<a class="headerlink" href="#how-to-use-the-content-of-a-struct-bio-structure" title="Permalink to this headline">¶</a></h3> +<p>To use the content of a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure, the structure's +support pages must be mapped to the kernel address space from where they can be +accessed. For mapping /unmapping, use the <code class="xref c c-macro docutils literal"><span class="pre">kmap_atomic</span></code> and +the <code class="xref c c-macro docutils literal"><span class="pre">kunmap_atomic</span></code> macros.</p> +<p>A typical example of use is:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">void</span> <span class="nf">my_block_transfer</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_block_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">start</span><span class="p">,</span> + <span class="kt">size_t</span> <span class="n">len</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">buffer</span><span class="p">,</span> <span class="kt">int</span> <span class="n">dir</span><span class="p">);</span> + + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_xfer_bio</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_block_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> <span class="k">struct</span> <span class="n">bio</span> <span class="o">*</span><span class="n">bio</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">bio_vec</span> <span class="n">bvec</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">bvec_iter</span> <span class="n">i</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">dir</span> <span class="o">=</span> <span class="n">bio_data_dir</span><span class="p">(</span><span class="n">bio</span><span class="p">);</span> + + <span class="cm">/* Do each segment independently. */</span> + <span class="n">bio_for_each_segment</span><span class="p">(</span><span class="n">bvec</span><span class="p">,</span> <span class="n">bio</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span> <span class="p">{</span> + <span class="n">sector_t</span> <span class="n">sector</span> <span class="o">=</span> <span class="n">i</span><span class="p">.</span><span class="n">bi_sector</span><span class="p">;</span> + <span class="kt">char</span> <span class="o">*</span><span class="n">buffer</span> <span class="o">=</span> <span class="n">kmap_atomic</span><span class="p">(</span><span class="n">bvec</span><span class="p">.</span><span class="n">bv_page</span><span class="p">);</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">offset</span> <span class="o">=</span> <span class="n">bvec</span><span class="p">.</span><span class="n">bv_offset</span><span class="p">;</span> + <span class="kt">size_t</span> <span class="n">len</span> <span class="o">=</span> <span class="n">bvec</span><span class="p">.</span><span class="n">bv_len</span><span class="p">;</span> + + <span class="cm">/* process mapped buffer */</span> + <span class="n">my_block_transfer</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">sector</span><span class="p">,</span> <span class="n">len</span><span class="p">,</span> <span class="n">buffer</span> <span class="o">+</span> <span class="n">offset</span><span class="p">,</span> <span class="n">dir</span><span class="p">);</span> + + <span class="n">kunmap_atomic</span><span class="p">(</span><span class="n">buffer</span><span class="p">);</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>As it can be seen from the example above, iterating through a +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> requires iterating through all of its segments. A segment +(<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio_vec</span></code>) is defined by the physical address page, the offset +in the page and its size.</p> +<p>To simplify the processing of a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code>, use the +<code class="xref c c-macro docutils literal"><span class="pre">bio_for_each_segment</span></code> macrodefinition. It will iterate through all +segments, and will also update global information stored in an iterator +(<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bvec_iter</span></code>) such as the current sector as well as other +internal information (segment vector index, number of bytes left to be +processed, etc.) .</p> +<p>You can store information in the mapped buffer, or extract information.</p> +<p>In case request queues are used and you needed to process the requests +at <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> level, use the <code class="xref c c-macro docutils literal"><span class="pre">rq_for_each_segment</span></code> +macrodefinition instead of the <code class="xref c c-macro docutils literal"><span class="pre">bio_for_each_segment</span></code> macrodefinition. +This macrodefinition iterates through each segment of each +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure of a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code> structure and +updates a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">req_iterator</span></code> structure. The +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">req_iterator</span></code> contains the current <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> +structure and the iterator that traverses its segments.</p> +<p>A typical example of use is:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">bio_vec</span> <span class="n">bvec</span><span class="p">;</span> +<span class="k">struct</span> <span class="n">req_iterator</span> <span class="n">iter</span><span class="p">;</span> + +<span class="n">rq_for_each_segment</span><span class="p">(</span><span class="n">bvec</span><span class="p">,</span> <span class="n">req</span><span class="p">,</span> <span class="n">iter</span><span class="p">)</span> <span class="p">{</span> + <span class="n">sector_t</span> <span class="n">sector</span> <span class="o">=</span> <span class="n">iter</span><span class="p">.</span><span class="n">iter</span><span class="p">.</span><span class="n">bi_sector</span><span class="p">;</span> + <span class="kt">char</span> <span class="o">*</span><span class="n">buffer</span> <span class="o">=</span> <span class="n">kmap_atomic</span><span class="p">(</span><span class="n">bvec</span><span class="p">.</span><span class="n">bv_page</span><span class="p">);</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">offset</span> <span class="o">=</span> <span class="n">bvec</span><span class="p">.</span><span class="n">bv_offset</span><span class="p">;</span> + <span class="kt">size_t</span> <span class="n">len</span> <span class="o">=</span> <span class="n">bvec</span><span class="p">.</span><span class="n">bv_len</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">dir</span> <span class="o">=</span> <span class="n">bio_data_dir</span><span class="p">(</span><span class="n">iter</span><span class="p">.</span><span class="n">bio</span><span class="p">);</span> + + <span class="n">my_block_transfer</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">sector</span><span class="p">,</span> <span class="n">len</span><span class="p">,</span> <span class="n">buffer</span> <span class="o">+</span> <span class="n">offset</span><span class="p">,</span> <span class="n">dir</span><span class="p">);</span> + + <span class="n">kunmap_atomic</span><span class="p">(</span><span class="n">buffer</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="free-a-struct-bio-structure"> +<h3>Free a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure<a class="headerlink" href="#free-a-struct-bio-structure" title="Permalink to this headline">¶</a></h3> +<p>Once a kernel subsystem uses a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure, it will have to +release the reference to it. This is done by calling <code class="xref c c-func docutils literal"><span class="pre">bio_put()</span></code> function.</p> +</div> +<div class="section" id="set-up-a-request-queue-at-struct-bio-level"> +<h3>Set up a request queue at <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> level<a class="headerlink" href="#set-up-a-request-queue-at-struct-bio-level" title="Permalink to this headline">¶</a></h3> +<p>We have previously seen how we can specify a function to be used to process +requests sent to the driver. The function receives as argument the requests and +carries out processing at <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code> level.</p> +<p>If, for flexibility reasons, we need to specify a function that carries +out processing at <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure level, we no longer +use request queues and we will need to fill the <code class="docutils literal"><span class="pre">submit_bio</span></code> field in the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">block_device_operations</span></code> associated to the driver.</p> +<p>Below is a typical example of initializing a function that carries out +processing at <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure level:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="c1">// the declaration of the function that carries out processing</span> +<span class="c1">// :c:type:`struct bio` structures</span> +<span class="k">static</span> <span class="n">blk_qc_t</span> <span class="nf">my_submit_bio</span><span class="p">(</span><span class="k">struct</span> <span class="n">bio</span> <span class="o">*</span><span class="n">bio</span><span class="p">);</span> + +<span class="k">struct</span> <span class="n">block_device_operations</span> <span class="n">my_block_ops</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">owner</span> <span class="o">=</span> <span class="n">THIS_MODULE</span><span class="p">,</span> + <span class="p">.</span><span class="n">submit_bio</span> <span class="o">=</span> <span class="n">my_submit_bio</span> + <span class="p">...</span> +<span class="p">};</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="further-reading"> +<h2>Further reading<a class="headerlink" href="#further-reading" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li><a class="reference external" href="http://static.lwn.net/images/pdf/LDD3/ch16.pdf">Linux Device Drivers 3rd Edition, Chapter 16. Block Drivers</a></li> +<li>Linux Kernel Development, Second Edition – Chapter 13. The Block I/O Layer</li> +<li><a class="reference external" href="https://lwn.net/Articles/58719/">A simple block driver</a></li> +<li><a class="reference external" href="https://lwn.net/Articles/25711/">The gendisk interface</a></li> +<li><a class="reference external" href="https://lwn.net/Articles/26404/">The bio structure</a></li> +<li><a class="reference external" href="https://lwn.net/Articles/27055/">Request queues</a></li> +<li><a class="reference external" href="https://elixir.bootlin.com/linux/v4.15/source/Documentation/block/request.txt">Documentation/block/request.txt - Struct request documentation</a></li> +<li><a class="reference external" href="https://elixir.bootlin.com/linux/v4.15/source/Documentation/block/biodoc.txt">Documentation/block/biodoc.txt - Notes on the Generic Block Layer</a></li> +<li><a class="reference external" href="https://elixir.bootlin.com/linux/v4.15/source/drivers/block/brd.c">drivers/block/brd/c - RAM backed block disk driver</a></li> +<li><a class="reference external" href="https://www.linuxjournal.com/article/6931">I/O Schedulers</a></li> +</ul> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is block_device_drivers. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/block_device_drivers/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="section" id="intro"> +<h3>0. Intro<a class="headerlink" href="#intro" title="Permalink to this headline">¶</a></h3> +<p>Using <a class="reference external" href="http://elixir.free-electrons.com/linux/latest/source">LXR</a> find the definitions of the following symbols in the Linux kernel:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio_vec</span></code></li> +<li><code class="xref c c-macro docutils literal"><span class="pre">bio_for_each_segment</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">block_device_operations</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code></li> +</ul> +</div></blockquote> +</div> +<div class="section" id="block-device"> +<h3>1. Block device<a class="headerlink" href="#block-device" title="Permalink to this headline">¶</a></h3> +<p>Create a kernel module that allows you to register or deregister a block device. +Start from the files in the <code class="file docutils literal"><span class="pre">1-2-3-6-ram-disk/kernel</span></code> directory in the +lab skeleton.</p> +<p>Follow the comments marked with <strong>TODO 1</strong> in the laboratory skeleton. Use the +existing macrodefinitions (<code class="xref c c-macro docutils literal"><span class="pre">MY_BLOCK_MAJOR</span></code>, +<code class="xref c c-macro docutils literal"><span class="pre">MY_BLKDEV_NAME</span></code>). Check the value returned by the register function, +and in case of error, return the error code.</p> +<p>Compile the module, copy it to the virtual machine and insert it into the +kernel. Verify that your device was successfully created inside the +<code class="file docutils literal"><span class="pre">/proc/devices</span></code>. +You will see a device with major 240.</p> +<p>Unload the kernel module and check that the device was unregistered.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Review the <a class="reference internal" href="#register-a-block-i-o-device">Register a block I/O device</a> section.</p> +</div> +<p>Change the <code class="xref c c-macro docutils literal"><span class="pre">MY_BLOCK_MAJOR</span></code> value to 7. Compile the module, copy it to +the virtual machine, and insert it into the kernel. Notice that the insertion +fails because there is already another driver/device registered in the kernel +with the major 7.</p> +<p>Restore the 240 value for the <code class="xref c c-macro docutils literal"><span class="pre">MY_BLOCK_MAJOR</span></code> macro.</p> +</div> +<div class="section" id="disk-registration"> +<h3>2. Disk registration<a class="headerlink" href="#disk-registration" title="Permalink to this headline">¶</a></h3> +<p>Modify the previous module to add a disk associated with the driver. Analyze the +macrodefinitions, <code class="xref c c-type docutils literal"><span class="pre">my_block_dev</span></code> structure and existing functions from +the <code class="file docutils literal"><span class="pre">ram-disk.c</span></code> file.</p> +<p>Follow the comments marked with <strong>TODO 2</strong>. Use the +<code class="xref c c-func docutils literal"><span class="pre">create_block_device()</span></code> and the <code class="xref c c-func docutils literal"><span class="pre">delete_block_device()</span></code> functions.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Review the <a class="reference internal" href="#register-a-disk">Register a disk</a> and <a class="reference internal" href="#process-a-request">Process a request</a> sections.</p> +</div> +<p>Fill in the <code class="xref c c-func docutils literal"><span class="pre">my_block_request()</span></code> function to process the request +without actually processing your request: display the "request received" message +and the following information: start sector, total size, data size from the +current <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure, direction. To validate a request type, +use the <code class="xref c c-func docutils literal"><span class="pre">blk_rq_is_passthrough()</span></code> (the function returns 0 in the case in +which we are interested, i.e. when the request is generated by the file system).</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">To find the needed info, review the <a class="reference internal" href="#requests-for-block-devices">Requests for block devices</a> +section.</p> +</div> +<p>Use the <code class="xref c c-func docutils literal"><span class="pre">blk_mq_end_request()</span></code> function to finish processing the +request.</p> +<p>Insert the module into the kernel and inspect the messages printed +by the module. When a device is added, a request is sent to the device. Check +the presence of <code class="file docutils literal"><span class="pre">/dev/myblock</span></code> and if it doesn't exist, create the device +using the command:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>mknod /dev/myblock b <span class="m">240</span> <span class="m">0</span> +</pre></div> +</div> +<p>To generate writing requests, use the command:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span><span class="nb">echo</span> <span class="s2">"abc"</span>> /dev/myblock +</pre></div> +</div> +<p>Notice that a write request is preceded by a read request. The request +is done to read the block from the disk and "update" its content with the +data provided by the user, without overwriting the rest. After reading and +updating, writing takes place.</p> +</div> +<div class="section" id="ram-disk"> +<h3>3. RAM disk<a class="headerlink" href="#ram-disk" title="Permalink to this headline">¶</a></h3> +<p>Modify the previous module to create a RAM disk: requests to the device will +result in reads/writes in a memory area.</p> +<p>The memory area <code class="xref c c-data docutils literal"><span class="pre">dev->data</span></code> is already allocated in the source code of +the module using <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code> and deallocated using <code class="xref c c-func docutils literal"><span class="pre">vfree()</span></code>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Review the <a class="reference internal" href="#process-a-request">Process a request</a> section.</p> +</div> +<p>Follow the comments marked with <strong>TODO 3</strong> to complete the +<code class="xref c c-func docutils literal"><span class="pre">my_block_transfer()</span></code> function to write/read the request information +in/from the memory area. The function will be called for each request within +the queue processing function: <code class="xref c c-func docutils literal"><span class="pre">my_block_request()</span></code>. To write/read +to/from the memory area, use <code class="xref c c-func docutils literal"><span class="pre">memcpy()</span></code>. To determine the write/read +information, use the fields of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code> structure.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">To find out the size of the request data, use the +<code class="xref c c-macro docutils literal"><span class="pre">blk_rq_cur_bytes</span></code> macro. Do not use the +<code class="xref c c-macro docutils literal"><span class="pre">blk_rq_bytes</span></code> macro.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">To find out the buffer associated to the request, use +<code class="xref c c-data docutils literal"><span class="pre">bio_data`(:c:data:`rq->bio</span></code>).</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">A description of useful macros is in the <a class="reference internal" href="#requests-for-block-devices">Requests for block devices</a> +section.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">You can find useful information in the +<a class="reference external" href="https://github.com/martinezjavier/ldd3/blob/master/sbull/sbull.c">block device driver example</a> +from <a class="reference external" href="http://lwn.net/Kernel/LDD3/">Linux Device Driver</a>.</p> +</div> +<p>For testing, use the test file <code class="file docutils literal"><span class="pre">user/ram-disk-test.c</span></code>. +The test program is compiled automatically at <code class="docutils literal"><span class="pre">make</span> <span class="pre">build</span></code>, copied to the +virtual machine at <code class="docutils literal"><span class="pre">make</span> <span class="pre">copy</span></code> and can be run on the QEMU virtual machine +using the command:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>./ram-disk-test +</pre></div> +</div> +<p>There is no need to insert the module into the kernel, it will be inserted by +the <code class="docutils literal"><span class="pre">ram-disk-test</span></code> command.</p> +<p>Some tests may fail because of lack of synchronization between the transmitted +data (flush).</p> +</div> +<div class="section" id="read-data-from-the-disk"> +<h3>4. Read data from the disk<a class="headerlink" href="#read-data-from-the-disk" title="Permalink to this headline">¶</a></h3> +<p>The purpose of this exercise is to read data from the +<code class="xref c c-macro docutils literal"><span class="pre">PHYSICAL_DISK_NAME</span></code> disk (<code class="file docutils literal"><span class="pre">/dev/vdb</span></code>) directly from the kernel.</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p>Before solving the exercise, we need to make sure the disk is +added to the virtual machine.</p> +<p>Check the variable <code class="docutils literal"><span class="pre">QEMU_OPTS</span></code> from <code class="file docutils literal"><span class="pre">qemu/Makefile</span></code>. +There should already be two extra disks added using <code class="docutils literal"><span class="pre">-drive</span> <span class="pre">...</span></code>.</p> +<p class="last">If there are not, generate a file that we will use as +the disk image using the command: +<strong class="command">dd if=/dev/zero of=qemu/mydisk.img bs=1024 count=1</strong> +and add the following option: +<strong class="command">-drive file=qemu/mydisk.img,if=virtio,format=raw</strong> +to <code class="file docutils literal"><span class="pre">qemu/Makefile</span></code> (in the <code class="xref c c-data docutils literal"><span class="pre">QEMU_OPTS</span></code> variable, +after the root disk).</p> +</div> +<p>Follow the comments marked with <strong>TODO 4</strong> in the directory <code class="file docutils literal"><span class="pre">4-5-relay/</span></code> +and implement <code class="xref c c-func docutils literal"><span class="pre">open_disk()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">close_disk()</span></code>. +Use the <code class="xref c c-func docutils literal"><span class="pre">blkdev_get_by_path()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">blkdev_put()</span></code> functions. The +device must be opened in read-write mode exclusively +(<code class="xref c c-macro docutils literal"><span class="pre">FMODE_READ</span></code> | <code class="xref c c-macro docutils literal"><span class="pre">FMODE_WRITE</span></code> | <code class="xref c c-macro docutils literal"><span class="pre">FMODE_EXCL</span></code>), and +as holder you must use the current module (<code class="xref c c-macro docutils literal"><span class="pre">THIS_MODULE</span></code>).</p> +<p>Implement the <code class="xref c c-func docutils literal"><span class="pre">send_test_bio()</span></code> function. You will have to create a new +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure and fill it, submit it and wait for it. Read the +first sector of the disk. To wait, call the <code class="xref c c-func docutils literal"><span class="pre">submit_bio_wait()</span></code> function.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>The first sector of the disk is the sector with the index 0. +This value must be used to initialize the field +<code class="xref c c-member docutils literal"><span class="pre">bi_iter.bi_sector</span></code> of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code>.</p> +<p class="last">For the read operation, use the <code class="xref c c-macro docutils literal"><span class="pre">REQ_OP_READ</span></code> macro to +initialize the <code class="xref c c-member docutils literal"><span class="pre">bi_opf</span></code> field of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code>.</p> +</div> +<p>After finishing the operation, display the first 3 bytes of data read by +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure. Use the format <code class="docutils literal"><span class="pre">"%</span> <span class="pre">02x"</span></code> for <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code> +to display the data and the <code class="xref c c-macro docutils literal"><span class="pre">kmap_atomic</span></code> and <code class="xref c c-macro docutils literal"><span class="pre">kunmap_atomic</span></code> +macros respectively.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">As an argument for the <code class="xref c c-func docutils literal"><span class="pre">kmap_atomic()</span></code> function, just use the +page which is allocated above in the code, in the <code class="xref c c-data docutils literal"><span class="pre">page</span></code> +variable.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Review the sections <a class="reference internal" href="../so2/lab7-block-device-drivers.html#bio-content"><span class="std std-ref">How to use the content of a struct bio structure</span></a> and <a class="reference internal" href="../so2/lab7-block-device-drivers.html#bio-completion"><span class="std std-ref">Wait for the completion of a struct bio structure</span></a>.</p> +</div> +<p>For testing, use the <code class="file docutils literal"><span class="pre">test-relay-disk</span></code> script, which is copied on the +virtual machine when running <strong class="command">make copy</strong>. If it is not copied, make +sure it is executable:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>chmod +x test-relay-disk +</pre></div> +</div> +<p>There is no need to load the module into the kernel, it will be loaded by +<strong class="command">test-relay-disk</strong>.</p> +<p>Use the command below to run the script:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>./test-relay-disk +</pre></div> +</div> +<p>The script writes "abc" at the beginning of the disk indicated by +<code class="xref c c-macro docutils literal"><span class="pre">PHYSICAL_DISK_NAME</span></code>. After running, the module will display 61 62 63 +(the corresponding hexadecimal values of letters "a", "b" and "c").</p> +</div> +<div class="section" id="write-data-to-the-disk"> +<h3>5. Write data to the disk<a class="headerlink" href="#write-data-to-the-disk" title="Permalink to this headline">¶</a></h3> +<p>Follow the comments marked with <strong>TODO 5</strong> to write a message +(<code class="xref c c-macro docutils literal"><span class="pre">BIO_WRITE_MESSAGE</span></code>) on the disk.</p> +<p>The <code class="xref c c-func docutils literal"><span class="pre">send_test_bio()</span></code> function receives as argument the operation type +(read or write). Call in the <code class="xref c c-func docutils literal"><span class="pre">relay_init()</span></code> function the function for +reading and in the <code class="xref c c-func docutils literal"><span class="pre">relay_exit()</span></code> function the function for writing. We +recommend using the <code class="xref c c-macro docutils literal"><span class="pre">REQ_OP_READ</span></code> and the <code class="xref c c-macro docutils literal"><span class="pre">REQ_OP_WRITE</span></code> +macros.</p> +<p>Inside the <code class="xref c c-func docutils literal"><span class="pre">send_test_bio()</span></code> function, if the operation is write, fill in +the buffer associated to the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure with the message +<code class="xref c c-macro docutils literal"><span class="pre">BIO_WRITE_MESSAGE</span></code>. Use the <code class="xref c c-macro docutils literal"><span class="pre">kmap_atomic</span></code> and the +<code class="xref c c-macro docutils literal"><span class="pre">kunmap_atomic</span></code> macros to work with the buffer associated to the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">You need to update the type of the operation associated to the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure by setting the <code class="xref c c-member docutils literal"><span class="pre">bi_opf</span></code> field +accordingly.</p> +</div> +<p>For testing, run the <code class="file docutils literal"><span class="pre">test-relay-disk</span></code> script using the command:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>./test-relay-disk +</pre></div> +</div> +<p>The script will display the <code class="docutils literal"><span class="pre">"read</span> <span class="pre">from</span> <span class="pre">/dev/sdb:</span> <span class="pre">64</span> <span class="pre">65</span> <span class="pre">66"</span></code> message at the +standard output.</p> +</div> +<div class="section" id="processing-requests-from-the-request-queue-at-struct-bio-level"> +<h3>6. Processing requests from the request queue at <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> level<a class="headerlink" href="#processing-requests-from-the-request-queue-at-struct-bio-level" title="Permalink to this headline">¶</a></h3> +<p>In the implementation from Exercise 3, we have only processed a +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio_vec</span></code> of the current <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> from the request. +We want to process all <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio_vec</span></code> structures from all +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structures. +For this, we will iterate through all <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> requests and through +all <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio_vec</span></code> structures (also called segments) of each +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code>.</p> +<p>Add, within the ramdisk implementation (<code class="file docutils literal"><span class="pre">1-2-3-6-ram-disk/</span></code> directory), +support for processing the requests from the request queue at +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> level. Follow the comments marked with <strong>TODO 6</strong>.</p> +<p>Set the <code class="xref c c-macro docutils literal"><span class="pre">USE_BIO_TRANSFER</span></code> macro to 1.</p> +<p>Implement the <code class="xref c c-func docutils literal"><span class="pre">my_xfer_request()</span></code> function. Use the +<code class="xref c c-macro docutils literal"><span class="pre">rq_for_each_segment</span></code> macro to iterate through the <code class="xref c c-type docutils literal"><span class="pre">bio_vec</span></code> +structures of each <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> from the request.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Review the indications and the code snippets from the +<a class="reference internal" href="../so2/lab7-block-device-drivers.html#bio-content"><span class="std std-ref">How to use the content of a struct bio structure</span></a> section.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> segment iterator to get the current +sector (<code class="xref c c-member docutils literal"><span class="pre">iter.iter.bi_sector</span></code>).</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use the request iterator to get the reference to the current +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> (<code class="xref c c-member docutils literal"><span class="pre">iter.bio</span></code>).</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use the <code class="xref c c-macro docutils literal"><span class="pre">bio_data_dir</span></code> macro to find the reading or writing +direction for a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code>.</p> +</div> +<p>Use the <code class="xref c c-macro docutils literal"><span class="pre">kmap_atomic</span></code> or the <code class="xref c c-macro docutils literal"><span class="pre">kunmap_atomic</span></code> macros to map +the pages of each <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure and access its associated +buffers. For the actual transfer, call the <code class="xref c c-func docutils literal"><span class="pre">my_block_transfer()</span></code> function +implemented in the previous exercise.</p> +<p>For testing, use the <code class="file docutils literal"><span class="pre">ram-disk-test.c</span></code> test file:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>./ram-disk-test +</pre></div> +</div> +<p>There is no need to insert the module into the kernel, it will be inserted by +the <strong class="command">ram-disk-test</strong> executable.</p> +<p>Some tests may crash because of lack of synchronization between the transmitted +data (flush).</p> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="deferred_work.html" class="btn btn-neutral float-left" title="Deferred work" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="filesystems_part1.html" class="btn btn-neutral float-right" title="File system drivers (Part 1)" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/labs/deferred_work.html b/refs/pull/405/merge/labs/deferred_work.html new file mode 100644 index 00000000..1ab912d1 --- /dev/null +++ b/refs/pull/405/merge/labs/deferred_work.html @@ -0,0 +1,1072 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Deferred work — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Block Device Drivers" href="block_device_drivers.html" /> + <link rel="prev" title="I/O access and Interrupts" href="interrupts.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Deferred work</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="#background-information">Background information</a></li> +<li class="toctree-l2"><a class="reference internal" href="#softirqs">Softirqs</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#tasklets">Tasklets</a></li> +<li class="toctree-l3"><a class="reference internal" href="#timers">Timers</a></li> +<li class="toctree-l3"><a class="reference internal" href="#locking">Locking</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#workqueues">Workqueues</a></li> +<li class="toctree-l2"><a class="reference internal" href="#kernel-threads">Kernel threads</a></li> +<li class="toctree-l2"><a class="reference internal" href="#further-reading">Further reading</a></li> +<li class="toctree-l2"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#intro">0. Intro</a></li> +<li class="toctree-l3"><a class="reference internal" href="#timer">1.Timer</a></li> +<li class="toctree-l3"><a class="reference internal" href="#periodic-timer">2. Periodic timer</a></li> +<li class="toctree-l3"><a class="reference internal" href="#timer-control-using-ioctl">3. Timer control using ioctl</a></li> +<li class="toctree-l3"><a class="reference internal" href="#blocking-operations">4. Blocking operations</a></li> +<li class="toctree-l3"><a class="reference internal" href="#workqueues-1">5. Workqueues</a></li> +<li class="toctree-l3"><a class="reference internal" href="#kernel-thread">6. Kernel thread</a></li> +<li class="toctree-l3"><a class="reference internal" href="#buffer-shared-between-timer-and-process">7. Buffer shared between timer and process</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Deferred work</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/labs/deferred_work.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="deferred-work"> +<h1>Deferred work<a class="headerlink" href="#deferred-work" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>Understanding deferred work (i.e. code scheduled to be executed at a +later time)</li> +<li>Implementation of common tasks that uses deferred work</li> +<li>Understanding the peculiarities of synchronization for deferred work</li> +</ul> +<p>Keywords: softirq, tasklet, struct tasklet_struct, bottom-half +handlers, jiffies, HZ, timer, struct timer_list, spin_lock_bh, +spin_unlock_bh, workqueue, struct work_struct, kernel thread, events/x</p> +</div> +<div class="section" id="background-information"> +<h2>Background information<a class="headerlink" href="#background-information" title="Permalink to this headline">¶</a></h2> +<p>Deferred work is a class of kernel facilities that allows one to +schedule code to be executed at a later timer. This scheduled code can +run either in the process context or in interruption context depending +on the type of deferred work. Deferred work is used to complement the +interrupt handler functionality since interrupts have important +requirements and limitations:</p> +<ul class="simple"> +<li>The execution time of the interrupt handler must be as small as +possible</li> +<li>In interrupt context we can not use blocking calls</li> +</ul> +<p>Using deferred work we can perform the minimum required work in the +interrupt handler and schedule an asynchronous action from the +interrupt handler to run at a later time and execute the rest of the +operations.</p> +<p>Deferred work that runs in interrupt context is also known as +bottom-half, since its purpose is to execute the rest of the actions +from an interrupt handler (top-half).</p> +<p>Timers are another type of deferred work that are used to schedule the +execution of future actions after a certain amount of time has passed.</p> +<p>Kernel threads are not themselves deferred work, but can be used to +complement the deferred work mechanisms. In general, kernel threads +are used as "workers" to process events whose execution contains +blocking calls.</p> +<p>There are three typical operations that are used with all types of +deferred work:</p> +<ol class="arabic simple"> +<li><strong>Initialization</strong>. Each type is described by a structure whose +fields will have to be initialized. The handler to be scheduled is +also set at this time.</li> +<li><strong>Scheduling</strong>. Schedules the execution of the handler as soon as +possible (or after expiry of a timeout).</li> +<li><strong>Masking</strong> or <strong>Canceling</strong>. Disables the execution of the +handler. This action can be either synchronous (which guarantees +that the handler will not run after the completion of canceling) or +asynchronous.</li> +</ol> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">When doing deferred work cleanup, like freeing the +structures associated with the deferred work or +removing the module and thus the handler code from the +kernel, always use the synchronous type of canceling +the deferred work.</p> +</div> +<p>The main types of deferred work are kernel threads and softirqs. Work +queues are implemented on top of kernel threads and tasklets and +timers on top of softirqs. Bottom-half handlers were the first +implementation of deferred work in Linux, but in the meantime it was +replaced by softirqs. That is why some functions presented +contain <em>bh</em> in their name.</p> +</div> +<div class="section" id="softirqs"> +<h2>Softirqs<a class="headerlink" href="#softirqs" title="Permalink to this headline">¶</a></h2> +<p>softirqs can not be used by device drivers, they are reserved for +various kernel subsystems. Because of this there is a fixed number of +softirqs defined at compile time. For the current kernel version we +have the following types defined:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">enum</span> <span class="p">{</span> + <span class="n">HI_SOFTIRQ</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> + <span class="n">TIMER_SOFTIRQ</span><span class="p">,</span> + <span class="n">NET_TX_SOFTIRQ</span><span class="p">,</span> + <span class="n">NET_RX_SOFTIRQ</span><span class="p">,</span> + <span class="n">BLOCK_SOFTIRQ</span><span class="p">,</span> + <span class="n">IRQ_POLL_SOFTIRQ</span><span class="p">,</span> + <span class="n">TASKLET_SOFTIRQ</span><span class="p">,</span> + <span class="n">SCHED_SOFTIRQ</span><span class="p">,</span> + <span class="n">HRTIMER_SOFTIRQ</span><span class="p">,</span> + <span class="n">RCU_SOFTIRQ</span><span class="p">,</span> + <span class="n">NR_SOFTIRQS</span> +<span class="p">};</span> +</pre></div> +</div> +<p>Each type has a specific purpose:</p> +<ul class="simple"> +<li><em>HI_SOFTIRQ</em> and <em>TASKLET_SOFTIRQ</em> - running tasklets</li> +<li><em>TIMER_SOFTIRQ</em> - running timers</li> +<li><em>NET_TX_SOFIRQ</em> and <em>NET_RX_SOFTIRQ</em> - used by the networking subsystem</li> +<li><em>BLOCK_SOFTIRQ</em> - used by the IO subsystem</li> +<li><em>BLOCK_IOPOLL_SOFTIRQ</em> - used by the IO subsystem to increase performance when the iopoll handler is invoked;</li> +<li><em>SCHED_SOFTIRQ</em> - load balancing</li> +<li><em>HRTIMER_SOFTIRQ</em> - implementation of high precision timers</li> +<li><em>RCU_SOFTIRQ</em> - implementation of RCU type mechanisms <a class="footnote-reference" href="#footnote-1" id="footnote-reference-1">[1]</a></li> +</ul> +<table class="docutils footnote" frame="void" id="footnote-1" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#footnote-reference-1">[1]</a></td><td>RCU is a mechanism by which destructive operations +(e.g. deleting an element from a chained list) are done in two +steps: (1) removing references to deleted data and (2) freeing +the memory of the element. The second setup is done only after +we are sure nobody uses the element anymore. The advantage of +this mechanism is that reading the data can be done without +synchronization. For more information see +Documentation/RCU/rcu.txt.</td></tr> +</tbody> +</table> +<p>The highest priority is the <em>HI_SOFTIRQ</em> type softirqs, followed in +order by the other softirqs defined. <em>RCU_SOFTIRQ</em> has the lowest +priority.</p> +<p>Softirqs are running in interrupt context which means that they can +not call blocking functions. If the sofitrq handler requires calls to +such functions, work queues can be scheduled to execute these blocking +calls.</p> +<div class="section" id="tasklets"> +<h3>Tasklets<a class="headerlink" href="#tasklets" title="Permalink to this headline">¶</a></h3> +<p>A tasklet is a special form of deferred work that runs in interrupt +context, just like softirqs. The main difference between sofirqs and tasklets +is that tasklets can be allocated dynamically and thus they can be used +by device drivers. A tasklet is represented by <code class="xref c c-type docutils literal"><span class="pre">struct</span> +<span class="pre">tasklet</span></code> and as many other kernel structures it needs to be +initialized before being used. A pre-initialized tasklet can be defined +as following:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">handler</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">data</span><span class="p">);</span> + +<span class="n">DECLARE_TASKLET</span><span class="p">(</span><span class="n">tasklet</span><span class="p">,</span> <span class="n">handler</span><span class="p">,</span> <span class="n">data</span><span class="p">);</span> +<span class="n">DECLARE_TASKLET_DISABLED</span><span class="p">(</span><span class="n">tasklet</span><span class="p">,</span> <span class="n">handler</span><span class="p">,</span> <span class="n">data</span><span class="p">);</span> +</pre></div> +</div> +<p>If we want to initialize the tasklet manually we can use the following +approach:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">handler</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">data</span><span class="p">);</span> + +<span class="k">struct</span> <span class="n">tasklet_struct</span> <span class="n">tasklet</span><span class="p">;</span> + +<span class="n">tasklet_init</span><span class="p">(</span><span class="o">&</span><span class="n">tasklet</span><span class="p">,</span> <span class="n">handler</span><span class="p">,</span> <span class="n">data</span><span class="p">);</span> +</pre></div> +</div> +<p>The <em>data</em> parameter will be sent to the handler when it is executed.</p> +<p>Programming tasklets for running is called scheduling. Tasklets are +running from softirqs. Tasklets scheduling is done with:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">tasklet_schedule</span><span class="p">(</span><span class="k">struct</span> <span class="n">tasklet_struct</span> <span class="o">*</span><span class="n">tasklet</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">tasklet_hi_schedule</span><span class="p">(</span><span class="k">struct</span> <span class="n">tasklet_struct</span> <span class="o">*</span><span class="n">tasklet</span><span class="p">);</span> +</pre></div> +</div> +<p>When using <em>tasklet_schedule</em>, a <em>TASKLET_SOFTIRQ</em> softirq is +scheduled and all tasklets scheduled are run. For +<em>tasklet_hi_schedule</em>, a <em>HI_SOFTIRQ</em> softirq is scheduled.</p> +<p>If a tasklet was scheduled multiple times and it did not run between +schedules, it will run once. Once the tasklet has run, it can be +re-scheduled, and will run again at a later timer. Tasklets can be +re-scheduled from their handlers.</p> +<p>Tasklets can be masked and the following functions can be used:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">tasklet_enable</span><span class="p">(</span><span class="k">struct</span> <span class="n">tasklet_struct</span> <span class="o">*</span> <span class="n">tasklet</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">tasklet_disable</span><span class="p">(</span><span class="k">struct</span> <span class="n">tasklet_struct</span> <span class="o">*</span> <span class="n">tasklet</span><span class="p">);</span> +</pre></div> +</div> +<p>Remember that since tasklets are running from softirqs, blocking calls +can not be used in the handler function.</p> +</div> +<div class="section" id="timers"> +<h3>Timers<a class="headerlink" href="#timers" title="Permalink to this headline">¶</a></h3> +<p>A particular type of deferred work, very often used, are timers. They +are defined by <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">timer_list</span></code>. They run in interrupt +context and are implemented on top of softirqs.</p> +<p>To be used, a timer must first be initialized by calling <code class="xref c c-func docutils literal"><span class="pre">timer_setup()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/sched.h></span><span class="cp"></span> + +<span class="kt">void</span> <span class="nf">timer_setup</span><span class="p">(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span> <span class="n">timer</span><span class="p">,</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">function</span><span class="p">)(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span><span class="p">),</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">);</span> +</pre></div> +</div> +<p>The above function initializes the internal fields of the structure +and associates <em>function</em> as the timer handler. Since timers are planned +over softirqs, blocking calls can not be used in the code associated +with the treatment function.</p> +<p>Scheduling a timer is done with <code class="xref c c-func docutils literal"><span class="pre">mod_timer()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="nf">mod_timer</span><span class="p">(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span><span class="n">timer</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">expires</span><span class="p">);</span> +</pre></div> +</div> +<p>Where <em>expires</em> is the time (in the future) to run the handler +function. The function can be used to schedule or reschedule a timer.</p> +<p>The time unit is <em>jiffie</em>. The absolute value of a jiffie +is dependent on the platform and it can be found using the +<code class="xref c c-type docutils literal"><span class="pre">HZ</span></code> macro that defines the number of jiffies for 1 second. To +convert between jiffies (<em>jiffies_value</em>) and seconds (<em>seconds_value</em>), +the following formulas are used:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">jiffies_value</span> <span class="o">=</span> <span class="n">seconds_value</span> <span class="o">*</span> <span class="n">HZ</span> <span class="p">;</span> +<span class="n">seconds_value</span> <span class="o">=</span> <span class="n">jiffies_value</span> <span class="o">/</span> <span class="n">HZ</span> <span class="p">;</span> +</pre></div> +</div> +<p>The kernel maintains a counter that contains the number of jiffies +since the last boot, which can be accessed via the <code class="xref c c-macro docutils literal"><span class="pre">jiffies</span></code> +global variable or macro. We can use it to calculate a time in the +future for timers:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/jiffies.h></span><span class="cp"></span> + +<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">current_jiffies</span><span class="p">,</span> <span class="n">next_jiffies</span><span class="p">;</span> +<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">seconds</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> + +<span class="n">current_jiffies</span> <span class="o">=</span> <span class="n">jiffies</span><span class="p">;</span> +<span class="n">next_jiffies</span> <span class="o">=</span> <span class="n">jiffies</span> <span class="o">+</span> <span class="n">seconds</span> <span class="o">*</span> <span class="n">HZ</span><span class="p">;</span> +</pre></div> +</div> +<p>To stop a timer, use <code class="xref c c-func docutils literal"><span class="pre">del_timer()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">del_timer_sync()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="nf">del_timer</span><span class="p">(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span><span class="n">timer</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">del_timer_sync</span><span class="p">(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span><span class="n">timer</span><span class="p">);</span> +</pre></div> +</div> +<p>These functions can be called for both a scheduled timer and an +unplanned timer. <code class="xref c c-func docutils literal"><span class="pre">del_timer_sync()</span></code> is used to eliminate the +races that can occur on multiprocessor systems, since at the end of +the call it is guaranteed that the timer processing function does not +run on any processor.</p> +<p>A frequent mistake in using timers is that we forget to turn off +timers. For example, before removing a module, we must stop the timers +because if a timer expires after the module is removed, the handler +function will no longer be loaded into the kernel and a kernel oops +will be generated.</p> +<p>The usual sequence used to initialize and schedule a one-second +timeout is:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/sched.h></span><span class="cp"></span> + +<span class="kt">void</span> <span class="nf">timer_function</span><span class="p">(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span><span class="p">);</span> + +<span class="k">struct</span> <span class="n">timer_list</span> <span class="n">timer</span> <span class="p">;</span> +<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">seconds</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> + +<span class="n">timer_setup</span><span class="p">(</span><span class="o">&</span><span class="n">timer</span><span class="p">,</span> <span class="n">timer_function</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> +<span class="n">mod_timer</span><span class="p">(</span><span class="o">&</span><span class="n">timer</span><span class="p">,</span> <span class="n">jiffies</span> <span class="o">+</span> <span class="n">seconds</span> <span class="o">*</span> <span class="n">HZ</span><span class="p">);</span> +</pre></div> +</div> +<p>And to stop it:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">del_timer_sync</span><span class="p">(</span><span class="o">&</span><span class="n">timer</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="locking"> +<h3>Locking<a class="headerlink" href="#locking" title="Permalink to this headline">¶</a></h3> +<p>For synchronization between code running in process context (A) and +code running in softirq context (B) we need to use special locking +primitives. We must use spinlock operations augmented with +deactivation of bottom-half handlers on the current processor in (A), +and in (B) only basic spinlock operations. Using spinlocks makes sure +that we don't have races between multiple CPUs while deactivating the +softirqs makes sure that we don't deadlock in the softirq is scheduled +on the same CPU where we already acquired a spinlock.</p> +<p>We can use the <code class="xref c c-func docutils literal"><span class="pre">local_bh_disable()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">local_bh_enable()</span></code> to disable and enable softirqs handlers (and +since they run on top of softirqs also timers and tasklets):</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">local_bh_disable</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">local_bh_enable</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> +</pre></div> +</div> +<p>Nested calls are allowed, the actual reactivation of the softirqs is +done only when all local_bh_disable() calls have been complemented by +local_bh_enable() calls:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* We assume that softirqs are enabled */</span> +<span class="n">local_bh_disable</span><span class="p">();</span> <span class="cm">/* Softirqs are now disabled */</span> +<span class="n">local_bh_disable</span><span class="p">();</span> <span class="cm">/* Softirqs remain disabled */</span> + +<span class="n">local_bh_enable</span><span class="p">();</span> <span class="cm">/* Softirqs remain disabled */</span> +<span class="n">local_bh_enable</span><span class="p">();</span> <span class="cm">/* Softirqs are now enabled */</span> +</pre></div> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">These above calls will disable the softirqs only on the +local processor and they are usually not safe to use, they must be +complemented with spinlocks.</p> +</div> +<p>Most of the time device drivers will use special versions of spinlocks +calls for synchronization like <code class="xref c c-func docutils literal"><span class="pre">spin_lock_bh()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock_bh()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">spin_lock_bh</span><span class="p">(</span><span class="n">spinlock_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">spin_unlock_bh</span><span class="p">(</span><span class="n">spinlock_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">);</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="workqueues"> +<h2>Workqueues<a class="headerlink" href="#workqueues" title="Permalink to this headline">¶</a></h2> +<p>Workqueues are used to schedule actions to run in process context. The +base unit with which they work is called work. There are two types of +work:</p> +<ul class="simple"> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">work_struct</span></code> - it schedules a task to run at +a later time</li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">delayed_work</span></code> - it schedules a task to run after at +least a given time interval</li> +</ul> +<p>A delayed work uses a timer to run after the specified time +interval. The calls with this type of work are similar to those for +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">work_struct</span></code>, but has <strong>_delayed</strong> in the functions +names.</p> +<p>Before using them a work item must be initialized. There are two types +of macros that can be used, one that declares and initializes the work +item at the same time and one that only initializes the work item (and +the declaration must be done separately):</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/workqueue.h></span><span class="cp"></span> + +<span class="n">DECLARE_WORK</span><span class="p">(</span><span class="n">name</span> <span class="p">,</span> <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">function</span><span class="p">)(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="p">));</span> +<span class="n">DECLARE_DELAYED_WORK</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="kt">void</span><span class="p">(</span><span class="o">*</span><span class="n">function</span><span class="p">)(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="p">));</span> + +<span class="n">INIT_WORK</span><span class="p">(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="n">work</span><span class="p">,</span> <span class="kt">void</span><span class="p">(</span><span class="o">*</span><span class="n">function</span><span class="p">)(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="p">));</span> +<span class="n">INIT_DELAYED_WORK</span><span class="p">(</span><span class="k">struct</span> <span class="n">delayed_work</span> <span class="o">*</span><span class="n">work</span><span class="p">,</span> <span class="kt">void</span><span class="p">(</span><span class="o">*</span><span class="n">function</span><span class="p">)(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="p">));</span> +</pre></div> +</div> +<p><code class="xref c c-func docutils literal"><span class="pre">DECLARE_WORK()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">DECLARE_DELAYED_WORK()</span></code> declare and +initialize a work item, and <code class="xref c c-func docutils literal"><span class="pre">INIT_WORK()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">INIT_DELAYED_WORK()</span></code> initialize an already declared work item.</p> +<p>The following sequence declares and initiates a work item:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/workqueue.h></span><span class="cp"></span> + +<span class="kt">void</span> <span class="nf">my_work_handler</span><span class="p">(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="n">work</span><span class="p">);</span> + +<span class="n">DECLARE_WORK</span><span class="p">(</span><span class="n">my_work</span><span class="p">,</span> <span class="n">my_work_handler</span><span class="p">);</span> +</pre></div> +</div> +<p>Or, if we want to initialize the work item separately:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">my_work_handler</span><span class="p">(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span> <span class="n">work</span><span class="p">);</span> + +<span class="k">struct</span> <span class="n">work_struct</span> <span class="n">my_work</span><span class="p">;</span> + +<span class="n">INIT_WORK</span><span class="p">(</span><span class="o">&</span><span class="n">my_work</span><span class="p">,</span> <span class="n">my_work_handler</span><span class="p">);</span> +</pre></div> +</div> +<p>Once declared and initialized, we can schedule the task using +<code class="xref c c-func docutils literal"><span class="pre">schedule_work()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">schedule_delayed_work()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">schedule_work</span><span class="p">(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="n">work</span><span class="p">);</span> + +<span class="n">schedule_delayed_work</span><span class="p">(</span><span class="k">struct</span> <span class="n">delayed_work</span> <span class="o">*</span><span class="n">work</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">delay</span><span class="p">);</span> +</pre></div> +</div> +<p><code class="xref c c-func docutils literal"><span class="pre">schedule_delayed_work()</span></code> can be used to plan a work item for +execution with a given delay. The delay time unit is jiffies.</p> +<p>Work items can not be masked but they can be canceled by calling +<code class="xref c c-func docutils literal"><span class="pre">cancel_delayed_work_sync()</span></code> or <code class="xref c c-func docutils literal"><span class="pre">cancel_work_sync()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="nf">cancel_work_sync</span><span class="p">(</span><span class="k">struct</span> <span class="n">delayed_work</span> <span class="o">*</span><span class="n">work</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">cancel_delayed_work_sync</span><span class="p">(</span><span class="k">struct</span> <span class="n">delayed_work</span> <span class="o">*</span><span class="n">work</span><span class="p">);</span> +</pre></div> +</div> +<p>The call only stops the subsequent execution of the work item. If the +work item is already running at the time of the call, it will continue +to run. In any case, when these calls return, it is guaranteed that +the task will no longer run.</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">While there are versions of these functions that are +not synchronous (.e.g. <code class="xref c c-func docutils literal"><span class="pre">cancel_work()</span></code>) do not +use them when you are performing cleanup work otherwise +race condition could occur.</p> +</div> +<p>We can wait for a workqueue to complete running all of its work items by calling <code class="xref c c-func docutils literal"><span class="pre">flush_scheduled_work()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">flush_scheduled_work</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> +</pre></div> +</div> +<p>This function is blocking and, therefore, can not be used in interrupt +context. The function will wait for all work items to be completed. +For delayed work items, <code class="xref c c-type docutils literal"><span class="pre">cancel_delayed_work</span></code> must be called +before <code class="xref c c-func docutils literal"><span class="pre">flush_scheduled_work()</span></code>.</p> +<p>Finally, the following functions can be used to schedule work items on +a particular processor (<code class="xref c c-func docutils literal"><span class="pre">schedule_delayed_work_on()</span></code>), or on all +processors (<code class="xref c c-func docutils literal"><span class="pre">schedule_on_each_cpu()</span></code>):</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="nf">schedule_delayed_work_on</span><span class="p">(</span><span class="kt">int</span> <span class="n">cpu</span><span class="p">,</span> <span class="k">struct</span> <span class="n">delayed_work</span> <span class="o">*</span><span class="n">work</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">delay</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">schedule_on_each_cpu</span><span class="p">(</span><span class="kt">void</span><span class="p">(</span><span class="o">*</span><span class="n">function</span><span class="p">)(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="p">));</span> +</pre></div> +</div> +<p>A usual sequence to initialize and schedule a work item is the following:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">my_work_handler</span><span class="p">(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="n">work</span><span class="p">);</span> + +<span class="k">struct</span> <span class="n">work_struct</span> <span class="n">my_work</span><span class="p">;</span> + +<span class="n">INIT_WORK</span><span class="p">(</span><span class="o">&</span><span class="n">my_work</span><span class="p">,</span> <span class="n">my_work_handler</span><span class="p">);</span> + +<span class="n">schedule_work</span><span class="p">(</span><span class="o">&</span><span class="n">my_work</span><span class="p">);</span> +</pre></div> +</div> +<p>And for waiting for termination of a work item:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">flush_scheduled_work</span><span class="p">();</span> +</pre></div> +</div> +<p>As you can see, the <em>my_work_handler</em> function receives the task as +the parameter. To be able to access the module's private data, you can +use <code class="xref c c-func docutils literal"><span class="pre">container_of()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">my_device_data</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">work_struct</span> <span class="n">my_work</span><span class="p">;</span> + <span class="c1">// ...</span> +<span class="p">};</span> + +<span class="kt">void</span> <span class="nf">my_work_handler</span><span class="p">(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="n">work</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span> <span class="n">my_data</span><span class="p">;</span> + + <span class="n">my_data</span> <span class="o">=</span> <span class="n">container_of</span><span class="p">(</span><span class="n">work</span><span class="p">,</span> <span class="k">struct</span> <span class="n">my_device_data</span><span class="p">,</span> <span class="n">my_work</span><span class="p">);</span> + <span class="c1">// ...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Scheduling work items with the functions above will run the handler in +the context of a kernel thread called <em>events/x</em>, where x is the +processor number. The kernel will initialize a kernel thread (or a +pool of workers) for each processor present in the system:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>$ ps -e +PID TTY TIME CMD +<span class="m">1</span>? <span class="m">00</span>:00:00 init +<span class="m">2</span> ? <span class="m">00</span>:00:00 ksoftirqd / <span class="m">0</span> +<span class="m">3</span> ? <span class="m">00</span>:00:00 events / <span class="m">0</span> <--- kernel thread that runs work items +<span class="m">4</span> ? <span class="m">00</span>:00:00 khelper +<span class="m">5</span> ? <span class="m">00</span>:00:00 kthread +<span class="m">7</span>? <span class="m">00</span>:00:00 kblockd / <span class="m">0</span> +<span class="m">8</span>? <span class="m">00</span>:00:00 kacpid +</pre></div> +</div> +<p>The above functions use a predefined workqueue (called events), and +they run in the context of the <em>events/x</em> thread, as noted +above. Although this is sufficient in most cases, it is a shared +resource and large delays in work items handlers can cause delays for +other queue users. For this reason there are functions for creating +additional queues.</p> +<p>A workqueue is represented by <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">workqueue_struct</span></code>. A new +workqueue can be created with these functions:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">workqueue_struct</span> <span class="o">*</span><span class="nf">create_workqueue</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">);</span> +<span class="k">struct</span> <span class="n">workqueue_struct</span> <span class="o">*</span><span class="nf">create_singlethread_workqueue</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">);</span> +</pre></div> +</div> +<p><code class="xref c c-func docutils literal"><span class="pre">create_workqueue()</span></code> uses one thread for each processor in the +system, and <code class="xref c c-func docutils literal"><span class="pre">create_singlethread_workqueue()</span></code> uses a single +thread.</p> +<p>To add a task in the new queue, use <code class="xref c c-func docutils literal"><span class="pre">queue_work()</span></code> or +<code class="xref c c-func docutils literal"><span class="pre">queue_delayed_work()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="nf">queue_work</span><span class="p">(</span><span class="k">struct</span> <span class="n">workqueue_struct</span> <span class="o">*</span> <span class="n">queue</span><span class="p">,</span> <span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="n">work</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">queue_delayed_work</span><span class="p">(</span><span class="k">struct</span> <span class="n">workqueue_struct</span> <span class="o">*</span><span class="n">queue</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">delayed_work</span> <span class="o">*</span> <span class="n">work</span> <span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">delay</span><span class="p">);</span> +</pre></div> +</div> +<p><code class="xref c c-func docutils literal"><span class="pre">queue_delayed_work()</span></code> can be used to plan a work for execution +with a given delay. The time unit for the delay is jiffies.</p> +<p>To wait for all work items to finish call <code class="xref c c-func docutils literal"><span class="pre">flush_workqueue()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">flush_workqueue</span><span class="p">(</span><span class="k">struct</span> <span class="n">worksqueue_struct</span> <span class="o">*</span> <span class="n">queue</span><span class="p">);</span> +</pre></div> +</div> +<p>And to destroy the workqueue call <code class="xref c c-func docutils literal"><span class="pre">destroy_workqueue()</span></code></p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">destroy_workqueue</span><span class="p">(</span><span class="k">struct</span> <span class="n">workqueue_struct</span> <span class="o">*</span><span class="n">queue</span><span class="p">);</span> +</pre></div> +</div> +<p>The next sequence declares and initializes an additional workqueue, +declares and initializes a work item and adds it to the queue:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">my_work_handler</span><span class="p">(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="n">work</span><span class="p">);</span> + +<span class="k">struct</span> <span class="n">work_struct</span> <span class="n">my_work</span><span class="p">;</span> +<span class="k">struct</span> <span class="n">workqueue_struct</span> <span class="o">*</span> <span class="n">my_workqueue</span><span class="p">;</span> + +<span class="n">my_workqueue</span> <span class="o">=</span> <span class="n">create_singlethread_workqueue</span><span class="p">(</span><span class="s">"my_workqueue"</span><span class="p">);</span> +<span class="n">INIT_WORK</span><span class="p">(</span><span class="o">&</span><span class="n">my_work</span><span class="p">,</span> <span class="n">my_work_handler</span><span class="p">);</span> + +<span class="n">queue_work</span><span class="p">(</span><span class="n">my_workqueue</span><span class="p">,</span> <span class="o">&</span><span class="n">my_work</span><span class="p">);</span> +</pre></div> +</div> +<p>And the next code sample shows how to remove the workqueue:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">flush_workqueue</span><span class="p">(</span><span class="n">my_workqueue</span><span class="p">);</span> +<span class="n">destroy_workqueue</span><span class="p">(</span><span class="n">my_workqueue</span><span class="p">);</span> +</pre></div> +</div> +<p>The work items planned with these functions will run in the context of +a new kernel thread called <em>my_workqueue</em>, the name passed to +<code class="xref c c-func docutils literal"><span class="pre">create_singlethread_workqueue()</span></code>.</p> +</div> +<div class="section" id="kernel-threads"> +<h2>Kernel threads<a class="headerlink" href="#kernel-threads" title="Permalink to this headline">¶</a></h2> +<p>Kernel threads have emerged from the need to run kernel code in +process context. Kernel threads are the basis of the workqueue +mechanism. Essentially, a kernel thread is a thread that only runs in +kernel mode and has no user address space or other user attributes.</p> +<p>To create a kernel thread, use <code class="xref c c-func docutils literal"><span class="pre">kthread_create()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/kthread.h></span><span class="cp"></span> + +<span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="nf">kthread_create</span><span class="p">(</span><span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">threadfn</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">),</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">namefmt</span><span class="p">[],</span> <span class="p">...);</span> +</pre></div> +</div> +<ul class="simple"> +<li><em>threadfn</em> is a function that will be run by the kernel thread</li> +<li><em>data</em> is a parameter to be sent to the function</li> +<li><em>namefmt</em> represents the kernel thread name, as it is displayed in +ps/top ; Can contain sequences %d , %s etc. Which will be replaced +according to the standard printf syntax.</li> +</ul> +<p>For example, the following call:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">kthread_create</span> <span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="s">"%skthread%d"</span><span class="p">,</span> <span class="s">"my"</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> +</pre></div> +</div> +<p>Will create a kernel thread with the name mykthread0.</p> +<p>The kernel thread created with this function will be stopped (in the +<em>TASK_INTERRUPTIBLE</em> state). To start the kernel thread, call the +<code class="xref c c-func docutils literal"><span class="pre">wake_up_process()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/sched.h></span><span class="cp"></span> + +<span class="kt">int</span> <span class="nf">wake_up_process</span><span class="p">(</span><span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">p</span><span class="p">);</span> +</pre></div> +</div> +<p>Alternatively, you can use <code class="xref c c-func docutils literal"><span class="pre">kthread_run()</span></code> to create and run a +kernel thread:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span> <span class="nf">kthread_run</span><span class="p">(</span><span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">threadfn</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">namefmt</span><span class="p">[],</span> <span class="p">...);</span> +</pre></div> +</div> +<p>Even if the programming restrictions for the function running within +the kernel thread are more relaxed and scheduling is closer to +scheduling in userspace, there are, however, some limitations to be +taken into account. We will list below the actions that can or can not +be made from a kernel thread:</p> +<ul class="simple"> +<li>can't access the user address space (even with copy_from_user, +copy_to_user) because a kernel thread does not have a user address +space</li> +<li>can't implement busy wait code that runs for a long time; if the +kernel is compiled without the preemptive option, that code will run +without being preempted by other kernel threads or user processes +thus hogging the system</li> +<li>can call blocking operations</li> +<li>can use spinlocks, but if the hold time of the lock is significant, +it is recommended to use mutexes</li> +</ul> +<p>The termination of a kernel thread is done voluntarily, within the +function running in the kernel thread, by calling <code class="xref c c-func docutils literal"><span class="pre">do_exit()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">fastcall</span> <span class="n">NORET_TYPE</span> <span class="kt">void</span> <span class="nf">do_exit</span><span class="p">(</span><span class="kt">long</span> <span class="n">code</span><span class="p">);</span> +</pre></div> +</div> +<p>Most of the implementations of kernel threads handlers use the same +model and it is recommended to start using the same model to avoid +common mistakes:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/kthread.h></span><span class="cp"></span> + +<span class="n">DECLARE_WAIT_QUEUE_HEAD</span><span class="p">(</span><span class="n">wq</span><span class="p">);</span> + +<span class="c1">// list events to be processed by kernel thread</span> +<span class="k">struct</span> <span class="n">list_head</span> <span class="n">events_list</span><span class="p">;</span> +<span class="k">struct</span> <span class="n">spin_lock</span> <span class="n">events_lock</span><span class="p">;</span> + + +<span class="c1">// structure describing the event to be processed</span> +<span class="k">struct</span> <span class="n">event</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="n">lh</span><span class="p">;</span> + <span class="kt">bool</span> <span class="n">stop</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">};</span> + +<span class="k">struct</span> <span class="n">event</span><span class="o">*</span> <span class="nf">get_next_event</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">event</span> <span class="o">*</span><span class="n">e</span><span class="p">;</span> + + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">events_lock</span><span class="p">);</span> + <span class="n">e</span> <span class="o">=</span> <span class="n">list_first_entry</span><span class="p">(</span><span class="o">&</span><span class="n">events_list</span><span class="p">,</span> <span class="k">struct</span> <span class="n">event</span><span class="o">*</span><span class="p">,</span> <span class="n">lh</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">e</span><span class="p">)</span> + <span class="n">list_del</span><span class="p">(</span><span class="o">&</span><span class="n">e</span><span class="o">-></span><span class="n">lh</span><span class="p">);</span> + <span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">events_lock</span><span class="p">);</span> + + <span class="k">return</span> <span class="n">e</span> +<span class="p">}</span> + +<span class="kt">int</span> <span class="nf">my_thread_f</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">event</span> <span class="o">*</span><span class="n">e</span><span class="p">;</span> + + <span class="k">while</span> <span class="p">(</span><span class="nb">true</span><span class="p">)</span> <span class="p">{</span> + <span class="n">wait_event</span><span class="p">(</span><span class="n">wq</span><span class="p">,</span> <span class="p">(</span><span class="n">e</span> <span class="o">=</span> <span class="n">get_next_event</span><span class="p">));</span> + + <span class="cm">/* Event processing */</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">e</span><span class="o">-></span><span class="n">stop</span><span class="p">)</span> + <span class="k">break</span><span class="p">;</span> + <span class="p">}</span> + + <span class="n">do_exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> +<span class="p">}</span> + +<span class="cm">/* start and start kthread */</span> +<span class="n">kthread_run</span><span class="p">(</span><span class="n">my_thread_f</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="s">"%skthread%d"</span><span class="p">,</span> <span class="s">"my"</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> +</pre></div> +</div> +<p>With the template above, the kernel thread requests can be issued +with:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">send_event</span><span class="p">(</span><span class="k">struct</span> <span class="n">event</span> <span class="o">*</span><span class="n">ev</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">events_lock</span><span class="p">);</span> + <span class="n">list_add</span><span class="p">(</span><span class="o">&</span><span class="n">ev</span><span class="o">-></span><span class="n">lh</span><span class="p">,</span> <span class="o">&</span><span class="n">events_list</span><span class="p">);</span> + <span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">events_lock</span><span class="p">);</span> + <span class="n">wake_up</span><span class="p">(</span><span class="o">&</span><span class="n">wq</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="further-reading"> +<h2>Further reading<a class="headerlink" href="#further-reading" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li><a class="reference external" href="http://lwn.net/images/pdf/LDD3/ch07.pdf">Linux Device Drivers, 3rd ed., Ch. 7: Time, Delays, and Deferred Work</a></li> +<li><a class="reference external" href="http://tldp.org/LDP/lkmpg/2.6/html/x1211.html">Scheduling Tasks</a></li> +<li><a class="reference external" href="http://lwn.net/Articles/23634/">Driver porting: the workqueue interface</a></li> +<li><a class="reference external" href="http://lwn.net/Articles/211279/">Workqueues get a rework</a></li> +<li><a class="reference external" href="http://lwn.net/Articles/65178/">Kernel threads made easy</a></li> +<li><a class="reference external" href="http://www.kernel.org/pub/linux/kernel/people/rusty/kernel-locking/index.html">Unreliable Guide to Locking</a></li> +</ul> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is deferred_work. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/deferred_work/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="section" id="intro"> +<h3>0. Intro<a class="headerlink" href="#intro" title="Permalink to this headline">¶</a></h3> +<p>Using <a class="reference external" href="http://elixir.free-electrons.com/linux/latest/source">LXR</a>, find the definitions of the following symbols:</p> +<ul class="simple"> +<li><code class="xref c c-macro docutils literal"><span class="pre">jiffies</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">timer_list</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">spin_lock_bh</span> <span class="pre">function()</span></code></li> +</ul> +</div> +<div class="section" id="timer"> +<h3>1.Timer<a class="headerlink" href="#timer" title="Permalink to this headline">¶</a></h3> +<p>We're looking at creating a simple kernel module that displays a +message at <em>TIMER_TIMEOUT</em> seconds after the module's kernel load.</p> +<p>Generate the skeleton for the task named <strong>1-2-timer</strong> and follow the +sections marked with <strong>TODO 1</strong> to complete the task.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>Use <cite>pr_info(...)</cite>. Messages will be displayed on the +console and can also be viewed using dmesg. When scheduling +the timer we need to use the absolute time of the system (in +the future) in number of ticks. The current time of the +system in the number of ticks is given by <code class="xref c c-type docutils literal"><span class="pre">jiffies</span></code>. +Thus, the absolute time we need to pass to the timer is +<code class="docutils literal"><span class="pre">jiffies</span> <span class="pre">+</span> <span class="pre">TIMER_TIMEOUT</span> <span class="pre">*</span> <span class="pre">HZ</span></code>.</p> +<p class="last">For more information review the <a class="reference internal" href="#timers">Timers</a> section.</p> +</div> +</div> +<div class="section" id="periodic-timer"> +<h3>2. Periodic timer<a class="headerlink" href="#periodic-timer" title="Permalink to this headline">¶</a></h3> +<p>Modify the previous module to display the message in once every +TIMER_TIMEOUT seconds. Follow the section marked with <strong>TODO 2</strong> in the +skeleton.</p> +</div> +<div class="section" id="timer-control-using-ioctl"> +<h3>3. Timer control using ioctl<a class="headerlink" href="#timer-control-using-ioctl" title="Permalink to this headline">¶</a></h3> +<p>We plan to display information about the current process after N +seconds of receiving a ioctl call from user space. N is transmitted as +ioctl parameter.</p> +<p>Generate the skeleton for the task named <strong>3-4-5-deferred</strong> and +follow the sections marked with <strong>TODO 1</strong> in the skeleton driver.</p> +<p>You will need to implement the following ioctl operations.</p> +<ul class="simple"> +<li>MY_IOCTL_TIMER_SET to schedule a timer to run after a number of +seconds which is received as an argument to ioctl. The timer does +not run periodically. +* This command receives directly a value, not a pointer.</li> +<li>MY_IOCTL_TIMER_CANCEL to deactivate the timer.</li> +</ul> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Review <a class="reference internal" href="../so2/lab3-device-drivers.html#ioctl"><span class="std std-ref">ioctl</span></a> for a way to access the ioctl argument.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Review the <a class="reference internal" href="#timers">Timers</a> section for information on enabling / +disabling a timer. In the timer handler, display the current +process identifier (PID) and the process executable image name.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">You can find the current process identifier using the <em>pid</em> +and <em>comm</em> fields of the current process. For details, +review <span class="xref std std-ref">proc-info</span>.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">To use the device driver from userspace you must create the +device character file <em>/dev/deferred</em> using the mknod +utility. Alternatively, you can run the +<em>3-4-5-deferred/kernel/makenode</em> script that performs this +operation.</p> +</div> +<p>Enable and disable the timer by calling user-space ioctl +operations. Use the <em>3-4-5-deferred/user/test</em> program to test +planning and canceling of the timer. The program receives the ioctl +type operation and its parameters (if any) on the command line.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>Run the test executable without arguments to observe the +command line options it accepts.</p> +<p>To enable the timer after 3 seconds use:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="p">.</span><span class="o">/</span><span class="n">test</span> <span class="n">s</span> <span class="mi">3</span> +</pre></div> +</div> +<p>To disable the timer use:</p> +<div class="last highlight-c"><div class="highlight"><pre><span></span><span class="p">.</span><span class="o">/</span><span class="n">test</span> <span class="n">c</span> +</pre></div> +</div> +</div> +<p>Note that every time the current process the timer runs from is +<em>swapper/0</em> with PID 0. This process is the idle process. It is +running when there is nothing else to run on. Because the virtual +machine is very light and does not do much it is natural to see this +process most of the time.</p> +</div> +<div class="section" id="blocking-operations"> +<h3>4. Blocking operations<a class="headerlink" href="#blocking-operations" title="Permalink to this headline">¶</a></h3> +<p>Next we want to see what happens when we perform blocking operations +in a timer routine. For this we try to call in the timer-handling +routines a function called alloc_io() that simulates a blocking +operation.</p> +<p>Modify the module so that when you receive <em>MY_IOCTL_TIMER_ALLOC</em> +command the timer handler will call <code class="xref c c-func docutils literal"><span class="pre">alloc_io()</span></code>. Follow the +sections marked with <strong>TODO 2</strong> in the skeleton.</p> +<p>Use the same timer. To differentiate functionality in the timer +handler, use a flag in the device structure. Use the +<em>TIMER_TYPE_ALLOC</em> and <em>TIMER_TYPE_SET</em> macros defined in the code +skeleton. For initialization, use TIMER_TYPE_NONE.</p> +<p>Run the test program to verify the functionality of task 3. Run the +test program again to call <code class="xref c c-func docutils literal"><span class="pre">alloc_io()</span></code>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The driver causes an error because a blocking function is +called in the atomic context (the timer handler runs +interrupt context).</p> +</div> +</div> +<div class="section" id="workqueues-1"> +<h3>5. Workqueues<a class="headerlink" href="#workqueues-1" title="Permalink to this headline">¶</a></h3> +<p>We will modify the module to prevent the error observed in the +previous task.</p> +<p>To do so, lets call <code class="xref c c-func docutils literal"><span class="pre">alloc_io()</span></code> using workqueues. Schedule a +work item from the timer handler In the work handler (running in +process context) call the <code class="xref c c-func docutils literal"><span class="pre">alloc_io()</span></code>. Follow the sections +marked with <strong>TODO 3</strong> in the skeleton and review the <a class="reference internal" href="#workqueues">Workqueues</a> +section if needed.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Add a new field with the type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">work_struct</span></code> +in your device structure. Initialize this field. Schedule +the work from the timer handler using <code class="xref c c-func docutils literal"><span class="pre">schedule_work()</span></code>. +Schedule the timer handler aften N seconds from the ioctl.</p> +</div> +</div> +<div class="section" id="kernel-thread"> +<h3>6. Kernel thread<a class="headerlink" href="#kernel-thread" title="Permalink to this headline">¶</a></h3> +<p>Implement a simple module that creates a kernel thread that shows the +current process identifier.</p> +<p>Generate the skeleton for the task named <strong>6-kthread</strong> and follow the +TODOs from the skeleton.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>There are two options for creating and running a thread:</p> +<ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">kthread_run()</span></code> to create and run the thread</li> +<li><code class="xref c c-func docutils literal"><span class="pre">kthread_create()</span></code> to create a suspended thread and +then start it running with <code class="xref c c-func docutils literal"><span class="pre">wake_up_process()</span></code>.</li> +</ul> +<p class="last">Review the <a class="reference internal" href="#kernel-threads">Kernel Threads</a> section if needed.</p> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p>Synchronize the thread termination with module unloading:</p> +<ul class="last simple"> +<li>The thread should finish when the module is unloaded</li> +<li>Wait for the kernel thread to exit before continuing +with unloading</li> +</ul> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>For synchronization use two wait queues and two flags.</p> +<p>Review <span class="xref std std-ref">waiting-queues</span> on how to use waiting queue.</p> +<p class="last">Use atomic variables for flags. Review <a class="reference internal" href="../so2/lab2-kernel-api.html#atomic-variables"><span class="std std-ref">Atomic variables</span></a>.</p> +</div> +</div> +<div class="section" id="buffer-shared-between-timer-and-process"> +<h3>7. Buffer shared between timer and process<a class="headerlink" href="#buffer-shared-between-timer-and-process" title="Permalink to this headline">¶</a></h3> +<p>The purpose of this task is to exercise the synchronization between a +deferrable action (a timer) and process context. Set up a periodic +timer that monitors a list of processes. If one of the processes +terminate a message is printed. Processes can be dynamically added to +the list. Use the <em>3-4-5-deferred/kernel/</em> skeleton as a base and +follow the <strong>TODO 4</strong> markings to complete the task.</p> +<p>When the <em>MY_IOCTL_TIMER_MON</em> command is received check that the given +process exists and if so add to the monitored list of +processes and then arm the timer after setting its type.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use <code class="xref c c-func docutils literal"><span class="pre">get_proc()</span></code> which checks the pid, finds the +associated <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code> and allocates a +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mon_proc</span></code> item you can add to your +list. Note that the function also increases the reference +counter of the task, so that its memory won't be free when +the task terminates.</p> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">Use a spinlock to protect the access to the list. Note +that since we share data with the timer handler we need +to disable bottom-half handlers in addition to taking +the lock. Review the <a class="reference internal" href="#locking">Locking</a> section.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Collect the information every second from a timer. Use the +existing timer and add new behaviour for it via the +TIMER_TYPE_ACCT. To set the flag, use the <em>t</em> argument of +the test program.</p> +</div> +<p>In the timer handler iterate over the list of monitored processes and +check if they have terminated. If so, print the process name and pid +then remove the process from the list, decrement the task usage +counter so that it's memory can be free and finally free the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mon_proc</span></code> structure.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use the <em>state</em> field of <code class="xref c c-func docutils literal"><span class="pre">struct</span> <span class="pre">task_struct()</span></code>. A +task has terminated if its state is <em>TASK_DEAD</em>.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use <code class="xref c c-func docutils literal"><span class="pre">put_task_struct()</span></code> to decrement the task usage +counter.</p> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">Make sure you protect the list access with a +spinlock. The simple variant will suffice.</p> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">Make sure to use the safe iteration over the list since +we may need to remove an item from the list.</p> +</div> +<p>Rearm the timer after checking the list.</p> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="interrupts.html" class="btn btn-neutral float-left" title="I/O access and Interrupts" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="block_device_drivers.html" class="btn btn-neutral float-right" title="Block Device Drivers" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/labs/device_drivers.html b/refs/pull/405/merge/labs/device_drivers.html new file mode 100644 index 00000000..a5663090 --- /dev/null +++ b/refs/pull/405/merge/labs/device_drivers.html @@ -0,0 +1,1200 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Character device drivers — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="I/O access and Interrupts" href="interrupts.html" /> + <link rel="prev" title="Kernel API" href="kernel_api.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_api.html">Kernel API</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Character device drivers</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#laboratory-objectives">Laboratory objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="#overview">Overview</a></li> +<li class="toctree-l2"><a class="reference internal" href="#majors-and-minors">Majors and minors</a></li> +<li class="toctree-l2"><a class="reference internal" href="#data-structures-for-a-character-device">Data structures for a character device</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#struct-file-operations"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code></a></li> +<li class="toctree-l3"><a class="reference internal" href="#inode-and-file-structures"><code class="docutils literal"><span class="pre">inode</span></code> and <code class="docutils literal"><span class="pre">file</span></code> structures</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#implementation-of-operations">Implementation of operations</a></li> +<li class="toctree-l2"><a class="reference internal" href="#registration-and-unregistration-of-character-devices">Registration and unregistration of character devices</a></li> +<li class="toctree-l2"><a class="reference internal" href="#access-to-the-address-space-of-the-process">Access to the address space of the process</a></li> +<li class="toctree-l2"><a class="reference internal" href="#open-and-release">Open and release</a></li> +<li class="toctree-l2"><a class="reference internal" href="#read-and-write">Read and write</a></li> +<li class="toctree-l2"><a class="reference internal" href="#ioctl-1">ioctl</a></li> +<li class="toctree-l2"><a class="reference internal" href="#waiting-queues">Waiting queues</a></li> +<li class="toctree-l2"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#intro">0. Intro</a></li> +<li class="toctree-l3"><a class="reference internal" href="#register-unregister">1. Register/unregister</a></li> +<li class="toctree-l3"><a class="reference internal" href="#register-an-already-registered-major">2. Register an already registered major</a></li> +<li class="toctree-l3"><a class="reference internal" href="#open-and-close">3. Open and close</a></li> +<li class="toctree-l3"><a class="reference internal" href="#access-restriction">4. Access restriction</a></li> +<li class="toctree-l3"><a class="reference internal" href="#read-operation">5. Read operation</a></li> +<li class="toctree-l3"><a class="reference internal" href="#write-operation">6. Write operation</a></li> +<li class="toctree-l3"><a class="reference internal" href="#ioctl-operation">7. ioctl operation</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#extra-exercises">Extra Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#ioctl-with-messaging">Ioctl with messaging</a></li> +<li class="toctree-l3"><a class="reference internal" href="#ioctl-with-waiting-queues">Ioctl with waiting queues</a></li> +<li class="toctree-l3"><a class="reference internal" href="#o-nonblock-implementation">O_NONBLOCK implementation</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Character device drivers</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/labs/device_drivers.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="character-device-drivers"> +<h1>Character device drivers<a class="headerlink" href="#character-device-drivers" title="Permalink to this headline">¶</a></h1> +<div class="section" id="laboratory-objectives"> +<h2>Laboratory objectives<a class="headerlink" href="#laboratory-objectives" title="Permalink to this headline">¶</a></h2> +<blockquote> +<div><ul class="simple"> +<li>understand the concepts behind character device driver</li> +<li>understand the various operations that can be performed on character devices</li> +<li>working with waiting queues</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="overview"> +<h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline">¶</a></h2> +<p>In UNIX, hardware devices are accessed by the user through special device +files. These files are grouped into the /dev directory, and system calls +<code class="docutils literal"><span class="pre">open</span></code>, <code class="docutils literal"><span class="pre">read</span></code>, <code class="docutils literal"><span class="pre">write</span></code>, <code class="docutils literal"><span class="pre">close</span></code>, <code class="docutils literal"><span class="pre">lseek</span></code>, <code class="docutils literal"><span class="pre">mmap</span></code> etc. are +redirected by the operating system to the device driver associated with the +physical device. The device driver is a kernel component (usually a module) +that interacts with a hardware device.</p> +<p>In the UNIX world there are two categories of device files and thus +device drivers: character and block. This division is done by the speed, +volume and way of organizing the data to be transferred from the device to the +system and vice versa. In the first category, there are slow devices, which +manage a small amount of data, and access to data does not require frequent +seek queries. Examples are devices such as keyboard, mouse, serial ports, +sound card, joystick. In general, operations with these devices (read, write) +are performed sequentially byte by byte. The second category includes devices +where data volume is large, data is organized on blocks, and search is common. +Examples of devices that fall into this category are hard drives, cdroms, ram +disks, magnetic tape drives. For these devices, reading and writing is done at +the data block level.</p> +<p>For the two types of device drivers, the Linux kernel offers different APIs. +If for character devices system calls go directly to device drivers, in case of +block devices, the drivers do not work directly with system calls. In +the case of block devices, communication between the user-space and the block +device driver is mediated by the file management subsystem and the block device +subsystem. The role of these subsystems is to prepare the device driver's +necessary resources (buffers), to keep the recently read data in the cache +buffer, and to order the read and write operations for performance reasons.</p> +</div> +<div class="section" id="majors-and-minors"> +<h2>Majors and minors<a class="headerlink" href="#majors-and-minors" title="Permalink to this headline">¶</a></h2> +<p>In UNIX, the devices traditionally had a unique, fixed identifier associated +with them. This tradition is preserved in Linux, although identifiers can be +dynamically allocated (for compatibility reasons, most drivers still use static +identifiers). The identifier consists of two parts: major and minor. The first +part identifies the device type (IDE disk, SCSI disk, serial port, etc.) +and the second one identifies the device (first disk, second serial port, +etc.). Most times, the major identifies the driver, while the minor identifies +each physical device served by the driver. In general, a driver will have a +major associate and will be responsible for all minors associated with that +major.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ ls -la /dev/hda? /dev/ttyS? +brw-rw---- <span class="m">1</span> root disk <span class="m">3</span>, <span class="m">1</span> <span class="m">2004</span>-09-18 <span class="m">14</span>:51 /dev/hda1 +brw-rw---- <span class="m">1</span> root disk <span class="m">3</span>, <span class="m">2</span> <span class="m">2004</span>-09-18 <span class="m">14</span>:51 /dev/hda2 +crw-rw---- <span class="m">1</span> root dialout <span class="m">4</span>, <span class="m">64</span> <span class="m">2004</span>-09-18 <span class="m">14</span>:52 /dev/ttyS0 +crw-rw---- <span class="m">1</span> root dialout <span class="m">4</span>, <span class="m">65</span> <span class="m">2004</span>-09-18 <span class="m">14</span>:52 /dev/ttyS1 +</pre></div> +</div> +<p>As can be seen from the example above, device-type information can be found +using the ls command. The special character files are identified by the <code class="docutils literal"><span class="pre">c</span></code> +character in the first column of the command output, and the block type by the +character <code class="docutils literal"><span class="pre">b</span></code>. In columns <code class="docutils literal"><span class="pre">5</span></code> and <code class="docutils literal"><span class="pre">6</span></code> of the result you can see the +major, respectively the minor for each device.</p> +<p>Certain major identifiers are statically assigned to devices (in the +<code class="docutils literal"><span class="pre">Documentation/admin-guide/devices.txt</span></code> file from the kernel sources). When choosing the +identifier for a new device, you can use two methods: static (choose a number +that does not seem to be used already) or dynamically. In /proc/devices are the +loaded devices, along with the major identifier.</p> +<p>To create a device type file, use the <code class="docutils literal"><span class="pre">mknod</span></code> command; the command receives the +type (<code class="docutils literal"><span class="pre">block</span></code> or <code class="docutils literal"><span class="pre">character</span></code>), <code class="docutils literal"><span class="pre">major</span></code> and <code class="docutils literal"><span class="pre">minor</span></code> of the device +(<code class="docutils literal"><span class="pre">mknod</span> <span class="pre">name</span> <span class="pre">type</span> <span class="pre">major</span> <span class="pre">minor</span></code>). Thus, if you want to create a character device +named <code class="docutils literal"><span class="pre">mycdev</span></code> with the major <code class="docutils literal"><span class="pre">42</span></code> and minor <code class="docutils literal"><span class="pre">0</span></code>, use the command:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># mknod /dev/mycdev c 42 0</span> +</pre></div> +</div> +<p>To create the block device with the name <code class="docutils literal"><span class="pre">mybdev</span></code> with the major 240 and minor 0 +the command will be:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># mknod /dev/mybdev b 240 0</span> +</pre></div> +</div> +<p>Next, we'll refer to character devices as drivers.</p> +</div> +<div class="section" id="data-structures-for-a-character-device"> +<h2>Data structures for a character device<a class="headerlink" href="#data-structures-for-a-character-device" title="Permalink to this headline">¶</a></h2> +<p>In the kernel, a character-type device is represented by +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">cdev</span></code>, a structure used to register it in the +system. Most driver operations use three important structures: +<code class="docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code>, <code class="docutils literal"><span class="pre">struct</span> <span class="pre">file</span></code> and <code class="docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code>.</p> +<div class="section" id="struct-file-operations"> +<h3><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code><a class="headerlink" href="#struct-file-operations" title="Permalink to this headline">¶</a></h3> +<p>As mentioned above, the character device drivers receive unaltered system calls +made by users over device-type files. Consequently, implementation of a character +device driver means implementing the system calls specific to files: <code class="docutils literal"><span class="pre">open</span></code>, +<code class="docutils literal"><span class="pre">close</span></code>, <code class="docutils literal"><span class="pre">read</span></code>, <code class="docutils literal"><span class="pre">write</span></code>, <code class="docutils literal"><span class="pre">lseek</span></code>, <code class="docutils literal"><span class="pre">mmap</span></code>, etc. These operations are +described in the fields of the <code class="docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code> structure:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> + +<span class="k">struct</span> <span class="n">file_operations</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">owner</span><span class="p">;</span> + <span class="n">loff_t</span> <span class="p">(</span><span class="o">*</span><span class="n">llseek</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="n">loff_t</span><span class="p">,</span> <span class="kt">int</span><span class="p">);</span> + <span class="kt">ssize_t</span> <span class="p">(</span><span class="o">*</span><span class="n">read</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="kt">char</span> <span class="n">__user</span> <span class="o">*</span><span class="p">,</span> <span class="kt">size_t</span><span class="p">,</span> <span class="n">loff_t</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">ssize_t</span> <span class="p">(</span><span class="o">*</span><span class="n">write</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">__user</span> <span class="o">*</span><span class="p">,</span> <span class="kt">size_t</span><span class="p">,</span> <span class="n">loff_t</span> <span class="o">*</span><span class="p">);</span> + <span class="p">[...]</span> + <span class="kt">long</span> <span class="p">(</span><span class="o">*</span><span class="n">unlocked_ioctl</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">);</span> + <span class="p">[...]</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">open</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">flush</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="n">fl_owner_t</span> <span class="n">id</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">release</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">);</span> + <span class="p">[...]</span> +</pre></div> +</div> +<p>It can be noticed that the signature of the function differs from the system +call that the user uses. The operating system sits between the user and +the device driver to simplify implementation in the device driver.</p> +<p><code class="docutils literal"><span class="pre">open</span></code> does not receive the parameter path or the various parameters that control +the file opening mode. Similarly, <code class="docutils literal"><span class="pre">read</span></code>, <code class="docutils literal"><span class="pre">write</span></code>, <code class="docutils literal"><span class="pre">release</span></code>, <code class="docutils literal"><span class="pre">ioctl</span></code>, <code class="docutils literal"><span class="pre">lseek</span></code> +do not receive as a parameter a file descriptor. Instead, these routines receive as +parameters two structures: <code class="docutils literal"><span class="pre">file</span></code> and <code class="docutils literal"><span class="pre">inode</span></code>. Both structures represent a file, +but from different perspectives.</p> +<dl class="docutils"> +<dt>Most parameters for the presented operations have a direct meaning:</dt> +<dd><ul class="first last simple"> +<li><code class="docutils literal"><span class="pre">file</span></code> and <code class="docutils literal"><span class="pre">inode</span></code> identifies the device type file;</li> +<li><code class="docutils literal"><span class="pre">size</span></code> is the number of bytes to be read or written;</li> +<li><code class="docutils literal"><span class="pre">offset</span></code> is the displacement to be read or written (to be updated +accordingly);</li> +<li><code class="docutils literal"><span class="pre">user_buffer</span></code> user buffer from which it reads / writes;</li> +<li><code class="docutils literal"><span class="pre">whence</span></code> is the way to seek (the position where the search operation starts);</li> +<li><code class="docutils literal"><span class="pre">cmd</span></code> and <code class="docutils literal"><span class="pre">arg</span></code> are the parameters sent by the users to the ioctl call (IO +control).</li> +</ul> +</dd> +</dl> +</div> +<div class="section" id="inode-and-file-structures"> +<h3><code class="docutils literal"><span class="pre">inode</span></code> and <code class="docutils literal"><span class="pre">file</span></code> structures<a class="headerlink" href="#inode-and-file-structures" title="Permalink to this headline">¶</a></h3> +<p>An <code class="docutils literal"><span class="pre">inode</span></code> represents a file from the point of view of the file system. Attributes +of an inode are the size, rights, times associated with the file. An inode uniquely +identifies a file in a file system.</p> +<p>The <code class="docutils literal"><span class="pre">file</span></code> structure is still a file, but closer to the user's point of view. +From the attributes of the file structure we list: the inode, the file name, +the file opening attributes, the file position. All open files at a given time +have associated a <code class="docutils literal"><span class="pre">file</span></code> structure.</p> +<p>To understand the differences between inode and file, we will use an analogy +from object-oriented programming: if we consider a class inode, then the files +are objects, that is, instances of the inode class. Inode represents the static +image of the file (the inode has no state), while the file represents the +dynamic image of the file (the file has state).</p> +<p>Returning to device drivers, the two entities have almost always standard ways +of using: the inode is used to determine the major and minor of the device on +which the operation is performed, and the file is used to determine the flags +with which the file was opened, but also to save and access (later) private +data.</p> +<p>The file structure contains, among many fields:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">f_mode</span></code>, which specifies read (<code class="docutils literal"><span class="pre">FMODE_READ</span></code>) or write +(<code class="docutils literal"><span class="pre">FMODE_WRITE</span></code>);</li> +<li><code class="docutils literal"><span class="pre">f_flags</span></code>, which specifies the file opening flags (<code class="docutils literal"><span class="pre">O_RDONLY</span></code>, +<code class="docutils literal"><span class="pre">O_NONBLOCK</span></code>, <code class="docutils literal"><span class="pre">O_SYNC</span></code>, <code class="docutils literal"><span class="pre">O_APPEND</span></code>, <code class="docutils literal"><span class="pre">O_TRUNC</span></code>, etc.);</li> +<li><code class="docutils literal"><span class="pre">f_op</span></code>, which specifies the operations associated with the file (pointer to +the <code class="docutils literal"><span class="pre">file_operations</span></code> structure );</li> +<li><code class="docutils literal"><span class="pre">private_data</span></code>, a pointer that can be used by the programmer to store +device-specific data; The pointer will be initialized to a memory location +assigned by the programmer.</li> +<li><code class="docutils literal"><span class="pre">f_pos</span></code>, the offset within the file</li> +</ul> +</div></blockquote> +<p>The inode structure contains, among much information, an <code class="docutils literal"><span class="pre">i_cdev</span></code> +field, which is a pointer to the structure that defines the character +device (when the inode corresponds to a character device).</p> +</div> +</div> +<div class="section" id="implementation-of-operations"> +<h2>Implementation of operations<a class="headerlink" href="#implementation-of-operations" title="Permalink to this headline">¶</a></h2> +<p>To implement a device driver, it is recommended that you create a structure +that contains information about the device, information used in the module. In +the case of a driver for a character device, the structure will contain a cdev +structure field to refer to the device. The following example uses the struct +my_device_data:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/cdev.h></span><span class="cp"></span> + +<span class="k">struct</span> <span class="n">my_device_data</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">cdev</span> <span class="n">cdev</span><span class="p">;</span> + <span class="cm">/* my data starts here */</span> + <span class="c1">//...</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_open</span><span class="p">(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="n">my_data</span><span class="p">;</span> + + <span class="n">my_data</span> <span class="o">=</span> <span class="n">container_of</span><span class="p">(</span><span class="n">inode</span><span class="o">-></span><span class="n">i_cdev</span><span class="p">,</span> <span class="k">struct</span> <span class="n">my_device_data</span><span class="p">,</span> <span class="n">cdev</span><span class="p">);</span> + + <span class="n">file</span><span class="o">-></span><span class="n">private_data</span> <span class="o">=</span> <span class="n">my_data</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_read</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> <span class="kt">char</span> <span class="n">__user</span> <span class="o">*</span><span class="n">user_buffer</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">size</span><span class="p">,</span> <span class="n">loff_t</span> <span class="o">*</span><span class="n">offset</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="n">my_data</span><span class="p">;</span> + + <span class="n">my_data</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="p">)</span> <span class="n">file</span><span class="o">-></span><span class="n">private_data</span><span class="p">;</span> + + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>A structure like <code class="docutils literal"><span class="pre">my_device_data</span></code> will contain the data associated with a device. +The <code class="docutils literal"><span class="pre">cdev</span></code> field (<code class="docutils literal"><span class="pre">cdev</span></code> type) is a character-type device and is used to record it +in the system and identify the device. The pointer to the <code class="docutils literal"><span class="pre">cdev</span></code> member can be +found using the <code class="docutils literal"><span class="pre">i_cdev</span></code> field of the <code class="docutils literal"><span class="pre">inode</span></code> structure (using the <code class="docutils literal"><span class="pre">container_of</span></code> +macro). In the private_data field of the file structure, information can be +stored at open which is then available in the <code class="docutils literal"><span class="pre">read</span></code>, <code class="docutils literal"><span class="pre">write</span></code>, <code class="docutils literal"><span class="pre">release</span></code>, etc. +routines.</p> +</div> +<div class="section" id="registration-and-unregistration-of-character-devices"> +<h2>Registration and unregistration of character devices<a class="headerlink" href="#registration-and-unregistration-of-character-devices" title="Permalink to this headline">¶</a></h2> +<p>The registration/unregistration of a device is made by specifying the major and +minor. The <code class="docutils literal"><span class="pre">dev_t</span></code> type is used to keep the identifiers of a device (both major +and minor) and can be obtained using the <code class="docutils literal"><span class="pre">MKDEV</span></code> macro.</p> +<p>For the static assignment and unallocation of device identifiers, the +<code class="docutils literal"><span class="pre">register_chrdev_region</span></code> and <code class="docutils literal"><span class="pre">unregister_chrdev_region</span></code> functions are used:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> + +<span class="kt">int</span> <span class="nf">register_chrdev_region</span><span class="p">(</span><span class="kt">dev_t</span> <span class="n">first</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">count</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">unregister_chrdev_region</span><span class="p">(</span><span class="kt">dev_t</span> <span class="n">first</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">count</span><span class="p">);</span> +</pre></div> +</div> +<p>It is recommended that device identifiers be dynamically assigned to the +<code class="docutils literal"><span class="pre">alloc_chrdev_region</span></code> function.</p> +<p>Below sequence reserves <code class="docutils literal"><span class="pre">my_minor_count</span></code> devices, starting with <code class="docutils literal"><span class="pre">my_major</span></code> +major and <code class="docutils literal"><span class="pre">my_first_minor</span></code> minor (if the max value for minor is exceeded, +move to the next major):</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> +<span class="p">...</span> + +<span class="n">err</span> <span class="o">=</span> <span class="n">register_chrdev_region</span><span class="p">(</span><span class="n">MKDEV</span><span class="p">(</span><span class="n">my_major</span><span class="p">,</span> <span class="n">my_first_minor</span><span class="p">),</span> <span class="n">my_minor_count</span><span class="p">,</span> + <span class="s">"my_device_driver"</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* report error */</span> + <span class="k">return</span> <span class="n">err</span><span class="p">;</span> +<span class="p">}</span> +<span class="p">...</span> +</pre></div> +</div> +<p>After assigning the identifiers, the character device will have to be +initialized (<code class="docutils literal"><span class="pre">cdev_init</span></code>) and the kernel will have to be notified(<code class="docutils literal"><span class="pre">cdev_add</span></code>). The +<code class="docutils literal"><span class="pre">cdev_add</span></code> function must be called only after the device is ready to receive +calls. Removing a device is done using the <code class="docutils literal"><span class="pre">cdev_del</span></code> function.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/cdev.h></span><span class="cp"></span> + +<span class="kt">void</span> <span class="nf">cdev_init</span><span class="p">(</span><span class="k">struct</span> <span class="n">cdev</span> <span class="o">*</span><span class="n">cdev</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file_operations</span> <span class="o">*</span><span class="n">fops</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">cdev_add</span><span class="p">(</span><span class="k">struct</span> <span class="n">cdev</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> <span class="kt">dev_t</span> <span class="n">num</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">count</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">cdev_del</span><span class="p">(</span><span class="k">struct</span> <span class="n">cdev</span> <span class="o">*</span><span class="n">dev</span><span class="p">);</span> +</pre></div> +</div> +<p>The following sequence registers and initializes MY_MAX_MINORS devices:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/cdev.h></span><span class="cp"></span> + +<span class="cp">#define MY_MAJOR 42</span> +<span class="cp">#define MY_MAX_MINORS 5</span> + +<span class="k">struct</span> <span class="n">my_device_data</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">cdev</span> <span class="n">cdev</span><span class="p">;</span> + <span class="cm">/* my data starts here */</span> + <span class="c1">//...</span> +<span class="p">};</span> + +<span class="k">struct</span> <span class="n">my_device_data</span> <span class="n">devs</span><span class="p">[</span><span class="n">MY_MAX_MINORS</span><span class="p">];</span> + +<span class="k">const</span> <span class="k">struct</span> <span class="n">file_operations</span> <span class="n">my_fops</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">owner</span> <span class="o">=</span> <span class="n">THIS_MODULE</span><span class="p">,</span> + <span class="p">.</span><span class="n">open</span> <span class="o">=</span> <span class="n">my_open</span><span class="p">,</span> + <span class="p">.</span><span class="n">read</span> <span class="o">=</span> <span class="n">my_read</span><span class="p">,</span> + <span class="p">.</span><span class="n">write</span> <span class="o">=</span> <span class="n">my_write</span><span class="p">,</span> + <span class="p">.</span><span class="n">release</span> <span class="o">=</span> <span class="n">my_release</span><span class="p">,</span> + <span class="p">.</span><span class="n">unlocked_ioctl</span> <span class="o">=</span> <span class="n">my_ioctl</span> +<span class="p">};</span> + +<span class="kt">int</span> <span class="nf">init_module</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="n">err</span><span class="p">;</span> + + <span class="n">err</span> <span class="o">=</span> <span class="n">register_chrdev_region</span><span class="p">(</span><span class="n">MKDEV</span><span class="p">(</span><span class="n">MY_MAJOR</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">MY_MAX_MINORS</span><span class="p">,</span> + <span class="s">"my_device_driver"</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* report error */</span> + <span class="k">return</span> <span class="n">err</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">for</span><span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">MY_MAX_MINORS</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* initialize devs[i] fields */</span> + <span class="n">cdev_init</span><span class="p">(</span><span class="o">&</span><span class="n">devs</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">cdev</span><span class="p">,</span> <span class="o">&</span><span class="n">my_fops</span><span class="p">);</span> + <span class="n">cdev_add</span><span class="p">(</span><span class="o">&</span><span class="n">devs</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">cdev</span><span class="p">,</span> <span class="n">MKDEV</span><span class="p">(</span><span class="n">MY_MAJOR</span><span class="p">,</span> <span class="n">i</span><span class="p">),</span> <span class="mi">1</span><span class="p">);</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>While the following sequence deletes and unregisters them:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">cleanup_module</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">i</span><span class="p">;</span> + + <span class="k">for</span><span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">MY_MAX_MINORS</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* release devs[i] fields */</span> + <span class="n">cdev_del</span><span class="p">(</span><span class="o">&</span><span class="n">devs</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">cdev</span><span class="p">);</span> + <span class="p">}</span> + <span class="n">unregister_chrdev_region</span><span class="p">(</span><span class="n">MKDEV</span><span class="p">(</span><span class="n">MY_MAJOR</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">MY_MAX_MINORS</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Initialization of the struct my_fops used the initialization +of members by name, defined in C99 standard (see designated +initializers and the file_operations structure). Structure +members who do not explicitly appear in this initialization +will be set to the default value for their type. For +example, after the initialization above, <code class="docutils literal"><span class="pre">my_fops.mmap</span></code> will +be NULL.</p> +</div> +</div> +<div class="section" id="access-to-the-address-space-of-the-process"> +<span id="access-to-process-address-space"></span><h2>Access to the address space of the process<a class="headerlink" href="#access-to-the-address-space-of-the-process" title="Permalink to this headline">¶</a></h2> +<p>A driver for a device is the interface between an application and hardware. As +a result, we often have to access user-space data. Accessing it can not be done +directly (by dereferencing a user-space pointer). Direct access of a +user-space pointer can lead to incorrect behavior (depending on architecture, a +user-space pointer may not be valid or mapped to kernel-space), a kernel oops +(the user-mode pointer can refer to a non-resident memory area) or security +issues. Proper access to user-space data is done by calling the macros / +functions below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><asm/uaccess.h></span><span class="cp"></span> + +<span class="n">put_user</span><span class="p">(</span><span class="n">type</span> <span class="n">val</span><span class="p">,</span> <span class="n">type</span> <span class="o">*</span><span class="n">address</span><span class="p">);</span> +<span class="n">get_user</span><span class="p">(</span><span class="n">type</span> <span class="n">val</span><span class="p">,</span> <span class="n">type</span> <span class="o">*</span><span class="n">address</span><span class="p">);</span> +<span class="kt">unsigned</span> <span class="kt">long</span> <span class="nf">copy_to_user</span><span class="p">(</span><span class="kt">void</span> <span class="n">__user</span> <span class="o">*</span><span class="n">to</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">from</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">n</span><span class="p">);</span> +<span class="kt">unsigned</span> <span class="kt">long</span> <span class="nf">copy_from_user</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">to</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="n">__user</span> <span class="o">*</span><span class="n">from</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">n</span><span class="p">);</span> +</pre></div> +</div> +<p>All macros / functions return 0 in case of success and another value in case of +error and have the following roles:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">put_user</span></code> store the value <code class="docutils literal"><span class="pre">val</span></code> to user-space address <code class="docutils literal"><span class="pre">address</span></code>; +Type can be one on 8, 16, 32, 64 bit (the maximum supported type depends on the +hardware platform);</li> +<li><code class="docutils literal"><span class="pre">get_user</span></code> analogue to the previous function, only that val will be set to a +value identical to the value at the user-space address given by address;</li> +<li><code class="docutils literal"><span class="pre">copy_to_user</span></code> copies <code class="docutils literal"><span class="pre">n</span></code> bytes from the kernel-space, from the address +referenced by <code class="docutils literal"><span class="pre">from</span></code> in user-space to the address referenced by <code class="docutils literal"><span class="pre">to</span></code>;</li> +<li><code class="docutils literal"><span class="pre">copy_from_user</span></code> copies <code class="docutils literal"><span class="pre">n</span></code> bytes from user-space from the address +referenced by <code class="docutils literal"><span class="pre">from</span></code> in kernel-space to the address referenced by <code class="docutils literal"><span class="pre">to</span></code>.</li> +</ul> +</div></blockquote> +<p>A common section of code that works with these functions is:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><asm/uaccess.h></span><span class="cp"></span> + +<span class="cm">/*</span> +<span class="cm"> * Copy at most size bytes to user space.</span> +<span class="cm"> * Return ''0'' on success and some other value on error.</span> +<span class="cm"> */</span> +<span class="k">if</span> <span class="p">(</span><span class="n">copy_to_user</span><span class="p">(</span><span class="n">user_buffer</span><span class="p">,</span> <span class="n">kernel_buffer</span><span class="p">,</span> <span class="n">size</span><span class="p">))</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EFAULT</span><span class="p">;</span> +<span class="k">else</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +</pre></div> +</div> +</div> +<div class="section" id="open-and-release"> +<h2>Open and release<a class="headerlink" href="#open-and-release" title="Permalink to this headline">¶</a></h2> +<p>The <code class="docutils literal"><span class="pre">open</span></code> function performs the initialization of a device. In most cases, +these operations refer to initializing the device and filling in specific data +(if it is the first open call). The release function is about releasing +device-specific resources: unlocking specific data and closing the device if +the last call is close.</p> +<p>In most cases, the open function will have the following structure:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">my_open</span><span class="p">(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="n">my_data</span> <span class="o">=</span> + <span class="n">container_of</span><span class="p">(</span><span class="n">inode</span><span class="o">-></span><span class="n">i_cdev</span><span class="p">,</span> <span class="k">struct</span> <span class="n">my_device_data</span><span class="p">,</span> <span class="n">cdev</span><span class="p">);</span> + + <span class="cm">/* validate access to device */</span> + <span class="n">file</span><span class="o">-></span><span class="n">private_data</span> <span class="o">=</span> <span class="n">my_data</span><span class="p">;</span> + + <span class="cm">/* initialize device */</span> + <span class="p">...</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>A problem that occurs when implementing the <code class="docutils literal"><span class="pre">open</span></code> function is access control. +Sometimes a device needs to be opened once at a time; More specifically, do not +allow the second open before the release. To implement this restriction, you +choose a way to handle an open call for an already open device: it can return +an error (<code class="docutils literal"><span class="pre">-EBUSY</span></code>), block open calls until a release operation, or shut down +the device before do the open.</p> +<p>At the user-space call of the open and close functions on the device, call +my_open and my_release in the driver. An example of a user-space call:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="n">fd</span> <span class="o">=</span> <span class="n">open</span><span class="p">(</span><span class="s">"/dev/my_device"</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="n">fd</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> +<span class="p">}</span> + +<span class="cm">/* do work */</span> +<span class="c1">//..</span> + +<span class="n">close</span><span class="p">(</span><span class="n">fd</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="read-and-write"> +<h2>Read and write<a class="headerlink" href="#read-and-write" title="Permalink to this headline">¶</a></h2> +<p>The read and write operations are reaching the device driver as a +result of an user-space program calling the read or write system calls:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="p">(</span><span class="n">read</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">buffer</span><span class="p">,</span> <span class="n">size</span><span class="p">)</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> +<span class="p">}</span> + +<span class="k">if</span> <span class="p">(</span><span class="n">write</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">buffer</span><span class="p">,</span> <span class="n">size</span><span class="p">)</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The <code class="docutils literal"><span class="pre">read</span></code> and <code class="docutils literal"><span class="pre">write</span></code> functions transfer data between the device and the +user-space: the read function reads the data from the device and transfers it +to the user-space, while writing reads the user-space data and writes it to the +device. The buffer received as a parameter is a user-space pointer, which is +why it is necessary to use the <code class="docutils literal"><span class="pre">copy_to_user</span></code> or <code class="docutils literal"><span class="pre">copy_from_user</span></code> functions.</p> +<p>The value returned by read or write can be:</p> +<blockquote> +<div><ul class="simple"> +<li>the number of bytes transferred; if the returned value is less than the size +parameter (the number of bytes requested), then it means that a partial +transfer was made. Most of the time, the user-space app calls the system call +(read or write) function until the required data number is transferred.</li> +<li>0 to mark the end of the file in the case of read ; if write returns the +value 0 then it means that no byte has been written and that no error has +occurred; In this case, the user-space application retries the write call.</li> +<li>a negative value indicating an error code.</li> +</ul> +</div></blockquote> +<p>To perform a data transfer consisting of several partial transfers, the +following operations should be performed:</p> +<blockquote> +<div><ul class="simple"> +<li>transfer the maximum number of possible bytes between the buffer received +as a parameter and the device (writing to the device/reading from the device +will be done from the offset received as a parameter);</li> +<li>update the offset received as a parameter to the position from which the +next read / write data will begin;</li> +<li>return the number of bytes transferred.</li> +</ul> +</div></blockquote> +<p>The sequence below shows an example for the read function that takes +into account the internal buffer size, user buffer size and the offset:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">my_read</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> <span class="kt">char</span> <span class="n">__user</span> <span class="o">*</span><span class="n">user_buffer</span><span class="p">,</span> + <span class="kt">size_t</span> <span class="n">size</span><span class="p">,</span> <span class="n">loff_t</span> <span class="o">*</span><span class="n">offset</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="n">my_data</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="p">)</span> <span class="n">file</span><span class="o">-></span><span class="n">private_data</span><span class="p">;</span> + <span class="kt">ssize_t</span> <span class="n">len</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">my_data</span><span class="o">-></span><span class="n">size</span> <span class="o">-</span> <span class="o">*</span><span class="n">offset</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">len</span> <span class="o"><=</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> + + <span class="cm">/* read data from my_data->buffer to user buffer */</span> + <span class="k">if</span> <span class="p">(</span><span class="n">copy_to_user</span><span class="p">(</span><span class="n">user_buffer</span><span class="p">,</span> <span class="n">my_data</span><span class="o">-></span><span class="n">buffer</span> <span class="o">+</span> <span class="o">*</span><span class="n">offset</span><span class="p">,</span> <span class="n">len</span><span class="p">))</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EFAULT</span><span class="p">;</span> + + <span class="o">*</span><span class="n">offset</span> <span class="o">+=</span> <span class="n">len</span><span class="p">;</span> + <span class="k">return</span> <span class="n">len</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The images below illustrate the read operation and how data is +transferred between the user-space and the driver:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>when the driver has enough data available (starting with the OFFSET +position) to accurately transfer the required size (SIZE) to the user.</li> +<li>when a smaller amount is transferred than required.</li> +</ol> +</div></blockquote> +<a class="reference internal image-reference" href="../_images/read.png"><img alt="../_images/read.png" src="../_images/read.png" style="width: 49%;" /></a> +<a class="reference internal image-reference" href="../_images/read2.png"><img alt="../_images/read2.png" src="../_images/read2.png" style="width: 49%;" /></a> +<p>We can look at the read operation implemented by the driver as a response to a +user-space read request. In this case, the driver is responsible for advancing +the offset according to how much it reads and returning the read size (which +may be less than what is required).</p> +<p>The structure of the write function is similar:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">my_write</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">__user</span> <span class="o">*</span><span class="n">user_buffer</span><span class="p">,</span> + <span class="kt">size_t</span> <span class="n">size</span><span class="p">,</span> <span class="n">loff_t</span> <span class="o">*</span> <span class="n">offset</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="n">my_data</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="p">)</span> <span class="n">file</span><span class="o">-></span><span class="n">private_data</span><span class="p">;</span> + <span class="kt">ssize_t</span> <span class="n">len</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">my_data</span><span class="o">-></span><span class="n">size</span> <span class="o">-</span> <span class="o">*</span><span class="n">offset</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">len</span> <span class="o"><=</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> + + <span class="cm">/* read data from user buffer to my_data->buffer */</span> + <span class="k">if</span> <span class="p">(</span><span class="n">copy_from_user</span><span class="p">(</span><span class="n">my_data</span><span class="o">-></span><span class="n">buffer</span> <span class="o">+</span> <span class="o">*</span><span class="n">offset</span><span class="p">,</span> <span class="n">user_buffer</span><span class="p">,</span> <span class="n">len</span><span class="p">))</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EFAULT</span><span class="p">;</span> + + <span class="o">*</span><span class="n">offset</span> <span class="o">+=</span> <span class="n">len</span><span class="p">;</span> + <span class="k">return</span> <span class="n">len</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The write operation will respond to a write request from user-space. In +this case, depending on the maximum driver capacity (MAXSIZ), it can +write more or less than the required size.</p> +<a class="reference internal image-reference" href="../_images/write.png"><img alt="../_images/write.png" src="../_images/write.png" style="width: 49%;" /></a> +<a class="reference internal image-reference" href="../_images/write2.png"><img alt="../_images/write2.png" src="../_images/write2.png" style="width: 49%;" /></a> +</div> +<div class="section" id="ioctl-1"> +<span id="ioctl"></span><h2>ioctl<a class="headerlink" href="#ioctl-1" title="Permalink to this headline">¶</a></h2> +<p>In addition to read and write operations, a driver needs the ability to perform +certain physical device control tasks. These operations are accomplished by +implementing a <code class="docutils literal"><span class="pre">ioctl</span></code> function. Initially, the ioctl system call used Big Kernel +Lock. That's why the call was gradually replaced with its unlocked version +called <code class="docutils literal"><span class="pre">unlocked_ioctl</span></code>. You can read more on LWN: +<a class="reference external" href="http://lwn.net/Articles/119652/">http://lwn.net/Articles/119652/</a></p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">long</span> <span class="nf">my_ioctl</span> <span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">cmd</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">arg</span><span class="p">);</span> +</pre></div> +</div> +<p><code class="docutils literal"><span class="pre">cmd</span></code> is the command sent from user-space. If a value is being sent from the +user-space call, it can be accessed directly. If a buffer is fetched, the arg +value will be a pointer to it, and must be accessed through the <code class="docutils literal"><span class="pre">copy_to_user</span></code> +or <code class="docutils literal"><span class="pre">copy_from_user</span></code>.</p> +<p>Before implementing the <code class="docutils literal"><span class="pre">ioctl</span></code> function, the numbers corresponding to the +commands must be chosen. One method is to choose consecutive numbers starting +at 0, but it is recommended to use <code class="docutils literal"><span class="pre">_IOC(dir,</span> <span class="pre">type,</span> <span class="pre">nr,</span> <span class="pre">size)</span></code> macro definition +to generate ioctl codes. The macro definition parameters are as follows:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">dir</span></code> represents the data transfer (<code class="docutils literal"><span class="pre">_IOC_NONE</span></code> , <code class="docutils literal"><span class="pre">_IOC_READ</span></code>, +<code class="docutils literal"><span class="pre">_IOC_WRITE</span></code>).</li> +<li><code class="docutils literal"><span class="pre">type</span></code> represents the magic number (<code class="docutils literal"><span class="pre">Documentation/ioctl/ioctl-number.txt</span></code>);</li> +<li><code class="docutils literal"><span class="pre">nr</span></code> is the ioctl code for the device;</li> +<li><code class="docutils literal"><span class="pre">size</span></code> is the size of the transferred data.</li> +</ul> +</div></blockquote> +<p>The following example shows an implementation for a <code class="docutils literal"><span class="pre">ioctl</span></code> function:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><asm/ioctl.h></span><span class="cp"></span> + +<span class="cp">#define MY_IOCTL_IN _IOC(_IOC_WRITE, 'k', 1, sizeof(my_ioctl_data))</span> + +<span class="k">static</span> <span class="kt">long</span> <span class="nf">my_ioctl</span> <span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">cmd</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">arg</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="n">my_data</span> <span class="o">=</span> + <span class="p">(</span><span class="k">struct</span> <span class="n">my_device_data</span><span class="o">*</span><span class="p">)</span> <span class="n">file</span><span class="o">-></span><span class="n">private_data</span><span class="p">;</span> + <span class="n">my_ioctl_data</span> <span class="n">mid</span><span class="p">;</span> + + <span class="k">switch</span><span class="p">(</span><span class="n">cmd</span><span class="p">)</span> <span class="p">{</span> + <span class="k">case</span> <span class="nl">MY_IOCTL_IN</span><span class="p">:</span> + <span class="k">if</span><span class="p">(</span> <span class="n">copy_from_user</span><span class="p">(</span><span class="o">&</span><span class="n">mid</span><span class="p">,</span> <span class="p">(</span><span class="n">my_ioctl_data</span> <span class="o">*</span><span class="p">)</span> <span class="n">arg</span><span class="p">,</span> + <span class="k">sizeof</span><span class="p">(</span><span class="n">my_ioctl_data</span><span class="p">))</span> <span class="p">)</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EFAULT</span><span class="p">;</span> + + <span class="cm">/* process data and execute command */</span> + + <span class="k">break</span><span class="p">;</span> + <span class="k">default</span><span class="o">:</span> + <span class="k">return</span> <span class="o">-</span><span class="n">ENOTTY</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>At the user-space call for the ioctl function, the my_ioctl function of the +driver will be called. An example of such a user-space call:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="p">(</span><span class="n">ioctl</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">MY_IOCTL_IN</span><span class="p">,</span> <span class="n">buffer</span><span class="p">)</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="waiting-queues"> +<h2>Waiting queues<a class="headerlink" href="#waiting-queues" title="Permalink to this headline">¶</a></h2> +<p>It is often necessary for a thread to wait for an operation to finish, +but it is desirable that this wait is not busy-waiting. Using waiting +queues we can block a thread until an event occurs. When the condition +is satisfied, elsewhere in the kernel, in another process, in an +interrupt or deferrable work, we will wake up the process.</p> +<p>A waiting queue is a list of processes that are waiting for a specific +event. A queue is defined with the <code class="docutils literal"><span class="pre">wait_queue_head_t</span></code> type and can +be used by the functions/macros:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/wait.h></span><span class="cp"></span> + +<span class="n">DECLARE_WAIT_QUEUE_HEAD</span><span class="p">(</span><span class="n">wq_name</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">init_waitqueue_head</span><span class="p">(</span><span class="n">wait_queue_head_t</span> <span class="o">*</span><span class="n">q</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">wait_event</span><span class="p">(</span><span class="n">wait_queue_head_t</span> <span class="n">q</span><span class="p">,</span> <span class="kt">int</span> <span class="n">condition</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">wait_event_interruptible</span><span class="p">(</span><span class="n">wait_queue_head_t</span> <span class="n">q</span><span class="p">,</span> <span class="kt">int</span> <span class="n">condition</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">wait_event_timeout</span><span class="p">(</span><span class="n">wait_queue_head_t</span> <span class="n">q</span><span class="p">,</span> <span class="kt">int</span> <span class="n">condition</span><span class="p">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">wait_event_interruptible_timeout</span><span class="p">(</span><span class="n">wait_queue_head_t</span> <span class="n">q</span><span class="p">,</span> <span class="kt">int</span> <span class="n">condition</span><span class="p">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">wake_up</span><span class="p">(</span><span class="n">wait_queue_head_t</span> <span class="o">*</span><span class="n">q</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">wake_up_interruptible</span><span class="p">(</span><span class="n">wait_queue_head_t</span> <span class="o">*</span><span class="n">q</span><span class="p">);</span> +</pre></div> +</div> +<p>The roles of the macros / functions above are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">init_waitqueue_head()</span></code> initializes the queue; to initialize the +queue at compile time, you can use the <code class="xref c c-macro docutils literal"><span class="pre">DECLARE_WAIT_QUEUE_HEAD</span></code> macro;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">wait_event()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">wait_event_interruptible()</span></code> adds the current thread to the +queue while the condition is false, sets it to TASK_UNINTERRUPTIBLE or +TASK_INTERRUPTIBLE and calls the scheduler to schedule a new thread; Waiting +will be interrupted when another thread will call the wake_up function;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">wait_event_timeout()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">wait_event_interruptible_timeout()</span></code> have the same +effect as the above functions, only waiting can be interrupted at the end of +the timeout received as a parameter;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">wake_up()</span></code> puts all threads off from state TASK_INTERRUPTIBLE and +TASK_UNINTERRUPTIBLE in TASK_RUNNING status; Remove these threads from the +queue;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">wake_up_interruptible()</span></code> same action, but only threads with TASK_INTERRUPTIBLE +status are woken up.</li> +</ul> +</div></blockquote> +<p>A simple example is that of a thread waiting to change the value of a flag. The +initializations are done by the sequence:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/sched.h></span><span class="cp"></span> + +<span class="n">wait_queue_head_t</span> <span class="n">wq</span><span class="p">;</span> +<span class="kt">int</span> <span class="n">flag</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + +<span class="n">init_waitqueue_head</span><span class="p">(</span><span class="o">&</span><span class="n">wq</span><span class="p">);</span> +</pre></div> +</div> +<p>A thread will wait for the flag to be changed to a value other than zero:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">wait_event_interruptible</span><span class="p">(</span><span class="n">wq</span><span class="p">,</span> <span class="n">flag</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">);</span> +</pre></div> +</div> +<p>While another thread will change the flag value and wake up the waiting threads:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">flag</span> <span class="o">=</span> <span class="mi">1</span> <span class="p">;</span> +<span class="n">wake_up_interruptible</span> <span class="p">(</span><span class="o">&</span><span class="n">wq</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is device_drivers. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/device_drivers/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="section" id="intro"> +<h3>0. Intro<a class="headerlink" href="#intro" title="Permalink to this headline">¶</a></h3> +<p>Using <a class="reference external" href="http://elixir.free-electrons.com/linux/latest/source">LXR</a> find the definitions +of the following symbols in the Linux kernel:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">generic_ro_fops</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">vfs_read()</span></code></li> +</ul> +</div></blockquote> +</div> +<div class="section" id="register-unregister"> +<h3>1. Register/unregister<a class="headerlink" href="#register-unregister" title="Permalink to this headline">¶</a></h3> +<p>The driver will control a single device with the <code class="docutils literal"><span class="pre">MY_MAJOR</span></code> major and +<code class="docutils literal"><span class="pre">MY_MINOR</span></code> minor (the macros defined in the kernel/so2_cdev.c file).</p> +<blockquote> +<div><ol class="arabic"> +<li><p class="first">Create <strong>/dev/so2_cdev</strong> character device node using <strong>mknod</strong>.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Read <a class="reference internal" href="#majors-and-minors">Majors and minors</a> section in the lab.</p> +</div> +</li> +<li><p class="first">Implement the registration and deregistration of the device with the name +<code class="docutils literal"><span class="pre">so2_cdev</span></code>, respectively in the init and exit module functions. Implement <strong>TODO 1</strong>.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Read the section <a class="reference internal" href="#registration-and-unregistration-of-character-devices">Registration and unregistration of character devices</a></p> +</div> +</li> +<li><p class="first">Display, using <code class="docutils literal"><span class="pre">pr_info</span></code>, a message after the registration and unregistration +operations to confirm that they were successful. Then load the module into the kernel:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ insmod so2_cdev.ko +</pre></div> +</div> +<p>And see character devices in <code class="docutils literal"><span class="pre">/proc/devices</span></code>:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ cat /proc/devices <span class="p">|</span> less +</pre></div> +</div> +<p>Identify the device type registered with major 42 . Note that <code class="docutils literal"><span class="pre">/proc/devices</span></code> +contains only the device types (major) but not the actual devices (i.e. minors).</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>Entries in /dev are not created by loading the module. These can be created +in two ways:</p> +<ul class="last simple"> +<li>manually, using the <code class="docutils literal"><span class="pre">mknod</span></code> command as we did above.</li> +<li>automatically using udev daemon</li> +</ul> +</div> +</li> +<li><p class="first">Unload the kernel module</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>rmmod so2_cdev +</pre></div> +</div> +</li> +</ol> +</div></blockquote> +</div> +<div class="section" id="register-an-already-registered-major"> +<h3>2. Register an already registered major<a class="headerlink" href="#register-an-already-registered-major" title="Permalink to this headline">¶</a></h3> +<p>Modify <strong>MY_MAJOR</strong> so that it points to an already used major number.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">See <code class="docutils literal"><span class="pre">/proc/devices</span></code> to get an already assigned major.</p> +</div> +<p>See <a class="reference external" href="http://elixir.free-electrons.com/linux/v4.9/source/include/uapi/asm-generic/errno-base.h">errno-base.h</a> +and figure out what does the error code mean. +Return to the initial configuration of the module.</p> +</div> +<div class="section" id="open-and-close"> +<h3>3. Open and close<a class="headerlink" href="#open-and-close" title="Permalink to this headline">¶</a></h3> +<p>Run <code class="docutils literal"><span class="pre">cat</span> <span class="pre">/dev/so2_cdev</span></code> to read data from our char device. +Reading does not work because the driver does not have the open function implemented. +Follow comments marked with TODO 2 and implement them.</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Initialize your device<ul> +<li>add a cdev struct field to <code class="docutils literal"><span class="pre">so2_device_data</span></code> structure.</li> +<li>Read the section <a class="reference internal" href="#registration-and-unregistration-of-character-devices">Registration and unregistration of character devices</a> in the lab.</li> +</ul> +</li> +<li>Implement the open and release functions in the driver.</li> +<li>Display a message in the open and release functions.</li> +<li>Read again <code class="docutils literal"><span class="pre">/dev/so2_cdev</span></code> file. Follow the messages displayed by the kernel. +We still get an error because <code class="docutils literal"><span class="pre">read</span></code> function is not yet implemented.</li> +</ol> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The prototype of a device driver's operations is in the <code class="docutils literal"><span class="pre">file_operations</span></code> +structure. Read <a class="reference internal" href="#open-and-release">Open and release</a> section.</p> +</div> +</div> +<div class="section" id="access-restriction"> +<h3>4. Access restriction<a class="headerlink" href="#access-restriction" title="Permalink to this headline">¶</a></h3> +<p>Restrict access to the device with atomic variables, so that a single process +can open the device at a time. The rest will receive the "device busy" error +(<code class="docutils literal"><span class="pre">-EBUSY</span></code>). Restricting access will be done in the open function displayed by +the driver. Follow comments marked with <strong>TODO 3</strong> and implement them.</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Add an <code class="docutils literal"><span class="pre">atomic_t</span></code> variable to the device structure.</li> +<li>Initialize the variable at module initialization.</li> +<li>Use the variable in the open function to restrict access to the device. We +recommend using <code class="xref c c-func docutils literal"><span class="pre">atomic_cmpxchg()</span></code>.</li> +<li>Reset the variable in the release function to retrieve access to the device.</li> +<li>To test your deployment, you'll need to simulate a long-term use of your +device. To simulate a sleep, call the scheduler at the end of the device opening:</li> +</ol> +</div></blockquote> +<div class="highlight-bash"><div class="highlight"><pre><span></span>set_current_state<span class="o">(</span>TASK_INTERRUPTIBLE<span class="o">)</span><span class="p">;</span> +schedule_timeout<span class="o">(</span><span class="m">1000</span><span class="o">)</span><span class="p">;</span> +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The advantage of the atomic_cmpxchg function is that it can check the +old value of the variable and set it up to a new value, all in one +atomic operation. Read more details about <a class="reference external" href="https://www.khronos.org/registry/OpenCL/sdk/1.1/docs/man/xhtml/atomic_cmpxchg.html">atomic_cmpxchg</a> +An example of use is <a class="reference external" href="http://elixir.free-electrons.com/linux/v4.9/source/lib/dump_stack.c#L24">here</a>.</p> +</div> +</div> +<div class="section" id="read-operation"> +<h3>5. Read operation<a class="headerlink" href="#read-operation" title="Permalink to this headline">¶</a></h3> +<p>Implement the read function in the driver. Follow comments marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">4</span></code> and implement them.</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Keep a buffer in <code class="docutils literal"><span class="pre">so2_device_data</span></code> structure initialized with the value of <code class="docutils literal"><span class="pre">MESSAGE</span></code> macro. +Initializing this buffer will be done in module <code class="docutils literal"><span class="pre">init</span></code> function.</li> +<li>At a read call, copy the contents of the kernel space buffer into the user +space buffer.<ul> +<li>Use the <code class="xref c c-func docutils literal"><span class="pre">copy_to_user()</span></code> function to copy information from kernel space to +user space.</li> +<li>Ignore the size and offset parameters at this time. You can assume that +the buffer in user space is large enough. You do not need to check the +validity of the size argument of the read function.</li> +<li>The value returned by the read call is the number of bytes transmitted +from the kernel space buffer to the user space buffer.</li> +</ul> +</li> +<li>After implementation, test using <code class="docutils literal"><span class="pre">cat</span> <span class="pre">/dev/so2_cdev</span></code>.</li> +</ol> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The command <code class="docutils literal"><span class="pre">cat</span> <span class="pre">/dev/so2_cdev</span></code> does not end (use Ctrl+C). +Read the <a class="reference internal" href="#read-and-write">read and write</a> sections and <a class="reference internal" href="#access-to-the-address-space-of-the-process">Access to the address space of the process</a> +If you want to display the offset value use a construction of the form: +<code class="docutils literal"><span class="pre">pr_info("Offset:</span> <span class="pre">%lld</span> <span class="pre">\n",</span> <span class="pre">*offset)</span></code>; The data type loff_t (used by offset ) is a typedef for long long int.</p> +</div> +<p>The <code class="docutils literal"><span class="pre">cat</span></code> command reads to the end of the file, and the end of the file is +signaled by returning the value 0 in the read. Thus, for a correct implementation, +you will need to update and use the offset received as a parameter in the read +function and return the value 0 when the user has reached the end of the buffer.</p> +<p>Modify the driver so that the <code class="docutils literal"><span class="pre">cat</span></code> commands ends:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Use the size parameter.</li> +<li>For every read, update the offset parameter accordingly.</li> +<li>Ensure that the read function returns the number of bytes that were copied +into the user buffer.</li> +</ol> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">By dereferencing the offset parameter it is possible to read and move the current +position in the file. Its value needs to be updated every time a read is done +successfully.</p> +</div> +</div> +<div class="section" id="write-operation"> +<h3>6. Write operation<a class="headerlink" href="#write-operation" title="Permalink to this headline">¶</a></h3> +<p>Add the ability to write a message into kernel buffer to replace the predefined message. Implement +the write function in the driver. Follow comments marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">5</span></code></p> +<p>Ignore the offset parameter at this time. You can assume that the driver buffer is +large enough. You do not need to check the validity of the write function size +argument.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The prototype of a device driver's operations is in the file_operations +structure. +Test using commands:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nb">echo</span> <span class="s2">"arpeggio"</span>> /dev/so2_cdev +cat /dev/so2_cdev +</pre></div> +</div> +<p class="last">Read the <a class="reference internal" href="#read-and-write">read and write</a> sections and <a class="reference internal" href="#access-to-the-address-space-of-the-process">Access to the address space of the process</a></p> +</div> +</div> +<div class="section" id="ioctl-operation"> +<h3>7. ioctl operation<a class="headerlink" href="#ioctl-operation" title="Permalink to this headline">¶</a></h3> +<p>For this exercise, we want to add the ioctl <code class="docutils literal"><span class="pre">MY_IOCTL_PRINT</span></code> to display the +message from the <code class="docutils literal"><span class="pre">IOCTL_MESSAGE</span></code> macro in the driver. +Follow the comments marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">6</span></code></p> +<p>For this:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Implement the ioctl function in the driver.</li> +<li>We need to use <code class="docutils literal"><span class="pre">user/so2_cdev_test.c</span></code> to call the +ioctl function with the appropriate parameters.</li> +<li>To test, we will use an user-space program (<code class="docutils literal"><span class="pre">user/so2_cdev_test.c</span></code>) +which will call the <code class="docutils literal"><span class="pre">ioctl</span></code> function with the required arguments.</li> +</ol> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The macro <code class="docutils literal"><span class="pre">MY_IOCTL_PRINT</span></code> is defined in the file <code class="docutils literal"><span class="pre">include/so2_cdev.h</span></code>, +which is shared between the kernel module and the user-space program.</p> +<p class="last">Read the <a class="reference internal" href="#ioctl">ioctl</a> section in the lab.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The user-space code is compiled automatically at <code class="docutils literal"><span class="pre">make</span> <span class="pre">build</span></code> and +copied at <code class="docutils literal"><span class="pre">make</span> <span class="pre">copy</span></code>.</p> +<p class="last">Because we need to compile the program for qemu machine which is 32 bit, +if your host is 64 bit then you need to install <code class="docutils literal"><span class="pre">gcc-multilib</span></code> package.</p> +</div> +</div> +</div> +<div class="section" id="extra-exercises"> +<h2>Extra Exercises<a class="headerlink" href="#extra-exercises" title="Permalink to this headline">¶</a></h2> +<div class="section" id="ioctl-with-messaging"> +<h3>Ioctl with messaging<a class="headerlink" href="#ioctl-with-messaging" title="Permalink to this headline">¶</a></h3> +<p>Add two ioctl operations to modify the message associated with the +driver. Use fixed-length buffer ( BUFFER_SIZE ).</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Add the <code class="docutils literal"><span class="pre">ioctl</span></code> function from the driver the following operations:<ul> +<li><code class="docutils literal"><span class="pre">MY_IOCTL_SET_BUFFER</span></code> for writing a message to the device;</li> +<li><code class="docutils literal"><span class="pre">MY_IOCTL_GET_BUFFER</span></code> to read a message from your device.</li> +</ul> +</li> +<li>For testing, pass the required command line arguments to the +user-space program.</li> +</ol> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Read the <a class="reference internal" href="#ioctl">ioctl</a> and <a class="reference internal" href="#access-to-the-address-space-of-the-process">Access to the address space of the process</a> +sections of the lab.</p> +</div> +</div> +<div class="section" id="ioctl-with-waiting-queues"> +<h3>Ioctl with waiting queues<a class="headerlink" href="#ioctl-with-waiting-queues" title="Permalink to this headline">¶</a></h3> +<p>Add two ioctl operations to the device driver for queuing.</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Add the <code class="docutils literal"><span class="pre">ioctl</span></code> function from the driver the following operations:<ul> +<li><code class="docutils literal"><span class="pre">MY_IOCTL_DOWN</span></code> to add the process to a queue;</li> +<li><code class="docutils literal"><span class="pre">MY_IOCTL_UP</span></code> to remove the process from a queue.</li> +</ul> +</li> +<li>Fill the device structure with a <code class="docutils literal"><span class="pre">wait_queue_head_t</span></code> field and a flag.</li> +<li>Do not forget to initialize the wait queue and flag.</li> +<li>Remove exclusive access condition from previous exercise</li> +<li>For testing, pass the required command line arguments to the +user-space program.</li> +</ol> +</div></blockquote> +<p>When the process is added to the queue, it will remain blocked in execution; To +run the queue command open a new console in the virtual machine with Alt+F2 ; +You can return to the previous console with Alt+F1. If you're connected via +SSH to the virtual machine, open a new console.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Read the <a class="reference internal" href="#ioctl">ioctl</a> and <a class="reference internal" href="#waiting-queues">Waiting queues</a> sections in the lab.</p> +</div> +</div> +<div class="section" id="o-nonblock-implementation"> +<h3>O_NONBLOCK implementation<a class="headerlink" href="#o-nonblock-implementation" title="Permalink to this headline">¶</a></h3> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>If a file is open with the <code class="docutils literal"><span class="pre">O_NONBLOCK</span></code> flag, then its +operations will be non-blocking.</p> +<p>In case data is not available when performing a read, the following +happens:</p> +<blockquote class="last"> +<div><ul class="simple"> +<li>if the file has been open with <code class="docutils literal"><span class="pre">O_NONBLOCK</span></code>, the read call +will return <code class="docutils literal"><span class="pre">-EWOULDBLOCK</span></code>.</li> +<li>otherwise, the current task (process) will be placed in a waiting +queue and will be unblocked as soon as data becomes available +(in our case, at write).</li> +</ul> +</div></blockquote> +</div> +<ul class="simple"> +<li>To allow unblocking the read operation, remove the exclusive access +condition from previous exercises.</li> +<li>You can use the queue defined for the previous exercise.</li> +<li>You can ignore the file offset.</li> +<li>Modify the initial size of data to <code class="docutils literal"><span class="pre">0</span></code>, to allow testing.</li> +<li>For testing, pass the required command line arguments to the +user-space program.<ul> +<li>when using the <code class="docutils literal"><span class="pre">n</span></code> option, the test program will change the open flags +to <code class="docutils literal"><span class="pre">O_NONBLOCK</span></code> and then perform a <code class="docutils literal"><span class="pre">read</span></code>.</li> +</ul> +</li> +<li>What are the flags used to open the file when running <code class="docutils literal"><span class="pre">cat</span> <span class="pre">/dev/so2_dev</span></code>?</li> +</ul> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="kernel_api.html" class="btn btn-neutral float-left" title="Kernel API" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="interrupts.html" class="btn btn-neutral float-right" title="I/O access and Interrupts" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/labs/device_model.html b/refs/pull/405/merge/labs/device_model.html new file mode 100644 index 00000000..f4618913 --- /dev/null +++ b/refs/pull/405/merge/labs/device_model.html @@ -0,0 +1,1311 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Linux Device Model — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Kernel Profiling" href="kernel_profiling.html" /> + <link rel="prev" title="Memory mapping" href="memory_mapping.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Linux Device Model</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#overview">Overview</a></li> +<li class="toctree-l2"><a class="reference internal" href="#sysfs">sysfs</a></li> +<li class="toctree-l2"><a class="reference internal" href="#basic-structures-in-linux-devices">Basic Structures in Linux Devices</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#the-kobject-structure">The kobject structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="#buses">Buses</a></li> +<li class="toctree-l3"><a class="reference internal" href="#devices">Devices</a></li> +<li class="toctree-l3"><a class="reference internal" href="#drivers">Drivers</a></li> +<li class="toctree-l3"><a class="reference internal" href="#classes">Classes</a></li> +<li class="toctree-l3"><a class="reference internal" href="#hotplug">Hotplug</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#plug-and-play">Plug and Play</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#pnp-bus">PNP bus</a></li> +<li class="toctree-l3"><a class="reference internal" href="#pnp-operations">PNP operations</a></li> +<li class="toctree-l3"><a class="reference internal" href="#adding-a-driver">Adding a driver</a></li> +<li class="toctree-l3"><a class="reference internal" href="#removing-a-driver">Removing a driver</a></li> +<li class="toctree-l3"><a class="reference internal" href="#adding-a-new-device">Adding a new device</a></li> +<li class="toctree-l3"><a class="reference internal" href="#removing-a-device">Removing a device</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#intro">0. Intro</a></li> +<li class="toctree-l3"><a class="reference internal" href="#bus-implementation">1. Bus implementation</a></li> +<li class="toctree-l3"><a class="reference internal" href="#add-type-and-version-device-attributes">2. Add type and version device attributes</a></li> +<li class="toctree-l3"><a class="reference internal" href="#add-del-and-add-bus-attributes">3. Add del and add bus attributes</a></li> +<li class="toctree-l3"><a class="reference internal" href="#register-the-bex-misc-driver">4. Register the bex misc driver</a></li> +<li class="toctree-l3"><a class="reference internal" href="#register-misc-device-in-the-bex-misc-probe-function">5. Register misc device in the bex_misc probe function</a></li> +<li class="toctree-l3"><a class="reference internal" href="#monitor-uevent-notifications">6. Monitor uevent notifications</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Linux Device Model</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/labs/device_model.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="linux-device-model"> +<h1>Linux Device Model<a class="headerlink" href="#linux-device-model" title="Permalink to this headline">¶</a></h1> +<div class="section" id="overview"> +<h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline">¶</a></h2> +<p>Plug and Play is a technology that offers support for automatically adding and +removing devices to the system. This reduces conflicts with the resources they +use by automatically configuring them at system startup. In order to achieve +these goals, the following features are required:</p> +<blockquote> +<div><ul class="simple"> +<li>Automatic detection of adding and removing devices in the system (the device +and its bus must notify the appropriate driver that a configuration change +occurred).</li> +<li>Resource management (addresses, irq lines, DMA channels, memory areas), +including resource allocation to devices and solving conflicts that may arise.</li> +<li>Devices must allow for software configuration (device resources - ports, +interrupts, DMA resources - must allow for driver assignment).</li> +<li>The drivers required for new devices must be loaded automatically by the +operating system when needed.</li> +<li>When the device and its bus allow, the system should be able to add or +remove the device from the system while it is running, without having to reboot +the system (hotplug).</li> +</ul> +</div></blockquote> +<p>For a system to support plug and play, the BIOS, operating system and the device +must support this technology. The device must have an ID that will provide to the +driver for identification, and the operating system must be able to identify +these configuration changes as they appear.</p> +<p>Plug and play devices are: PCI devices (network cards), USB (keyboard, mouse, +printer), etc.</p> +<p>Prior to version 2.6, the kernel did not have a unified model to get +information about devices. +For this reason, a model for Linux devices, Linux Device Model, was developed.</p> +<p>The primary purpose of this model is to maintain internal data structures that +reflect the state and structure of the system. Such information includes what +devices are in the system, how they are in terms of power management, what bus +they are attached to, what drivers they have, along with the structure of the +buses, devices, drivers in the system.</p> +<p>To maintain this information, the kernel uses the following entities:</p> +<blockquote> +<div><ul class="simple"> +<li>device - a physical device that is attached to a bus</li> +<li>driver - a software entity that can be associated with a device and performs +operations with it</li> +<li>bus - a device to which other devices can be attached</li> +<li>class - a type of device that has a similar behavior; There is a class for +disks, partitions, serial ports, etc.</li> +<li>subsystem - a view on the structure of the system; Kernel subsystems +include devices (hierarchical view of all devices in the system), buses (bus +view of devices according to how they are attached to buses), classes, etc.</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="sysfs"> +<h2>sysfs<a class="headerlink" href="#sysfs" title="Permalink to this headline">¶</a></h2> +<p>The kernel provides a representation of its model in userspace through the +sysfs virtual file system. It is usually mounted in the /sys directory and +contains the following subdirectories:</p> +<blockquote> +<div><ul class="simple"> +<li>block - all block devices available in the system (disks, partitions)</li> +<li>bus - types of bus to which physical devices are connected (pci, ide, usb)</li> +<li>class - drivers classes that are available in the system (net, sound, usb)</li> +<li>devices - the hierarchical structure of devices connected to the system</li> +<li>firmware - information from system firmware (ACPI)</li> +<li>fs - information about mounted file systems</li> +<li>kernel - kernel status information (logged-in users, hotplug)</li> +<li>module - the list of modules currently loaded</li> +<li>power - information related to the power management subsystem</li> +</ul> +</div></blockquote> +<p>As you can see, there is a correlation between the kernel data structures +within the described model and the subdirectories in the sysfs virtual file +system. Although this likeness may lead to confusion between the two concepts, +they are different. The kernel device model can work without the sysfs file +system, but the reciprocal is not true.</p> +<p>The sysfs information is found in files that contain an attribute. Some +standard attributes (represented by files or directories with the same name) +are as follows:</p> +<blockquote> +<div><ul class="simple"> +<li>dev - Major and minor device identifier. It can be used to automatically +create entries in the /dev directory</li> +<li>device - a symbolic link to the directory containing devices; It can be +used to discover the hardware devices that provide a particular service (for +example, the ethi PCI card)</li> +<li>driver - a symbolic link to the driver directory (located in +/sys/bus/*/drivers )</li> +</ul> +</div></blockquote> +<p>Other attributes are available, depending on the bus and driver used.</p> +<img alt="../_images/ditaa-a5f399cb84561893770eb45ceeb827ce6d4a2336.png" src="../_images/ditaa-a5f399cb84561893770eb45ceeb827ce6d4a2336.png" /> +</div> +<div class="section" id="basic-structures-in-linux-devices"> +<h2>Basic Structures in Linux Devices<a class="headerlink" href="#basic-structures-in-linux-devices" title="Permalink to this headline">¶</a></h2> +<p>Linux Device Model provides a number of structures to ensure the interaction +between a hardware device and a device driver. The whole model is based on +kobject structure. Hierarchies are built using this structure and the following +structures are implemented:</p> +<blockquote> +<div><ul class="simple"> +<li>struct bus_type</li> +<li>struct device</li> +<li>struct device_driver</li> +</ul> +</div></blockquote> +<img alt="../_images/ditaa-f7ee56960e76c3e80fcbe59fafa38c3d93eac261.png" src="../_images/ditaa-f7ee56960e76c3e80fcbe59fafa38c3d93eac261.png" /> +<div class="section" id="the-kobject-structure"> +<h3>The kobject structure<a class="headerlink" href="#the-kobject-structure" title="Permalink to this headline">¶</a></h3> +<p>A kobject structure does not perform a single function. This structure is +usually integrated into a larger one. A kobject structure actually +incorporates a set of features that will be offered to a higher abstraction +object in the Linux Device Model hierarchy.</p> +<p>For example, the cdev structure has the following definition:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">cdev</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">kobject</span> <span class="n">kob</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">owner</span><span class="p">;</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">file_operations</span> <span class="o">*</span><span class="n">ops</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="n">list</span><span class="p">;</span> + <span class="kt">dev_t</span> <span class="n">dev</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">count</span><span class="p">;</span> +<span class="p">};</span> +</pre></div> +</div> +<p>Note that this structure includes a <code class="docutils literal"><span class="pre">kobject</span></code> structure field.</p> +<p>A kobject structure is defined as follows:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">kobject</span> <span class="p">{</span> + <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="n">entry</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">kobject</span> <span class="o">*</span><span class="n">parent</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">kset</span> <span class="o">*</span><span class="n">kset</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">kobj_type</span> <span class="o">*</span><span class="n">ktype</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">sysfs_dirent</span> <span class="o">*</span><span class="n">sd</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">kref</span> <span class="n">kref</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="nl">state_initialized</span><span class="p">:</span><span class="mi">1</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="nl">state_in_sysfs</span><span class="p">:</span><span class="mi">1</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="nl">state_add_uevent_sent</span><span class="p">:</span><span class="mi">1</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="nl">state_remove_uevent_sent</span><span class="p">:</span><span class="mi">1</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="nl">uevent_suppress</span><span class="p">:</span><span class="mi">1</span><span class="p">;</span> +<span class="p">};</span> +</pre></div> +</div> +<p>As we can see, the kobject structures are in a hierarchy: an object has a +parent and holds a kset member, which contains objects on the same level.</p> +<p>Working with the structure involves initializing it with the +<code class="xref c c-func docutils literal"><span class="pre">kobject_init()</span></code> function. +Also in the initialization process it is necessary to set the name of the +<code class="docutils literal"><span class="pre">kobject</span></code> structure, which will appear in sysfs, using the +<code class="xref c c-func docutils literal"><span class="pre">kobject_set_name()</span></code> function.</p> +<p>Any operation on a kobject is done by incrementing its internal counter using +<code class="xref c c-func docutils literal"><span class="pre">kobject_get()</span></code>, or decrementing if it is no longer used using +<code class="xref c c-func docutils literal"><span class="pre">kobject_put()</span></code>. +Thus, a kobject object will only be released when its internal counter reaches 0. +A method of notifying this is needed so that the resources associated with the +device structure which included the kobject structure are released +(for example, cdev). +The method is called <code class="docutils literal"><span class="pre">release</span></code> and is associated with the object via the ktype +field (<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">kobj_type</span></code>).</p> +<p>The kobject structure is the basic structure of the Linux Device Model. +The structures in the higher levels of the model are <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bus_type</span></code>, +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">device</span></code> and <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">device_driver</span></code>.</p> +</div> +<div class="section" id="buses"> +<h3>Buses<a class="headerlink" href="#buses" title="Permalink to this headline">¶</a></h3> +<p>A bus is a communication channel between the processor and an input/output +device. To ensure that the model is generic, all input/output devices are +connected to the processor via such a bus (even if it can be a virtual one +without a physical hardware correspondent).</p> +<p>When adding a system bus, it will appear in the sysfs file system in +<code class="docutils literal"><span class="pre">/sys/bus</span></code>. +As with kobjects, buses can be organized into hierarchies and will be represented +in sysfs.</p> +<p>In the Linux Device Model, a bus is represented by the structure +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bus_type</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">bus_type</span> <span class="p">{</span> + <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">;</span> + <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">dev_name</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev_root</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">bus_attribute</span> <span class="o">*</span><span class="n">bus_attrs</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">device_attribute</span> <span class="o">*</span><span class="n">dev_attrs</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">driver_attribute</span> <span class="o">*</span><span class="n">drv_attrs</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">subsys_private</span> <span class="o">*</span><span class="n">p</span><span class="p">;</span> + + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">match</span><span class="p">)(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> <span class="k">struct</span> <span class="n">device_driver</span> <span class="o">*</span><span class="n">drv</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">uevent</span><span class="p">)(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> <span class="k">struct</span> <span class="n">kobj_uevent_env</span> <span class="o">*</span><span class="n">env</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">probe</span><span class="p">)(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">remove</span><span class="p">)(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">);</span> + <span class="c1">//...</span> +<span class="p">};</span> +</pre></div> +</div> +<p>It can be noticed that a bus has a name, lists of default attributes, a number +of specific functions, and the driver's private data. +The <code class="docutils literal"><span class="pre">uevent</span></code> function (formerly <code class="docutils literal"><span class="pre">hotplug</span></code>) is used with hotplug devices.</p> +<p>Bus operations are the registration, the implementation of the operations +described in the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bus_type</span></code> structure and the iteration and +inspection of the devices connected to the bus.</p> +<p>A bus is registered using <code class="xref c c-func docutils literal"><span class="pre">bus_register()</span></code>, and unregistered using +<code class="xref c c-func docutils literal"><span class="pre">bus_unregister()</span></code>.</p> +<p>Implementation example:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/device.h></span><span class="cp"></span> +<span class="cm">/* mybus.c */</span> + +<span class="c1">//bus type</span> +<span class="k">struct</span> <span class="n">bus_type</span> <span class="n">my_bus_type</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="s">"mybus"</span><span class="p">,</span> + <span class="p">.</span><span class="n">match</span> <span class="o">=</span> <span class="n">my_match</span><span class="p">,</span> + <span class="p">.</span><span class="n">uevent</span> <span class="o">=</span> <span class="n">my_uevent</span><span class="p">,</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="n">__init</span> <span class="nf">my_bus_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">err</span><span class="p">;</span> + + <span class="c1">//...</span> + <span class="n">err</span> <span class="o">=</span> <span class="n">bus_register</span><span class="p">(</span><span class="o">&</span><span class="n">my_bus_type</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span><span class="p">)</span> + <span class="k">return</span> <span class="n">err</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="n">__exit</span> <span class="nf">my_bus_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="c1">//...</span> + <span class="n">bus_unregister</span><span class="p">(</span><span class="o">&</span><span class="n">my_bus_type</span><span class="p">);</span> + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The functions that will normally be initialized within a bus_type structure are +<code class="docutils literal"><span class="pre">match</span></code> and <code class="docutils literal"><span class="pre">uevent</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/device.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/string.h></span><span class="cp"></span> +<span class="cm">/* mybus.c */</span> + +<span class="c1">// match devices to drivers; just do a simple name test</span> +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_match</span><span class="p">(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> <span class="k">struct</span> <span class="n">device_driver</span> <span class="o">*</span><span class="n">driver</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="o">!</span><span class="n">strncmp</span><span class="p">(</span><span class="n">dev_name</span><span class="p">(</span><span class="n">dev</span><span class="p">),</span> <span class="n">driver</span><span class="o">-></span><span class="n">name</span><span class="p">,</span> <span class="n">strlen</span><span class="p">(</span><span class="n">driver</span><span class="o">-></span><span class="n">name</span><span class="p">));</span> +<span class="p">}</span> + +<span class="c1">// respond to hotplug user events; add environment variable DEV_NAME</span> +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_uevent</span><span class="p">(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> <span class="k">struct</span> <span class="n">kobj_uevent_env</span> <span class="o">*</span><span class="n">env</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">add_uevent_var</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="s">"DEV_NAME=%s"</span><span class="p">,</span> <span class="n">dev_name</span><span class="p">(</span><span class="n">dev</span><span class="p">));</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The <code class="docutils literal"><span class="pre">match</span></code> function is used when a new device or a new driver is added to the +bus. Its role is to make a comparison between the device ID and the driver ID. +The <code class="docutils literal"><span class="pre">uevent</span></code> function is called before generating a hotplug in user-space and +has the role of adding environment variables.</p> +<p>Other possible operations on a bus are iterating over the drivers or devices +attached to it. +Although we can not directly access them (lists of drivers and devices +being stored in the private data of the driver, the <code class="docutils literal"><span class="pre">subsys_private</span> <span class="pre">*p</span></code> field), +these can be iterated using the <code class="xref c c-macro docutils literal"><span class="pre">bus_for_each_dev</span></code> and +<code class="xref c c-macro docutils literal"><span class="pre">bus_for_each_drv</span></code> macros.</p> +<p>The Linux Device Model interface allows you to create attributes for the +associated objects. These attributes will have a corresponding file in the +bus subdirectory in sysfs. The attributes associated with a bus are +described by the bus_attribute structure :</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">bus_attribute</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">attribute</span> <span class="n">attr</span><span class="p">;</span> + <span class="kt">ssize_t</span> <span class="p">(</span><span class="o">*</span><span class="n">show</span><span class="p">)(</span><span class="k">struct</span> <span class="n">bus_type</span> <span class="o">*</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">buf</span><span class="p">);</span> + <span class="kt">ssize_t</span> <span class="p">(</span><span class="o">*</span><span class="n">store</span><span class="p">)(</span><span class="k">struct</span> <span class="n">bus_type</span> <span class="o">*</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">buf</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">count</span><span class="p">);</span> +<span class="p">};</span> +</pre></div> +</div> +<p>Typically, an attribute is defined by the <code class="xref c c-macro docutils literal"><span class="pre">BUS_ATTR</span></code> macro. +The <code class="xref c c-func docutils literal"><span class="pre">bus_create_file()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">bus_remove_file()</span></code> functions can be +used to add/delete an attribute within the bus structure.</p> +<p>An example of defining an attribute for <code class="docutils literal"><span class="pre">my_bus</span></code> is shown below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* mybus.c */</span> + +<span class="cp">#define MY_BUS_DESCR "SO2 rules forever"</span> + +<span class="c1">// export a simple bus attribute</span> +<span class="k">static</span> <span class="kt">ssize_t</span> <span class="nf">my_show_bus_descr</span><span class="p">(</span><span class="k">struct</span> <span class="n">bus_type</span> <span class="o">*</span><span class="n">bus</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">buf</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="n">snprintf</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="n">PAGE_SIZE</span><span class="p">,</span> <span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">MY_BUS_DESCR</span><span class="p">);</span> +<span class="p">}</span> + +<span class="cm">/*</span> +<span class="cm"> * define attribute - attribute name is descr;</span> +<span class="cm"> * full name is bus_attr_descr;</span> +<span class="cm"> * sysfs entry should be /sys/bus/mybus/descr</span> +<span class="cm"> */</span> +<span class="n">BUS_ATTR</span><span class="p">(</span><span class="n">descr</span><span class="p">,</span> <span class="mo">0444</span><span class="p">,</span> <span class="n">my_show_bus_descr</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span> + +<span class="c1">// specify attribute - in module init function</span> +<span class="k">static</span> <span class="kt">int</span> <span class="n">__init</span> <span class="nf">my_bus_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">err</span><span class="p">;</span> + <span class="c1">//...</span> + <span class="n">err</span> <span class="o">=</span> <span class="n">bus_create_file</span><span class="p">(</span><span class="o">&</span><span class="n">my_bus_type</span><span class="p">,</span> <span class="o">&</span><span class="n">bus_attr_descr</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> + <span class="p">}</span> + <span class="c1">//...</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="n">__exit</span> <span class="nf">my_bus_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="c1">//...</span> + <span class="n">bus_remove_file</span><span class="p">(</span><span class="o">&</span><span class="n">my_bus_type</span><span class="p">,</span> <span class="o">&</span><span class="n">bus_attr_descr</span><span class="p">);</span> + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The bus is represented by both a <code class="docutils literal"><span class="pre">bus_type</span></code> object and a <code class="docutils literal"><span class="pre">device</span></code> object, +as we will see later (the bus is also a device).</p> +</div> +<div class="section" id="devices"> +<h3>Devices<a class="headerlink" href="#devices" title="Permalink to this headline">¶</a></h3> +<p>Any device in the system has a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">device</span></code> structure associated +with it. +Devices are discovered by different kernel methods (hotplug, device drivers, +system initialization) and are registered in the system. Each device present in +the kernel has an entry in <code class="docutils literal"><span class="pre">/sys/devices</span></code>.</p> +<p>At the lowest level, a device in Linux Device Model is represented by a +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">device</span></code> structure:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">device</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">parent</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">device_private</span> <span class="o">*</span><span class="n">p</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">kobject</span> <span class="n">kobj</span><span class="p">;</span> + + <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">init_name</span><span class="p">;</span> <span class="cm">/* initial name of the device */</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">bus_type</span> <span class="o">*</span><span class="n">bus</span><span class="p">;</span> <span class="cm">/* type of bus device is on */</span> + <span class="k">struct</span> <span class="n">device_driver</span> <span class="o">*</span><span class="n">driver</span><span class="p">;</span> <span class="cm">/* which driver has allocated this</span> +<span class="cm"> device */</span> + <span class="c1">//...</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">release</span><span class="p">)(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">);</span> +<span class="p">};</span> +</pre></div> +</div> +<p>Structure fields include the parent device that is usually a controller, the +associated <code class="docutils literal"><span class="pre">kobject</span></code>, the bus it is connected to, the device driver, and a +function called when the device counter reaches 0 (<code class="docutils literal"><span class="pre">release</span></code>).</p> +<p>As usual, we have the registration/unregistration functions +<code class="xref c c-func docutils literal"><span class="pre">device_register()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">device_unregister()</span></code>.</p> +<p>To work with attributes, we have structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">device_attribute</span></code>, +the macro <code class="xref c c-macro docutils literal"><span class="pre">DEVICE_ATTR</span></code> for definition, and the functions +<code class="xref c c-func docutils literal"><span class="pre">device_create_file()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">device_remove_file()</span></code> for adding/removing +the attribute to/from the device.</p> +<p>One important thing to note is that the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">device</span></code> structure is +usually not used directly, but it is added to another structure. For example:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="c1">// my device type</span> +<span class="k">struct</span> <span class="n">my_device</span> <span class="p">{</span> + <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">my_driver</span> <span class="o">*</span><span class="n">driver</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">device</span> <span class="n">dev</span><span class="p">;</span> +<span class="p">};</span> +</pre></div> +</div> +<p>Typically, a bus driver will export functions to add or remove such a +device, as shown below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* mybus.c */</span> + +<span class="cm">/* BUS DEVICE (parent) */</span> + +<span class="c1">// parent device release</span> +<span class="k">static</span> <span class="kt">void</span> <span class="nf">my_bus_device_release</span><span class="p">(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span> +<span class="p">{</span> +<span class="p">}</span> + +<span class="c1">// parent device</span> +<span class="k">static</span> <span class="k">struct</span> <span class="n">device</span> <span class="n">my_bus_device</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">init_name</span> <span class="o">=</span> <span class="s">"mybus0"</span><span class="p">,</span> + <span class="p">.</span><span class="n">release</span> <span class="o">=</span> <span class="n">my_bus_device_release</span> +<span class="p">};</span> + +<span class="cm">/* DEVICE */</span> + +<span class="cm">/*</span> +<span class="cm"> * as we are not using the reference count, we use a no-op</span> +<span class="cm"> * release function</span> +<span class="cm"> */</span> +<span class="k">static</span> <span class="kt">void</span> <span class="nf">my_dev_release</span><span class="p">(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span> +<span class="p">{</span> +<span class="p">}</span> + +<span class="kt">int</span> <span class="nf">my_register_device</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_device</span> <span class="o">*</span><span class="n">mydev</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">mydev</span><span class="o">-></span><span class="n">dev</span><span class="p">.</span><span class="n">bus</span> <span class="o">=</span> <span class="o">&</span><span class="n">my_bus_type</span><span class="p">;</span> + <span class="n">mydev</span><span class="o">-></span><span class="n">dev</span><span class="p">.</span><span class="n">parent</span> <span class="o">=</span> <span class="o">&</span><span class="n">my_bus_device</span><span class="p">;</span> + <span class="n">mydev</span><span class="o">-></span><span class="n">dev</span><span class="p">.</span><span class="n">release</span> <span class="o">=</span> <span class="n">my_dev_release</span><span class="p">;</span> + <span class="n">dev_set_name</span><span class="p">(</span><span class="o">&</span><span class="n">mydev</span><span class="o">-></span><span class="n">dev</span><span class="p">,</span> <span class="n">mydev</span><span class="o">-></span><span class="n">name</span><span class="p">);</span> + + <span class="k">return</span> <span class="n">device_register</span><span class="p">(</span><span class="o">&</span><span class="n">mydev</span><span class="o">-></span><span class="n">dev</span><span class="p">);</span> +<span class="p">}</span> + +<span class="kt">void</span> <span class="nf">my_unregister_device</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_device</span> <span class="o">*</span><span class="n">mydev</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">device_unregister</span><span class="p">(</span><span class="o">&</span><span class="n">mydev</span><span class="o">-></span><span class="n">dev</span><span class="p">);</span> +<span class="p">}</span> + +<span class="cm">/* export register/unregister device functions */</span> +<span class="n">EXPORT_SYMBOL</span><span class="p">(</span><span class="n">my_register_device</span><span class="p">);</span> +<span class="n">EXPORT_SYMBOL</span><span class="p">(</span><span class="n">my_unregister_device</span><span class="p">);</span> +</pre></div> +</div> +<p>As seen, the functions <code class="docutils literal"><span class="pre">my_register_device</span></code> and <code class="docutils literal"><span class="pre">my_unregister_device</span></code>, used +to add/remove a device to/from a bus, are defined in the same file where the +bus is defined. Device structures are not initialized; they will be initialized +when the devices are discovered by the system (by hotplug or direct registration +from driver) and the function <code class="docutils literal"><span class="pre">my_register_device</span></code> will be called to add a +device to the bus.</p> +<p>To use the bus defined above in the driver implementation, we must define a +structure of type <code class="docutils literal"><span class="pre">my_device</span></code>, initialize it and register it using the function +exported by the bus (<code class="docutils literal"><span class="pre">my_register_device</span></code>).</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* mydriver.c */</span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">my_device</span> <span class="n">mydev</span><span class="p">;</span> +<span class="kt">char</span> <span class="n">devname</span><span class="p">[</span><span class="n">NAME_SIZE</span><span class="p">];</span> +<span class="c1">//...</span> + +<span class="c1">//register</span> +<span class="kt">int</span> <span class="n">err</span><span class="p">;</span> + +<span class="n">sprintf</span><span class="p">(</span><span class="n">devname</span><span class="p">,</span> <span class="s">"mydev0"</span><span class="p">);</span> +<span class="n">mydev</span><span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">devname</span><span class="p">;</span> +<span class="n">mydev</span><span class="p">.</span><span class="n">driver</span> <span class="o">=</span> <span class="o">&</span><span class="n">mydriver</span><span class="p">;</span> +<span class="n">dev_set_drvdata</span><span class="p">(</span><span class="o">&</span><span class="n">mydev</span><span class="p">.</span><span class="n">dev</span><span class="p">,</span> <span class="o">&</span><span class="n">mydev</span><span class="p">);</span> +<span class="n">err</span> <span class="o">=</span> <span class="n">my_register_device</span><span class="p">(</span><span class="o">&</span><span class="n">mydev</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/*handle error */</span> +<span class="p">}</span> + +<span class="c1">//..</span> + +<span class="c1">//unregister</span> +<span class="n">my_unregister_device</span><span class="p">(</span><span class="o">&</span><span class="n">mydev</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="drivers"> +<h3>Drivers<a class="headerlink" href="#drivers" title="Permalink to this headline">¶</a></h3> +<p>Linux Device Model is used to allow simple association between system +devices and drivers. Drivers can export information independent of the physical +device.</p> +<p>In sysfs, driver information has no single subdirectory associated; They can be +found in the directory structure in different places: the loaded module is in +<code class="docutils literal"><span class="pre">/sys/module</span></code>, in <code class="docutils literal"><span class="pre">/sys/devices</span></code> you can find the driver associated with +each device, in <code class="docutils literal"><span class="pre">/sys/class</span></code> the drivers belonging to a class, in +<code class="docutils literal"><span class="pre">/sys/bus</span></code> the drivers associated to each bus.</p> +<p>A device driver is identified by the structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">device_driver</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">device_driver</span> <span class="p">{</span> + <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">bus_type</span> <span class="o">*</span><span class="n">bus</span><span class="p">;</span> + + <span class="k">struct</span> <span class="n">driver_private</span> <span class="o">*</span><span class="n">p</span><span class="p">;</span> + + <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">owner</span><span class="p">;</span> + <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">mod_name</span><span class="p">;</span> <span class="cm">/* used for built-in modules */</span> + + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">probe</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">remove</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">shutdown</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">suspend</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> <span class="n">pm_message_t</span> <span class="n">state</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">resume</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">);</span> +<span class="p">};</span> +</pre></div> +</div> +<p>Among the structure fields we find the name of the driver (appears in <code class="docutils literal"><span class="pre">sysfs</span></code>), +the bus with which the driver works, and functions called at various times in a +device's operation.</p> +<p>As before, we have the functions <code class="xref c c-func docutils literal"><span class="pre">driver_register()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">driver_unregister()</span></code> to register/unregister a driver.</p> +<p>To work with attributes, we have the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">driver_attribute</span></code> structure, +the macro <code class="xref c c-type docutils literal"><span class="pre">DRIVER_ATTR</span></code> for definition, and the functions +<code class="xref c c-func docutils literal"><span class="pre">driver_create_file()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">driver_remove_file()</span></code> functions for +adding the attribute to the device.</p> +<p>As with devices, the structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">device_driver</span></code> is usually +incorporated into another structure specific to a particular bus (PCI, USB, etc.):</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* mybus.c */</span> + +<span class="c1">// my driver type</span> +<span class="k">struct</span> <span class="n">my_driver</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">module</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">device_driver</span> <span class="n">driver</span><span class="p">;</span> +<span class="p">};</span> + +<span class="cp">#define to_my_driver(drv) container_of(drv, struct my_driver, driver);</span> + +<span class="kt">int</span> <span class="nf">my_register_driver</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_driver</span> <span class="o">*</span><span class="n">driver</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">err</span><span class="p">;</span> + + <span class="n">driver</span><span class="o">-></span><span class="n">driver</span><span class="p">.</span><span class="n">bus</span> <span class="o">=</span> <span class="o">&</span><span class="n">my_bus_type</span><span class="p">;</span> + <span class="n">err</span><span class="o">=</span> <span class="n">driver_register</span><span class="p">(</span><span class="o">&</span><span class="n">driver</span><span class="o">-></span><span class="n">driver</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span><span class="p">)</span> + <span class="k">return</span> <span class="n">err</span><span class="p">;</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">void</span> <span class="nf">my_unregister_driver</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_driver</span> <span class="o">*</span><span class="n">driver</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">driver_unregister</span><span class="p">(</span><span class="o">&</span><span class="n">driver</span><span class="o">-></span><span class="n">driver</span><span class="p">);</span> +<span class="p">}</span> + +<span class="cm">/* export register/unregister driver functions */</span> +<span class="n">EXPORT_SYMBOL</span><span class="p">(</span><span class="n">my_register_driver</span><span class="p">);</span> +<span class="n">EXPORT_SYMBOL</span><span class="p">(</span><span class="n">my_unregister_driver</span><span class="p">);</span> +</pre></div> +</div> +<p>Driver registration/unregistration operations are exported for use in +other modules.</p> +<p>As for devices, the operations for drivers are defined when the bus is +initialized and they are exported to be used by drivers. When implementing a +driver that works with devices attached to the bus, we will call the functions +<code class="docutils literal"><span class="pre">my_register_driver</span></code> and <code class="docutils literal"><span class="pre">my_unregister_driver</span></code> to associate with the bus.</p> +<p>To use the functions (in the driver implementation), we must declare a structure +of type <code class="docutils literal"><span class="pre">my_driver</span></code>, initialize it and register using the function exported +by the bus.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* mydriver.c */</span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">my_driver</span> <span class="n">mydriver</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">module</span> <span class="o">=</span> <span class="n">THIS_MODULE</span><span class="p">,</span> + <span class="p">.</span><span class="n">driver</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="s">"mydriver"</span><span class="p">,</span> + <span class="p">},</span> +<span class="p">};</span> +<span class="c1">//...</span> + +<span class="c1">//register</span> +<span class="kt">int</span> <span class="n">err</span><span class="p">;</span> +<span class="n">err</span> <span class="o">=</span> <span class="n">my_register_driver</span><span class="p">(</span><span class="o">&</span><span class="n">mydriver</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/*handle error */</span> +<span class="p">}</span> +<span class="c1">//..</span> + +<span class="c1">//unregister</span> +<span class="n">my_unregister_driver</span><span class="p">(</span><span class="o">&</span><span class="n">mydriver</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="classes"> +<h3>Classes<a class="headerlink" href="#classes" title="Permalink to this headline">¶</a></h3> +<p>A class is a high-level view of the Linux Device Model, which abstracts +implementation details. For example, there are drivers for SCSI and ATA +drivers, but all belong to the class of disks. Classes provide a grouping of +devices based on functionality, not how they are connected or how they work. +Classes have a correspondent in <code class="docutils literal"><span class="pre">/sys/classes</span></code>.</p> +<p>There are two main structures that describe the classes: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">class</span></code> +and <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">device</span></code>. +The class structure describes a generic class, while the structure +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">device</span></code> describes a class associated with a device. +There are functions for initializing/deinitiating and adding attributes for each +of these, described in <code class="docutils literal"><span class="pre">include/linux/device.h</span></code>.</p> +<p>The advantage of using classes is that the <code class="docutils literal"><span class="pre">udev</span></code> program in userspace, which we +will discuss later, allows the automatic creation of devices in the <code class="docutils literal"><span class="pre">/dev</span></code> +directory based on class information.</p> +<p>For this reason, we will continue to present a small set of functions that work +with classes to simplify the use of the plug and play mechanism.</p> +<p>A generic class is described by structure class structure:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">class</span> <span class="p">{</span> + <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">owner</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">kobject</span> <span class="o">*</span><span class="n">dev_kobj</span><span class="p">;</span> + + <span class="k">struct</span> <span class="n">subsys_private</span> <span class="o">*</span><span class="n">p</span><span class="p">;</span> + + <span class="k">struct</span> <span class="n">class_attribute</span> <span class="o">*</span><span class="n">class_attrs</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">class_device_attribute</span> <span class="o">*</span><span class="n">class_dev_attrs</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">device_attribute</span> <span class="o">*</span><span class="n">dev_attrs</span><span class="p">;</span> + + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">dev_uevent</span><span class="p">)(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> <span class="k">struct</span> <span class="n">kobj_uevent_env</span> <span class="o">*</span><span class="n">env</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">class_release</span><span class="p">)(</span><span class="k">struct</span> <span class="n">class</span> <span class="o">*</span><span class="n">class</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">dev_release</span><span class="p">)(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">);</span> + <span class="c1">//...</span> +<span class="p">};</span> +</pre></div> +</div> +<p>The <code class="xref c c-func docutils literal"><span class="pre">class_register()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">class_unregister()</span></code> functions can be +used for initialization/deinitialization.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="k">struct</span> <span class="n">class</span> <span class="n">my_class</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="s">"myclass"</span><span class="p">,</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="n">__init</span> <span class="nf">my_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">err</span><span class="p">;</span> + <span class="c1">//...</span> + <span class="n">err</span> <span class="o">=</span> <span class="n">class_register</span><span class="p">(</span><span class="o">&</span><span class="n">my_class</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> + <span class="p">}</span> + <span class="c1">//...</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="n">__exit</span> <span class="nf">my_cleanup</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="c1">//...</span> + <span class="n">class_unregister</span><span class="p">(</span><span class="o">&</span><span class="n">my_class</span><span class="p">);</span> + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>A class associated with a device is described by the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">device</span></code> +structure. +The <code class="xref c c-func docutils literal"><span class="pre">device_create()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">device_destroy()</span></code> functions can be used +for initialization/deinitialization. +The <code class="xref c c-func docutils literal"><span class="pre">device_create()</span></code> function initializes the <code class="docutils literal"><span class="pre">device</span></code> structure, +and assigns the generic <code class="docutils literal"><span class="pre">class</span></code> structure and the device received as a +parameter to it; +In addition, it will create an attribute of the class, <code class="docutils literal"><span class="pre">dev</span></code>, which contains +the minor and major of the device (<code class="docutils literal"><span class="pre">minor:major</span></code>). +Thus, udev utility in usermode can read the necessary data from this attribute +file to create a node in the <code class="docutils literal"><span class="pre">/dev</span></code> directory by calling <code class="docutils literal"><span class="pre">makenod</span></code>.</p> +<p>An example of initialization:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">device</span><span class="o">*</span> <span class="n">my_classdev</span><span class="p">;</span> +<span class="k">struct</span> <span class="n">cdev</span> <span class="n">cdev</span><span class="p">;</span> +<span class="k">struct</span> <span class="n">device</span> <span class="n">dev</span><span class="p">;</span> + +<span class="c1">//init class for device cdev.dev</span> +<span class="n">my_classdev</span> <span class="o">=</span> <span class="n">device_create</span><span class="p">(</span><span class="o">&</span><span class="n">my_class</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">cdev</span><span class="p">.</span><span class="n">dev</span><span class="p">,</span> <span class="o">&</span><span class="n">dev</span><span class="p">,</span> <span class="s">"myclass0"</span><span class="p">);</span> + +<span class="c1">//destroy class for device cdev.dev</span> +<span class="n">device_destroy</span><span class="p">(</span><span class="o">&</span><span class="n">my_class</span><span class="p">,</span> <span class="n">cdev</span><span class="p">.</span><span class="n">dev</span><span class="p">);</span> +</pre></div> +</div> +<p>When a new device is discovered, a class and a node will be assigned to it and +a node will be created in the <code class="docutils literal"><span class="pre">/dev</span></code> directory. +For the example above, the node <code class="docutils literal"><span class="pre">/dev/myclass0</span></code> will be generated.</p> +</div> +<div class="section" id="hotplug"> +<h3>Hotplug<a class="headerlink" href="#hotplug" title="Permalink to this headline">¶</a></h3> +<p><code class="docutils literal"><span class="pre">Hotplug</span></code> describes the mechanism for adding or removing a device from the +system while it is running without having to reboot the system.</p> +<p>A hotplug event is a notification from the kernel to the user-space when something +changes in the system configuration. These events are generated when creating +or removing a kobject from the kernel. Since these objects are the basis of the +Linux Device Model, being included in all structures (<code class="docutils literal"><span class="pre">struct</span> <span class="pre">bus_type</span></code>, +<code class="docutils literal"><span class="pre">struct</span> <span class="pre">device</span></code>, <code class="docutils literal"><span class="pre">struct</span> <span class="pre">device_driver</span></code>, <code class="docutils literal"><span class="pre">struct</span> <span class="pre">class</span></code>, etc.), a hotplug event +will be generated when any of these structures is created or removed (<code class="docutils literal"><span class="pre">uevent</span></code>).</p> +<p>When a device is discovered in the system, an event is generated. Depending on +the point where it resides in Linux Device Model, the functions corresponding +to the event will be called (usually, the <code class="docutils literal"><span class="pre">uevent</span></code> function associated to the +bus or the class). Using these functions, the driver has the ability to set +system variables for the user-space. +The generated event then reaches the user-space. Here is the <code class="docutils literal"><span class="pre">udev</span></code> +utility that captures these events. There are configuration files for this +utility in the <code class="docutils literal"><span class="pre">/etc/udev/</span></code> directory. Different rules can be specified to +capture only certain events and perform certain actions, depending on the +system variables set in the kernel or in <code class="docutils literal"><span class="pre">uevent</span></code> functions.</p> +<p>An important consequence is that in this way the plug and play mechanism can be +achieved; with the help of <code class="docutils literal"><span class="pre">udev</span></code> and the classes (described above), entries +in the <code class="docutils literal"><span class="pre">/dev/</span></code> directories can be automatically created for devices, and using +<code class="docutils literal"><span class="pre">udev</span></code> drivers can be automatically loaded for a device.</p> +<p>Rules for <code class="docutils literal"><span class="pre">udev</span></code> are located <code class="docutils literal"><span class="pre">/etc/udev/rules.d</span></code>. +Any file that ends with <code class="docutils literal"><span class="pre">.rules</span></code> in this directory will be parsed when an +event occurs. For more details on how to write rules in these files see +<a class="reference external" href="http://www.reactivated.net/writing_udev_rules.html">Writing udev rules</a>. +For testing, there are utilities such as <code class="docutils literal"><span class="pre">udevmonitor</span></code>, <code class="docutils literal"><span class="pre">udevinfo</span></code> and +<code class="docutils literal"><span class="pre">udevtest</span></code>.</p> +<p>For a quick example, consider the situation where we want to automatically load +a driver for a device when an event occurs. We can create a new file +/etc/udev/rules.d/myrules.rules, we will have the following line:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nv">SUBSYSTEM</span><span class="o">==</span><span class="s2">"pnp"</span>, ATTRS<span class="o">{</span>id<span class="o">}==</span><span class="s2">"PNP0400"</span>, <span class="nv">RUN</span><span class="o">+=</span><span class="s2">"/sbin/insmod /root/mydriver.ko"</span> +</pre></div> +</div> +<p>This will choose from the events generated only those belonging to the <code class="docutils literal"><span class="pre">pnp</span></code> +subsystem (connected to <code class="docutils literal"><span class="pre">PNP</span></code> bus) and having an id attribute with the value +<code class="docutils literal"><span class="pre">PNP0400</span></code>.</p> +<p>When this rule will be found, the command specified under <code class="docutils literal"><span class="pre">RUN</span></code> will be +executed to insert the appropriate driver in the kernel.</p> +</div> +</div> +<div class="section" id="plug-and-play"> +<h2>Plug and Play<a class="headerlink" href="#plug-and-play" title="Permalink to this headline">¶</a></h2> +<p>As noted above, in Linux Device Model all devices are connected by a bus, even if +it has a corresponding physical hardware or it is virtual.</p> +<p>The kernel already has implemented most buses using a <code class="docutils literal"><span class="pre">bus_type</span></code> structure +and functions to register/unregister drivers and devices. +To implement a driver, we must first determine the bus to which the supported +devices are connected and use the structures and functions exported by this bus. +The main buses are <code class="docutils literal"><span class="pre">PCI</span></code>, <code class="docutils literal"><span class="pre">USB</span></code>, <code class="docutils literal"><span class="pre">PNP</span></code>, <code class="docutils literal"><span class="pre">IDE</span></code>, <code class="docutils literal"><span class="pre">SCSI</span></code>, <code class="docutils literal"><span class="pre">platform</span></code>, +<code class="docutils literal"><span class="pre">ACPI</span></code>, etc.</p> +<div class="section" id="pnp-bus"> +<h3>PNP bus<a class="headerlink" href="#pnp-bus" title="Permalink to this headline">¶</a></h3> +<p>The plug and play mechanism provides a means of detecting and setting the resources +for legacy driver that may not be configured or otherwise. All plug and play +drivers, protocols, services are based on Plug and Play level. It is responsible +for the exchange of information between drivers and protocols. The following +protocols are available:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">PNPBIOS</span></code> - used for systems such as serial and parallel ports</li> +<li><code class="docutils literal"><span class="pre">ISAPNP</span></code> - offers support for the ISA bus</li> +<li><code class="docutils literal"><span class="pre">ACPI</span></code> - offering, among other things, information about system-level devices</li> +</ul> +</div></blockquote> +<p>The kernel contains a bus, called <code class="docutils literal"><span class="pre">pnp_bus</span></code>, that is used for connecting by +many drivers. +The implementation and working with the bus follow the Linux Device Model and +is very similar to what we discussed above.</p> +<p>The main functions and structures exported by the bus, which can be used by +drivers, are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">pnp_driver</span></code> - driver type associated to the bus</li> +<li><code class="xref c c-func docutils literal"><span class="pre">pnp_register_driver()</span></code> - function used to register a PNP driver in the system</li> +<li><code class="xref c c-func docutils literal"><span class="pre">pnp_unregister_driver()</span></code> - function used to unregister a PNP driver from the system</li> +</ul> +</div></blockquote> +<p>As noted in previous sections, the bus has a function called <code class="docutils literal"><span class="pre">match</span></code> used to +associate the devices with the appropriate drivers. +For example, when discovering a new device, a driver which meets the condition +given by the <code class="docutils literal"><span class="pre">match</span></code> function regarding to the new device. Usually, this +condition is a comparation of IDs (driver id and device id). +A common approach is using a static table in each driver, which holds information +about the devices supported by the driver, which will be used by the bus +when verifying the condition. For example, for a parallel port device we have +the table <code class="docutils literal"><span class="pre">parport_pc_pnp_tbl</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">pnp_device_id</span> <span class="n">parport_pc_pnp_tbl</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> + <span class="cm">/* Standard LPT Printer Port */</span> + <span class="p">{.</span><span class="n">id</span> <span class="o">=</span> <span class="s">"PNP0400"</span><span class="p">,</span> <span class="p">.</span><span class="n">driver_data</span> <span class="o">=</span> <span class="mi">0</span><span class="p">},</span> + <span class="cm">/* ECP Printer Port */</span> + <span class="p">{.</span><span class="n">id</span> <span class="o">=</span> <span class="s">"PNP0401"</span><span class="p">,</span> <span class="p">.</span><span class="n">driver_data</span> <span class="o">=</span> <span class="mi">0</span><span class="p">},</span> +<span class="p">};</span> + +<span class="n">MODULE_DEVICE_TABLE</span><span class="p">(</span><span class="n">pnp</span><span class="p">,</span> <span class="n">parport_pc_pnp_tbl</span><span class="p">);</span> +</pre></div> +</div> +<p>Each driver declares and initializes a structure <code class="docutils literal"><span class="pre">pnp_driver</span></code>, such as +<code class="docutils literal"><span class="pre">parport_pc_pnp_driver</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">parport_pc_pnp_probe</span><span class="p">(</span><span class="k">struct</span> <span class="n">pnp_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">pnp_id</span> <span class="o">*</span><span class="n">card_id</span><span class="p">,</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">pnp_id</span> <span class="o">*</span><span class="n">dev_id</span><span class="p">);</span> +<span class="k">static</span> <span class="kt">void</span> <span class="nf">parport_pc_pnp_remove</span><span class="p">(</span><span class="k">struct</span> <span class="n">pnp_dev</span><span class="o">*</span> <span class="n">dev</span><span class="p">);</span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">pnp_driver</span> <span class="n">parport_pc_pnp_driver</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="s">"parport_pc"</span><span class="p">,</span> + <span class="p">.</span><span class="n">id_table</span> <span class="o">=</span> <span class="n">parport_pc_pnp_tbl</span><span class="p">,</span> + <span class="p">.</span><span class="n">probe</span> <span class="o">=</span> <span class="n">parport_pc_pnp_probe</span><span class="p">,</span> + <span class="p">.</span><span class="n">remove</span> <span class="o">=</span> <span class="n">parport_pc_pnp_remove</span><span class="p">,</span> +<span class="p">};</span> +</pre></div> +</div> +<p>We can notice that the structure has as fields a pointer to the table declared +above and two functions, which are called when a new device is detected and when +it is removed from the system. +As all the structures presented above, the driver must be registered to the +system:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="n">__init</span> <span class="nf">parport_pc_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">err</span> <span class="o">=</span> <span class="n">pnp_register_driver</span><span class="p">(</span><span class="o">&</span><span class="n">parport_pc_pnp_driver</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> + <span class="p">}</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="n">__exit</span> <span class="nf">parport_pc_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pnp_unregister_driver</span><span class="p">(</span><span class="o">&</span><span class="n">parport_pc_pnp_driver</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="pnp-operations"> +<h3>PNP operations<a class="headerlink" href="#pnp-operations" title="Permalink to this headline">¶</a></h3> +<p>So far we have discussed the Linux Device Model and its API. To +implement a plug and play driver, we must respect the Linux Device Model model.</p> +<p>Most often, adding a bus in the kernel is not necessary, as most of the existing +buses are already implemented (PCI, USB, etc.). Thus, we must first identify the +bus to which the device is attached. +In the examples below, we will consider that this bus is bus PNP and we will +use the structures and functions described above.</p> +<img alt="../_images/ditaa-4e1f9758808dba9e61bc0e48faf4365d377f9d32.png" src="../_images/ditaa-4e1f9758808dba9e61bc0e48faf4365d377f9d32.png" /> +</div> +<div class="section" id="adding-a-driver"> +<h3>Adding a driver<a class="headerlink" href="#adding-a-driver" title="Permalink to this headline">¶</a></h3> +<p>In addition to the usual operations, a driver must follow the Linux Device Model. +Thus, it will be registered in the system using the functions provided by +the bus for this purpose. +Usually, the bus provides a particular driver structure containing a +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">device_driver</span></code> structure, that the driver must initialize and +register using a function <code class="docutils literal"><span class="pre">*_register_driver</span></code>. +For example, for the <code class="docutils literal"><span class="pre">PNP</span></code> bus, the driver must declare and initialize a +structure of type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">pnp_driver</span></code> and register it using +<code class="docutils literal"><span class="pre">pnp_register_drvier</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="k">struct</span> <span class="n">pnp_driver</span> <span class="n">my_pnp_driver</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="s">"mydriver"</span><span class="p">,</span> + <span class="p">.</span><span class="n">id_table</span> <span class="o">=</span> <span class="n">my_pnp_tbl</span><span class="p">,</span> + <span class="p">.</span><span class="n">probe</span> <span class="o">=</span> <span class="n">my_pnp_probe</span><span class="p">,</span> + <span class="p">.</span><span class="n">remove</span> <span class="o">=</span> <span class="n">my_pnp_remove</span><span class="p">,</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="n">__init</span> <span class="nf">my_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">err</span> <span class="o">=</span> <span class="n">pnp_register_driver</span><span class="p">(</span><span class="o">&</span><span class="n">my_pnp_driver</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Unlike legacy drivers, plug and play drivers don't register devices at +initialization in the init function (<code class="docutils literal"><span class="pre">my_init</span></code> in the example above) using +<code class="xref c c-func docutils literal"><span class="pre">register_device()</span></code>.</p> +<p>As described above, each bus has a <cite>match</cite> function which is called when a new +device is detected in the system to determine the associated driver. +Thus, there must be a way for each driver to export information about the +devices it supports, to allow this check to pass and have its functions further +called. +In the examples presented in this lab, the match function does a simple +comparison between the device name and the driver name. Most drivers use a table +containing information devices and store a pointer to this table in the +driver structure. +For example, a driver associated to a <code class="docutils literal"><span class="pre">PNP</span></code> bus defines a table of type +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">pnp_device_id</span></code> and initializes the field <code class="docutils literal"><span class="pre">id_table</span></code> from the +structure <code class="docutils literal"><span class="pre">pnp_driver</span> <span class="pre">my_pnp_driver</span></code> with a pointer to it:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">pnp_device_id</span> <span class="n">my_pnp_tbl</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> + <span class="cm">/* Standard LPT Printer Port */</span> + <span class="p">{.</span><span class="n">id</span> <span class="o">=</span> <span class="s">"PNP0400"</span><span class="p">,</span> <span class="p">.</span><span class="n">driver_data</span> <span class="o">=</span> <span class="mi">0</span><span class="p">},</span> + <span class="cm">/* ECP Printer Port */</span> + <span class="p">{.</span><span class="n">id</span> <span class="o">=</span> <span class="s">"PNP0401"</span><span class="p">,</span> <span class="p">.</span><span class="n">driver_data</span> <span class="o">=</span> <span class="mi">0</span><span class="p">},</span> + <span class="p">{</span> <span class="p">}</span> +<span class="p">};</span> + +<span class="n">MODULE_DEVICE_TABLE</span><span class="p">(</span><span class="n">pnp</span><span class="p">,</span><span class="n">my_pnp_tbl</span><span class="p">);</span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">pnp_driver</span> <span class="n">my_pnp_driver</span> <span class="o">=</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="p">.</span><span class="n">id_table</span> <span class="o">=</span> <span class="n">my_pnp_tbl</span><span class="p">,</span> + <span class="c1">//...</span> +<span class="p">};</span> +</pre></div> +</div> +<p>In the example above, the driver supports multiple parallel port devices, +defined in the table <code class="docutils literal"><span class="pre">my_pnp_tbl</span></code>. This information is used by the bus in +the <code class="docutils literal"><span class="pre">match_device</span></code> function. +When adding a driver, the bus driver will be associated to it and new entires +in <code class="docutils literal"><span class="pre">sysfs</span></code> will be created based on the driver name. +Then the bus <code class="docutils literal"><span class="pre">match</span></code> function will be called for every supported device, +to associate the driver with any connected device that it supports.</p> +</div> +<div class="section" id="removing-a-driver"> +<h3>Removing a driver<a class="headerlink" href="#removing-a-driver" title="Permalink to this headline">¶</a></h3> +<p>To remove a driver from the kernel, in addition to operations required for a +legacy driver, we must unregister the <code class="docutils literal"><span class="pre">device_driver</span></code> structure. +For a driver associated with the <code class="docutils literal"><span class="pre">PNP</span></code> bus, we must unregister the <code class="docutils literal"><span class="pre">pnp_driver</span></code> +structure using the <code class="xref c c-func docutils literal"><span class="pre">pnp_unregister_driver()</span></code> function:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="k">struct</span> <span class="n">pnp_driver</span> <span class="n">my_pnp_driver</span><span class="p">;</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="n">__exit</span> <span class="nf">my_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pnp_unregister_driver</span><span class="p">(</span><span class="o">&</span><span class="n">my_pnp_driver</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Unlike legacy drivers, plug and play drivers don't unregister devices in the +module unload function (<code class="docutils literal"><span class="pre">my_exit</span></code>). When a driver is removed, all the +references to it will be removed for all the devices it supports, and entries +from <code class="docutils literal"><span class="pre">sysfs</span></code> will also be removed.</p> +</div> +<div class="section" id="adding-a-new-device"> +<h3>Adding a new device<a class="headerlink" href="#adding-a-new-device" title="Permalink to this headline">¶</a></h3> +<p>As we saw above, plug and play drivers do not register devices at initialization. +This operation will take place in the <code class="docutils literal"><span class="pre">probe</span></code> function, which is called when +a new device is detected. A device attached to the <code class="docutils literal"><span class="pre">PNP</span></code> bus will be added to +the system by the function <code class="docutils literal"><span class="pre">probe</span></code> from the <code class="docutils literal"><span class="pre">pnp_driver</span></code> structure:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">my_pnp_probe</span><span class="p">(</span><span class="k">struct</span> <span class="n">pnp_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">pnp_id</span> <span class="o">*</span><span class="n">card_id</span><span class="p">,</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">pnp_id</span> <span class="o">*</span><span class="n">dev_id</span><span class="p">)</span> <span class="p">{</span> + <span class="kt">int</span> <span class="n">err</span><span class="p">,</span> <span class="n">iobase</span><span class="p">,</span> <span class="n">nr_ports</span><span class="p">,</span> <span class="n">irq</span><span class="p">;</span> + + <span class="c1">//get irq & ports</span> + <span class="k">if</span> <span class="p">(</span><span class="n">pnp_irq_valid</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span> + <span class="n">irq</span> <span class="o">=</span> <span class="n">pnp_irq</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">pnp_port_valid</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span> <span class="p">{</span> + <span class="n">iobase</span> <span class="o">=</span> <span class="n">pnp_port_start</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> + <span class="p">}</span> <span class="k">else</span> + <span class="k">return</span> <span class="o">-</span><span class="n">ENODEV</span><span class="p">;</span> + <span class="n">nr_ports</span> <span class="o">=</span> <span class="n">pnp_port_len</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> + + <span class="cm">/* register device dev */</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">pnp_driver</span> <span class="n">my_pnp_driver</span> <span class="o">=</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="p">.</span><span class="n">probe</span> <span class="o">=</span> <span class="n">my_pnp_probe</span><span class="p">,</span> + <span class="c1">//...</span> +<span class="p">};</span> +</pre></div> +</div> +<p>Upon detection of a device in the kernel (at boot or by the insertion of the +device through <code class="docutils literal"><span class="pre">hotplug</span></code>), an interrupt is generated and reaches the bus +driver. +The device is registered using the function <code class="xref c c-func docutils literal"><span class="pre">device_register()</span></code> and it is +attached to the bus. A call to the user space will also be generated, and the +event can be treated by <code class="docutils literal"><span class="pre">udev</span></code>. Then, the list of drivers associated with the +bus is iterated and the <code class="docutils literal"><span class="pre">match</span></code> function is called for each of them. +The <code class="docutils literal"><span class="pre">match</span></code> function tries to find a driver for the new device. After a +suitable driver is found for the device, the <code class="docutils literal"><span class="pre">probe</span></code> function of the driver +is called. If the function ends successfully, the device is added to the driver's +list of devices and new entries are created in <code class="docutils literal"><span class="pre">sysfs</span></code> based on the device name.</p> +</div> +<div class="section" id="removing-a-device"> +<h3>Removing a device<a class="headerlink" href="#removing-a-device" title="Permalink to this headline">¶</a></h3> +<p>As we saw above, the plug and play drivers don't unregister devices when the +driver is unloaded. This operation is done in the <code class="docutils literal"><span class="pre">remove</span></code> function, which +is called when a device is removed from the system. +In case of a device attached to the <code class="docutils literal"><span class="pre">PNP</span></code> bus, the unregister will be done +in the <code class="docutils literal"><span class="pre">remove</span></code> function specified in the <code class="docutils literal"><span class="pre">pnp_driver</span></code> structure:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">void</span> <span class="nf">my_pnp_remove</span><span class="p">(</span><span class="k">struct</span> <span class="n">pnp_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* unregister device dev */</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">pnp_driver</span> <span class="n">my_pnp_driver</span> <span class="o">=</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="p">.</span><span class="n">remove</span> <span class="o">=</span> <span class="n">my_pnp_remove</span><span class="p">,</span> +<span class="p">};</span> +</pre></div> +</div> +<p>As seen in the example above, when the removal of a device is detected, the +<code class="docutils literal"><span class="pre">my_pnp_remove</span></code> function is called. A user-space call is also generated, which +can be detected by <code class="docutils literal"><span class="pre">udev</span></code>, and entries are removed from <code class="docutils literal"><span class="pre">sysfs</span></code>.</p> +</div> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is device_model. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/device_model/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="section" id="intro"> +<h3>0. Intro<a class="headerlink" href="#intro" title="Permalink to this headline">¶</a></h3> +<p>Find the definitions of the following symbols in the Linux kernel:</p> +<blockquote> +<div><ul class="simple"> +<li>functions <code class="docutils literal"><span class="pre">dev_name</span></code>, <code class="docutils literal"><span class="pre">dev_set_name</span></code>.</li> +<li>functions <code class="docutils literal"><span class="pre">pnp_device_probe</span></code>, <code class="docutils literal"><span class="pre">pnp_bus_match</span></code>, <code class="docutils literal"><span class="pre">pnp_register_driver</span></code> +and the <code class="docutils literal"><span class="pre">pnp_bus_type</span></code> variable.</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="bus-implementation"> +<h3>1. Bus implementation<a class="headerlink" href="#bus-implementation" title="Permalink to this headline">¶</a></h3> +<p>Analyze the contents of the <code class="docutils literal"><span class="pre">bex.c</span></code>, a module that implements a bus +driver. Follow the comments marked with <strong>TODO 1</strong> and implement the missing +functionality: register the bus driver and add a new device named <code class="docutils literal"><span class="pre">root</span></code> +with type <code class="docutils literal"><span class="pre">none</span></code> and version 1.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">See <code class="xref c c-func docutils literal"><span class="pre">bex_add_dev()</span></code>.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">The register and unregister must be done using <code class="xref c c-func docutils literal"><span class="pre">bus_register()</span></code> +and <code class="xref c c-func docutils literal"><span class="pre">bus_unregister()</span></code>.</p> +</div> +<p>Load the module and verify that the bus is visible in <code class="docutils literal"><span class="pre">/sys/bus</span></code>. Verify +that the device is visible in <code class="docutils literal"><span class="pre">/sys/bus/bex/devices</span></code>.</p> +<p>Remove the module and notice that the <code class="docutils literal"><span class="pre">sysfs</span></code> entries are removed.</p> +</div> +<div class="section" id="add-type-and-version-device-attributes"> +<h3>2. Add type and version device attributes<a class="headerlink" href="#add-type-and-version-device-attributes" title="Permalink to this headline">¶</a></h3> +<p>Add two read-only device attributes, <code class="docutils literal"><span class="pre">type</span></code> and <code class="docutils literal"><span class="pre">version</span></code>. Follow the +<strong>TODO 2</strong> markings.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>You will need to add the two attributes in the structure +<code class="docutils literal"><span class="pre">bex_dev_attrs</span></code>, as follows:</p> +<p class="last"><code class="docutils literal"><span class="pre">&dev_attr_<insert-attribute-type-here>.attr,</span></code></p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>A possible implementation for the show function is the following:</p> +<div class="last highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">ssize_t</span> +<span class="nf">type_show</span><span class="p">(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> <span class="k">struct</span> <span class="n">device_attribute</span> <span class="o">*</span><span class="n">attr</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">buf</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">bex_device</span> <span class="o">*</span><span class="n">bex_dev</span> <span class="o">=</span> <span class="n">to_bex_device</span><span class="p">(</span><span class="n">dev</span><span class="p">);</span> + + <span class="k">return</span> <span class="n">sprintf</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">bex_dev</span><span class="o">-></span><span class="n">type</span><span class="p">);</span> +<span class="p">}</span> +<span class="n">DEVICE_ATTR_RO</span><span class="p">(</span><span class="n">type</span><span class="p">);</span> +</pre></div> +</div> +</div> +<p>Observe that two new attributes are visible in +/sys/bus/bex/devices/root. Check the contents of these attributes.</p> +</div> +<div class="section" id="add-del-and-add-bus-attributes"> +<h3>3. Add del and add bus attributes<a class="headerlink" href="#add-del-and-add-bus-attributes" title="Permalink to this headline">¶</a></h3> +<p>Add two write-only bus attributes, <code class="docutils literal"><span class="pre">del</span></code> and <code class="docutils literal"><span class="pre">add</span></code>. del expects the name +of a device to delete, while add expects the name, type and version to +create a new device. Follow the <strong>TODO 3</strong> markings and review +<a class="reference internal" href="#buses">Buses</a>.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use <code class="xref c c-func docutils literal"><span class="pre">sscanf()</span></code> to parse the input from sysfs and +<code class="xref c c-func docutils literal"><span class="pre">bex_del_dev()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">bex_add_dev()</span></code> to delete +and create a new device.</p> +</div> +<p>An example for the store function is the following:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">ssize_t</span> <span class="nf">add_store</span><span class="p">(</span><span class="k">struct</span> <span class="n">bus_type</span> <span class="o">*</span><span class="n">bt</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">buf</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">count</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">char</span> <span class="n">name</span><span class="p">[</span><span class="mi">32</span><span class="p">];</span> + <span class="kt">int</span> <span class="n">ret</span><span class="p">;</span> + + <span class="n">ret</span> <span class="o">=</span> <span class="n">sscanf</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="s">"%31s"</span><span class="p">,</span> <span class="n">name</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">ret</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">)</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EINVAL</span><span class="p">;</span> + + <span class="p">...</span> +<span class="p">}</span> +<span class="n">BUS_ATTR</span><span class="p">(</span><span class="n">add</span><span class="p">,</span> <span class="n">S_IWUSR</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">add_store</span><span class="p">);</span> +</pre></div> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">The store functions should return <code class="docutils literal"><span class="pre">0</span></code> if +<code class="docutils literal"><span class="pre">bex_add_dev</span></code>/<code class="docutils literal"><span class="pre">bex_del_dev</span></code> fail and <code class="docutils literal"><span class="pre">count</span></code> otherwise.</p> +</div> +<p>Create a new device and observe that is visible in +<code class="docutils literal"><span class="pre">/sys/bus/devices</span></code>. Delete it and observe it disapears from <code class="docutils literal"><span class="pre">sysfs</span></code>.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>Use echo to write into the bus attributes:</p> +<div class="last highlight-shell"><div class="highlight"><pre><span></span>$ <span class="nb">echo</span> <span class="s2">"name type 1"</span> > /sys/bus/bex/add +$ <span class="nb">echo</span> <span class="s2">"name"</span> > /sys/bus/bex/del +</pre></div> +</div> +</div> +</div> +<div class="section" id="register-the-bex-misc-driver"> +<h3>4. Register the bex misc driver<a class="headerlink" href="#register-the-bex-misc-driver" title="Permalink to this headline">¶</a></h3> +<p>Modify <strong>bex-misc.c</strong> so that it registers the driver with the bex +bus. Insert the <code class="docutils literal"><span class="pre">bmx_misc.ko</span></code> module and create a new bex device from +sysfs with the name "test", type "misc", version 2. Follow the <strong>TODO +4</strong> markings.</p> +<p>Observe that the driver is visible in <code class="docutils literal"><span class="pre">/sys/bus/bex/drivers</span></code>.</p> +<p>Why isn't the probe function called?</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Notice that the bus match function in <strong>bex.c</strong> is not +implemented.</p> +</div> +<p>Implement the bus matching function in <strong>bex.c</strong>. Follow the <strong>TODO 5</strong> +markings. Try again to create a new bex device and observe that this +time the <code class="docutils literal"><span class="pre">probe</span></code> function from the <code class="docutils literal"><span class="pre">bex_misc</span></code> driver is called.</p> +</div> +<div class="section" id="register-misc-device-in-the-bex-misc-probe-function"> +<h3>5. Register misc device in the bex_misc probe function<a class="headerlink" href="#register-misc-device-in-the-bex-misc-probe-function" title="Permalink to this headline">¶</a></h3> +<p>Modify <strong>bex_misc.c</strong> to refuse probing if <code class="docutils literal"><span class="pre">version</span> <span class="pre">></span> <span class="pre">1</span></code>. Also, register the +defined misc device in <code class="docutils literal"><span class="pre">bex_misc_probe</span></code> and deregister it in +<code class="docutils literal"><span class="pre">bex_misc_remove</span></code>. Follow the <strong>TODO 6</strong> markings.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use <code class="xref c c-func docutils literal"><span class="pre">misc_register()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">misc_deregister()</span></code>.</p> +</div> +<p>Create a new device with the name "test", type "misc" and version 2 +and observe that the probe fails. Create a new device with the name +"test2", type "misc" and version 1 and observe that the probe is +successful.</p> +<p>Inspect <code class="docutils literal"><span class="pre">/sys/bus/bex/devices/test2</span></code> and observe that we have a new +entry. Identify the major and minor for the misc device, create a +character device file and try to read and write from the misc device +buffer.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">The major and minor should be visible in the dev attribute +of the misc device</p> +</div> +</div> +<div class="section" id="monitor-uevent-notifications"> +<h3>6. Monitor uevent notifications<a class="headerlink" href="#monitor-uevent-notifications" title="Permalink to this headline">¶</a></h3> +<p>Use the <code class="docutils literal"><span class="pre">udevadm</span> <span class="pre">monitor</span></code> command and observe what happens when:</p> +<ul class="simple"> +<li>the <code class="docutils literal"><span class="pre">bex.ko</span></code> and <code class="docutils literal"><span class="pre">bex_misc.ko</span></code> modules are inserted</li> +<li>a new device with the type "type" is created</li> +<li>a new device with the type "misc" and version 2 is created</li> +<li>a new device with the type "misc" and version 1 is created</li> +<li>all of the above are removed</li> +</ul> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="memory_mapping.html" class="btn btn-neutral float-left" title="Memory mapping" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="kernel_profiling.html" class="btn btn-neutral float-right" title="Kernel Profiling" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/labs/filesystems_part1.html b/refs/pull/405/merge/labs/filesystems_part1.html new file mode 100644 index 00000000..593bfb35 --- /dev/null +++ b/refs/pull/405/merge/labs/filesystems_part1.html @@ -0,0 +1,958 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>File system drivers (Part 1) — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="File system drivers (Part 2)" href="filesystems_part2.html" /> + <link rel="prev" title="Block Device Drivers" href="block_device_drivers.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">File system drivers (Part 1)</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="#virtual-filesystem-vfs">Virtual Filesystem (VFS)</a></li> +<li class="toctree-l2"><a class="reference internal" href="#the-general-file-system-model">The general file system model</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#superblock">superblock</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#localization">Localization:</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#inode">inode</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#localization-1">Localization:</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#file">file</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#localization-2">Localization:</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#dentry">dentry</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#register-and-unregister-filesystems">Register and unregister filesystems</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#functions-mount-kill-sb">Functions mount, kill_sb</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#superblock-in-vfs">Superblock in VFS</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#the-struct-super-block-structure">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="#superblock-operations">Superblock operations</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#the-fill-super-function">The <code class="docutils literal"><span class="pre">fill_super()</span></code> function</a></li> +<li class="toctree-l2"><a class="reference internal" href="#buffer-cache">Buffer cache</a></li> +<li class="toctree-l2"><a class="reference internal" href="#functions-and-useful-macros">Functions and useful macros</a></li> +<li class="toctree-l2"><a class="reference internal" href="#further-reading">Further reading</a></li> +<li class="toctree-l2"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#myfs">myfs</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#register-and-unregister-the-myfs-file-system">1. Register and unregister the myfs file system</a></li> +<li class="toctree-l4"><a class="reference internal" href="#completing-myfs-superblock">2. Completing myfs superblock</a></li> +<li class="toctree-l4"><a class="reference internal" href="#initialize-myfs-root-inode">3. Initialize myfs root inode</a></li> +<li class="toctree-l4"><a class="reference internal" href="#test-myfs-mount-and-unmount">4. Test myfs mount and unmount</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#minfs">minfs</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#registering-and-unregistering-the-minfs-file-system">1. Registering and unregistering the minfs file system</a></li> +<li class="toctree-l4"><a class="reference internal" href="#completing-minfs-superblock">2. Completing minfs superblock</a></li> +<li class="toctree-l4"><a class="reference internal" href="#creating-and-destroying-minfs-inodes">3. Creating and destroying minfs inodes</a></li> +<li class="toctree-l4"><a class="reference internal" href="#initialize-minfs-root-inode">4. Initialize minfs root inode</a></li> +<li class="toctree-l4"><a class="reference internal" href="#testing-of-minfs-mount-and-unmount">5. Testing of minfs mount and unmount</a></li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">File system drivers (Part 1)</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/labs/filesystems_part1.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="file-system-drivers-part-1"> +<h1>File system drivers (Part 1)<a class="headerlink" href="#file-system-drivers-part-1" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<blockquote> +<div><ul class="simple"> +<li>acquiring knowledge about the Virtual Filesystem (VFS) in Linux and understanding concepts regarding 'inode', 'dentry', 'file', superblock and data block.</li> +<li>understanding the process of mounting a file system inside VFS.</li> +<li>knowledge regarding various file system types and understanding differences between file systems with physical support (on disk) and the ones without physical support.</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="virtual-filesystem-vfs"> +<h2>Virtual Filesystem (VFS)<a class="headerlink" href="#virtual-filesystem-vfs" title="Permalink to this headline">¶</a></h2> +<p>The Virtual Filesystem (also known as VFS) is a component of the kernel that handles all system calls related to files and file systems. +VFS is a generic interface between the user and a particular file system. +This abstraction simplifies the implementation of file systems and provides an easier integration of multiple file systems. This way, the implementation of a file system is accomplished by using the API provided by the VFS, and the generic hardware and I/O subsystem communication parts are handled by VFS.</p> +<p>From a functional point of view, file systems can be grouped into:</p> +<blockquote> +<div><ul class="simple"> +<li>disk file systems (ext3, ext4, xfs, fat, ntfs, etc.)</li> +<li>network file systems (nfs, smbfs/cifs, ncp, etc.)</li> +<li>virtual filesystems (procfs, sysfs, sockfs, pipefs, etc.)</li> +</ul> +</div></blockquote> +<p>A Linux kernel instance will use VFS for the hierarchy (a tree) of directories and files. +A new file system will be added as a VFS subtree using the mount operation. +A file system is usually mounted from the environment for which it was built (from a block type device, from network, etc.). +In particular, however, the VFS can use a normal file as a virtual block device, so it is possible to mount disk file systems over normal files. This way, stacks of file systems can be created.</p> +<p>The basic idea of VFS is to provide a single file model that can represent files from any file system. +The file system driver is responsible for bringing to the common denominator. +This way the kernel can create a single directory structure that contains the entire system. +There will be a file system that will be the root, the rest being mounted in its various directories.</p> +</div> +<div class="section" id="the-general-file-system-model"> +<h2>The general file system model<a class="headerlink" href="#the-general-file-system-model" title="Permalink to this headline">¶</a></h2> +<p>The general file system model, to which any implemented file system needs to be reduced, consists of several well-defined entities: <code class="xref c c-type docutils literal"><span class="pre">superblock</span></code>, <code class="xref c c-type docutils literal"><span class="pre">inode</span></code>, <code class="xref c c-type docutils literal"><span class="pre">file</span></code>, and <code class="xref c c-type docutils literal"><span class="pre">dentry</span></code>. +These entities are file system metadata (they contain information about data or other metadata).</p> +<p>Model entities interact using some VFS or kernel subsystems: dentry cache, inode cache, buffer cache. +Each entity is treated as an object: it has a associated data structure and a pointer to a table of methods. The induction of particular behavior for each component is done by replacing the associated methods.</p> +<div class="section" id="superblock"> +<h3>superblock<a class="headerlink" href="#superblock" title="Permalink to this headline">¶</a></h3> +<p>The superblock stores the information needed for a mounted file system:</p> +<blockquote> +<div><ul class="simple"> +<li>inode and blocks locations</li> +<li>file system block size</li> +<li>maximum filename length</li> +<li>maximum file size</li> +<li>the location of the root inode</li> +</ul> +</div></blockquote> +<div class="section" id="localization"> +<h4>Localization:<a class="headerlink" href="#localization" title="Permalink to this headline">¶</a></h4> +<blockquote> +<div><ul class="simple"> +<li>In the case of disk file systems, the superblock has a correspondent in the first block of the disk. (Filesystem Control Block).</li> +<li>In VFS, all superblocks of filesystems are retained in a list of structures of type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> and the methods in structures of type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_operations</span></code>.</li> +</ul> +</div></blockquote> +</div> +</div> +<div class="section" id="inode"> +<h3>inode<a class="headerlink" href="#inode" title="Permalink to this headline">¶</a></h3> +<p>The inode (index node) keeps information about a file in the general sense (abstraction): regular file, directory, special file (pipe, fifo), block device, character device, link, or anything that can be abstracted as a file.</p> +<p>An inode stores information like:</p> +<blockquote> +<div><ul class="simple"> +<li>file type;</li> +<li>file size;</li> +<li>access rights;</li> +<li>access or modify time;</li> +<li>location of data on the disk (pointers to disk blocks containing data).</li> +</ul> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Usually, the inode does not contain the file name. The name is stored by the <code class="xref c c-type docutils literal"><span class="pre">dentry</span></code> entity. This way, an inode can have multiple names (hardlinks).</p> +</div> +<div class="section" id="localization-1"> +<h4>Localization:<a class="headerlink" href="#localization-1" title="Permalink to this headline">¶</a></h4> +<p>Like the superblock, the <code class="xref c c-type docutils literal"><span class="pre">inode</span></code> has a disk correspondent. +The inodes on disk are generally grouped into a specialized area (inode area) separated from the data blocks area; In some file systems, the equivalents of the inodes are spread in the file system structure (FAT); +As a VFS entity, an inode is represented by the structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code> and by the operations with it defined in the structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode_operations</span></code>.</p> +<p>Each inode is generally identified by a number. On Linux, the <code class="docutils literal"><span class="pre">-i</span></code> argument of the <code class="docutils literal"><span class="pre">ls</span></code> command shows the inode number associated with each file:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">razvan@valhalla:~/school/so2/wiki$</span> ls -i +<span class="go">1277956 lab10.wiki 1277962 lab9.wikibak 1277964 replace_lxr.sh</span> +<span class="go">1277954 lab9.wiki 1277958 link.txt 1277955 homework.wiki</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="file"> +<h3>file<a class="headerlink" href="#file" title="Permalink to this headline">¶</a></h3> +<p>File is the component of the file system model that is closest to the user. +The structure exists only as a VFS entity in memory and has no physical correspondent on disk.</p> +<p>While the inode abstracts a file on the disk, the file structure abstracts an open file. +From the point of view of the process, the file entity abstracts the file. From the point of view of the file system implementation, however, the inode is the entity that abstracts the file.</p> +<p>The file structure maintains information such as:</p> +<blockquote> +<div><ul class="simple"> +<li>file cursor position;</li> +<li>file opening rights;</li> +<li>pointer to the associated inode (eventually its index).</li> +</ul> +</div></blockquote> +<div class="section" id="localization-2"> +<h4>Localization:<a class="headerlink" href="#localization-2" title="Permalink to this headline">¶</a></h4> +<blockquote> +<div><ul class="simple"> +<li>The structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file</span></code> is the associated VFS entity, and the structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code> represents the operations associated with it.</li> +</ul> +</div></blockquote> +</div> +</div> +<div class="section" id="dentry"> +<h3>dentry<a class="headerlink" href="#dentry" title="Permalink to this headline">¶</a></h3> +<p>The dentry (directory entry) associates an inode with a file name.</p> +<p>Generally, a dentry structure contains two fields:</p> +<blockquote> +<div><ul class="simple"> +<li>an integer that identifies the inode;</li> +<li>a string representing its name.</li> +</ul> +</div></blockquote> +<p>The dentry is a specific part of a path that can be a directory or a file. For example, for the path <code class="docutils literal"><span class="pre">/bin/vi</span></code>, dentry objects will be created for <code class="docutils literal"><span class="pre">/</span></code>, <code class="docutils literal"><span class="pre">bin</span></code>, and <code class="docutils literal"><span class="pre">vi</span></code> (a total of 3 dentry objects).</p> +<blockquote> +<div><ul class="simple"> +<li>the dentry has a correspondent on the disk, but the correspondence is not direct because each file system keeps the dentries in a specific way</li> +<li>in VFS, the dentry entity is represented by the structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">dentry</span></code> and the operations with it are defined in the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">dentry_operations</span></code> structure.</li> +</ul> +</div></blockquote> +</div> +</div> +<div class="section" id="register-and-unregister-filesystems"> +<span id="registerunregistersection"></span><h2>Register and unregister filesystems<a class="headerlink" href="#register-and-unregister-filesystems" title="Permalink to this headline">¶</a></h2> +<p>In the current version, the Linux kernel supports about 50 file systems, including:</p> +<blockquote> +<div><ul class="simple"> +<li>ext2/ ext4</li> +<li>reiserfs</li> +<li>xfs</li> +<li>fat</li> +<li>ntfs</li> +<li>iso9660</li> +<li>udf for CDs and DVDs</li> +<li>hpfs</li> +</ul> +</div></blockquote> +<p>On a single system, however, it is unlikely that there will be more than 5-6 file systems. For this reason, file systems (or, more correctly, file system types) are implemented as modules and can be loaded or unloaded at any time.</p> +<p>In order to be able to dynamically load / unload a file system module, a file system registration / deregistration API is required. The structure describing a particular file system is <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_system_type</span></code>:</p> +<blockquote> +<div><blockquote> +<div><div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> + +<span class="k">struct</span> <span class="n">file_system_type</span> <span class="p">{</span> + <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">fs_flags</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">dentry</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="n">mount</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">file_system_type</span> <span class="o">*</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span> + <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">kill_sb</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">super_block</span> <span class="o">*</span><span class="p">);</span> + <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">owner</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">file_system_type</span> <span class="o">*</span> <span class="n">next</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">hlist_head</span> <span class="n">fs_supers</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">lock_class_key</span> <span class="n">s_lock_key</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">lock_class_key</span> <span class="n">s_umount_key</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">};</span> +</pre></div> +</div> +</div></blockquote> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">name</span></code> is a string representing the name that will identify a file system (the argument passed to <code class="docutils literal"><span class="pre">mount</span> <span class="pre">-t</span></code>).</li> +<li><code class="docutils literal"><span class="pre">owner</span></code> is <code class="docutils literal"><span class="pre">THIS_MODULE</span></code> for file systems implemented in modules, and <code class="docutils literal"><span class="pre">NULL</span></code> if they are written directly into the kernel.</li> +<li>The <code class="docutils literal"><span class="pre">mount</span></code> function reads the superblock from the disk in memory when loading the file system. The function is unique to each file system.</li> +<li>The <code class="docutils literal"><span class="pre">kill_sb</span></code> function releases the super-block from memory.</li> +<li><code class="docutils literal"><span class="pre">fs_flags</span></code> specifies the flags with which the file system must be mounted. An example of such flag is <code class="docutils literal"><span class="pre">FS_REQUIRES_DEV</span></code> that specifies to VFS that the file system needs a disk (it is not a virtual file system).</li> +<li><code class="docutils literal"><span class="pre">fs_supers</span></code> is a list containing all the superblocks associated with this file system. Since the same file system can be mounted multiple times, there will be a separate superblock for each mount.</li> +</ul> +</div></blockquote> +<p>The <em>registration of a file system</em> into the kernel is generally performed in the module initialization function. For registration, the programmer will have to</p> +<blockquote> +<div><ol class="arabic simple"> +<li>initialize a structure of type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_system_type</span></code> with the name, the flags, the function that implements the superblock reading operation and the reference to the structure that identifies the current module</li> +<li>call the <code class="xref c c-func docutils literal"><span class="pre">register_filesystem()</span></code> function.</li> +</ol> +</div></blockquote> +<p>When unloading the module, you must unregister the file system by calling the <code class="xref c c-func docutils literal"><span class="pre">unregister_filesystem()</span></code> function.</p> +<p>An example of registering a virtual file system is found in the code for <code class="docutils literal"><span class="pre">ramfs</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="k">struct</span> <span class="n">file_system_type</span> <span class="n">ramfs_fs_type</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="s">"ramfs"</span><span class="p">,</span> + <span class="p">.</span><span class="n">mount</span> <span class="o">=</span> <span class="n">ramfs_mount</span><span class="p">,</span> + <span class="p">.</span><span class="n">kill_sb</span> <span class="o">=</span> <span class="n">ramfs_kill_sb</span><span class="p">,</span> + <span class="p">.</span><span class="n">fs_flags</span> <span class="o">=</span> <span class="n">FS_USERNS_MOUNT</span><span class="p">,</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="n">__init</span> <span class="nf">init_ramfs_fs</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">test_and_set_bit</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">&</span><span class="n">once</span><span class="p">))</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> + <span class="k">return</span> <span class="n">register_filesystem</span><span class="p">(</span><span class="o">&</span><span class="n">ramfs_fs_type</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<div class="section" id="functions-mount-kill-sb"> +<span id="functionsmountkillsbsection"></span><h3>Functions mount, kill_sb<a class="headerlink" href="#functions-mount-kill-sb" title="Permalink to this headline">¶</a></h3> +<p>When mounting the file system, the kernel calls the mount function defined within the structure <code class="xref c c-type docutils literal"><span class="pre">file_system_type</span></code>. The function makes a set of initializations and returns a dentry (the structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">dentry</span></code>) that represents the mount point directory. Usually <code class="xref c c-func docutils literal"><span class="pre">mount()</span></code> is a simple function that calls one of the functions:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">mount_bdev()</span></code>, which mounts a file system stored on a block device</li> +<li><code class="xref c c-func docutils literal"><span class="pre">mount_single()</span></code>, which mounts a file system that shares an instance between all mount operations</li> +<li><code class="xref c c-func docutils literal"><span class="pre">mount_nodev()</span></code>, which mounts a file system that is not on a physical device</li> +<li><code class="xref c c-func docutils literal"><span class="pre">mount_pseudo()</span></code>, a helper function for pseudo-file systems (<code class="docutils literal"><span class="pre">sockfs</span></code>, <code class="docutils literal"><span class="pre">pipefs</span></code>, generally file systems that can not be mounted)</li> +</ul> +</div></blockquote> +<p>These functions get as parameter a pointer to a function <code class="xref c c-func docutils literal"><span class="pre">fill_super()</span></code> that will be called after the superblock initialization to finish its initialization by the driver. An example of such a function can be found in the <code class="docutils literal"><span class="pre">fill_super</span></code> section.</p> +<p>When unmounting the file system, the kernel calls <code class="xref c c-func docutils literal"><span class="pre">kill_sb()</span></code>, which performs cleanup operations and invokes one of the functions:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">kill_block_super()</span></code>, which unmounts a file system on a block device</li> +<li><code class="xref c c-func docutils literal"><span class="pre">kill_anon_super()</span></code>, which unmounts a virtual file system (information is generated when requested)</li> +<li><code class="xref c c-func docutils literal"><span class="pre">kill_litter_super()</span></code>, which unmounts a file system that is not on a physical device (the information is kept in memory)</li> +</ul> +</div></blockquote> +<p>An example for a file system without disk support is the <code class="xref c c-func docutils literal"><span class="pre">ramfs_mount()</span></code> function in the <code class="docutils literal"><span class="pre">ramfs</span></code> file system:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">dentry</span> <span class="o">*</span><span class="nf">ramfs_mount</span><span class="p">(</span><span class="k">struct</span> <span class="n">file_system_type</span> <span class="o">*</span><span class="n">fs_type</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">flags</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">dev_name</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="n">mount_nodev</span><span class="p">(</span><span class="n">fs_type</span><span class="p">,</span> <span class="n">flags</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">ramfs_fill_super</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<p>An example for a file system from disk is the <code class="xref c c-func docutils literal"><span class="pre">minix_mount()</span></code> function in the <code class="docutils literal"><span class="pre">minix</span></code> file system:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">dentry</span> <span class="o">*</span><span class="nf">minix_mount</span><span class="p">(</span><span class="k">struct</span> <span class="n">file_system_type</span> <span class="o">*</span><span class="n">fs_type</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">flags</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">dev_name</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="n">mount_bdev</span><span class="p">(</span><span class="n">fs_type</span><span class="p">,</span> <span class="n">flags</span><span class="p">,</span> <span class="n">dev_name</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">minix_fill_super</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="superblock-in-vfs"> +<h2>Superblock in VFS<a class="headerlink" href="#superblock-in-vfs" title="Permalink to this headline">¶</a></h2> +<p>The superblock exists both as a physical entity (entity on disk) and as a VFS entity (within the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> structure). +The superblock contains only metainformation and is used to write and read metadata from the disk (inodes, directory entries). +A superblock (and implicitly the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> structure) will contain information about the block device used, the list of inodes, a pointer to the inode of the file system root directory, and a pointer to the superblock operations.</p> +<div class="section" id="the-struct-super-block-structure"> +<h3>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> structure<a class="headerlink" href="#the-struct-super-block-structure" title="Permalink to this headline">¶</a></h3> +<p>Part of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> structure definition is presented below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">super_block</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="kt">dev_t</span> <span class="n">s_dev</span><span class="p">;</span> <span class="cm">/* identifier */</span> + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">s_blocksize_bits</span><span class="p">;</span> <span class="cm">/* block size in bits */</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">s_blocksize</span><span class="p">;</span> <span class="cm">/* block size in bytes */</span> + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">s_dirt</span><span class="p">;</span> <span class="cm">/* dirty flag */</span> + <span class="n">loff_t</span> <span class="n">s_maxbytes</span><span class="p">;</span> <span class="cm">/* max file size */</span> + <span class="k">struct</span> <span class="n">file_system_type</span> <span class="o">*</span><span class="n">s_type</span><span class="p">;</span> <span class="cm">/* filesystem type */</span> + <span class="k">struct</span> <span class="n">super_operations</span> <span class="o">*</span><span class="n">s_op</span><span class="p">;</span> <span class="cm">/* superblock methods */</span> + <span class="c1">//...</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">s_flags</span><span class="p">;</span> <span class="cm">/* mount flags */</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">s_magic</span><span class="p">;</span> <span class="cm">/* filesystem’s magic number */</span> + <span class="k">struct</span> <span class="n">dentry</span> <span class="o">*</span><span class="n">s_root</span><span class="p">;</span> <span class="cm">/* directory mount point */</span> + <span class="c1">//...</span> + <span class="kt">char</span> <span class="n">s_id</span><span class="p">[</span><span class="mi">32</span><span class="p">];</span> <span class="cm">/* informational name */</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">s_fs_info</span><span class="p">;</span> <span class="cm">/* filesystem private info */</span> +<span class="p">};</span> +</pre></div> +</div> +<dl class="docutils"> +<dt>The superblock stores global information for an instance of a file system:</dt> +<dd><ul class="first last simple"> +<li>the physical device on which it resides</li> +<li>block size</li> +<li>the maximum size of a file</li> +<li>file system type</li> +<li>the operations it supports</li> +<li>magic number (identifies the file system)</li> +<li>the root directory <code class="docutils literal"><span class="pre">dentry</span></code></li> +</ul> +</dd> +</dl> +<p>Additionally, a generic pointer (<code class="docutils literal"><span class="pre">void</span> <span class="pre">*</span></code>) stores the private data of the file system. +The superblock can be viewed as an abstract object to which its own data is added when there is a concrete implementation.</p> +</div> +<div class="section" id="superblock-operations"> +<span id="superblocksection"></span><h3>Superblock operations<a class="headerlink" href="#superblock-operations" title="Permalink to this headline">¶</a></h3> +<p>The superblock operations are described by the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_operations</span></code> structure:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">super_operations</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">write_inode</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">writeback_control</span> <span class="o">*</span><span class="n">wbc</span><span class="p">);</span> + <span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="n">alloc_inode</span><span class="p">)(</span><span class="k">struct</span> <span class="n">super_block</span> <span class="o">*</span><span class="n">sb</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">destroy_inode</span><span class="p">)(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="p">);</span> + + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">put_super</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">super_block</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">statfs</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">dentry</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">kstatfs</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">remount_fs</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">super_block</span> <span class="o">*</span><span class="p">,</span> <span class="kt">int</span> <span class="o">*</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="p">);</span> + <span class="c1">//...</span> +<span class="p">};</span> +</pre></div> +</div> +<p>The fields of the structure are function pointers with the following meanings:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">write_inode</span></code>, <code class="docutils literal"><span class="pre">alloc_inode</span></code>, <code class="docutils literal"><span class="pre">destroy_inode</span></code> write, allocate, respectively release resources associated with an inode and are described in the next lab</li> +<li><code class="docutils literal"><span class="pre">put_super</span></code> is called when the superblock is released at <code class="docutils literal"><span class="pre">umount</span></code>; within this function, any resources (generally memory) from the file system's private data must be released;</li> +<li><code class="docutils literal"><span class="pre">remount_fs</span></code> is called when the kernel detects a remount attempt (mount flag <code class="docutils literal"><span class="pre">MS_REMOUNTM</span></code>); most of the time here must be detected if a switch from read-only to read-write or vice versa is attempted; this can be done simply because both the old flags (in <code class="docutils literal"><span class="pre">sb->s_flags</span></code>) and the new flags (the <code class="docutils literal"><span class="pre">flags</span></code> argument) can be accessed; <code class="docutils literal"><span class="pre">data</span></code> is a pointer to the data sent by <code class="xref c c-func docutils literal"><span class="pre">mount()</span></code> that represent file system specific options;</li> +<li><code class="docutils literal"><span class="pre">statfs</span></code> is called when a <code class="docutils literal"><span class="pre">statfs</span></code> system call is done (try <code class="docutils literal"><span class="pre">stat</span> <span class="pre">–f</span></code> or <code class="docutils literal"><span class="pre">df</span></code>); this call must fill the fields of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">kstatfs</span></code> structure, as it is done, for example, in the <code class="xref c c-func docutils literal"><span class="pre">ext4_statfs()</span></code> function.</li> +</ul> +</div></blockquote> +</div> +</div> +<div class="section" id="the-fill-super-function"> +<span id="fillsupersection"></span><h2>The <code class="xref c c-func docutils literal"><span class="pre">fill_super()</span></code> function<a class="headerlink" href="#the-fill-super-function" title="Permalink to this headline">¶</a></h2> +<p>As specified, the <code class="xref c c-func docutils literal"><span class="pre">fill_super()</span></code> function is called to terminate the superblock initialization. This initialization involves filling the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> structure fields and the initialization of the root directory inode.</p> +<p>An example of implementation is the <code class="xref c c-func docutils literal"><span class="pre">ramfs_fill_super()</span></code> function which is called to initialize the remaining fields in the superblock:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/pagemap.h></span><span class="cp"></span> + +<span class="cp">#define RAMFS_MAGIC 0x858458f6</span> + +<span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">super_operations</span> <span class="n">ramfs_ops</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">statfs</span> <span class="o">=</span> <span class="n">simple_statfs</span><span class="p">,</span> + <span class="p">.</span><span class="n">drop_inode</span> <span class="o">=</span> <span class="n">generic_delete_inode</span><span class="p">,</span> + <span class="p">.</span><span class="n">show_options</span> <span class="o">=</span> <span class="n">ramfs_show_options</span><span class="p">,</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">ramfs_fill_super</span><span class="p">(</span><span class="k">struct</span> <span class="n">super_block</span> <span class="o">*</span><span class="n">sb</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">int</span> <span class="n">silent</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">ramfs_fs_info</span> <span class="o">*</span><span class="n">fsi</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">err</span><span class="p">;</span> + + <span class="n">save_mount_options</span><span class="p">(</span><span class="n">sb</span><span class="p">,</span> <span class="n">data</span><span class="p">);</span> + + <span class="n">fsi</span> <span class="o">=</span> <span class="n">kzalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">ramfs_fs_info</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + <span class="n">sb</span><span class="o">-></span><span class="n">s_fs_info</span> <span class="o">=</span> <span class="n">fsi</span><span class="p">;</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">fsi</span><span class="p">)</span> + <span class="k">return</span> <span class="o">-</span><span class="n">ENOMEM</span><span class="p">;</span> + + <span class="n">err</span> <span class="o">=</span> <span class="n">ramfs_parse_options</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="o">&</span><span class="n">fsi</span><span class="o">-></span><span class="n">mount_opts</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span><span class="p">)</span> + <span class="k">return</span> <span class="n">err</span><span class="p">;</span> + + <span class="n">sb</span><span class="o">-></span><span class="n">s_maxbytes</span> <span class="o">=</span> <span class="n">MAX_LFS_FILESIZE</span><span class="p">;</span> + <span class="n">sb</span><span class="o">-></span><span class="n">s_blocksize</span> <span class="o">=</span> <span class="n">PAGE_SIZE</span><span class="p">;</span> + <span class="n">sb</span><span class="o">-></span><span class="n">s_blocksize_bits</span> <span class="o">=</span> <span class="n">PAGE_SHIFT</span><span class="p">;</span> + <span class="n">sb</span><span class="o">-></span><span class="n">s_magic</span> <span class="o">=</span> <span class="n">RAMFS_MAGIC</span><span class="p">;</span> + <span class="n">sb</span><span class="o">-></span><span class="n">s_op</span> <span class="o">=</span> <span class="o">&</span><span class="n">ramfs_ops</span><span class="p">;</span> + <span class="n">sb</span><span class="o">-></span><span class="n">s_time_gran</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> + + <span class="n">inode</span> <span class="o">=</span> <span class="n">ramfs_get_inode</span><span class="p">(</span><span class="n">sb</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">S_IFDIR</span> <span class="o">|</span> <span class="n">fsi</span><span class="o">-></span><span class="n">mount_opts</span><span class="p">.</span><span class="n">mode</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> + <span class="n">sb</span><span class="o">-></span><span class="n">s_root</span> <span class="o">=</span> <span class="n">d_make_root</span><span class="p">(</span><span class="n">inode</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">sb</span><span class="o">-></span><span class="n">s_root</span><span class="p">)</span> + <span class="k">return</span> <span class="o">-</span><span class="n">ENOMEM</span><span class="p">;</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The kernel provides generic function to implement operations with file system structures. +The <code class="xref c c-func docutils literal"><span class="pre">generic_delete_inode()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">simple_statfs()</span></code> functions used in the above code are such functions and can be used to implement the drivers if their functionality is sufficient.</p> +<p>The <code class="xref c c-func docutils literal"><span class="pre">ramfs_fill_super()</span></code> function in the above code fills some fields in the superblock, then reads the root inode and allocates the root dentry. +Reading the root inode is done in the <code class="xref c c-func docutils literal"><span class="pre">ramfs_get_inode()</span></code> function, and consists of allocating a new inode using <code class="xref c c-func docutils literal"><span class="pre">new_inode()</span></code> and initializing it. In order to free the inode, <code class="xref c c-func docutils literal"><span class="pre">iput()</span></code> is used, and <code class="xref c c-func docutils literal"><span class="pre">d_make_root()</span></code> is used to allocate the root dentry.</p> +<p>An example implementation for a disk file system is the <code class="xref c c-func docutils literal"><span class="pre">minix_fill_super()</span></code> function in the minix file system. +The functionality for the disk file system is similar to that of the virtual file system, with the exception of using the buffer cache. +Also, the minix file system keeps private data using the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minix_sb_info</span></code> structure. +A large part of this function deals with the initialization of these private data. +The private data is allocated using the <code class="xref c c-func docutils literal"><span class="pre">kzalloc()</span></code> function and stored in the <code class="docutils literal"><span class="pre">s_fs_info</span></code> field of the superblock structure.</p> +<p>VFS functions typically get as arguments the superblock, an inode and/or a dentry that contain a pointer to the superblock so that these private data can be easily accessed.</p> +</div> +<div class="section" id="buffer-cache"> +<span id="buffercachesection"></span><h2>Buffer cache<a class="headerlink" href="#buffer-cache" title="Permalink to this headline">¶</a></h2> +<p>Buffer cache is a kernel subsystem that handles caching (both read and write) blocks from block devices. +The base entity used by buffer cache is the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">buffer_head</span></code> structure. +The most important fields in this structure are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">b_data</span></code>, pointer to a memory area where the data was read from or where the data must be written to</li> +<li><code class="docutils literal"><span class="pre">b_size</span></code>, buffer size</li> +<li><code class="docutils literal"><span class="pre">b_bdev</span></code>, the block device</li> +<li><code class="docutils literal"><span class="pre">b_blocknr</span></code>, the number of block on the device that has been loaded or needs to be saved on the disk</li> +<li><code class="docutils literal"><span class="pre">b_state</span></code>, the status of the buffer</li> +</ul> +</div></blockquote> +<p>There are some important functions that work with these structures:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">__bread()</span></code>: reads a block with the given number and given size in a <code class="docutils literal"><span class="pre">buffer_head</span></code> structure; in case of success returns a pointer to the <code class="docutils literal"><span class="pre">buffer_head</span></code> structure, otherwise it returns <code class="docutils literal"><span class="pre">NULL</span></code>;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">sb_bread()</span></code>: does the same thing as the previous function, but the size of the read block is taken from the superblock, as well as the device from which the read is done;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">mark_buffer_dirty()</span></code>: marks the buffer as dirty (sets the <code class="docutils literal"><span class="pre">BH_Dirty</span></code> bit); the buffer will be written to the disk at a later time (from time to time the <code class="docutils literal"><span class="pre">bdflush</span></code> kernel thread wakes up and writes the buffers to disk);</li> +<li><code class="xref c c-func docutils literal"><span class="pre">brelse()</span></code>: frees up the memory used by the buffer, after it has previously written the buffer on disk if needed;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">map_bh()</span></code>: associates the buffer-head with the corresponding sector.</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="functions-and-useful-macros"> +<h2>Functions and useful macros<a class="headerlink" href="#functions-and-useful-macros" title="Permalink to this headline">¶</a></h2> +<p>The super block typically contains a map of occupied blocks (by inodes, dentries, data) in the form of a bitmap (vector of bits). To work with such maps, it is recommend to use the following features:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">find_first_zero_bit()</span></code>, to find the first zero bit in a memory area. The size parameter means the number of bits in the search area;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">test_and_set_bit()</span></code>, to set a bit and get the old value;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">test_and_clear_bit()</span></code>, to delete a bit and get the old value;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">test_and_change_bit()</span></code>, to invert the value of a bit and get the old value.</li> +</ul> +</div></blockquote> +<p>The following macrodefinitions can be used to verify the type of an inode:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">S_ISDIR</span></code> (<code class="docutils literal"><span class="pre">inode->i_mode</span></code>) to check if the inode is a directory;</li> +<li><code class="docutils literal"><span class="pre">S_ISREG</span></code> (<code class="docutils literal"><span class="pre">inode->i_mode</span></code>) to check if the inode is a regular file (not a link or device file).</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="further-reading"> +<h2>Further reading<a class="headerlink" href="#further-reading" title="Permalink to this headline">¶</a></h2> +<ol class="arabic simple"> +<li>Robert Love -- Linux Kernel Development, Second Edition -- Chapter +12. The Virtual Filesystem</li> +<li>Understanding the Linux Kernel, 3rd edition - Chapter 12. The Virtual +Filesystem</li> +<li><a class="reference external" href="http://www.coda.cs.cmu.edu/doc/talks/linuxvfs/">Linux Virtual File System (presentation)</a></li> +<li><a class="reference external" href="http://www.cyberciti.biz/tips/understanding-unixlinux-file-system-part-i.html">Understanding Unix/Linux Filesystem</a></li> +<li><a class="reference external" href="http://lwn.net/Articles/57369/">Creating Linux virtual filesystems</a></li> +<li><a class="reference external" href="http://www.tldp.org/LDP/tlk/fs/filesystem.html">The Linux Documentation Project - VFS</a></li> +<li><a class="reference external" href="http://www.linux.it/~rubini/docs/vfs/vfs.html">The "Virtual File System" in Linux</a></li> +<li><a class="reference external" href="http://inglorion.net/documents/tutorials/tutorfs/">A Linux Filesystem Tutorial</a></li> +<li><a class="reference external" href="http://www.win.tue.nl/~aeb/linux/lk/lk-8.html">The Linux Virtual File System</a></li> +<li><a class="reference external" href="http://lxr.free-electrons.com/source/Documentation/filesystems/vfs.txt">Documentation/filesystems/vfs.txt</a></li> +<li><a class="reference external" href="http://lxr.free-electrons.com/source/fs/">File systems sources</a></li> +</ol> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is filesystems. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/filesystems/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="section" id="myfs"> +<h3>myfs<a class="headerlink" href="#myfs" title="Permalink to this headline">¶</a></h3> +<p>To begin, we plan to get familiar with the interface exposed by the Linux kernel and the Virtual File System (VFS) component. That is why, for the beginning, we will work with a simple, virtual file system (i.e. without physical disk support). The file system is called <code class="docutils literal"><span class="pre">myfs</span></code>.</p> +<p>For this we will access the <code class="docutils literal"><span class="pre">myfs/</span></code> subdirectory in the laboratory skeleton. We will implement the superblock operations within this lab, and the next lab will continue with the inode operations.</p> +<div class="section" id="register-and-unregister-the-myfs-file-system"> +<h4>1. Register and unregister the myfs file system<a class="headerlink" href="#register-and-unregister-the-myfs-file-system" title="Permalink to this headline">¶</a></h4> +<p>The first step in working with the file system is to register and unregister it. We want to do this for the file system described in <code class="docutils literal"><span class="pre">myfs.c</span></code>. Check the file contents and follow the directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">1</span></code>.</p> +<p>The steps you need to take are described in the section <a class="reference internal" href="../so2/lab8-filesystems-part1.html#registerunregistersection"><span class="std std-ref">Register and unregister filesystems</span></a>. Use the <code class="docutils literal"><span class="pre">"myfs"</span></code> string for the file system name.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>Within the file system structure, use the <code class="docutils literal"><span class="pre">myfs_mount</span></code> function present in the code skeleton to fill the superblock (done when mounting). In <code class="docutils literal"><span class="pre">myfs_mount</span></code> call the function specific to a file system without disk support. As an argument for the specific mount function, use the function of type <code class="docutils literal"><span class="pre">fill_super</span></code> defined in the code skeleton. You can review the <a class="reference internal" href="../so2/lab8-filesystems-part1.html#functionsmountkillsbsection"><span class="std std-ref">Functions mount, kill_sb</span></a> section.</p> +<p class="last">To destroy the superblock (done at unmounting) use <code class="docutils literal"><span class="pre">kill_litter_super</span></code>, also a function specific to a file system without disk support. The function is already implemented, you need to fill it in the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_system_type</span></code> structure.</p> +</div> +<p>After completing the sections marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">1</span></code> , compile the module, copy it to the QEMU virtual machine, and start the virtual machine. Load the kernel module and then check the presence of the <code class="docutils literal"><span class="pre">myfs</span></code> file system within the <code class="docutils literal"><span class="pre">/proc/filesystems</span></code> file.</p> +<p>At the moment, the file system is only registered, it does not expose operations to use it. If we try to mount it, the operation will fail. To try mounting, we create mount point <code class="docutils literal"><span class="pre">/mnt/myfs/</span></code>.</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> mkdir -p /mnt/myfs +</pre></div> +</div> +<p>and then we use the <code class="docutils literal"><span class="pre">mount</span></code> command:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> mount -t myfs none /mnt/myfs +</pre></div> +</div> +<p>The error message we get shows that we have not implemented the operations that work on the superblock. We will have to implement the operations on the superblock and initialize the root inode. We will do this further.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The <code class="docutils literal"><span class="pre">none</span></code> argument sent to the <code class="docutils literal"><span class="pre">mount</span></code> command indicates that we do not have a device from which to mount, the file system being a virtual one. Similarly, this is how the <code class="docutils literal"><span class="pre">procfs</span></code> or <code class="docutils literal"><span class="pre">sysfs</span></code> filesystems are mounted on Linux systems.</p> +</div> +</div> +<div class="section" id="completing-myfs-superblock"> +<h4>2. Completing myfs superblock<a class="headerlink" href="#completing-myfs-superblock" title="Permalink to this headline">¶</a></h4> +<p>To be able to mount the file system, we need to fill its superblock's fields, that is, a generic VFS structure of type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code>. +We will fill out the structure within the <code class="xref c c-func docutils literal"><span class="pre">myfs_fill_super()</span></code> function; the superblock is represented by the variable <code class="docutils literal"><span class="pre">sb</span></code> passed as an argument to the function. +Follow the hints marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">2</span></code>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>To fill the <code class="docutils literal"><span class="pre">myfs_fill_super</span></code> function, you can start from the example in the section <a class="reference internal" href="../so2/lab8-filesystems-part1.html#fillsupersection"><span class="std std-ref">The fill_super() function</span></a>.</p> +<p class="last">For the superblock structure fields, use the macros defined within the code skeleton wherever possible.</p> +</div> +<p>The <code class="docutils literal"><span class="pre">s_op</span></code> field in the superblock structure must be initialized to the superblock operations structures (type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_operations</span></code>). You need to define such a structure.</p> +<p>For information on defining the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_operations</span></code> structure and filling the superblock, see the section <a class="reference internal" href="../so2/lab8-filesystems-part1.html#superblocksection"><span class="std std-ref">Superblock operations</span></a>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Initialize the <code class="docutils literal"><span class="pre">drop_inode</span></code> and <code class="docutils literal"><span class="pre">statfs</span></code> fields of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_operations</span></code> structure.</p> +</div> +<p>Although the superblock will be properly initialized at this time, the mount operation will continue to fail. +In order for the operation to be successfully completed, the root inode will have to be initialized, which we will do for the next exercise.</p> +</div> +<div class="section" id="initialize-myfs-root-inode"> +<h4>3. Initialize myfs root inode<a class="headerlink" href="#initialize-myfs-root-inode" title="Permalink to this headline">¶</a></h4> +<p>The root inode is the inode of the file system root directory (i.e. <code class="docutils literal"><span class="pre">/</span></code>). +Initialization is done when the file system is mounted. +The <code class="docutils literal"><span class="pre">myfs_fill_super</span></code> function, called at mount, is the one that calls the <code class="docutils literal"><span class="pre">myfs_get_inode</span></code> function that creates and initializes an inode. +Typically, this function is used to create and initialize all inodes; In this exercise, however, we will only create the root inode.</p> +<p>The <code class="xref c c-type docutils literal"><span class="pre">inode</span></code> is allocated inside the <code class="docutils literal"><span class="pre">myfs_get_inode</span></code> function (local variable <code class="docutils literal"><span class="pre">inode</span></code>, allocated using the <code class="xref c c-func docutils literal"><span class="pre">new_inode()</span></code> function call).</p> +<p>To successfully complete mounting the file system, you will need to fill the <code class="docutils literal"><span class="pre">myfs_get_inode</span></code> function. Follow directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">3</span></code>. A starting point is the <a class="reference external" href="https://elixir.bootlin.com/linux/latest/source/fs/ramfs/inode.c#L63">ramfs_get_inode</a> function.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>To initialize <code class="docutils literal"><span class="pre">uid</span></code>, <code class="docutils literal"><span class="pre">gid</span></code> and <code class="docutils literal"><span class="pre">mode</span></code> , you can use the <code class="xref c c-func docutils literal"><span class="pre">inode_init_owner()</span></code> function as it is used in <code class="xref c c-func docutils literal"><span class="pre">ramfs_get_inode()</span></code>. +When you call <code class="xref c c-func docutils literal"><span class="pre">inode_init_owner()</span></code>, use <code class="docutils literal"><span class="pre">NULL</span></code> as the second parameter because there is no parent directory for the created inode.</p> +<p>Initialize the <code class="docutils literal"><span class="pre">i_atime</span></code>, <code class="docutils literal"><span class="pre">i_ctime</span></code>, and <code class="docutils literal"><span class="pre">i_mtime</span></code> of the VFS inode to the value returned by the <code class="xref c c-func docutils literal"><span class="pre">current_time()</span></code> function.</p> +<p>You will need to initialize the operations for the inode of type directory. To do this, follow the steps:</p> +<blockquote class="last"> +<div><ol class="arabic simple"> +<li>Check if this is a directory type inode using the <code class="docutils literal"><span class="pre">S_ISDIR</span></code> macro.</li> +<li>For the <code class="docutils literal"><span class="pre">i_op</span></code> and <code class="docutils literal"><span class="pre">i_fop</span></code> fields, use kernel functions that are already implemented:<ul> +<li>for <code class="docutils literal"><span class="pre">i_op</span></code>: <code class="xref c c-type docutils literal"><span class="pre">simple_dir_inode_operations</span></code>.</li> +<li>for <code class="docutils literal"><span class="pre">i_fop</span></code>: <code class="xref c c-type docutils literal"><span class="pre">simple_dir_operations</span></code></li> +</ul> +</li> +<li>Increase the number of links for the directory using the <code class="xref c c-func docutils literal"><span class="pre">inc_nlink()</span></code> function.</li> +</ol> +</div></blockquote> +</div> +</div> +<div class="section" id="test-myfs-mount-and-unmount"> +<h4>4. Test myfs mount and unmount<a class="headerlink" href="#test-myfs-mount-and-unmount" title="Permalink to this headline">¶</a></h4> +<p>Now we can mount the filesystem. +Follow the steps above to compile the kernel module, copy to the virtual machine, and start the virtual machine, then insert the kernel module, create the mount point <code class="docutils literal"><span class="pre">/mnt/myfs/</span></code>, and mount the file system. +We verify that the file system was mounted by inspecting the <code class="docutils literal"><span class="pre">/proc/mounts</span></code> file.</p> +<p>What inode number does the <code class="docutils literal"><span class="pre">/mnt/myfs</span></code> directory have? Why?</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>To display the inode number of a directory, use the command:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">ls -di /path/to/directory</span> +</pre></div> +</div> +<p class="last">where <code class="docutils literal"><span class="pre">/path/to/directory/</span></code> is the path to the directory whose inode number we want to display.</p> +</div> +<p>We check myfs file system statistics using the following command:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">stat -f /mnt/myfs</span> +</pre></div> +</div> +<p>We want to see what the mount point <code class="docutils literal"><span class="pre">/mnt/myfs</span></code> contains and if we can create files. +For this we run the commands:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ls -la /mnt/myfs +<span class="gp">#</span> touch /mnt/myfs/a.txt +</pre></div> +</div> +<p>We can see that we can not create the <code class="docutils literal"><span class="pre">a.txt</span></code> file on the file system. +This is because we have not implemented the operations to work with inodes in the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_operations</span></code> structure. +We will implement these operations within the next lab.</p> +<p>Unmount the file system using the command</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">umount /mnt/myfs</span> +</pre></div> +</div> +<p>Unload the kernel module corresponding to the file system as well.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>To test the entire functionality, you can use the <code class="docutils literal"><span class="pre">test-myfs.sh</span></code> script:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">./test-myfs.sh</span> +</pre></div> +</div> +<p>The script is copied to the virtual machine using <code class="docutils literal"><span class="pre">make</span> <span class="pre">copy</span></code> only if it is executable:</p> +<div class="last highlight-console"><div class="highlight"><pre><span></span><span class="gp">student@workstation:~/linux/tools/labs$</span> chmod +x skels/filesystems/myfs/test-myfs.sh +</pre></div> +</div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The statistics displayed for the file system are minimal because the information is provided by the simple_statfs function.</p> +</div> +</div> +</div> +<div class="section" id="minfs"> +<h3>minfs<a class="headerlink" href="#minfs" title="Permalink to this headline">¶</a></h3> +<p>Next, we will implement the basics of a very simple file system, called <code class="docutils literal"><span class="pre">minfs</span></code>, with disk support. +We will use a disk in the virtual machine that we will format and mount with the <code class="docutils literal"><span class="pre">minfs</span></code> filesystem.</p> +<p>For this we will access the <code class="docutils literal"><span class="pre">minfs/kernel</span></code> directory from the laboratory skeleton and work with the code in <code class="docutils literal"><span class="pre">minfs.c</span></code>. +Just like <code class="docutils literal"><span class="pre">myfs</span></code> we will not implement the operations for working with inodes. We will just limit to working with the superblock and, therefore, mounting. +The rest of the operations will be implemented in the next lab.</p> +<p>Follow the diagram below to clarify the role of structures within the <code class="docutils literal"><span class="pre">minfs</span></code> file system.</p> +<img alt="../_images/minfs.png" src="../_images/minfs.png" /> +<div class="section" id="registering-and-unregistering-the-minfs-file-system"> +<h4>1. Registering and unregistering the minfs file system<a class="headerlink" href="#registering-and-unregistering-the-minfs-file-system" title="Permalink to this headline">¶</a></h4> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>Before solving the exercise, we need to add a disk to the virtual machine. To do this, generate a file that we will use as the disk image using the following command:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">dd if=/dev/zero of=mydisk.img bs=1M count=100</span> +</pre></div> +</div> +<p class="last">and add the <code class="docutils literal"><span class="pre">-drive</span> <span class="pre">file=mydisk.img,if=virtio,format=raw</span></code> argument to the <code class="docutils literal"><span class="pre">qemu</span></code> command in <code class="docutils literal"><span class="pre">qemu/Makefile</span></code> (in the <code class="docutils literal"><span class="pre">QEMU_OPTS</span></code> variable). +The new argument for the <code class="docutils literal"><span class="pre">qemu</span></code> command must be added after the one for the existing disk (<code class="docutils literal"><span class="pre">YOCTO_IMAGE</span></code>).</p> +</div> +<p>To register and unregister the file system, you will need to fill the <code class="docutils literal"><span class="pre">minfs_fs_type</span></code> and <code class="docutils literal"><span class="pre">minfs_mount</span></code> functions in <code class="docutils literal"><span class="pre">minfs.c</span></code>. Follow the directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">1</span></code>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>In the file system structure, for mount, use the <code class="docutils literal"><span class="pre">minfs_mount</span></code> function from in the code skeleton. +In this function, call the function to mount a file system with disk support (See the <a class="reference internal" href="../so2/lab8-filesystems-part1.html#functionsmountkillsbsection"><span class="std std-ref">Functions mount, kill_sb</span></a> section. Use <code class="xref c c-func docutils literal"><span class="pre">mount_bdev()</span></code>). +Choose the most suitable function for destroying the superblock (done at unmount); keep in mind that it is a file system with disk support. Use the <code class="xref c c-func docutils literal"><span class="pre">kill_block_super()</span></code> function.</p> +<p>Initialize the <code class="docutils literal"><span class="pre">fs_flags</span></code> field of the <code class="xref c c-type docutils literal"><span class="pre">minfs_fs_type</span></code> structure with the appropriate value for a file system with disk support. See the section <a class="reference internal" href="../so2/lab8-filesystems-part1.html#registerunregistersection"><span class="std std-ref">Register and unregister filesystems</span></a>.</p> +<p class="last">The function for filling the superblock is <code class="docutils literal"><span class="pre">minfs_fill_super</span></code>.</p> +</div> +<p>After completing the sections marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">1</span></code>, compile the module, copy it into the QEMU virtual machine, and start the virtual machine. +Load the kernel module and then check the presence of the <code class="docutils literal"><span class="pre">minfs</span></code> file system within the <code class="docutils literal"><span class="pre">/proc/filesystems</span></code> file.</p> +<p>To test the mounting of the <code class="docutils literal"><span class="pre">minfs</span></code> file system we will need to format the disk with its structure. Formatting requires the <code class="docutils literal"><span class="pre">mkfs.minfs</span></code> formatting tool from the <code class="docutils literal"><span class="pre">minfs/user</span></code> directory. The utility is automatically compiled when running <code class="docutils literal"><span class="pre">make</span> <span class="pre">build</span></code> and copied to the virtual machine at <code class="docutils literal"><span class="pre">make</span> <span class="pre">copy</span></code>.</p> +<p>After compiling, copying, and starting the virtual machine, format the <code class="docutils literal"><span class="pre">/dev/vdd</span></code> using the formatting utility:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ./mkfs.minfs /dev/vdd +</pre></div> +</div> +<p>Load the kernel module:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> insmod minfs.ko +</pre></div> +</div> +<p>Create mount point <code class="docutils literal"><span class="pre">/mnt/minfs/</span></code>:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> mkdir -p /mnt/minfs/ +</pre></div> +</div> +<p>and mount the filesystem</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> mount -t minfs /dev/vdd /mnt/minfs/ +</pre></div> +</div> +<p>The operation fails because the root inode is not initialized.</p> +</div> +<div class="section" id="completing-minfs-superblock"> +<h4>2. Completing minfs superblock<a class="headerlink" href="#completing-minfs-superblock" title="Permalink to this headline">¶</a></h4> +<p>To be able to mount the file system, you will need to fill the superblock (i.e a structure with type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code>) within the <code class="docutils literal"><span class="pre">minfs_fill_super</span></code> function; it is the <code class="docutils literal"><span class="pre">s</span></code> argument of the function. +The structure of operations on the superblock is already defined: <code class="docutils literal"><span class="pre">minfs_ops</span></code>. +Follow the directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">2</span></code>. You can also follow the implementation of the <a class="reference external" href="https://elixir.bootlin.com/linux/latest/source/fs/minix/inode.c#L153">minix_fill_super</a> function.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>Some structures are found in the header file <code class="docutils literal"><span class="pre">minfs.h</span></code>.</p> +<p>For information on working with buffers, go to the <a class="reference internal" href="../so2/lab8-filesystems-part1.html#buffercachesection"><span class="std std-ref">Buffer cache</span></a> section.</p> +<p>Read the first block on the disk (block with index 0). +To read the block, use the <code class="xref c c-func docutils literal"><span class="pre">sb_bread()</span></code> function. +Cast the read data (the <code class="docutils literal"><span class="pre">b_data</span></code> field in the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">buffer_head</span></code> structure) to the structure storing the <code class="docutils literal"><span class="pre">minfs</span></code> superblock information on the disk: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minfs_super_block</span></code>, defined in the source code file.</p> +<p class="last">Structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minfs_super_block</span></code> holds file system-specific information that is not found in the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> generic structure (in this case only version). +Those additional information (found in <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minfs_super_block</span></code> (on disk) but not in <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> (VFS)) will be stored in the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minfs_sb_info</span></code> structure.</p> +</div> +<p>To check the functionality, we need a function for reading the root inode. +For the time being, use the <code class="docutils literal"><span class="pre">myfs_get_inode</span></code> function from <code class="docutils literal"><span class="pre">myfs</span></code> file system exercises. +Copy the function into the source code and call it the same as you did for myfs. +The third argument when calling the <code class="docutils literal"><span class="pre">myfs_get_inode</span></code> function is the inode creation permissions, similar to the virtual file system exercise (myfs).</p> +<p>Validate the implementation by executing the commands from the previous exercise.</p> +</div> +<div class="section" id="creating-and-destroying-minfs-inodes"> +<h4>3. Creating and destroying minfs inodes<a class="headerlink" href="#creating-and-destroying-minfs-inodes" title="Permalink to this headline">¶</a></h4> +<p>For mounting, we need to initialize the root inode, and to get the root inode, we need to implement the functions to work with inodes. +That is, you need to implement the <code class="docutils literal"><span class="pre">minfs_alloc_inode</span></code> and <code class="docutils literal"><span class="pre">minfs_destroy_inode</span></code> functions. +Follow the directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">3</span></code>. You can use the <code class="xref c c-func docutils literal"><span class="pre">minix_alloc_inode()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">minix_destroy_inode()</span></code> functions as a model.</p> +<p>For the implementation, look at the macros and structures in the <code class="docutils literal"><span class="pre">minfs.h</span></code> header file.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>For memory allocation/deallocation in <code class="docutils literal"><span class="pre">minfs_alloc_inode</span></code> and <code class="docutils literal"><span class="pre">minfs_destroy_inode</span></code>, we recommend using <code class="xref c c-func docutils literal"><span class="pre">kzalloc()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">kfree()</span></code>.</p> +<p>In <code class="docutils literal"><span class="pre">minfs_alloc_inode</span></code> allocate structures with type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code>, but only return structures with type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code>, i.e. return those given by the <code class="docutils literal"><span class="pre">vfs_inode</span></code> field.</p> +<p>In the <code class="docutils literal"><span class="pre">minfs_alloc_inode</span></code> function, call <code class="xref c c-func docutils literal"><span class="pre">inode_init_once()</span></code> to initialize the inode.</p> +<p class="last">In the <code class="docutils literal"><span class="pre">destroy_inode</span></code> function, you can access the structure with type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code> using the <code class="docutils literal"><span class="pre">container_of</span></code> macro.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">In this exercise, you have implemented the <code class="docutils literal"><span class="pre">minfs_alloc_inode</span></code> and <code class="docutils literal"><span class="pre">minfs_destroy_inode</span></code> functions, but they are not yet called. The correctness of the implementation will be checked at the end of the next exercise.</p> +</div> +</div> +<div class="section" id="initialize-minfs-root-inode"> +<h4>4. Initialize minfs root inode<a class="headerlink" href="#initialize-minfs-root-inode" title="Permalink to this headline">¶</a></h4> +<p>Initializing the root inode is required in order to mount the file system. +For this, you will need to complete the <code class="docutils literal"><span class="pre">minfs_ops</span></code> structure with the <code class="docutils literal"><span class="pre">minfs_alloc_inode</span></code> and <code class="docutils literal"><span class="pre">minfs_destroy_inode</span></code> functions and fill the <code class="docutils literal"><span class="pre">minfs_iget</span></code> function.</p> +<p>The <code class="docutils literal"><span class="pre">minfs_iget</span></code> function is the function called to allocate a VFS inode (i.e. <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code>) and fill it with minfs inode-specific information from the disk (i.e. <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode</span></code>).</p> +<p>Follow the directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">4</span></code>. +Fill out the <code class="docutils literal"><span class="pre">alloc_inode</span></code> and <code class="docutils literal"><span class="pre">destroy_inode</span></code> fields of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_operations</span></code> structure with the functions implemented in the previous step.</p> +<p>The information about the root inode is found in the second block on the disk (the inode with index 1). +Make <code class="docutils literal"><span class="pre">minfs_iget</span></code> read the root minfs inode from the disk (<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode</span></code>) and fill in the VFS inode (<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code>).</p> +<p>In the <code class="docutils literal"><span class="pre">minfs_fill_super</span></code> function, replace the <code class="docutils literal"><span class="pre">myfs_get_inode</span></code> call with the <code class="docutils literal"><span class="pre">minfs_iget</span></code> function call.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>To implement the <code class="docutils literal"><span class="pre">minfs_iget</span></code> function, follow the implementation of <a class="reference external" href="https://elixir.bootlin.com/linux/v4.15/source/fs/minix/inode.c#L460">V1_minix_iget</a>. +To read a block, use the <code class="xref c c-func docutils literal"><span class="pre">sb_bread()</span></code> function. +Cast the read data (the <code class="docutils literal"><span class="pre">b_data</span></code> field of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">buffer_head</span></code> structure) to the minfs inode from the disk (<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode</span></code>).</p> +<p>The <code class="docutils literal"><span class="pre">i_uid</span></code>, <code class="docutils literal"><span class="pre">i_gid</span></code>, <code class="docutils literal"><span class="pre">i_mode</span></code>, <code class="docutils literal"><span class="pre">i_size</span></code> must be filled in the VFS inode with the values in the minfs inode structure read from disk. +To initialize the <code class="docutils literal"><span class="pre">i_uid</span></code> and <code class="docutils literal"><span class="pre">i_gid</span> <span class="pre">fields</span></code>, use the functions <code class="xref c c-func docutils literal"><span class="pre">i_uid_write()</span></code> , and <code class="xref c c-func docutils literal"><span class="pre">i_gid_write()</span></code>.</p> +<p>Initialize the <code class="docutils literal"><span class="pre">i_atime</span></code> , <code class="docutils literal"><span class="pre">i_ctime</span></code>, and <code class="docutils literal"><span class="pre">i_mtime</span></code> fields of the VFS inode to the value returned by the <code class="xref c c-func docutils literal"><span class="pre">current_time()</span></code> function.</p> +<p>You will need to initialize the operations for the inode with type directory. To do this, follow the steps:</p> +<blockquote class="last"> +<div><ol class="arabic simple"> +<li>Check if this is a directory type inode using the <code class="docutils literal"><span class="pre">S_ISDIR</span></code> macro.</li> +<li>For the <code class="docutils literal"><span class="pre">i_op</span></code> and <code class="docutils literal"><span class="pre">i_fop</span></code> fields, use kernel functions already implemented:<ul> +<li>for <code class="docutils literal"><span class="pre">i_op</span></code>: <code class="xref c c-func docutils literal"><span class="pre">simple_dir_inode_operations()</span></code> .</li> +<li>for <code class="docutils literal"><span class="pre">i_fop</span></code>: <code class="xref c c-func docutils literal"><span class="pre">simple_dir_operations()</span></code></li> +</ul> +</li> +<li>Increment the number of links for the directory using the <code class="xref c c-func docutils literal"><span class="pre">inc_nlink()</span></code> function.</li> +</ol> +</div></blockquote> +</div> +</div> +<div class="section" id="testing-of-minfs-mount-and-unmount"> +<h4>5. Testing of minfs mount and unmount<a class="headerlink" href="#testing-of-minfs-mount-and-unmount" title="Permalink to this headline">¶</a></h4> +<p>Now we can mount the filesystem. +Follow the steps above to compile the kernel module, copy to the virtual machine, start the virtual machine, and then insert the kernel module, create mount point <code class="docutils literal"><span class="pre">/mnt/minfs/</span></code> and mount the file system. +We verify that the file system was mounted by investigating the <code class="docutils literal"><span class="pre">/proc/mounts</span></code> file.</p> +<p>We check that everything is fine by listing the mount point contents <code class="docutils literal"><span class="pre">/mnt/minfs/</span></code>:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ls /mnt/minfs/ +</pre></div> +</div> +<p>After mount and verification, unmount the file system and unload the module from the kernel.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>Alternatively, to test the entire functionality, you can use the <code class="docutils literal"><span class="pre">test-minfs.sh</span></code> script:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ./test-minfs.sh +</pre></div> +</div> +<p>The script is copied to the virtual machine when running the <code class="docutils literal"><span class="pre">make</span> <span class="pre">copy</span></code> command only if is executable.</p> +<div class="last highlight-console"><div class="highlight"><pre><span></span><span class="gp">student@workstation:~/linux/tools/labs$</span> chmod +x skels/filesystems/minfs/user/test-minfs.sh +</pre></div> +</div> +</div> +</div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="block_device_drivers.html" class="btn btn-neutral float-left" title="Block Device Drivers" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="filesystems_part2.html" class="btn btn-neutral float-right" title="File system drivers (Part 2)" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/labs/filesystems_part2.html b/refs/pull/405/merge/labs/filesystems_part2.html new file mode 100644 index 00000000..fe3d9eeb --- /dev/null +++ b/refs/pull/405/merge/labs/filesystems_part2.html @@ -0,0 +1,1215 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>File system drivers (Part 2) — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Networking" href="networking.html" /> + <link rel="prev" title="File system drivers (Part 1)" href="filesystems_part1.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">File system drivers (Part 2)</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="#inode">Inode</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#the-inode-structure">The inode structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="#inode-operations">Inode operations</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#getting-an-inode">Getting an inode</a></li> +<li class="toctree-l4"><a class="reference internal" href="#superoperations">Superoperations</a></li> +<li class="toctree-l4"><a class="reference internal" href="#inode-operations-1">inode_operations</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#the-file-structure">The file structure</a></li> +<li class="toctree-l2"><a class="reference internal" href="#regular-files-inodes">Regular files inodes</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#regular-files-inode-operations">Regular files inode operations</a></li> +<li class="toctree-l3"><a class="reference internal" href="#address-space-operations">Address space operations</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#dentry-structure">Dentry structure</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#dentry-operations">Dentry operations</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#directory-inodes-operations">Directory inodes operations</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#creating-an-inode">Creating an inode</a></li> +<li class="toctree-l3"><a class="reference internal" href="#creating-a-directory">Creating a directory</a></li> +<li class="toctree-l3"><a class="reference internal" href="#creating-a-link">Creating a link</a></li> +<li class="toctree-l3"><a class="reference internal" href="#creating-a-symbolic-link">Creating a symbolic link</a></li> +<li class="toctree-l3"><a class="reference internal" href="#deleting-a-link">Deleting a link</a></li> +<li class="toctree-l3"><a class="reference internal" href="#deleting-a-directory">Deleting a directory</a></li> +<li class="toctree-l3"><a class="reference internal" href="#searching-for-an-inode-in-a-directory">Searching for an inode in a directory</a></li> +<li class="toctree-l3"><a class="reference internal" href="#iterating-through-entries-in-a-directory">Iterating through entries in a directory</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#bitmap-operations">Bitmap operations</a></li> +<li class="toctree-l2"><a class="reference internal" href="#further-reading">Further reading</a></li> +<li class="toctree-l2"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#myfs">myfs</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#directory-operations">1. Directory operations</a></li> +<li class="toctree-l4"><a class="reference internal" href="#file-operations">2. File operations</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#minfs">minfs</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#iterate-operation">1. Iterate operation</a></li> +<li class="toctree-l4"><a class="reference internal" href="#lookup-operation">2. Lookup operation</a></li> +<li class="toctree-l4"><a class="reference internal" href="#create-operation">3. Create operation</a></li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">File system drivers (Part 2)</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/labs/filesystems_part2.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="file-system-drivers-part-2"> +<h1>File system drivers (Part 2)<a class="headerlink" href="#file-system-drivers-part-2" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<blockquote> +<div><ul class="simple"> +<li>Improving the knowledge about inode, file and dentry.</li> +<li>Acquiring knowledge about adding support for working with regular files and directories in VFS (<em>Virtual File System</em>).</li> +<li>Acquiring knowledge about the internal implementation of a file system.</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="inode"> +<h2>Inode<a class="headerlink" href="#inode" title="Permalink to this headline">¶</a></h2> +<p>The inode is an essential component of a UNIX file system and, at the same time, an important component of VFS. An inode is a metadata (it has information about information). +An inode uniquely identifies a file on disk and holds information about it (uid, gid, access rights, access times, pointers to data blocks, etc.). +An important aspect is that an inode does not have information about the file name (it is retained by the associated <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">dentry</span></code> structure).</p> +<p>The inode refers to a file on the disk. To refer an open file (associated with a file descriptor within a process), the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file</span></code> structure is used. +An inode can have any number of (zero or more) <code class="docutils literal"><span class="pre">file</span></code> structures associated (multiple processes can open the same file, or a process can open the same file several times).</p> +<p>Inode exists both as a VFS entity (in memory) and as a disk entity (for UNIX, HFS, NTFS, etc.). +The inode in VFS is represented by the structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code>. +Like the other structures in VFS, <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code> is a generic structure that covers the options for all supported file types, even those that do not have an associated disk entity (such as FAT).</p> +<div class="section" id="the-inode-structure"> +<h3>The inode structure<a class="headerlink" href="#the-inode-structure" title="Permalink to this headline">¶</a></h3> +<p>The inode structure is the same for all file systems. In general, file systems also have private information. These are referenced through the <code class="docutils literal"><span class="pre">i_private</span></code> field of the structure. +Conventionally, the structure that keeps that particular information is called <code class="docutils literal"><span class="pre"><fsname>_inode_info</span></code>, where <code class="docutils literal"><span class="pre">fsname</span></code> represents the file system name. For example, minix and ext4 filesystems store particular information in structures <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minix_inode_info</span></code>, or <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">ext4_inode_info</span></code>.</p> +<p>Some of the important fields of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code> are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">i_sb</span></code> : The superblock structure of the file system the inode belongs to.</li> +<li><code class="docutils literal"><span class="pre">i_rdev</span></code>: the device on which this file system is mounted</li> +<li><code class="docutils literal"><span class="pre">i_ino</span></code> : the number of the inode (uniquely identifies the inode within the file system)</li> +<li><code class="docutils literal"><span class="pre">i_blkbits</span></code>: number of bits used for the block size == log<sub>2</sub>(block size)</li> +<li><code class="docutils literal"><span class="pre">i_mode</span></code>, <code class="docutils literal"><span class="pre">i_uid</span></code>, <code class="docutils literal"><span class="pre">i_gid</span></code>: access rights, uid, gid</li> +<li><code class="docutils literal"><span class="pre">i_size</span></code>: file/directory/etc. size in bytes</li> +<li><code class="docutils literal"><span class="pre">i_mtime</span></code>, <code class="docutils literal"><span class="pre">i_atime</span></code>, <code class="docutils literal"><span class="pre">i_ctime</span></code>: change, access, and creation time</li> +<li><code class="docutils literal"><span class="pre">i_nlink</span></code>: the number of names entries (dentries) that use this inode; for file systems without links (either hard or symbolic) this is always set to 1</li> +<li><code class="docutils literal"><span class="pre">i_blocks</span></code>: the number of blocks used by the file (all blocks, not just data); this is only used by the quota subsystem</li> +<li><code class="docutils literal"><span class="pre">i_op</span></code>, <code class="docutils literal"><span class="pre">i_fop</span></code>: pointers to operations structures: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode_operations</span></code> and <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code>; <code class="docutils literal"><span class="pre">i_mapping->a_ops</span></code> contains a pointer to <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">address_space_operations</span></code>.</li> +<li><code class="docutils literal"><span class="pre">i_count</span></code>: the inode counter indicating how many kernel components use it.</li> +</ul> +</div></blockquote> +<p>Some functions that can be used to work with inodes:</p> +<blockquote> +<div><ul> +<li><p class="first"><code class="xref c c-func docutils literal"><span class="pre">new_inode()</span></code>: creates a new inode, sets the <code class="docutils literal"><span class="pre">i_nlink</span></code> field to 1 and initializes <code class="docutils literal"><span class="pre">i_blkbits</span></code>, <code class="docutils literal"><span class="pre">i_sb</span></code> and <code class="docutils literal"><span class="pre">i_dev</span></code>;</p> +</li> +<li><p class="first"><code class="xref c c-func docutils literal"><span class="pre">insert_inode_hash()</span></code>: adds the inode to the hash table of inodes; an interesting effect of this call is that the inode will be written to the disk if it is marked as dirty;</p> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p class="last">An inode created with <code class="xref c c-func docutils literal"><span class="pre">new_inode()</span></code> is not in the hash table, and unless you have serious reasons not to, you must enter it in the hash table;</p> +</div> +</li> +<li><p class="first"><code class="xref c c-func docutils literal"><span class="pre">mark_inode_dirty()</span></code>: marks the inode as dirty; at a later moment, it will be written on the disc;</p> +</li> +<li><p class="first"><code class="xref c c-func docutils literal"><span class="pre">iget_locked()</span></code>: loads the inode with the given number from the disk, if it is not already loaded;</p> +</li> +<li><p class="first"><code class="xref c c-func docutils literal"><span class="pre">unlock_new_inode()</span></code>: used in conjunction with <code class="xref c c-func docutils literal"><span class="pre">iget_locked()</span></code>, releases the lock on the inode;</p> +</li> +<li><p class="first"><code class="xref c c-func docutils literal"><span class="pre">iput()</span></code>: tells the kernel that the work on the inode is finished; if no one else uses it, it will be destroyed (after being written on the disk if it is maked as dirty);</p> +</li> +<li><p class="first"><code class="xref c c-func docutils literal"><span class="pre">make_bad_inode()</span></code>: tells the kernel that the inode can not be used; It is generally used from the function that reads the inode when the inode could not be read from the disk, being invalid.</p> +</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="inode-operations"> +<h3>Inode operations<a class="headerlink" href="#inode-operations" title="Permalink to this headline">¶</a></h3> +<div class="section" id="getting-an-inode"> +<h4>Getting an inode<a class="headerlink" href="#getting-an-inode" title="Permalink to this headline">¶</a></h4> +<p>One of the main inode operations is obtaining an inode (the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code> in VFS). +Until version <code class="docutils literal"><span class="pre">2.6.24</span></code> of the Linux kernel, the developer defined a <code class="docutils literal"><span class="pre">read_inode</span></code> function. +Starting with version <code class="docutils literal"><span class="pre">2.6.25</span></code>, the developer must define a <code class="docutils literal"><span class="pre"><fsname>_iget</span></code> where <code class="docutils literal"><span class="pre"><fsname></span></code> is the name of the file system. +This function is responsible with finding the VFS inode if it exists or creating a new one and filling it with the information from the disk.</p> +<p>Generally, this function will call <code class="xref c c-func docutils literal"><span class="pre">iget_locked()</span></code> to get the inode structure from VFS. If the inode is newly created then it will need to read the inode from the disk (using <code class="xref c c-func docutils literal"><span class="pre">sb_bread()</span></code>) and fill in the useful information.</p> +<p>An example of such a function is <code class="xref c c-func docutils literal"><span class="pre">minix_iget()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="nf">V1_minix_iget</span><span class="p">(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">buffer_head</span> <span class="o">*</span> <span class="n">bh</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">minix_inode</span> <span class="o">*</span> <span class="n">raw_inode</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">minix_inode_info</span> <span class="o">*</span><span class="n">minix_inode</span> <span class="o">=</span> <span class="n">minix_i</span><span class="p">(</span><span class="n">inode</span><span class="p">);</span> + <span class="kt">int</span> <span class="n">i</span><span class="p">;</span> + + <span class="n">raw_inode</span> <span class="o">=</span> <span class="n">minix_V1_raw_inode</span><span class="p">(</span><span class="n">inode</span><span class="o">-></span><span class="n">i_sb</span><span class="p">,</span> <span class="n">inode</span><span class="o">-></span><span class="n">i_ino</span><span class="p">,</span> <span class="o">&</span><span class="n">bh</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">raw_inode</span><span class="p">)</span> <span class="p">{</span> + <span class="n">iget_failed</span><span class="p">(</span><span class="n">inode</span><span class="p">);</span> + <span class="k">return</span> <span class="n">ERR_PTR</span><span class="p">(</span><span class="o">-</span><span class="n">EIO</span><span class="p">);</span> + <span class="p">...</span> +<span class="p">}</span> + +<span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">minix_iget</span><span class="p">(</span><span class="k">struct</span> <span class="n">super_block</span> <span class="o">*</span><span class="n">sb</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">ino</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span><span class="p">;</span> + + <span class="n">inode</span> <span class="o">=</span> <span class="n">iget_locked</span><span class="p">(</span><span class="n">sb</span><span class="p">,</span> <span class="n">ino</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">inode</span><span class="p">)</span> + <span class="k">return</span> <span class="n">ERR_PTR</span><span class="p">(</span><span class="o">-</span><span class="n">ENOMEM</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="n">inode</span><span class="o">-></span><span class="n">i_state</span> <span class="o">&</span> <span class="n">I_NEW</span><span class="p">))</span> + <span class="k">return</span> <span class="n">inode</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">INODE_VERSION</span><span class="p">(</span><span class="n">inode</span><span class="p">)</span> <span class="o">==</span> <span class="n">MINIX_V1</span><span class="p">)</span> + <span class="k">return</span> <span class="n">V1_minix_iget</span><span class="p">(</span><span class="n">inode</span><span class="p">);</span> + <span class="p">...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The minix_iget function gets the VFS inode using <code class="xref c c-func docutils literal"><span class="pre">iget_locked()</span></code>. +If the inode is already existing (not new == the <code class="docutils literal"><span class="pre">I_NEW</span></code> flag is not set) the function returns. +Otherwise, the function calls the <code class="xref c c-func docutils literal"><span class="pre">V1_minix_iget()</span></code> function that will read the inode from the disk using <code class="xref c c-func docutils literal"><span class="pre">minix_V1_raw_inode()</span></code> and then complete the VFS inode with the read information.</p> +</div> +<div class="section" id="superoperations"> +<h4>Superoperations<a class="headerlink" href="#superoperations" title="Permalink to this headline">¶</a></h4> +<p>Many of the superoperations (components of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_operations</span></code> structure used by the superblock) are used when working with inodes. These operations are described next:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">alloc_inode</span></code>: allocates an inode. +Usually, this funcion allocates a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre"><fsname>_inode_info</span></code> structure and performs basic VFS inode initialization (using <code class="xref c c-func docutils literal"><span class="pre">inode_init_once()</span></code>); +minix uses for allocation the <code class="xref c c-func docutils literal"><span class="pre">kmem_cache_alloc()</span></code> function that interacts with the SLAB subsystem. +For each allocation, the cache construction is called, which in the case of minix is the <code class="xref c c-func docutils literal"><span class="pre">init_once()</span></code> function. +Alternatively, <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> can be used, in which case the <code class="xref c c-func docutils literal"><span class="pre">inode_init_once()</span></code> function should be called. +The <code class="xref c c-func docutils literal"><span class="pre">alloc_inode()</span></code> function will be called by the <code class="xref c c-func docutils literal"><span class="pre">new_inode()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">iget_locked()</span></code> functions.</li> +<li><code class="docutils literal"><span class="pre">write_inode</span></code> : saves/updates the inode received as a parameter on disk; to update the inode, though inefficient, for beginners it is recommended to use the following sequence of operations:<ul> +<li>load the inode from the disk using the <code class="xref c c-func docutils literal"><span class="pre">sb_bread()</span></code> function;</li> +<li>modify the buffer according to the saved inode;</li> +<li>mark the buffer as dirty using <code class="xref c c-func docutils literal"><span class="pre">mark_buffer_dirty()</span></code>; the kernel will then handle its writing on the disk;</li> +<li>an example is the <code class="xref c c-func docutils literal"><span class="pre">minix_write_inode()</span></code> function in the <code class="docutils literal"><span class="pre">minix</span></code> file system</li> +</ul> +</li> +<li><code class="docutils literal"><span class="pre">evict_inode</span></code>: removes any information about the inode with the number received in the <code class="docutils literal"><span class="pre">i_ino</span></code> field from the disk and memory (both the inode on the disk and the associated data blocks). This involves performing the following operations:<ul> +<li>delete the inode from the disk;</li> +<li>updates disk bitmaps (if any);</li> +<li>delete the inode from the page cache by calling <code class="xref c c-func docutils literal"><span class="pre">truncate_inode_pages()</span></code>;</li> +<li>delete the inode from memory by calling <code class="xref c c-func docutils literal"><span class="pre">clear_inode()</span></code> ;</li> +<li>an example is the <code class="xref c c-func docutils literal"><span class="pre">minix_evict_inode()</span></code> function from the minix file system.</li> +</ul> +</li> +<li><code class="docutils literal"><span class="pre">destroy_inode</span></code> releases the memory occupied by inode</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="inode-operations-1"> +<h4>inode_operations<a class="headerlink" href="#inode-operations-1" title="Permalink to this headline">¶</a></h4> +<p>The inode operations are described by the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode_operations</span></code> structure.</p> +<p>Inodes are of several types: file, directory, special file (pipe, fifo), block device, character device, link etc. +For this reason, the operations that an inode needs to implement are different for each type of inode. +Below are detailed operations for a <a class="reference internal" href="../so2/lab9-filesystems-part2.html#fileinodes"><span class="std std-ref">file type inode</span></a> and a <a class="reference internal" href="../so2/lab9-filesystems-part2.html#directoryinodes"><span class="std std-ref">directory inode</span></a>.</p> +<p>The operations of an inode are initialized and accessed using the <code class="docutils literal"><span class="pre">i_op</span></code> field of the structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code>.</p> +</div> +</div> +</div> +<div class="section" id="the-file-structure"> +<h2>The file structure<a class="headerlink" href="#the-file-structure" title="Permalink to this headline">¶</a></h2> +<p>The <code class="docutils literal"><span class="pre">file</span></code> structure corresponds to a file open by a process and exists only in memory, being associated with an inode. +It is the closest VFS entity to user-space; the structure fields contain familiar information of a user-space file (access mode, file position, etc.) and the operations with it are performed by known system calls (<code class="docutils literal"><span class="pre">read</span></code>, <code class="docutils literal"><span class="pre">write</span></code> , etc.).</p> +<p>The file operations are described by the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code> structure.</p> +<p>The file operations for a file system are initialized using the <code class="docutils literal"><span class="pre">i_fop</span></code> field of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code> structure. +When opening a file, the VFS initializes the <code class="docutils literal"><span class="pre">f_op</span></code> field of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file</span></code> structure with address of <code class="docutils literal"><span class="pre">inode->i_fop</span></code>, such that subsequent system calls use the value stored in the <code class="docutils literal"><span class="pre">file->f_op</span></code>.</p> +</div> +<div class="section" id="regular-files-inodes"> +<span id="fileinodes"></span><h2>Regular files inodes<a class="headerlink" href="#regular-files-inodes" title="Permalink to this headline">¶</a></h2> +<p>To work with the inode, the <code class="docutils literal"><span class="pre">i_op</span></code> and <code class="docutils literal"><span class="pre">i_fop</span></code> fields of the inode structure must be filled in. +The type of the inode determines the operations that it needs to implement.</p> +<div class="section" id="regular-files-inode-operations"> +<span id="fileoperations"></span><h3>Regular files inode operations<a class="headerlink" href="#regular-files-inode-operations" title="Permalink to this headline">¶</a></h3> +<p>In the <code class="docutils literal"><span class="pre">minix</span></code> file system, the <code class="docutils literal"><span class="pre">minix_file_inode_operations</span></code> structure is defined for the operations on an inode and for the file operations the <code class="docutils literal"><span class="pre">minix_file_operations</span></code> structure is defined:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">const</span> <span class="k">struct</span> <span class="n">file_operations</span> <span class="n">minix_file_operations</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">llseek</span> <span class="o">=</span> <span class="n">generic_file_llseek</span><span class="p">,</span> + <span class="p">.</span><span class="n">read_iter</span> <span class="o">=</span> <span class="n">generic_file_read_iter</span><span class="p">,</span> + <span class="c1">//...</span> + <span class="p">.</span><span class="n">write_iter</span> <span class="o">=</span> <span class="n">generic_file_write_iter</span><span class="p">,</span> + <span class="c1">//...</span> + <span class="p">.</span><span class="n">mmap</span> <span class="o">=</span> <span class="n">generic_file_mmap</span><span class="p">,</span> + <span class="c1">//...</span> +<span class="p">};</span> + +<span class="k">const</span> <span class="k">struct</span> <span class="n">inode_operations</span> <span class="n">minix_file_inode_operations</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">setattr</span> <span class="o">=</span> <span class="n">minix_setattr</span><span class="p">,</span> + <span class="p">.</span><span class="n">getattr</span> <span class="o">=</span> <span class="n">minix_getattr</span><span class="p">,</span> +<span class="p">};</span> + + <span class="c1">//...</span> + <span class="k">if</span> <span class="p">(</span><span class="n">S_ISREG</span><span class="p">(</span><span class="n">inode</span><span class="o">-></span><span class="n">i_mode</span><span class="p">))</span> <span class="p">{</span> + <span class="n">inode</span><span class="o">-></span><span class="n">i_op</span> <span class="o">=</span> <span class="o">&</span><span class="n">minix_file_inode_operations</span><span class="p">;</span> + <span class="n">inode</span><span class="o">-></span><span class="n">i_fop</span> <span class="o">=</span> <span class="o">&</span><span class="n">minix_file_operations</span><span class="p">;</span> + <span class="p">}</span> + <span class="c1">//...</span> +</pre></div> +</div> +<p>The functions <code class="xref c c-func docutils literal"><span class="pre">generic_file_llseek()</span></code> , <code class="xref c c-func docutils literal"><span class="pre">generic_file_mmap()</span></code> , <code class="xref c c-func docutils literal"><span class="pre">generic_file_read_iter()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">generic_file_write_iter()</span></code> are implemented in the kernel.</p> +<p>For simple file systems, only the truncation operation (<code class="docutils literal"><span class="pre">truncate</span></code> system call) must be implemented. +Although initially there was a dedicated operation, starting with 3.14 the operation was embedded in <code class="docutils literal"><span class="pre">setattr</span></code>: if the paste size is different from the current size of the inode, then a truncate operation must be performed. +An example of implementing this verification is in the <code class="xref c c-func docutils literal"><span class="pre">minix_setattr()</span></code> function:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">minix_setattr</span><span class="p">(</span><span class="k">struct</span> <span class="n">dentry</span> <span class="o">*</span><span class="n">dentry</span><span class="p">,</span> <span class="k">struct</span> <span class="n">iattr</span> <span class="o">*</span><span class="n">attr</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span> <span class="o">=</span> <span class="n">d_inode</span><span class="p">(</span><span class="n">dentry</span><span class="p">);</span> + <span class="kt">int</span> <span class="n">error</span><span class="p">;</span> + + <span class="n">error</span> <span class="o">=</span> <span class="n">setattr_prepare</span><span class="p">(</span><span class="n">dentry</span><span class="p">,</span> <span class="n">attr</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">error</span><span class="p">)</span> + <span class="k">return</span> <span class="n">error</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">((</span><span class="n">attr</span><span class="o">-></span><span class="n">ia_valid</span> <span class="o">&</span> <span class="n">ATTR_SIZE</span><span class="p">)</span> <span class="o">&&</span> + <span class="n">attr</span><span class="o">-></span><span class="n">ia_size</span> <span class="o">!=</span> <span class="n">i_size_read</span><span class="p">(</span><span class="n">inode</span><span class="p">))</span> <span class="p">{</span> + <span class="n">error</span> <span class="o">=</span> <span class="n">inode_newsize_ok</span><span class="p">(</span><span class="n">inode</span><span class="p">,</span> <span class="n">attr</span><span class="o">-></span><span class="n">ia_size</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">error</span><span class="p">)</span> + <span class="k">return</span> <span class="n">error</span><span class="p">;</span> + + <span class="n">truncate_setsize</span><span class="p">(</span><span class="n">inode</span><span class="p">,</span> <span class="n">attr</span><span class="o">-></span><span class="n">ia_size</span><span class="p">);</span> + <span class="n">minix_truncate</span><span class="p">(</span><span class="n">inode</span><span class="p">);</span> + <span class="p">}</span> + + <span class="n">setattr_copy</span><span class="p">(</span><span class="n">inode</span><span class="p">,</span> <span class="n">attr</span><span class="p">);</span> + <span class="n">mark_inode_dirty</span><span class="p">(</span><span class="n">inode</span><span class="p">);</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The truncate operation involves:</p> +<blockquote> +<div><ul class="simple"> +<li>freeing blocks of data on the disk that are now extra (if the new dimension is smaller than the old one) or allocating new blocks (for cases where the new dimension is larger)</li> +<li>updating disk bit maps (if used);</li> +<li>updating the inode;</li> +<li>filling with zero the space that was left unused from the last block using the <code class="xref c c-func docutils literal"><span class="pre">block_truncate_page()</span></code> function.</li> +</ul> +</div></blockquote> +<p>An example of the implementation of the cropping operation is the <code class="xref c c-func docutils literal"><span class="pre">minix_truncate()</span></code> function in the <code class="docutils literal"><span class="pre">minix</span></code> file system.</p> +</div> +<div class="section" id="address-space-operations"> +<span id="addressspaceoperations"></span><h3>Address space operations<a class="headerlink" href="#address-space-operations" title="Permalink to this headline">¶</a></h3> +<p>There is a close link between the address space of a process and files: the execution of the programs is done almost exclusively by mapping the file into the process address space. +Because this approach works very well and is quite general, it can also be used for regular system calls such as <code class="docutils literal"><span class="pre">read</span></code> and <code class="docutils literal"><span class="pre">write</span></code>.</p> +<p>The structure that describes the address space is <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">address_space</span></code>, and the operations with it are described by the structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">address_space_operations</span></code>. To initialize the address space operations, fill <code class="docutils literal"><span class="pre">inode->i_mapping->a_ops</span></code> of the file type inode.</p> +<p>An example is the <code class="docutils literal"><span class="pre">minix_aops</span></code> structure in the minix file system:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">address_space_operations</span> <span class="n">minix_aops</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">readpage</span> <span class="o">=</span> <span class="n">minix_readpage</span><span class="p">,</span> + <span class="p">.</span><span class="n">writepage</span> <span class="o">=</span> <span class="n">minix_writepage</span><span class="p">,</span> + <span class="p">.</span><span class="n">write_begin</span> <span class="o">=</span> <span class="n">minix_write_begin</span><span class="p">,</span> + <span class="p">.</span><span class="n">write_end</span> <span class="o">=</span> <span class="n">generic_write_end</span><span class="p">,</span> + <span class="p">.</span><span class="n">bmap</span> <span class="o">=</span> <span class="n">minix_bmap</span> +<span class="p">};</span> + +<span class="c1">//...</span> +<span class="k">if</span> <span class="p">(</span><span class="n">S_ISREG</span><span class="p">(</span><span class="n">inode</span><span class="o">-></span><span class="n">i_mode</span><span class="p">))</span> <span class="p">{</span> + <span class="n">inode</span><span class="o">-></span><span class="n">i_mapping</span><span class="o">-></span><span class="n">a_ops</span> <span class="o">=</span> <span class="o">&</span><span class="n">minix_aops</span><span class="p">;</span> +<span class="p">}</span> +<span class="c1">//...</span> +</pre></div> +</div> +<p>The <code class="xref c c-func docutils literal"><span class="pre">generic_write_end()</span></code> function is already implemented. +Most of the specific functions are very easy to implement, as follows:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">minix_writepage</span><span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">,</span> <span class="k">struct</span> <span class="n">writeback_control</span> <span class="o">*</span><span class="n">wbc</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="n">block_write_full_page</span><span class="p">(</span><span class="n">page</span><span class="p">,</span> <span class="n">minix_get_block</span><span class="p">,</span> <span class="n">wbc</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">minix_readpage</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="n">block_read_full_page</span><span class="p">(</span><span class="n">page</span><span class="p">,</span> <span class="n">minix_get_block</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">minix_write_failed</span><span class="p">(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="n">mapping</span><span class="p">,</span> <span class="n">loff_t</span> <span class="n">to</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span> <span class="o">=</span> <span class="n">mapping</span><span class="o">-></span><span class="n">host</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">to</span> <span class="o">></span> <span class="n">inode</span><span class="o">-></span><span class="n">i_size</span><span class="p">)</span> <span class="p">{</span> + <span class="n">truncate_pagecache</span><span class="p">(</span><span class="n">inode</span><span class="p">,</span> <span class="n">inode</span><span class="o">-></span><span class="n">i_size</span><span class="p">);</span> + <span class="n">minix_truncate</span><span class="p">(</span><span class="n">inode</span><span class="p">);</span> + <span class="p">}</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">minix_write_begin</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> <span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="n">mapping</span><span class="p">,</span> + <span class="n">loff_t</span> <span class="n">pos</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">len</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">flags</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">page</span> <span class="o">**</span><span class="n">pagep</span><span class="p">,</span> <span class="kt">void</span> <span class="o">**</span><span class="n">fsdata</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">ret</span><span class="p">;</span> + + <span class="n">ret</span> <span class="o">=</span> <span class="n">block_write_begin</span><span class="p">(</span><span class="n">mapping</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">len</span><span class="p">,</span> <span class="n">flags</span><span class="p">,</span> <span class="n">pagep</span><span class="p">,</span> + <span class="n">minix_get_block</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">unlikely</span><span class="p">(</span><span class="n">ret</span><span class="p">))</span> + <span class="n">minix_write_failed</span><span class="p">(</span><span class="n">mapping</span><span class="p">,</span> <span class="n">pos</span> <span class="o">+</span> <span class="n">len</span><span class="p">);</span> + + <span class="k">return</span> <span class="n">ret</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="n">sector_t</span> <span class="nf">minix_bmap</span><span class="p">(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="n">mapping</span><span class="p">,</span> <span class="n">sector_t</span> <span class="n">block</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="n">generic_block_bmap</span><span class="p">(</span><span class="n">mapping</span><span class="p">,</span> <span class="n">block</span><span class="p">,</span> <span class="n">minix_get_block</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<p>All that needs to be done is to implement <code class="xref c c-type docutils literal"><span class="pre">minix_get_block</span></code>, which has to translate a block of a file into a block on the device. +If the flag <code class="docutils literal"><span class="pre">create</span></code> received as a parameter is set, a new block must be allocated. +In case a new block is created, the bit map must be updated accordingly. +To notify the kernel not to read the block from the disk, <code class="docutils literal"><span class="pre">bh</span></code> must be marked with <code class="xref c c-func docutils literal"><span class="pre">set_buffer_new()</span></code>. The buffer must be associated with the block through <code class="xref c c-func docutils literal"><span class="pre">map_bh()</span></code>.</p> +</div> +</div> +<div class="section" id="dentry-structure"> +<h2>Dentry structure<a class="headerlink" href="#dentry-structure" title="Permalink to this headline">¶</a></h2> +<p>Directories operations use the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">dentry</span></code> structure. +Its main task is to make links between inodes and filenames. +The important fields of this structure are presented below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">dentry</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">d_inode</span><span class="p">;</span> <span class="cm">/* associated inode */</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">dentry</span> <span class="o">*</span><span class="n">d_parent</span><span class="p">;</span> <span class="cm">/* dentry object of parent */</span> + <span class="k">struct</span> <span class="n">qstr</span> <span class="n">d_name</span><span class="p">;</span> <span class="cm">/* dentry name */</span> + <span class="c1">//...</span> + + <span class="k">struct</span> <span class="n">dentry_operations</span> <span class="o">*</span><span class="n">d_op</span><span class="p">;</span> <span class="cm">/* dentry operations table */</span> + <span class="k">struct</span> <span class="n">super_block</span> <span class="o">*</span><span class="n">d_sb</span><span class="p">;</span> <span class="cm">/* superblock of file */</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">d_fsdata</span><span class="p">;</span> <span class="cm">/* filesystem-specific data */</span> + <span class="c1">//...</span> +<span class="p">};</span> +</pre></div> +</div> +<p>Fields meaning:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">d_inode</span></code>: the inode referenced by this dentry;</li> +<li><code class="docutils literal"><span class="pre">d_parent</span></code>: the dentry associated with the parent directory;</li> +<li><code class="docutils literal"><span class="pre">d_name</span></code>: a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">qstr</span></code> structure that contains the fields <code class="docutils literal"><span class="pre">name</span></code> and <code class="docutils literal"><span class="pre">len</span></code> (the name and the length of the name).</li> +<li><code class="docutils literal"><span class="pre">d_op</span></code>: operations with dentries, represented by the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">dentry_operations</span></code> structure. +The kernel implements default operations so there is no need to (re)implement them. Some file systems can do optimizations based on the specific structure of the dentries.</li> +<li><code class="docutils literal"><span class="pre">d_fsdata</span></code>: field reserved for the file system that implements dentry operations;</li> +</ul> +</div></blockquote> +<div class="section" id="dentry-operations"> +<h3>Dentry operations<a class="headerlink" href="#dentry-operations" title="Permalink to this headline">¶</a></h3> +<p>The most commonly operations applied to dentries are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">d_make_root</span></code>: allocates the root dentry. It is generally used in the function that is called to read the superblock (<code class="docutils literal"><span class="pre">fill_super</span></code>), which must initialize the root directory. +So the root inode is obtained from the superblock and is used as an argument to this function, to fill the <code class="docutils literal"><span class="pre">s_root</span></code> field from the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> structure.</li> +<li><code class="docutils literal"><span class="pre">d_add</span></code>: associates a dentry with an inode; the dentry received as a parameter in the calls discussed above signifies the entry (name, length) that needs to be created. This function will be used when creating/loading a new inode that does not have a dentry associated with it and has not yet been introduced to the hash table of inodes (at <code class="docutils literal"><span class="pre">lookup</span></code>);</li> +<li><code class="docutils literal"><span class="pre">d_instantiate</span></code>: The lighter version of the previous call, in which the dentry was previously added in the hash table.</li> +</ul> +</div></blockquote> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p class="last"><code class="docutils literal"><span class="pre">d_instantiate</span></code> must be used to implement create calls (<code class="docutils literal"><span class="pre">mkdir</span></code>, <code class="docutils literal"><span class="pre">mknod</span></code>, <code class="docutils literal"><span class="pre">rename</span></code>, <code class="docutils literal"><span class="pre">symlink</span></code>) and NOT <code class="docutils literal"><span class="pre">d_add</span></code>.</p> +</div> +</div> +</div> +<div class="section" id="directory-inodes-operations"> +<span id="directoryinodes"></span><h2>Directory inodes operations<a class="headerlink" href="#directory-inodes-operations" title="Permalink to this headline">¶</a></h2> +<p>The operations for directory type inodes have a higher complexity level than the ones for files. +The developer must define operations for inodes and operations for files. +In <code class="docutils literal"><span class="pre">minix</span></code>, these operations are defined in <code class="xref c c-type docutils literal"><span class="pre">minix_dir_inode_operations</span></code> and <code class="xref c c-type docutils literal"><span class="pre">minix_dir_operations</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">inode_operations</span> <span class="n">minix_dir_inode_operations</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">create</span> <span class="o">=</span> <span class="n">minix_create</span><span class="p">,</span> + <span class="p">.</span><span class="n">lookup</span> <span class="o">=</span> <span class="n">minix_lookup</span><span class="p">,</span> + <span class="p">.</span><span class="n">link</span> <span class="o">=</span> <span class="n">minix_link</span><span class="p">,</span> + <span class="p">.</span><span class="n">unlink</span> <span class="o">=</span> <span class="n">minix_unlink</span><span class="p">,</span> + <span class="p">.</span><span class="n">symlink</span> <span class="o">=</span> <span class="n">minix_symlink</span><span class="p">,</span> + <span class="p">.</span><span class="n">mkdir</span> <span class="o">=</span> <span class="n">minix_mkdir</span><span class="p">,</span> + <span class="p">.</span><span class="n">rmdir</span> <span class="o">=</span> <span class="n">minix_rmdir</span><span class="p">,</span> + <span class="p">.</span><span class="n">mknod</span> <span class="o">=</span> <span class="n">minix_mknod</span><span class="p">,</span> + <span class="c1">//...</span> +<span class="p">};</span> + +<span class="k">struct</span> <span class="n">file_operations</span> <span class="n">minix_dir_operations</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">llseek</span> <span class="o">=</span> <span class="n">generic_file_llseek</span><span class="p">,</span> + <span class="p">.</span><span class="n">read</span> <span class="o">=</span> <span class="n">generic_read_dir</span><span class="p">,</span> + <span class="p">.</span><span class="n">iterate</span> <span class="o">=</span> <span class="n">minix_readdir</span><span class="p">,</span> + <span class="c1">//...</span> +<span class="p">};</span> + + <span class="c1">//...</span> + <span class="k">if</span> <span class="p">(</span><span class="n">S_ISDIR</span><span class="p">(</span><span class="n">inode</span><span class="o">-></span><span class="n">i_mode</span><span class="p">))</span> <span class="p">{</span> + <span class="n">inode</span><span class="o">-></span><span class="n">i_op</span> <span class="o">=</span> <span class="o">&</span><span class="n">minix_dir_inode_operations</span><span class="p">;</span> + <span class="n">inode</span><span class="o">-></span><span class="n">i_fop</span> <span class="o">=</span> <span class="o">&</span><span class="n">minix_dir_operations</span><span class="p">;</span> + <span class="n">inode</span><span class="o">-></span><span class="n">i_mapping</span><span class="o">-></span><span class="n">a_ops</span> <span class="o">=</span> <span class="o">&</span><span class="n">minix_aops</span><span class="p">;</span> + <span class="p">}</span> + <span class="c1">//...</span> +</pre></div> +</div> +<p>The only function already implemented is <code class="xref c c-func docutils literal"><span class="pre">generic_read_dir()</span></code>.</p> +<p>The functions that implement the operations on directory inodes are the ones described below.</p> +<div class="section" id="creating-an-inode"> +<h3>Creating an inode<a class="headerlink" href="#creating-an-inode" title="Permalink to this headline">¶</a></h3> +<p>The inode creation function is indicated by the field <code class="docutils literal"><span class="pre">create</span></code> in the <code class="docutils literal"><span class="pre">inode_operations</span></code> structure. +In the minix case, the function is <code class="xref c c-func docutils literal"><span class="pre">minix_create()</span></code>. +This function is called by the <code class="docutils literal"><span class="pre">open</span></code> and <code class="docutils literal"><span class="pre">creat</span></code> system calls. Such a function performs the following operations:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Introduces a new entry into the physical structure on the disk; the update of the bit maps on the disk must not be forgotten.</li> +<li>Configures access rights to those received as a parameter.</li> +<li>Marks the inode as dirty with the <code class="xref c c-func docutils literal"><span class="pre">mark_inode_dirty()</span></code> function.</li> +<li>Instantiates the directory entry (<code class="docutils literal"><span class="pre">dentry</span></code>) with the <code class="docutils literal"><span class="pre">d_instantiate</span></code> function.</li> +</ol> +</div></blockquote> +</div> +<div class="section" id="creating-a-directory"> +<h3>Creating a directory<a class="headerlink" href="#creating-a-directory" title="Permalink to this headline">¶</a></h3> +<p>The directory creation function is indicated by the <code class="docutils literal"><span class="pre">mkdir</span></code> field in the <code class="docutils literal"><span class="pre">inode_operations</span></code> structure. +In the minix case, the function is <code class="xref c c-func docutils literal"><span class="pre">minix_mkdir()</span></code>. +This function is called by the <code class="docutils literal"><span class="pre">mkdir</span></code> system call. Such a function performs the following operations:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Calls <code class="xref c c-func docutils literal"><span class="pre">minix_create()</span></code>.</li> +<li>Allocates a data block for the directory.</li> +<li>Creates the <code class="docutils literal"><span class="pre">"."</span></code> and <code class="docutils literal"><span class="pre">".."</span></code> entries.</li> +</ol> +</div></blockquote> +</div> +<div class="section" id="creating-a-link"> +<h3>Creating a link<a class="headerlink" href="#creating-a-link" title="Permalink to this headline">¶</a></h3> +<p>The link creation function (hard link) is indicated by the <code class="docutils literal"><span class="pre">link</span></code> field in the <code class="docutils literal"><span class="pre">inode_operations</span></code> structure. +In the minix case, the function is <code class="xref c c-func docutils literal"><span class="pre">minix_link()</span></code>. +This function is called by the <code class="docutils literal"><span class="pre">link</span></code> system call. Such a function performs the following operations:</p> +<blockquote> +<div><ul class="simple"> +<li>Binds the new dentry to the inode.</li> +<li>Increments the <code class="docutils literal"><span class="pre">i_nlink</span></code> field of the inode.</li> +<li>Marks the inode as dirty using the <code class="xref c c-func docutils literal"><span class="pre">mark_inode_dirty()</span></code> function.</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="creating-a-symbolic-link"> +<h3>Creating a symbolic link<a class="headerlink" href="#creating-a-symbolic-link" title="Permalink to this headline">¶</a></h3> +<p>The symbolic link creation function is indicated by the <code class="docutils literal"><span class="pre">symlink</span></code> field in the <code class="docutils literal"><span class="pre">inode_operations</span></code> structure. +In the minix case, the function is <code class="xref c c-func docutils literal"><span class="pre">minix_symlink()</span></code>. +The operations to be performed are similar to <code class="docutils literal"><span class="pre">minix_link</span></code> with the differences being given by the fact that a symbolic link is created.</p> +</div> +<div class="section" id="deleting-a-link"> +<h3>Deleting a link<a class="headerlink" href="#deleting-a-link" title="Permalink to this headline">¶</a></h3> +<p>The link delete function (hard link) is indicated by the <code class="docutils literal"><span class="pre">unlink</span></code> field in the <code class="docutils literal"><span class="pre">inode_operations</span></code> structure. +In the minix case, the function is <code class="xref c c-func docutils literal"><span class="pre">minix_unlink()</span></code>. +This function is called by the <code class="docutils literal"><span class="pre">unlink</span></code> system call. Such a function performs the following operations:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Deletes the directory entry given as a parameter from the physical disk structure.</li> +<li>Decrements the <code class="docutils literal"><span class="pre">i_nlink</span></code> counter of the inode to which the entry points (otherwise the inode will never be deleted).</li> +</ol> +</div></blockquote> +</div> +<div class="section" id="deleting-a-directory"> +<h3>Deleting a directory<a class="headerlink" href="#deleting-a-directory" title="Permalink to this headline">¶</a></h3> +<p>The directory delete function is indicated by the <code class="docutils literal"><span class="pre">rmdir</span></code> field in the <code class="docutils literal"><span class="pre">inode_operations</span></code> structure. +In the minix case, the function is <code class="xref c c-func docutils literal"><span class="pre">minix_rmdir()</span></code>. +This function is called by the <code class="docutils literal"><span class="pre">rmdir</span></code> system call. +Such a function performs the following operations:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Performs the operations done by <code class="docutils literal"><span class="pre">minix_unlink</span></code>.</li> +<li>Ensures that the directory is empty; otherwise, returns <code class="docutils literal"><span class="pre">ENOTEMPTY</span></code>.</li> +<li>Also deletes the data blocks.</li> +</ol> +</div></blockquote> +</div> +<div class="section" id="searching-for-an-inode-in-a-directory"> +<h3>Searching for an inode in a directory<a class="headerlink" href="#searching-for-an-inode-in-a-directory" title="Permalink to this headline">¶</a></h3> +<p>The function that searches for an entry in a directory and extracts the inode is indicated by the <code class="docutils literal"><span class="pre">lookup</span></code> field in the <code class="docutils literal"><span class="pre">inode_operations</span></code> structure. +In the minix case, the function is <code class="docutils literal"><span class="pre">minix_lookup</span></code>. +This function is called indirectly when information about the inode associated with an entry in a directory is needed. +Such a function performs the following operations:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Searches in the directory indicated by <code class="docutils literal"><span class="pre">dir</span></code> the entry having the name <code class="docutils literal"><span class="pre">dentry->d_name.name</span></code>.</li> +<li>If the entry is found, it will return <code class="docutils literal"><span class="pre">NULL</span></code> and associate the inode with the name using the <code class="xref c c-func docutils literal"><span class="pre">d_add()</span></code> function.</li> +<li>Otherwise, returns <code class="docutils literal"><span class="pre">ERR_PTR</span></code>.</li> +</ol> +</div></blockquote> +</div> +<div class="section" id="iterating-through-entries-in-a-directory"> +<h3>Iterating through entries in a directory<a class="headerlink" href="#iterating-through-entries-in-a-directory" title="Permalink to this headline">¶</a></h3> +<p>The function which iterates through the entries in a directory (lists the directory contents) is indicated by the field <code class="docutils literal"><span class="pre">iterate</span></code> in the <code class="docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code> structure. +In the minix case, the function is <code class="docutils literal"><span class="pre">minix_readdir</span></code>. +This function is called by the <code class="docutils literal"><span class="pre">readdir</span></code> system call.</p> +<p>The function returns either all entries in the directory or just a part when the buffer allocated for it is not available. +A call of this function can return:</p> +<blockquote> +<div><ul class="simple"> +<li>a number equal to the existing number of entries if there is enough space in the corresponding user space buffer;</li> +<li>a number smaller than the actual number of entries, as much as there was space in the corresponding user space buffer;</li> +<li><code class="docutils literal"><span class="pre">0</span></code>, where there are no more entries to read.</li> +</ul> +</div></blockquote> +<p>The function will be called consecutively until all available entries are read. The function is called at least twice.</p> +<blockquote> +<div><ul class="simple"> +<li>It is only called twice if:<ul> +<li>the first call reads all entries and returns their number;</li> +<li>the second call returns 0, having no other entries to read.</li> +</ul> +</li> +<li>It is called more than twice if the first call does not return the total number of entries.</li> +</ul> +</div></blockquote> +<p>The function performs the following operations:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Iterates over the entries (the dentries) from the current directory.</li> +<li>For each dentry found, increments <code class="docutils literal"><span class="pre">ctx->pos</span></code>.</li> +<li>For each valid dentry (an inode other than <code class="docutils literal"><span class="pre">0</span></code>, for example), calls the <code class="xref c c-func docutils literal"><span class="pre">dir_emit()</span></code> function.</li> +<li>If the <code class="xref c c-func docutils literal"><span class="pre">dir_emit()</span></code> function returns a value other than zero, it means that the buffer in the user space is full and the function returns.</li> +</ol> +</div></blockquote> +<p>The arguments of the <code class="docutils literal"><span class="pre">dir_emit</span></code> function are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">ctx</span></code> is the directory iteration context, passed as an argument to the <code class="docutils literal"><span class="pre">iterate</span></code> function;</li> +<li><code class="docutils literal"><span class="pre">name</span></code> is the name of the entry (a string of characters);</li> +<li><code class="docutils literal"><span class="pre">name_len</span></code> is the length of the entry name;</li> +<li><code class="docutils literal"><span class="pre">ino</span></code> is the inode number associated with the entry;</li> +<li><code class="docutils literal"><span class="pre">type</span></code> identifies the entry type: <code class="docutils literal"><span class="pre">DT_REG</span></code> (file), <code class="docutils literal"><span class="pre">DT_DIR</span></code> (directory), <code class="docutils literal"><span class="pre">DT_UNKNOWN</span></code> etc. <code class="docutils literal"><span class="pre">DT_UNKNOWN</span></code> can be used when the entry type is unknown.</li> +</ul> +</div></blockquote> +</div> +</div> +<div class="section" id="bitmap-operations"> +<span id="bitmapoperations"></span><h2>Bitmap operations<a class="headerlink" href="#bitmap-operations" title="Permalink to this headline">¶</a></h2> +<p>When working with the file systems, management information (what block is free or busy, what inode is free or busy) is stored using bitmaps. +For this we often need to use bit operations. Such operations are:</p> +<blockquote> +<div><ul class="simple"> +<li>searching the first 0 bit: representing a free block or inode</li> +<li>marking a bit as 1: marking a busy block or inode</li> +</ul> +</div></blockquote> +<p>The bitmap operations are found in headers from <code class="docutils literal"><span class="pre">include/asm-generic/bitops</span></code>, especially in <code class="docutils literal"><span class="pre">find.h</span></code> and <code class="docutils literal"><span class="pre">atomic.h</span></code>. Usual functions, with names indicating their role, are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">find_first_zero_bit()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">find_first_bit()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">set_bit()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">clear_bit()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">test_and_set_bit()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">test_and_clear_bit()</span></code></li> +</ul> +</div></blockquote> +<p>These functions usually receive the address of the bitmap, possibly its size (in bytes) and, if necessary, the index of the bit that needs to be activated (set) or deactivated (clear).</p> +<p>Some usage examples are listed below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">map</span><span class="p">;</span> +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">array_map</span><span class="p">[</span><span class="n">NUM_BYTES</span><span class="p">];</span> +<span class="kt">size_t</span> <span class="n">idx</span><span class="p">;</span> +<span class="kt">int</span> <span class="n">changed</span><span class="p">;</span> + +<span class="cm">/* Find first zero bit in 32 bit integer. */</span> +<span class="n">idx</span> <span class="o">=</span> <span class="n">find_first_zero_bit</span><span class="p">(</span><span class="o">&</span><span class="n">map</span><span class="p">,</span> <span class="mi">32</span><span class="p">);</span> +<span class="n">printk</span> <span class="p">(</span><span class="n">KERN_ALERT</span> <span class="s">"The %zu-th bit is the first zero bit.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">idx</span><span class="p">);</span> + +<span class="cm">/* Find first one bit in NUM_BYTES bytes array. */</span> +<span class="n">idx</span> <span class="o">=</span> <span class="n">find_first_bit</span><span class="p">(</span><span class="n">array_map</span><span class="p">,</span> <span class="n">NUM_BYTES</span> <span class="o">*</span> <span class="mi">8</span><span class="p">);</span> +<span class="n">printk</span> <span class="p">(</span><span class="n">KERN_ALERT</span> <span class="s">"The %zu-th bit is the first one bit.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">idx</span><span class="p">);</span> + +<span class="cm">/*</span> +<span class="cm"> * Clear the idx-th bit in integer.</span> +<span class="cm"> * It is assumed idx is less the number of bits in integer.</span> +<span class="cm"> */</span> +<span class="n">clear_bit</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="o">&</span><span class="n">map</span><span class="p">);</span> + +<span class="cm">/*</span> +<span class="cm"> * Test and set the idx-th bit in array.</span> +<span class="cm"> * It is assumed idx is less the number of bits in array.</span> +<span class="cm"> */</span> +<span class="n">changed</span> <span class="o">=</span> <span class="n">__test_and_set_bit</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="o">&</span><span class="n">sbi</span><span class="o">-></span><span class="n">imap</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="n">changed</span><span class="p">)</span> + <span class="n">printk</span><span class="p">(</span><span class="n">KERN_ALERT</span> <span class="s">"%zu-th bit changed</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">idx</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="further-reading"> +<h2>Further reading<a class="headerlink" href="#further-reading" title="Permalink to this headline">¶</a></h2> +<ol class="arabic simple"> +<li>Robert Love -- Linux Kernel Development, Second Edition -- Chapter +12. The Virtual Filesystem</li> +<li>Understanding the Linux Kernel, 3rd edition - Chapter 12. The Virtual +Filesystem</li> +<li><a class="reference external" href="http://www.coda.cs.cmu.edu/doc/talks/linuxvfs/">Linux Virtual File System (presentation)</a></li> +<li><a class="reference external" href="http://www.cyberciti.biz/tips/understanding-unixlinux-file-system-part-i.html">Understanding Unix/Linux Filesystem</a></li> +<li><a class="reference external" href="http://lwn.net/Articles/57369/">Creating Linux virtual filesystems</a></li> +<li><a class="reference external" href="http://www.tldp.org/LDP/tlk/fs/filesystem.html">The Linux Documentation Project - VFS</a></li> +<li><a class="reference external" href="http://www.linux.it/~rubini/docs/vfs/vfs.html">The "Virtual File System" in Linux</a></li> +<li><a class="reference external" href="http://inglorion.net/documents/tutorials/tutorfs/">A Linux Filesystem Tutorial</a></li> +<li><a class="reference external" href="http://www.win.tue.nl/~aeb/linux/lk/lk-8.html">The Linux Virtual File System</a></li> +<li><a class="reference external" href="http://lxr.free-electrons.com/source/Documentation/filesystems/vfs.txt">Documentation/filesystems/vfs.txt</a></li> +<li><a class="reference external" href="http://lxr.free-electrons.com/source/fs/">File systems sources</a></li> +</ol> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is filesystems. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/filesystems/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>In this lab, we will continue the implementation of the file systems started in the previous one. +For this, we will generate the laboratory skeleton using the following command:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">TODO=5 LABS=filesystems make skels</span> +</pre></div> +</div> +<p class="last">After this, we will start the implementation from <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">5</span></code>.</p> +</div> +<div class="section" id="myfs"> +<h3>myfs<a class="headerlink" href="#myfs" title="Permalink to this headline">¶</a></h3> +<p>For the exercises below, we will use the <code class="docutils literal"><span class="pre">myfs</span></code> file system whose implementation we started with the previous lab. +We stopped after mounting the file system and now we will continue with the operations for regular files and directories. +At the end of these exercises, we will be able to create, modify and delete regular directories and files.</p> +<p>We will mostly use the <code class="docutils literal"><span class="pre">inode</span></code> and <code class="docutils literal"><span class="pre">dentry</span></code> VFS structures. +The <code class="docutils literal"><span class="pre">inode</span></code> structure defines a file (of any type: regular, directory, link), while the <code class="docutils literal"><span class="pre">dentry</span></code> structure defines a name, which is an entry in a directory.</p> +<p>For this we will access the <code class="docutils literal"><span class="pre">myfs</span></code> directory in the lab skeleton. +The previously generated skeleton contains the solution for the previous lab; we will start from this. As in the previous lab, we will use the <code class="docutils literal"><span class="pre">ramfs</span></code> file system as a starting point.</p> +<div class="section" id="directory-operations"> +<h4>1. Directory operations<a class="headerlink" href="#directory-operations" title="Permalink to this headline">¶</a></h4> +<p>To begin with, we will implement the operations for working with directories. +The operations of creating a file or deleting a file are also directory operations; these operations result in adding or deleting a directory entry (<em>dentry</em>).</p> +<p>At the end of this exercise we will be able to create and delete entries in the file system. We will not be able to read and write to regular files; we will do so in the next exercise.</p> +<p>Follow directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">5</span></code> which will guide you through the steps you need to take.</p> +<p>You will need to specify the following directory operations:</p> +<blockquote> +<div><ul class="simple"> +<li>create a file (<code class="docutils literal"><span class="pre">create</span></code> function)</li> +<li>search (<code class="docutils literal"><span class="pre">lookup</span></code> function)</li> +<li>link (<code class="docutils literal"><span class="pre">link</span></code> function)</li> +<li>create directory (<code class="docutils literal"><span class="pre">mkdir</span></code> function)</li> +<li>deletion (<code class="docutils literal"><span class="pre">rmdir</span></code> and <code class="docutils literal"><span class="pre">unlink</span></code> functions)</li> +<li>create node (<code class="docutils literal"><span class="pre">mknod</span></code>)</li> +<li>rename (<code class="docutils literal"><span class="pre">rename</span></code> function)</li> +</ul> +</div></blockquote> +<p>For this, define the <code class="docutils literal"><span class="pre">myfs_dir_inode_operations</span></code> structure in the code, where marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">5</span></code>. +To begin, just define the structure <code class="docutils literal"><span class="pre">myfs_dir_inode_operations</span></code>; you will define the structures <code class="docutils literal"><span class="pre">myfs_file_operations</span></code>, <code class="docutils literal"><span class="pre">myfs_file_inode_operations</span></code> , and <code class="docutils literal"><span class="pre">myfs_aops</span></code> in the next exercise.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>Read the section <a class="reference internal" href="../so2/lab9-filesystems-part2.html#directoryinodes"><span class="std std-ref">Directory inodes operations</span></a></p> +<p class="last">As a model, you are following the <code class="docutils literal"><span class="pre">ramfs_dir_inode_operations</span></code> structure.</p> +</div> +<p>Implement the <code class="docutils literal"><span class="pre">mkdir</span></code>, <code class="docutils literal"><span class="pre">mknod</span></code> and <code class="docutils literal"><span class="pre">create</span></code> operations inside <code class="docutils literal"><span class="pre">myfs_mkdir</span></code>, <code class="docutils literal"><span class="pre">myfs_mknod</span></code> and <code class="docutils literal"><span class="pre">myfs_create</span></code>. +These operations will allow you to create directories and files in the file system.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>We recommend making the code modular using a <code class="docutils literal"><span class="pre">mknod</span></code> function, which you can also use for the next exercise. +For inode reading and allocation, use <code class="docutils literal"><span class="pre">myfs_get_inode</span></code>, which is already implemented.</p> +<p>As a model, follow the next functions implemented in the <code class="docutils literal"><span class="pre">ramfs</span></code> file system:</p> +<blockquote class="last"> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">ramfs_mknod()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">ramfs_mkdir()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">ramfs_create()</span></code></li> +</ul> +</div></blockquote> +</div> +<p>For the other functions, use generic calls (<code class="docutils literal"><span class="pre">simple_*</span></code>) already defined in VFS.</p> +<p>In the <code class="docutils literal"><span class="pre">myfs_get_inode</span></code> function, initialize the operations fields of the directory inodes:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">i_op</span></code> must be initialized to the address of the structure <code class="docutils literal"><span class="pre">myfs_dir_inode_operations</span></code>;</li> +<li><code class="docutils literal"><span class="pre">i_fop</span></code> must be initialized to the address of the structure <code class="docutils literal"><span class="pre">simple_dir_operations</span></code>, defined in VFS.</li> +</ul> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p><code class="docutils literal"><span class="pre">i_op</span></code> is a pointer to a structure of type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode_operations</span></code> containing operations that have to do with the inode, which are, for a directory, creating a new entry, listing entries, deleting entries, etc.</p> +<p class="last"><code class="docutils literal"><span class="pre">i_fop</span></code> is a pointer to a structure of type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code> containing operations that have to do with the <code class="docutils literal"><span class="pre">file</span></code> structure associated with the inode, such as <code class="docutils literal"><span class="pre">read</span></code>, <code class="docutils literal"><span class="pre">write</span></code>, and <code class="docutils literal"><span class="pre">lseek</span></code>.</p> +</div> +<div class="section" id="testing"> +<h5>Testing<a class="headerlink" href="#testing" title="Permalink to this headline">¶</a></h5> +<p>Once the module is done, we can test the creation of files and directories. +To do this, we compile the kernel module (using <code class="docutils literal"><span class="pre">make</span> <span class="pre">build</span></code>) and copy the resulting file (<code class="docutils literal"><span class="pre">myfs.ko</span></code>) and the test scripts (<code class="docutils literal"><span class="pre">test-myfs-{1,2}.sh</span></code>) in the virtual machine directory (using <code class="docutils literal"><span class="pre">make</span> <span class="pre">copy</span></code>).</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The test scripts are copied to the virtual machine using <code class="docutils literal"><span class="pre">make</span> <span class="pre">copy</span></code> only if they are executable:</p> +<div class="last highlight-console"><div class="highlight"><pre><span></span><span class="gp">student@workstation:~/linux/tools/labs$</span> chmod +x skels/filesystems/myfs/test-myfs-*.sh +</pre></div> +</div> +</div> +<p>After starting the virtual machine, insert the module, create the mount point and mount the file system:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> insmod myfs.ko +<span class="gp">#</span> mkdir -p /mnt/myfs +<span class="gp">#</span> mount -t myfs none /mnt/myfs +</pre></div> +</div> +<p>Now we can create file hierarchies and subdirectories in the mounted directory (<code class="docutils literal"><span class="pre">/mnt/myfs</span></code>). +We use commands like the ones below:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> touch /mnt/myfs/peanuts.txt +<span class="gp">#</span> mkdir -p /mnt/myfs/mountain/forest +<span class="gp">#</span> touch /mnt/myfs/mountain/forest/tree.txt +<span class="gp">#</span> rm /mnt/myfs/mountain/forest/tree.txt +<span class="gp">#</span> rmdir /mnt/myfs/mountain/forest +</pre></div> +</div> +<p>At this time we can not read or write files. When running commands such as the following ones we will get errors.</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> <span class="nb">echo</span> <span class="s2">"chocolate"</span> > /mnt/myfs/peanuts.txt +<span class="gp">#</span> cat /mnt/myfs/peanuts.txt +</pre></div> +</div> +<p>This happens because we have not implemented the operations for working with files; we will do so further.</p> +<p>To unload the kernel module, use the command</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">umount /mnt/myfs</span> +<span class="go">rmmod myfs</span> +</pre></div> +</div> +<p>To test the functionality provided by the kernel module, we can use the dedicated script <code class="docutils literal"><span class="pre">test-myfs-1.sh</span></code>. +If the implementation is correct, no error messages will be displayed.</p> +</div> +</div> +<div class="section" id="file-operations"> +<h4>2. File operations<a class="headerlink" href="#file-operations" title="Permalink to this headline">¶</a></h4> +<p>We want to implement the operations for working with files, which are used for accessing a file's content: read, write, truncate, etc. +For this you will specify the operations described in the structures <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode_operations</span></code>, <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code> and <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">address_space_operations</span></code>.</p> +<p>Follow the locations marked with <code class="docutils literal"><span class="pre">TODO</span></code> 6 which will guide you through the steps you need to take.</p> +<p>Start by defining <code class="docutils literal"><span class="pre">myfs_file_inode_operations</span></code> and <code class="docutils literal"><span class="pre">myfs_file_operations</span></code>.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>Read the section <a class="reference internal" href="../so2/lab9-filesystems-part2.html#fileoperations"><span class="std std-ref">Regular files inode operations</span></a>.</p> +<p>Use the generic function provided by VFS.</p> +<p class="last">An example of implementation is the <code class="docutils literal"><span class="pre">ramfs</span></code> file system. +Follow the implementation of <code class="docutils literal"><span class="pre">ramfs_file_inode_operations</span></code> and <code class="docutils literal"><span class="pre">ramfs_file_operations</span></code>.</p> +</div> +<p>Inside the function <code class="docutils literal"><span class="pre">myfs_get_inode</span></code>, initialize the operations fields for the regular file inodes:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">i_op</span></code> must be initialized to <code class="docutils literal"><span class="pre">myfs_file_inode_operations</span></code>;</li> +<li><code class="docutils literal"><span class="pre">i_fop</span></code> msust be initialized to <code class="docutils literal"><span class="pre">myfs_file_operations</span></code>.</li> +</ul> +</div></blockquote> +<p>Continue with defining the structure <code class="docutils literal"><span class="pre">myfs_aops</span></code>.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>Read the section <a class="reference internal" href="../so2/lab9-filesystems-part2.html#addressspaceoperations"><span class="std std-ref">Address space operations</span></a>.</p> +<p>Use the generic functions provided by VFS.</p> +<p>An implementation example is the <code class="docutils literal"><span class="pre">ramfs</span></code> file system: the <code class="docutils literal"><span class="pre">ramfs_aops</span></code> structure.</p> +<p class="last">You do not need to define the function of type <code class="docutils literal"><span class="pre">set_page_dirty</span></code>.</p> +</div> +<p>Initialize the <code class="docutils literal"><span class="pre">i_mapping->a_ops</span></code> field of the inode structure to <code class="docutils literal"><span class="pre">myfs_aops</span></code>.</p> +<div class="section" id="testing-1"> +<h5>Testing<a class="headerlink" href="#testing-1" title="Permalink to this headline">¶</a></h5> +<p>For testing, we use the steps described in the previous exercise. +In addition to those steps, we will now be able to read, write and modify a file using commands like the ones below:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> <span class="nb">echo</span> <span class="s2">"chocolate"</span> > /mnt/myfs/peanuts.txt +<span class="gp">#</span> cat /mnt/myfs/peanuts.txt +</pre></div> +</div> +<p>To test the functionality provided by the module, we can use the dedicated script:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ./test-myfs-2.sh +</pre></div> +</div> +<p>If the implementation is correct, no error messages will be displayed when running the above script.</p> +</div> +</div> +</div> +<div class="section" id="minfs"> +<h3>minfs<a class="headerlink" href="#minfs" title="Permalink to this headline">¶</a></h3> +<p>For the exercises below, we will use the minfs file system whose development started in the previous lab. +This is a file system with disk support. +We stopped after mounting the file system and now we will continue with the operations on regular files and directories. +At the end of these exercises we will be able to create and delete entries in the file system.</p> +<p>We will mainly use the <code class="xref c c-type docutils literal"><span class="pre">inode</span></code> and <code class="xref c c-type docutils literal"><span class="pre">dentry</span></code> VFS structures. +The inode structure defines a file (of any type: regular, directory, link), while the dentry structure defines a name, which is a directory entry.</p> +<p>For this we will access the <code class="docutils literal"><span class="pre">minfs/kernel</span></code> directory from the laboratory skeleton. +The generated skeleton contains the solution from the previous lab; we will start from this. +As in the previous lab, we will use the <code class="docutils literal"><span class="pre">minix</span></code> file system as a starting point.</p> +<p>We will use the formatting tool <code class="docutils literal"><span class="pre">mkfs.minfs</span></code> in the <code class="docutils literal"><span class="pre">minfs/user</span></code> directory which is automatically compiled when running <code class="docutils literal"><span class="pre">make</span> <span class="pre">build</span></code> and copied to the virtual machine at <code class="docutils literal"><span class="pre">make</span> <span class="pre">copy</span></code>.</p> +<p>The formatting tool prepares a virtual machine disk using a command like</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ./mkfs.minfs /dev/vdb +</pre></div> +</div> +<p>After formatting, the disk has a structure like the one in the diagram below:</p> +<img alt="../_images/minfs_arch.png" src="../_images/minfs_arch.png" /> +<p>As shown in the diagram, <code class="docutils literal"><span class="pre">minfs</span></code> is a minimalist file system. +<code class="docutils literal"><span class="pre">minfs</span></code> contains a maximum of 32 inodes, each inode having a single data block (the file size is limited to block size). +The super block contains a 32-bit map (<code class="docutils literal"><span class="pre">imap</span></code>), each bit indicating the use of an inode.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Before you start working, go through the <code class="docutils literal"><span class="pre">minfs/kernel/minfs.h</span></code> header file. +This file contains the structures and macros that will be used in these exercises. +These structures and macros define the file system as described in the diagram above.</p> +</div> +<div class="section" id="iterate-operation"> +<h4>1. Iterate operation<a class="headerlink" href="#iterate-operation" title="Permalink to this headline">¶</a></h4> +<p>At first we want to be able to list the contents of the root directory. +For this we must be able to read the entries in the root directory, which means implementing the <code class="docutils literal"><span class="pre">iterate</span></code> operation. +The <code class="docutils literal"><span class="pre">iterate</span></code> operation is a field within the <code class="docutils literal"><span class="pre">minfs_dir_operations</span></code> structure (of type <code class="docutils literal"><span class="pre">file_operations</span></code>) and is implemented by the function <code class="docutils literal"><span class="pre">minfs_readdir</span></code>. We need to implement this function.</p> +<p>Follow directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">5</span></code> which will guide you through the steps you need to take.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>Read the section <a class="reference internal" href="../so2/lab9-filesystems-part2.html#directoryinodes"><span class="std std-ref">Directory inodes operations</span></a></p> +<p>As a starting point, follow the <code class="xref c c-func docutils literal"><span class="pre">minix_readdir()</span></code> function. +The function is rather complicated, but it gives you an insight into the steps you have to do.</p> +<p class="last">Follow, in <code class="docutils literal"><span class="pre">minfs.c</span></code> and <code class="docutils literal"><span class="pre">minfs.h</span></code>, the definitions of structures <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code>, <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode</span></code> and <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_dir_entry</span></code>. +You will use them in the <code class="docutils literal"><span class="pre">minfs_readdir</span></code> implementation.</p> +</div> +<p>Obtain the inode and the structure <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code> associated with the directory. +The structure <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code> is useful to find out the directory's data block. +From this structure you get the <code class="docutils literal"><span class="pre">data_block</span></code> field, representing the data block index on the disk.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p class="last">To get the structure <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code> structure, use <code class="xref c c-func docutils literal"><span class="pre">list_entry()</span></code> or <code class="xref c c-func docutils literal"><span class="pre">container_of()</span></code>.</p> +</div> +<p>Use <code class="xref c c-func docutils literal"><span class="pre">sb_bread()</span></code> to read the directory data block.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>The data block of the directory is indicated by the <code class="docutils literal"><span class="pre">data_block</span></code> field of the structure <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code> corresponding to the directory.</p> +<p class="last">The data in the block is referenced by the <code class="docutils literal"><span class="pre">b_data</span></code> field of the <code class="docutils literal"><span class="pre">buffer_head</span></code> structure (the usual code will be <code class="docutils literal"><span class="pre">bh->b_data</span></code>). +This block (being the data block of a directory) contains an array of at most <code class="docutils literal"><span class="pre">MINFS_NUM_ENTRIES</span></code> entries of type <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_dir_entry</span></code> (directory entries specific to <code class="docutils literal"><span class="pre">minfs</span></code>). +Use casting to <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_dir_entry</span> <span class="pre">*</span></code> to work with the data in the block.</p> +</div> +<p>Iterate over all the entries in the data block and fill the user space buffer inside the <code class="docutils literal"><span class="pre">for</span></code> loop.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>For each index, get the corresponding entry of the <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_dir_entry</span></code> by using pointer arithmetics on the <code class="docutils literal"><span class="pre">bh->b_data</span></code> field. +Ignore dentries that have an <code class="docutils literal"><span class="pre">ino</span></code> field equal to 0. Such a dentry is a free slot in the director's dentry list.</p> +<p>For each valid entry, there is an existing call <code class="xref c c-func docutils literal"><span class="pre">dir_emit()</span></code> with the appropriate parameters. This is the call that sends the dentries to the caller (and then to user space).</p> +<p class="last">Check the call examples in <code class="xref c c-func docutils literal"><span class="pre">qnx6_readdir()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">minix_readdir()</span></code>.</p> +</div> +<div class="section" id="testing-2"> +<h5>Testing<a class="headerlink" href="#testing-2" title="Permalink to this headline">¶</a></h5> +<p>Once the module is done, we can test the listing of the root directory contents. +To do this, we compile the kernel module (<code class="docutils literal"><span class="pre">make</span> <span class="pre">build</span></code>) and copy the result to the virtual machine together with the test scripts (<code class="docutils literal"><span class="pre">minfs/user/test-minfs-{0,1}.sh</span></code>) and the formatting utility (<code class="docutils literal"><span class="pre">minfs/user/mkfs.minfs</span></code>) using <code class="docutils literal"><span class="pre">make</span> <span class="pre">copy</span></code>, then start the machine.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The test scripts are copied to the virtual machine only if they are executable:</p> +<div class="last highlight-console"><div class="highlight"><pre><span></span><span class="gp">student@eg106:~/src/linux/tools/labs$</span> chmod +x skels/filesystems/minfs/user/test-minfs*.sh +</pre></div> +</div> +</div> +<p>After we start the virtual machine, we format the <code class="docutils literal"><span class="pre">/dev/vdb</span></code> disk, create the mount point and mount the file system:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ./mkfs.minfs /dev/vdb +<span class="gp">#</span> mkdir -p /mnt/minfs +<span class="gp">#</span> mount -t minfs /dev/vdb /mnt/minfs +</pre></div> +</div> +<p>Now we can list the contents of the root directory:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ls -l /mnt/minfs +</pre></div> +</div> +<p>We notice that there is already a file (<code class="docutils literal"><span class="pre">a.txt</span></code>); it is created by the formatting utility.</p> +<p>We also notice that we are not allowed to display information for a file using the <code class="docutils literal"><span class="pre">ls</span></code> command. +This is because we have not implemented the <code class="docutils literal"><span class="pre">lookup</span></code> function. We will implement it in the next exercise.</p> +<p>To test the functionality provided by the module, we can use the dedicated script:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ./test-minfs-0.sh +<span class="gp">#</span> ./test-minfs-1.sh +</pre></div> +</div> +</div> +</div> +<div class="section" id="lookup-operation"> +<h4>2. Lookup operation<a class="headerlink" href="#lookup-operation" title="Permalink to this headline">¶</a></h4> +<p>To properly list the contents of a directory, we need to implement the search functionality, ie the <code class="docutils literal"><span class="pre">lookup</span></code> operation. +The <code class="docutils literal"><span class="pre">lookup</span></code> operation is a field within the <code class="docutils literal"><span class="pre">minfs_dir_inode_operations</span></code> structure (of type <code class="docutils literal"><span class="pre">inode_operations</span></code>) and is implemented by the <code class="docutils literal"><span class="pre">minfs_lookup</span></code> function. +This function (<code class="docutils literal"><span class="pre">minfs_lookup</span></code>) needs to be implemented. +We will actually implement the <code class="docutils literal"><span class="pre">minfs_find_entry</span></code> function called by <code class="docutils literal"><span class="pre">minfs_lookup</span></code> .</p> +<p>Follow directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">6</span></code> which will tell you the steps you need to take.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>Read the section <a class="reference internal" href="../so2/lab9-filesystems-part2.html#directoryinodes"><span class="std std-ref">Directory inodes operations</span></a></p> +<p class="last">As a starting point, read the functions <code class="xref c c-func docutils literal"><span class="pre">qnx6_find_entry()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">minix_find_entry()</span></code>.</p> +</div> +<p>In the <code class="docutils literal"><span class="pre">minfs_find_entry</span></code> function, iterate over the directory where the dentry is: <code class="docutils literal"><span class="pre">dentry->d_parent->d_inode</span></code>. +Iterating means going through the entries in the directory's data block (of type <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_dir_entry</span></code>) and locate, if it exists, the requested entry.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>From the structure of type <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code> corresponding to the directory, find out the data block index and read it (<code class="docutils literal"><span class="pre">sb_read</span></code>). +You will access the block contents using <code class="docutils literal"><span class="pre">bh->b_data</span></code>. +The directory data block contains an array of at most <code class="docutils literal"><span class="pre">MINFS_NUM_ENTRIES</span></code> entries of type <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_dir_entry</span></code>. +Use pointer arithmetics to get entries of type <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_dir_entry</span></code> from the data block (<code class="docutils literal"><span class="pre">bh->b_data</span></code>).</p> +<p>Check the presence of the name (stored in the local variable <code class="docutils literal"><span class="pre">name</span></code>) in the directory (if there is an entry in the data block whose name is a string equal to the given name). Use <code class="xref c c-func docutils literal"><span class="pre">strcmp()</span></code> to verify.</p> +<p>Ignore dentries that have an <code class="docutils literal"><span class="pre">ino</span></code> field equal to <code class="docutils literal"><span class="pre">0</span></code>. Those dentries are free slots in the directory dentry list.</p> +<p class="last">Store in the <code class="docutils literal"><span class="pre">final_de</span></code> variable the dentry found. +If you do not find any dentry, then the <code class="docutils literal"><span class="pre">final_de</span></code> variable will have the value <code class="docutils literal"><span class="pre">NULL</span></code>, the value with which it was initialized.</p> +</div> +<p>Comment the <code class="docutils literal"><span class="pre">simple_lookup</span></code> call in the <code class="docutils literal"><span class="pre">minfs_lookup</span></code> function to invoke the implementation of <code class="docutils literal"><span class="pre">minfs_readdir</span></code>.</p> +<div class="section" id="testing-3"> +<h5>Testing<a class="headerlink" href="#testing-3" title="Permalink to this headline">¶</a></h5> +<p>For testing, we use the steps described in the previous exercise. +The long file listing (<code class="docutils literal"><span class="pre">ls</span> <span class="pre">-l</span></code>) of the contents of a directory (root directory) will display permissions and other file-specific information:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ls -l /mnt/minfs +</pre></div> +</div> +<p>To test the functionality provided by the module, we can use the dedicated scripts:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ./test-minfs-0.sh +<span class="gp">#</span> ./test-minfs-1.sh +</pre></div> +</div> +<p>If the implementation is correct, no error messages will be displayed when running the scripts above.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>After mounting the file system using the command</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> mount -t minfs /dev/vdb /mnt/minfs +</pre></div> +</div> +<p>we try to create a file using the command</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> touch /mnt/minfs/peanuts.txt +</pre></div> +</div> +<p class="last">We notice that we get an error because we did not implement the directory operations that allow us to create a file. +We will do this for the next exercise.</p> +</div> +</div> +</div> +<div class="section" id="create-operation"> +<h4>3. Create operation<a class="headerlink" href="#create-operation" title="Permalink to this headline">¶</a></h4> +<p>In order to allow the creation of a file in a directory, we must implement the <code class="docutils literal"><span class="pre">create</span></code> operation. +The <code class="docutils literal"><span class="pre">create</span></code> operation is a field in the <code class="docutils literal"><span class="pre">minfs_dir_inode_operations</span></code> structure (of type <code class="xref c c-type docutils literal"><span class="pre">inode_operations</span></code>) and is implemented by the <code class="docutils literal"><span class="pre">minfs_create</span></code> function. We need to implement this function. +In fact, we will implement the <code class="docutils literal"><span class="pre">minfs_new_inode</span></code> (which creates and initializes an inode) and <code class="docutils literal"><span class="pre">minfs_add_link</span></code> which adds a link (or name or <em>dentry</em>) for the created inode.</p> +<p>Follow directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">7</span></code> which will guide you through the steps you need to take.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>Read the section <a class="reference internal" href="../so2/lab9-filesystems-part2.html#directoryinodes"><span class="std std-ref">Directory inodes operations</span></a></p> +<p class="last">Inspect the code in the <code class="docutils literal"><span class="pre">minfs_create</span></code> and the skeleton of functions <code class="docutils literal"><span class="pre">minfs_new_inode</span></code> and <code class="docutils literal"><span class="pre">minfs_add_link</span></code>.</p> +</div> +<p>Implement the function <code class="docutils literal"><span class="pre">minfs_new_inode</span></code>. Inside this function you will create (using <code class="xref c c-func docutils literal"><span class="pre">new_inode()</span></code>) and initialize an inode. The initialization is done using the data from disk.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>Use the <code class="xref c c-func docutils literal"><span class="pre">minix_new_inode()</span></code> function as a model. +Find the first free inode in imap (<code class="docutils literal"><span class="pre">sbi->imap</span></code>). +Use bitwise operations (<code class="docutils literal"><span class="pre">find_first_zero_bit</span></code> and <code class="docutils literal"><span class="pre">set_bit</span></code>). +Read the <a class="reference internal" href="../so2/lab9-filesystems-part2.html#bitmapoperations"><span class="std std-ref">Bitmap operations</span></a> section.</p> +<p>The buffer for the superblock (<code class="docutils literal"><span class="pre">sbi->sbh</span></code>) must be marked as dirty .</p> +<p class="last">You must initialize the usual fields as it is done for the <code class="docutils literal"><span class="pre">myfs</span></code> file system. +Initialize the <code class="docutils literal"><span class="pre">i_mode</span></code> field to <code class="docutils literal"><span class="pre">0</span></code> in the call to <code class="docutils literal"><span class="pre">inode_init_owner</span></code>. It will be initialized in the caller later.</p> +</div> +<p>Implement the <code class="docutils literal"><span class="pre">minfs_add_link</span></code> function. The function adds a new dentry (<code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_dir_entry</span></code>) to the parent directory data block (<code class="docutils literal"><span class="pre">dentry->d_parent->d_inode</span></code>).</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p class="last">Use the function <code class="docutils literal"><span class="pre">minix_add_link</span></code> function as a model.</p> +</div> +<p>In <code class="docutils literal"><span class="pre">minfs_add_link</span></code> we want to find the first free place for the dentry. +For this, you will iterate over the directory data block and you will find the first free entry. A free dentry has the <code class="docutils literal"><span class="pre">ino</span></code> field equal to <code class="docutils literal"><span class="pre">0</span></code>.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>In order to work with the directory, get the inode of type <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code> corresponding to the parent directory (the <strong>dir</strong> inode). +Do not use the variable <code class="docutils literal"><span class="pre">inode</span></code> to get <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code>; that inode belongs to the file, not to the parent directory inside which you want to add the link/dentry. +To get the <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code> structure, use <code class="xref c c-func docutils literal"><span class="pre">container_of()</span></code>.</p> +<p>The structure <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code> is useful for finding the directory data block (the one indicated by the <code class="docutils literal"><span class="pre">dentry->d_parent->d_inode</span></code>, which is the <code class="docutils literal"><span class="pre">dir</span></code> variable). +From this structure, get the <code class="docutils literal"><span class="pre">data_block</span></code> field, representing index of the data block on the disk. +This block contains the entries in the directory. Use <code class="xref c c-func docutils literal"><span class="pre">sb_bread()</span></code> to read the block and then <code class="docutils literal"><span class="pre">bh->b_data</span></code> to refer to the data. +The block contains at most <code class="docutils literal"><span class="pre">MINFS_NUM_ENTRIES</span></code> entries of type <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_dir_entry</span></code>.</p> +<p>If all entries are occupied, return <code class="docutils literal"><span class="pre">-ENOSPC</span></code>.</p> +<p>Iterate over the entries in the data block using the variable <code class="docutils literal"><span class="pre">de</span></code> and extract the first free entry (for which the <code class="docutils literal"><span class="pre">ino</span></code> field is <code class="docutils literal"><span class="pre">0</span></code>).</p> +<p>When you have found a free place, fill in the corresponding entry:</p> +<blockquote> +<div><ul class="simple"> +<li>the <code class="docutils literal"><span class="pre">inode->i_ino</span></code> field in <code class="docutils literal"><span class="pre">de->ino</span></code></li> +<li>the <code class="docutils literal"><span class="pre">dentry->d_name.name</span></code> field in <code class="docutils literal"><span class="pre">de->name</span></code></li> +</ul> +</div></blockquote> +<p class="last">Then mark the buffer dirty.</p> +</div> +<div class="section" id="testing-4"> +<h5>Testing<a class="headerlink" href="#testing-4" title="Permalink to this headline">¶</a></h5> +<p>For testing, we use the steps described in the previous exercise. +Now we can create files within the file system:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> touch /mnt/minfs/peanuts.txt +</pre></div> +</div> +<p>To test the functionality provided by the module, we can use the dedicated script:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ./test-minfs-2.sh +</pre></div> +</div> +<p>If the deployment is valid, no error messages will be displayed following the above script run.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The current implementation of the <code class="docutils literal"><span class="pre">minfs</span></code> file system is not definitive. +To be complete, the implementations needs function to delete files, create and delete directories, rename entries, and modify the contents of a file.</p> +</div> +</div> +</div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="filesystems_part1.html" class="btn btn-neutral float-left" title="File system drivers (Part 1)" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="networking.html" class="btn btn-neutral float-right" title="Networking" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/labs/infrastructure.html b/refs/pull/405/merge/labs/infrastructure.html new file mode 100644 index 00000000..7f32d602 --- /dev/null +++ b/refs/pull/405/merge/labs/infrastructure.html @@ -0,0 +1,228 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Infrastructure — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Introduction" href="introduction.html" /> + <link rel="prev" title="Virtualization" href="../lectures/virt.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul class="current"> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Infrastructure</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/labs/infrastructure.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="infrastructure"> +<h1>Infrastructure<a class="headerlink" href="#infrastructure" title="Permalink to this headline">¶</a></h1> +<p>In order to facilitate learning each topic has a hands-on exercises +section which will contain in-depth, incremental clues on how to solve +one or multiple tasks. To focus on a particular issue most of the +tasks will be performed on existing skeleton drivers. Each skeleton +driver has clearly marked sections that needs to be filled in order to +complete the tasks.</p> +<p>The skeleton drivers are generated from full source examples located +in tools/labs/templates. To solve tasks you start by generating the +skeleton drivers, running the <strong>skels</strong> target in <em>tools/labs</em>. To +keep the workspace clean it is recommended to generate the skeletons +for one lab only and clean the workspace before start working on a new +lab. Labs can be selected by using the <strong>LABS</strong> variable:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span>kernel_modules make skels + +tools/labs $ ls skels/kernel_modules/ +<span class="m">1</span>-2-test-mod <span class="m">3</span>-error-mod <span class="m">4</span>-multi-mod <span class="m">5</span>-oops-mod <span class="m">6</span>-cmd-mod <span class="se">\</span> +<span class="m">7</span>-list-proc <span class="m">8</span>-kprobes <span class="m">9</span>-kdb +</pre></div> +</div> +<p>You can also use the same variable to generate skeletons for specific +tasks:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><span class="s2">"kernel_modules/6-cmd-mod kernel_modules/8-kprobes"</span> make skels + +tools/labs$ ls skels/kernel_modules +<span class="m">6</span>-cmd-mod <span class="m">8</span>-kprobes +</pre></div> +</div> +<p>For each task you may have multiple steps to perform, usually +incremental. These steps are marked in the source code as well as in +the lab exercises with the keyword <em>TODO</em>. If we have multiple steps +to perform they will be prefixed by a number, like <em>TODO1</em>, <em>TODO2</em>, +etc. If no number is used it is assumed to be the one and only +step. If you want to resume a task from a certain step, you can using +the <strong>TODO</strong> variable. The following example will generate the +skeleton with the first <em>TODO</em> step resolved:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">TODO</span><span class="o">=</span><span class="m">2</span> <span class="nv">LABS</span><span class="o">=</span><span class="s2">"kernel_modules/8-kprobes"</span> skels +</pre></div> +</div> +<p>Once the skelton drivers are generated you can build them with the +<strong>build</strong> make target:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +<span class="nb">echo</span> <span class="s2">"# autogenerated, do not edit "</span> > skels/Kbuild +<span class="k">for</span> i in ./kernel_modules/8-kprobes<span class="p">;</span> <span class="k">do</span> <span class="nb">echo</span> <span class="s2">"obj-m += </span><span class="nv">$i</span><span class="s2">/"</span> >> skels/Kbuild<span class="p">;</span> <span class="k">done</span> +make -C /home/tavi/src/linux <span class="nv">M</span><span class="o">=</span>/home/tavi/src/linux/tools/labs/skels <span class="nv">ARCH</span><span class="o">=</span>x86 modules +make<span class="o">[</span><span class="m">1</span><span class="o">]</span>: Entering directory <span class="s1">'/home/tavi/src/linux'</span> +CC <span class="o">[</span>M<span class="o">]</span> /home/tavi/src/linux/tools/labs/skels/./kernel_modules/8-kprobes/kprobes.o +Building modules, stage <span class="m">2</span>. +MODPOST <span class="m">1</span> modules +CC /home/tavi/src/linux/tools/labs/skels/./kernel_modules/8-kprobes/kprobes.mod.o +LD <span class="o">[</span>M<span class="o">]</span> /home/tavi/src/linux/tools/labs/skels/./kernel_modules/8-kprobes/kprobes.ko +make<span class="o">[</span><span class="m">1</span><span class="o">]</span>: Leaving directory <span class="s1">'/home/tavi/src/linux'</span> +</pre></div> +</div> +<p>To copy the drivers to the VM you can use either use ssh or update the +VM image directly using the <strong>copy</strong> target:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make copy +... +<span class="s1">'skels/kernel_modules/8-kprobes/kprobes.ko'</span> -> <span class="s1">'/tmp/tmp.4UMKcISmQM/home/root/skels/kernel_modules/8-kprobes/kprobes.ko'</span> +</pre></div> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">The <strong>copy</strong> target will fail if the VM is +running. This is intentional so that we avoid corrupting the +filesystem.</p> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../lectures/virt.html" class="btn btn-neutral float-left" title="Virtualization" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="introduction.html" class="btn btn-neutral float-right" title="Introduction" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/labs/interrupts.html b/refs/pull/405/merge/labs/interrupts.html new file mode 100644 index 00000000..79341d97 --- /dev/null +++ b/refs/pull/405/merge/labs/interrupts.html @@ -0,0 +1,1261 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>I/O access and Interrupts — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Deferred work" href="deferred_work.html" /> + <link rel="prev" title="Character device drivers" href="device_drivers.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">I/O access and Interrupts</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="#background-information">Background information</a></li> +<li class="toctree-l2"><a class="reference internal" href="#accessing-the-hardware">Accessing the hardware</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#request-access-to-i-o-ports">Request access to I/O ports</a></li> +<li class="toctree-l3"><a class="reference internal" href="#accessing-i-o-ports">Accessing I/O ports</a></li> +<li class="toctree-l3"><a class="reference internal" href="#accessing-i-o-ports-from-userspace">5. Accessing I/O ports from userspace</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#interrupt-handling">Interrupt handling</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#requesting-an-interrupt">Requesting an interrupt</a></li> +<li class="toctree-l3"><a class="reference internal" href="#implementing-an-interrupt-handler">Implementing an interrupt handler</a></li> +<li class="toctree-l3"><a class="reference internal" href="#locking">Locking</a></li> +<li class="toctree-l3"><a class="reference internal" href="#interrupt-statistics">Interrupt statistics</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#further-reading">Further reading</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#serial-port">Serial Port</a></li> +<li class="toctree-l3"><a class="reference internal" href="#parallel-port">Parallel port</a></li> +<li class="toctree-l3"><a class="reference internal" href="#keyboard-controller">Keyboard controller</a></li> +<li class="toctree-l3"><a class="reference internal" href="#linux-device-drivers">Linux device drivers</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#intro">0. Intro</a></li> +<li class="toctree-l3"><a class="reference internal" href="#keyboard-driver">Keyboard driver</a></li> +<li class="toctree-l3"><a class="reference internal" href="#request-the-i-o-ports">1. Request the I/O ports</a></li> +<li class="toctree-l3"><a class="reference internal" href="#interrupt-handling-routine">2. Interrupt handling routine</a></li> +<li class="toctree-l3"><a class="reference internal" href="#store-ascii-keys-to-buffer">3. Store ASCII keys to buffer</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#reading-the-data-register">Reading the data register</a></li> +<li class="toctree-l4"><a class="reference internal" href="#interpreting-the-scancode">Interpreting the scancode</a></li> +<li class="toctree-l4"><a class="reference internal" href="#store-characters-to-the-buffer">Store characters to the buffer</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#reading-the-buffer">4. Reading the buffer</a></li> +<li class="toctree-l3"><a class="reference internal" href="#reset-the-buffer">5. Reset the buffer</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#extra-exercises">Extra Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#kfifo">1. kfifo</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">I/O access and Interrupts</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/labs/interrupts.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="i-o-access-and-interrupts"> +<h1>I/O access and Interrupts<a class="headerlink" href="#i-o-access-and-interrupts" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>communication with peripheral devices</li> +<li>implement interrupt handlers</li> +<li>synchronizing interrupts with process context</li> +</ul> +<p>Keywords: IRQ, I/O port, I/O address, base address, UART, request_region, release_region, inb, outb</p> +</div> +<div class="section" id="background-information"> +<h2>Background information<a class="headerlink" href="#background-information" title="Permalink to this headline">¶</a></h2> +<p>A peripheral device is controlled by writing and reading its +registers. Often, a device has multiple registers that can be accessed +at consecutive addresses either in the memory address space or in the +I/O address space. Each device connected to the I/O bus has a set of +I/O addresses, called I/O ports. I/O ports can be mapped to physical +memory addresses so that the processor can communicate with the device +through instructions that work directly with the memory. For +simplicity, we will directly use I/O ports (without mapping to physical +memory addresses) to communicate with physical devices.</p> +<p>The I/O ports of each device are structured into a set of specialized +registers to provide a uniform programming interface. Thus, most +devices will have the following types of registers:</p> +<ul class="simple"> +<li><strong>Control</strong> registers that receive device commands</li> +<li><strong>Status</strong> registers, which contain information about the device's +internal status</li> +<li><strong>Input</strong> registers from which data is taken from the device</li> +<li><strong>Output</strong> registers in which the data is written to transmit it to the +device</li> +</ul> +<p>Physical ports are differentiated by the number of bits: they can be +8, 16 or 32-bit ports.</p> +<p>For example, the parallel port has 8 8-bit I/O ports starting at base +address 0x378. The data log is found at base address (0x378), status +register at base + 1 (0x379), and control at base address + 2 +(0x37a). The data log is both an entry and exit log.</p> +<p>Although there are devices that can be fully controlled using I/O +ports or special memory areas, there are situations where this is +insufficient. The main problem that needs to be addressed is that +certain events occur at undefined moments in time and it is +inefficient for the processor (CPU) to interrogate the status of the +device repeatedly (polling). The way to solve this problem is using an +Interrupt ReQuest (IRQ) which is a hardware notification by which the +processor is announced that a particular external event happened.</p> +<p>For IRQs to be useful device drivers must implement handlers, i.e. a +particular sequence of code that handles the interrupt. Because in +many situations the number of interrupts available is limited, a +device driver must behave in an orderly fashion with interruptions: +interrupts must be requested before being used and released when they +are no longer needed. In addition, in some situations, device drivers +must share an interrupt or synchronize with interrupts. All of these will be +discussed further.</p> +<p>When we need to access shared resources between an interrupt +routine (A) and code running in process context or in bottom-half +context (B), we must use a special synchronization technique. In (A) +we need to use a spinlock primitive, and in (B) we must disable +interrupts AND use a spinlock primitive. Disabling interrupts is not +enough because the interrupt routine can run on a processor other than +the one running (B).</p> +<p>Using only a spinlock can lead to a deadlock. The classic example of +deadlock in this case is:</p> +<ol class="arabic simple"> +<li>We run a process on the X processor, and we acquire the lock</li> +<li>Before releasing the lock, an interrupt is generated on the X processor</li> +<li>The interrupt handling routine will try to acquire the lock and it +will go into an infinite loop</li> +</ol> +</div> +<div class="section" id="accessing-the-hardware"> +<h2>Accessing the hardware<a class="headerlink" href="#accessing-the-hardware" title="Permalink to this headline">¶</a></h2> +<p>In Linux, the I/O ports access is implemented on all architectures and +there are several APIs that can be used.</p> +<div class="section" id="request-access-to-i-o-ports"> +<h3>Request access to I/O ports<a class="headerlink" href="#request-access-to-i-o-ports" title="Permalink to this headline">¶</a></h3> +<p>Before accessing I/O ports we first must request access to them, to +make sure there is only one user. In order to do so, one must use the +<code class="xref c c-func docutils literal"><span class="pre">request_region()</span></code> function:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/ioport.h></span><span class="cp"></span> + +<span class="k">struct</span> <span class="n">resource</span> <span class="o">*</span><span class="nf">request_region</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">first</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">n</span><span class="p">,</span> + <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">);</span> +</pre></div> +</div> +<p>To release a reserved region one must use the <code class="xref c c-func docutils literal"><span class="pre">release_region()</span></code> function:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">release_region</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">start</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">n</span><span class="p">);</span> +</pre></div> +</div> +<p>For example, the serial port COM1 has the base address 0x3F8 and it +has 8 ports and this is a code snippet of how to request access to +these ports:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/ioport.h></span><span class="cp"></span> + +<span class="cp">#define MY_BASEPORT 0x3F8</span> +<span class="cp">#define MY_NR_PORTS 8</span> + +<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">request_region</span><span class="p">(</span><span class="n">MY_BASEPORT</span><span class="p">,</span> <span class="n">MY_NR_PORTS</span><span class="p">,</span> <span class="s">"com1"</span><span class="p">))</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> + <span class="k">return</span> <span class="o">-</span><span class="n">ENODEV</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>To release the ports one would use something like:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">release_region</span><span class="p">(</span><span class="n">MY_BASEPORT</span><span class="p">,</span> <span class="n">MY_NR_PORTS</span><span class="p">);</span> +</pre></div> +</div> +<p>Most of the time, port requests are done at the driver initialization +or probe time and the port releasing is done at the removal of the +device or module.</p> +<p>All of the port requests can be seen from userspace via the +<code class="file docutils literal"><span class="pre">/proc/ioports</span></code> file:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>$ cat /proc/ioports +<span class="m">0000</span>-001f : dma1 +<span class="m">0020</span>-0021 : pic1 +<span class="m">0040</span>-005f : timer +<span class="m">0060</span>-006f : keyboard +<span class="m">0070</span>-0077 : rtc +<span class="m">0080</span>-008f : dma page reg +00a0-00a1 : pic2 +00c0-00df : dma2 +00f0-00ff : fpu +<span class="m">0170</span>-0177 : ide1 +01f0-01f7 : ide0 +<span class="m">0376</span>-0376 : ide1 +<span class="m">0378</span>-037a : parport0 +037b-037f : parport0 +03c0-03df : vga+ +03f6-03f6 : ide0 +03f8-03ff : serial +... +</pre></div> +</div> +</div> +<div class="section" id="accessing-i-o-ports"> +<h3>Accessing I/O ports<a class="headerlink" href="#accessing-i-o-ports" title="Permalink to this headline">¶</a></h3> +<p>After a driver has obtained the desired I/O port range, one can +perform read or write operations on these ports. Since physical ports +are differentiated by the number of bits (8, 16, or 32 bits), there +are different port access functions depending on their size. The +following port access functions are defined in asm/io.h:</p> +<ul class="simple"> +<li><em>unsigned inb(int port)</em>, reads one byte (8 bits) from port</li> +<li><em>void outb(unsigned char byte, int port)</em>, writes one byte (8 bits) to port</li> +<li><em>unsigned inw(int port)</em>, reads two bytes (16-bit) ports</li> +<li><em>void outw(unsigned short word, int port)</em>, writes two bytes (16-bits) to port</li> +<li><em>unsigned inl (int port)</em>, reads four bytes (32-bits) from port</li> +<li><em>void outl(unsigned long word, int port)</em>, writes four bytes (32-bits) to port</li> +</ul> +<p>The port argument specifies the address of the port where the reads or +writes are done, and its type is platform dependent (may be unsigned +long or unsigned short).</p> +<p>Some devices may have problems when the processor is trying to +transfer data too fast to and from the device. To avoid this issue we +may need to insert a delay after an I/O operation and there are functions +you can use that introduce this delay. Their names are similar to +those described above, with the exception that it ends in _p: inb_p, +outb_p, etc.</p> +<p>For example, the following sequence writes a byte on COM1 serial port +and then reads it:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><asm/io.h></span><span class="cp"></span> +<span class="cp">#define MY_BASEPORT 0x3F8</span> + +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">value</span> <span class="o">=</span> <span class="mh">0xFF</span><span class="p">;</span> +<span class="n">outb</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">MY_BASEPORT</span><span class="p">);</span> +<span class="n">value</span> <span class="o">=</span> <span class="n">inb</span><span class="p">(</span><span class="n">MY_BASEPORT</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="accessing-i-o-ports-from-userspace"> +<h3>5. Accessing I/O ports from userspace<a class="headerlink" href="#accessing-i-o-ports-from-userspace" title="Permalink to this headline">¶</a></h3> +<p>Although the functions described above are defined for device drivers, +they can also be used in user space by including the <sys/io.h> +header. In order to be used, ioperm or iopl must first be called to +get permission to perform port operations. The ioperm function obtains +permission for individual ports, while iopl for the entire I/O address +space. To use these features, the user must be root.</p> +<p>The following sequence used in user space gets permission for the +first 3 ports of the serial port, and then releases them:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><sys/io.h></span><span class="cp"></span> +<span class="cp">#define MY_BASEPORT 0x3F8</span> + +<span class="k">if</span> <span class="p">(</span><span class="n">ioperm</span><span class="p">(</span><span class="n">MY_BASEPORT</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> +<span class="p">}</span> + +<span class="k">if</span> <span class="p">(</span><span class="n">ioperm</span><span class="p">(</span><span class="n">MY_BASEPORT</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The third parameter of the ioperm function is used to request or +release port permission: 1 to get permission and 0 to release.</p> +</div> +</div> +<div class="section" id="interrupt-handling"> +<h2>Interrupt handling<a class="headerlink" href="#interrupt-handling" title="Permalink to this headline">¶</a></h2> +<div class="section" id="requesting-an-interrupt"> +<h3>Requesting an interrupt<a class="headerlink" href="#requesting-an-interrupt" title="Permalink to this headline">¶</a></h3> +<p>As with other resources, a driver must gain access to an interrupt +line before it can use it and release it at the end of the execution.</p> +<p>In Linux, the request to obtain and release an interrupt is done using +the <code class="xref c c-func docutils literal"><span class="pre">requests_irq()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">free_irq()</span></code> functions:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/interrupt.h></span><span class="cp"></span> + +<span class="k">typedef</span> <span class="nf">irqreturn_t</span> <span class="p">(</span><span class="o">*</span><span class="n">irq_handler_t</span><span class="p">)(</span><span class="kt">int</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">request_irq</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">irq_no</span><span class="p">,</span> <span class="n">irq_handler_t</span> <span class="n">handler</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">dev_name</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">dev_id</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">free_irq</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">irq_no</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">dev_id</span><span class="p">);</span> +</pre></div> +</div> +<p>Note that to get an interrupt, the developer calls +<code class="xref c c-func docutils literal"><span class="pre">request_irq()</span></code>. When calling this function you must specify the +interrupt number (<em>irq_no</em>), a handler that will be called when the +interrupt is generated (<em>handler</em>), flags that will instruct the +kernel about the desired behaviour (<em>flags</em>), the name of the device +using this interrupt (<em>dev_name</em>), and a pointer that can be +configured by the user at any value, and that has no global +significance (<em>dev_id</em>). Most of the time, <em>dev_id</em> will be +pointer to the device driver's private data. When the interrupt is +released, using the <code class="xref c c-func docutils literal"><span class="pre">free_irq()</span></code> function, the developer must +send the same pointer value (<em>dev_id</em>) along with the same interrupt +number (<em>irq_no</em>). The device name (<em>dev_name</em>) is used to display +statistics in <em>/proc/interrupts</em>.</p> +<p>The value that <code class="xref c c-func docutils literal"><span class="pre">request_irq()</span></code> returns is 0 if the entry was +successful or a negative error code indicating the reason for the +failure. A typical value is <em>-EBUSY</em> which means that the interrupt +was already requested by another device driver.</p> +<p>The <em>handler</em> function is executed in interrupt context which means +that we can't call blocking APIs such as <code class="xref c c-func docutils literal"><span class="pre">mutex_lock()</span></code> or +<code class="xref c c-func docutils literal"><span class="pre">msleep()</span></code>. We must also avoid doing a lot of work in the +interrupt handler and instead use deferred work if needed. The actions +performed in the interrupt handler include reading the device +registers to get the status of the device and acknowledge the +interrupt, operations that most of the time can be performed with +non-blocking calls.</p> +<p>There are situations where although a device uses interrupts we can't +read the device's registers in a non-blocking mode (for example a +sensor connected to an I2C or SPI bus whose driver does not guarantee +that bus read / write operations are non-blocking ). In this +situation, in the interruption, we must plan a work-in-process action +(work queue, kernel thread) to access the device's registers. Because +such a situation is relatively common, the kernel provides the +<code class="xref c c-func docutils literal"><span class="pre">request_threaded_irq()</span></code> function to write interrupt handling +routines running in two phases: a process-phase and an interrupt +context phase:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/interrupt.h></span><span class="cp"></span> + +<span class="kt">int</span> <span class="nf">request_threaded_irq</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">irq</span><span class="p">,</span> <span class="n">irq_handler_t</span> <span class="n">handler</span><span class="p">,</span> + <span class="n">irq_handler_t</span> <span class="n">thread_fn</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">dev</span><span class="p">);</span> +</pre></div> +</div> +<p><em>handler</em> is the function running in interrupt context, and will +implement critical operations while the thread_fn function runs in +process context and implements the rest of the operations.</p> +<p>The flags that can be transmitted when an interruption is made are:</p> +<ul class="simple"> +<li><em>IRQF_SHARED</em> announces the kernel that the interrupt can be +shared with other devices. If this flag is not set, then if there is +already a handler associated with the requested interrupt, the +request for interrupt will fail. A shared interrupt is handled in a +special way by the kernel: all the associated interrupt handlers +will be executed until the device that generated the interrupt will +be identified. But how can a device driver know if the interrupt +handling routine was activated by an interrupt generated by the +device it manages? Virtually all devices that offer interrupt +support have a status register that can be interrogated in the +handling routine to see if the interrupt was or was not generated by +the device (for example, in the case of the 8250 serial port, this +status register is IIR - Interrupt Information Register). When +requesting a shared interrupt, the dev_id argument must be unique +and it must not be NULL. Usually it is set to module's private +data.</li> +<li><em>IRQF_ONESHOT</em> interrupt will be reactivated after running the process +context routine; Without this flag, the interrupt will be +reactivated after running the handler routine in the context of +the interrupt</li> +</ul> +<p>Requesting the interrupt can be done either at the initialization of +the driver (<code class="xref c c-func docutils literal"><span class="pre">init_module()</span></code>), when the device is probed, or when +the device is used (e.g. during <em>open</em>).</p> +<p>The following example performs the interrupt request for the COM1 +serial port:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/interrupt.h></span><span class="cp"></span> + +<span class="cp">#define MY_BASEPORT 0x3F8</span> +<span class="cp">#define MY_IRQ 4</span> + +<span class="k">static</span> <span class="nf">my_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="p">[...]</span> + <span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="n">my_data</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">err</span><span class="p">;</span> + + <span class="n">err</span> <span class="o">=</span> <span class="n">request_irq</span><span class="p">(</span><span class="n">MY_IRQ</span><span class="p">,</span> <span class="n">my_handler</span><span class="p">,</span> <span class="n">IRQF_SHARED</span><span class="p">,</span> + <span class="s">"com1"</span><span class="p">,</span> <span class="n">my_data</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error*/</span> + <span class="k">return</span> <span class="n">err</span><span class="p">;</span> + <span class="p">}</span> + <span class="p">[...]</span> +<span class="p">}</span> +</pre></div> +</div> +<p>As you can see, the IRQ for serial port COM1 is 4, which is used in +shared mode (IRQF_SHARED).</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">When requesting a shared interrupt (IRQF_SHARED) the +<em>dev_id</em> argument can not be NULL.</p> +</div> +<p>To release the interrupt associated with the serial port, the +following operations will be executed:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">free_irq</span> <span class="p">(</span><span class="n">MY_IRQ</span><span class="p">,</span> <span class="n">my_data</span><span class="p">);</span> +</pre></div> +</div> +<p>During the initialization function (<code class="xref c c-func docutils literal"><span class="pre">init_module()</span></code>), or in the +function that opens the device, interrupts must be activated for the +device. This operation is dependent on the device, but most often +involves setting a bit from the control register.</p> +<p>As an example, for the 8250 serial port, the following operations must +be performed to enable interrupts:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><asm/io.h></span><span class="cp"></span> +<span class="cp">#define MY_BASEPORT 0x3F8</span> + +<span class="n">outb</span><span class="p">(</span><span class="mh">0x08</span><span class="p">,</span> <span class="n">MY_BASEPORT</span><span class="o">+</span><span class="mi">4</span><span class="p">);</span> +<span class="n">outb</span><span class="p">(</span><span class="mh">0x01</span><span class="p">,</span> <span class="n">MY_BASEPORT</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span> +</pre></div> +</div> +<p>In the above example, two operations are performed:</p> +<ol class="arabic simple"> +<li>All interruptions are activated by setting bit 3 (Aux Output 2) in +the MCR register - Modem Control Register</li> +<li>The RDAI (Transmit Holding Register Empty Interrupt) is activated +by setting the appropriate bit in the IER - Interrupt Enable +Register.</li> +</ol> +</div> +<div class="section" id="implementing-an-interrupt-handler"> +<h3>Implementing an interrupt handler<a class="headerlink" href="#implementing-an-interrupt-handler" title="Permalink to this headline">¶</a></h3> +<p>Lets take a look at the signature of the interrupt handler function:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">irqreturn_t</span> <span class="p">(</span><span class="o">*</span><span class="n">handler</span><span class="p">)(</span><span class="kt">int</span> <span class="n">irq_no</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">dev_id</span><span class="p">);</span> +</pre></div> +</div> +<p>The function receives as parameters the number of the interrupt +(<em>irq_no</em>) and the pointer sent to <code class="xref c c-func docutils literal"><span class="pre">request_irq()</span></code> when the +interrupt was requested. The interrupt handling routine must return a +value with a type of <code class="xref c c-type docutils literal"><span class="pre">typedef</span> <span class="pre">irqreturn_t</span></code>. For the current kernel +version, there are three valid values: <em>IRQ_NONE</em>, <em>IRQ_HANDLED</em>, +and <em>IRQ_WAKE_THREAD</em>. The device driver must return <em>IRQ_NONE</em> if +it notices that the interrupt has not been generated by the device it +is in charge. Otherwise, the device driver must return <em>IRQ_HANDLED</em> +if the interrupt can be handled directly from the interrupt context or +<em>IRQ_WAKE_THREAD</em> to schedule the running of the process context +processing function.</p> +<p>The skeleton for an interrupt handler is:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">irqreturn_t</span> <span class="nf">my_handler</span><span class="p">(</span><span class="kt">int</span> <span class="n">irq_no</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">dev_id</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="n">my_data</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="p">)</span> <span class="n">dev_id</span><span class="p">;</span> + + <span class="cm">/* if interrupt is not for this device (shared interrupts) */</span> + <span class="cm">/* return IRQ_NONE;*/</span> + + <span class="cm">/* clear interrupt-pending bit */</span> + <span class="cm">/* read from device or write to device*/</span> + + <span class="k">return</span> <span class="n">IRQ_HANDLED</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Typically, the first thing executed in the interrupt handler is to +determine whether the interrupt was generated by the device that the +driver ordered. This usually reads information from the device's +registers to indicate whether the device has generated an +interrupt. The second thing is to reset the interrupt pending bit on +the physical device as most devices will no longer generate +interruptions until this bit has been reset (e.g. for the 8250 +serial port bit 0 in the IIR register must be cleared).</p> +</div> +<div class="section" id="locking"> +<h3>Locking<a class="headerlink" href="#locking" title="Permalink to this headline">¶</a></h3> +<p>Because the interrupt handlers run in interrupt context the actions +that can be performed are limited: unable to access user space memory, +can't call blocking functions. Also, synchronization using spinlocks is +tricky and can lead to deadlocks if the spinlock used is already +acquired by a process that has been interrupted by the running +handler.</p> +<p>However, there are cases where device drivers have to synchronize +using interrupts, such as when data is shared between the interrupt +handler and process context or bottom-half handlers. In these +situations it is necessary to both deactivate the interrupt and use +spinlocks.</p> +<p>There are two ways to disable interrupts: disabling all interrupts, at +the processor level, or disabling a particular interrupt at the device +or interrupt controller level. Processor disabling is faster and is +therefore preferred. For this purpose, there are locking functions +that disable and enable interrupts acquiring and release a spinlock at +the same time: <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock_irqrestore()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irq()</span></code>, and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock_irq()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/spinlock.h></span><span class="cp"></span> + +<span class="kt">void</span> <span class="nf">spin_lock_irqsave</span> <span class="p">(</span><span class="n">spinlock_t</span> <span class="o">*</span> <span class="n">lock</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">spin_unlock_irqrestore</span> <span class="p">(</span><span class="n">spinlock_t</span> <span class="o">*</span> <span class="n">lock</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">spin_lock_irq</span> <span class="p">(</span><span class="n">spinlock_t</span> <span class="o">*</span> <span class="n">lock</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">spin_unlock_irq</span> <span class="p">(</span><span class="n">spinlock_t</span> <span class="o">*</span> <span class="n">lock</span><span class="p">);</span> +</pre></div> +</div> +<p>The <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> function disables interrupts for the +local processor before it obtains the spinlock; The previous state of +the interrupts is saved in <em>flags</em>.</p> +<p>If you are absolutely sure that the interrupts on the current +processor have not already been disabled by someone else and you are +sure you can activate the interrupts when you release the spinlock, +you can use <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irq()</span></code>.</p> +<p>For read / write spinlocks there are similar functions available:</p> +<ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">read_lock_irqsave()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">read_unlock_irqrestore()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">read_lock_irq()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">read_unlock_irq()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">write_lock_irqsave()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">write_unlock_irqrestore()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">write_lock_irq()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">write_unlock_irq()</span></code></li> +</ul> +<p>If we want to disable interrupts at the interrupt controller level +(not recommended because disabling a particular interrupt is slower, +we can not disable shared interrupts) we can do this with +<code class="xref c c-func docutils literal"><span class="pre">disable_irq()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">disable_irq_nosync()</span></code>, and +<code class="xref c c-func docutils literal"><span class="pre">enable_irq()</span></code>. Using these functions will disable the interrupts on +all processors. Calls can be nested: if disable_irq is called twice, +it will require as many calls enable_irq to enable it. The difference +between disable_irq and disable_irq_nosync is that the first one will +wait for the executed handlers to finish. Because of this, +<code class="xref c c-func docutils literal"><span class="pre">disable_irq_nosync()</span></code> is generally faster, but may lead to +races with the interrupts handler, so when not sure use +<code class="xref c c-func docutils literal"><span class="pre">disable_irq()</span></code>.</p> +<p>The following sequence disables and then enables the interrupt for +the COM1 serial port:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define MY_IRQ 4</span> + +<span class="n">disable_irq</span> <span class="p">(</span><span class="n">MY_IRQ</span><span class="p">);</span> +<span class="n">enable_irq</span> <span class="p">(</span><span class="n">MY_IRQ</span><span class="p">);</span> +</pre></div> +</div> +<p>It is also possible to disable interrupts at the device level. This +approach is also slower than disabling interrupts at the processor +level, but it works with shared interrupts. The way to accomplish this +is device specific and it usually means we have to clear a bit from +one of the control registers.</p> +<p>It is also possible to disable all interrupts for the current +processor independent of taking locks. Disabling all interruptions by +device drivers for synchronization purposes is inappropriate because +races are still possible if the interrupt is handled on another +CPU. For reference, the functions that disable / enable interrupts on +the local processor are <code class="xref c c-func docutils literal"><span class="pre">local_irq_disable()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">local_irq_enable()</span></code>.</p> +<p>In order to use a resource shared between process context and the +interrupt handling routine, the functions described above will be used +as follows:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">spinlock_t</span> <span class="n">lock</span><span class="p">;</span> + +<span class="cm">/* IRQ handling routine: interrupt context */</span> +<span class="n">irqreturn_t</span> <span class="nf">kbd_interrupt_handle</span><span class="p">(</span><span class="kt">int</span> <span class="n">irq_no</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span> <span class="n">dev_id</span><span class="p">)</span> +<span class="p">{</span> + <span class="p">...</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> + <span class="cm">/* Critical region - access shared resource */</span> + <span class="n">spin_unlock</span> <span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> + <span class="p">...</span> +<span class="p">}</span> + +<span class="cm">/* Process context: Disable interrupts when locking */</span> +<span class="k">static</span> <span class="kt">void</span> <span class="nf">my_access</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + + <span class="n">spin_lock_irqsave</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="cm">/* Critical region - access shared resource */</span> + <span class="n">spin_unlock_irqrestore</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + + <span class="p">...</span> +<span class="p">}</span> + +<span class="kt">void</span> <span class="nf">my_init</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="p">...</span> + <span class="n">spin_lock_init</span> <span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> + <span class="p">...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The <em>my_access function</em> above runs in process context. To +synchronize access to the shared data, we disable the interrupts and +use the spinlock <em>lock</em>, i.e. the <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock_irqrestore()</span></code> functions.</p> +<p>In the interrupt handling routine, we use the <code class="xref c c-func docutils literal"><span class="pre">spin_lock()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock()</span></code> functions to access the shared resource.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The <em>flags</em> argument for <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock_irqrestore()</span></code> is a value and not a pointer but keep +in mind that <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> function changes the value of +the flag, since this is actually a macro.</p> +</div> +</div> +<div class="section" id="interrupt-statistics"> +<h3>Interrupt statistics<a class="headerlink" href="#interrupt-statistics" title="Permalink to this headline">¶</a></h3> +<p>Information and statistics about system interrupts can be found in +<em>/proc/interrupts</em> or <em>/proc/stat</em>. Only system interrupts with +associated interrupt handlers appear in <em>/proc/interrupts</em>:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span><span class="c1"># cat /proc/interrupts</span> + CPU0 +<span class="m">0</span>: <span class="m">7514294</span> IO-APIC-edge timer +<span class="m">1</span>: <span class="m">4528</span> IO-APIC-edge i8042 +<span class="m">6</span>: <span class="m">2</span> IO-APIC-edge floppy +<span class="m">8</span>: <span class="m">1</span> IO-APIC-edge rtc +<span class="m">9</span>: <span class="m">0</span> IO-APIC-level acpi +<span class="m">12</span>: <span class="m">2301</span> IO-APIC-edge i8042 +<span class="m">15</span>: <span class="m">41</span> IO-APIC-edge ide1 +<span class="m">16</span>: <span class="m">3230</span> IO-APIC-level ioc0 +<span class="m">17</span>: <span class="m">1016</span> IO-APIC-level vmxnet ether +NMI: <span class="m">0</span> +LOC: <span class="m">7229438</span> +ERR: <span class="m">0</span> +MIS: <span class="m">0</span> +</pre></div> +</div> +<p>The first column specifies the IRQ associated with the interrupt. The +following column shows the number of interrupts that were generated +for each processor in the system; The last two columns provide +information about the interrupt controller and the device name that +registered the handler for that interrupt.</p> +<p>The <em>/proc/state</em> file provides information about system activity, +including the number of interruptions generated since the last (re)boot +of the system:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span><span class="c1"># cat /proc/stat | grep in</span> +intr <span class="m">7765626</span> <span class="m">7754228</span> <span class="m">4620</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">2</span> <span class="m">0</span> <span class="m">1</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">2377</span> <span class="m">0</span> <span class="m">0</span> <span class="m">41</span> <span class="m">3259</span> <span class="m">1098</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> +<span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> +<span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> +<span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> +<span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> +<span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> +</pre></div> +</div> +<p>Each line in the <em>/proc/state</em> file begins with a keyword that +specifies the meaning of the information on the line. For information +on interrupts, this keyword is intr. The first number on the line +represents the total number of interrupts, and the other numbers +represent the number of interrupts for each IRQ, starting at 0. The +counter includes the number of interrupts for all processors in the +system.</p> +</div> +</div> +<div class="section" id="further-reading"> +<h2>Further reading<a class="headerlink" href="#further-reading" title="Permalink to this headline">¶</a></h2> +<div class="section" id="serial-port"> +<h3>Serial Port<a class="headerlink" href="#serial-port" title="Permalink to this headline">¶</a></h3> +<ul class="simple"> +<li><a class="reference external" href="http://en.wikipedia.org/wiki/Serial_port">Serial Port</a></li> +<li><a class="reference external" href="http://www.beyondlogic.org/serial/serial.htm">Interfacing the Serial / RS232 Port</a></li> +</ul> +</div> +<div class="section" id="parallel-port"> +<h3>Parallel port<a class="headerlink" href="#parallel-port" title="Permalink to this headline">¶</a></h3> +<ul class="simple"> +<li><a class="reference external" href="http://www.beyondlogic.org/spp/parallel.htm">Interfacing the Standard Parallel Port</a></li> +<li><a class="reference external" href="http://www.lvr.com/parport.htm">Parallel Port Central</a></li> +</ul> +</div> +<div class="section" id="keyboard-controller"> +<h3>Keyboard controller<a class="headerlink" href="#keyboard-controller" title="Permalink to this headline">¶</a></h3> +<ul class="simple"> +<li><a class="reference external" href="http://en.wikipedia.org/wiki/Intel_8042">Intel 8042</a></li> +<li>drivers/input/serio/i8042.c</li> +<li>drivers/input/keyboard/atkbd.c</li> +</ul> +</div> +<div class="section" id="linux-device-drivers"> +<h3>Linux device drivers<a class="headerlink" href="#linux-device-drivers" title="Permalink to this headline">¶</a></h3> +<ul class="simple"> +<li><a class="reference external" href="http://lwn.net/images/pdf/LDD3/ch09.pdf">Linux Device Drivers, 3rd ed., Ch. 9 - Communicating with Hardware</a></li> +<li><a class="reference external" href="http://lwn.net/images/pdf/LDD3/ch10.pdf">Linux Device Drivers, 3rd ed., Ch. 10 - Interrupt Handling</a></li> +<li><a class="reference external" href="http://tldp.org/LDP/lkmpg/2.6/html/x1256.html">Interrupt Handlers</a></li> +</ul> +</div> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is interrupts. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/interrupts/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="section" id="intro"> +<h3>0. Intro<a class="headerlink" href="#intro" title="Permalink to this headline">¶</a></h3> +<p>Using <a class="reference external" href="http://elixir.free-electrons.com/linux/latest/source">LXR</a>, find the definitions of the following symbols in the Linux kernel:</p> +<ul class="simple"> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">resource</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">request_region()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">__request_region()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">request_irq()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">request_threaded_irq()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">inb()</span></code> for the x86 architecture.</li> +</ul> +<p>Analyze the following Linux code:</p> +<ul class="simple"> +<li>Keyboard initialization function <code class="xref c c-func docutils literal"><span class="pre">i8042_setup_kbd()</span></code></li> +<li>The AT or PS/2 keyboard interrupt function <code class="xref c c-func docutils literal"><span class="pre">atkbd_interrupt()</span></code></li> +</ul> +</div> +<div class="section" id="keyboard-driver"> +<h3>Keyboard driver<a class="headerlink" href="#keyboard-driver" title="Permalink to this headline">¶</a></h3> +<p>The next exercise's objective is to create a driver that uses the +keyboard IRQ, inspect the incoming key codes and stores them in a +buffer. The buffer will be accessible from userspace via character +device driver.</p> +</div> +<div class="section" id="request-the-i-o-ports"> +<h3>1. Request the I/O ports<a class="headerlink" href="#request-the-i-o-ports" title="Permalink to this headline">¶</a></h3> +<p>To start with, we aim to allocate memory in the I/O space for hardware +devices. We will see that we cannot allocate space for the keyboard +because the designated region is already allocated. Then we will allocate +I/O space for unused ports.</p> +<p>The <em>kbd.c</em> file contains a skeleton for the keyboard driver. Browse +the source code and inspect <code class="xref c c-func docutils literal"><span class="pre">kbd_init()</span></code>. Notice that the I/O +ports we need are I8042_STATUS_REG and I8042_DATA_REG.</p> +<p>Follow the sections maked with <strong>TODO 1</strong> in the skeleton. Request the I/O +ports in <code class="xref c c-func docutils literal"><span class="pre">kbd_init()</span></code> and make sure to check for errors and to properly +clean-up in case of errors. When requesting, set the reserving caller's ID +string (<code class="docutils literal"><span class="pre">name</span></code>) with <code class="docutils literal"><span class="pre">MODULE_NAME</span></code> macro. Also, add code to release the I/O +ports in <code class="xref c c-func docutils literal"><span class="pre">kbd_exit()</span></code>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">You can review the <a class="reference internal" href="#request-access-to-i-o-ports">Request access to I/O ports</a> section before +proceeding.</p> +</div> +<p>Now build the module and copy it to the VM image:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +tools/labs $ make copy +</pre></div> +</div> +<p>Now start the VM and insert the module:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>root@qemux86:~# insmod skels/interrupts/kbd.ko +kbd: loading out-of-tree module taints kernel. +insmod: can't insert 'skels/interrupts/kbd.ko': Device or resource busy +</pre></div> +</div> +<p>Notice that you get an error when trying to request the I/O +ports. This is because we already have a driver that has requested the +I/O ports. To validate check the <code class="file docutils literal"><span class="pre">/proc/ioports</span></code> file for the +<code class="docutils literal"><span class="pre">STATUS_REG</span></code> and <code class="docutils literal"><span class="pre">DATA_REG</span></code> values:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>root@qemux86:~# cat /proc/ioports <span class="p">|</span> egrep <span class="s2">"(0060|0064)"</span> +<span class="m">0060</span>-0060 : keyboard +<span class="m">0064</span>-0064 : keyboard +</pre></div> +</div> +<p>Lets find out which driver register these ports and try to remove the +module associated with it.</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>$ find -name <span class="se">\*</span>.c <span class="p">|</span> xargs grep <span class="se">\"</span>keyboard<span class="se">\"</span> + +find -name <span class="se">\*</span>.c <span class="p">|</span> xargs grep <span class="se">\"</span>keyboard<span class="se">\"</span> <span class="p">|</span> egrep <span class="s1">'(0x60|0x64)'</span> +... +./arch/x86/kernel/setup.c:<span class="o">{</span> .name <span class="o">=</span> <span class="s2">"keyboard"</span>, .start <span class="o">=</span> 0x60, .end <span class="o">=</span> 0x60, +./arch/x86/kernel/setup.c:<span class="o">{</span> .name <span class="o">=</span> <span class="s2">"keyboard"</span>, .start <span class="o">=</span> 0x64, .end <span class="o">=</span> 0x64 +</pre></div> +</div> +<p>It looks like the I/O ports are registered by the kernel during the +boot, and we won't be able to remove the associated module. Instead, +let's trick the kernel and register ports 0x61 and 0x65.</p> +<p>Use the function <code class="xref c c-func docutils literal"><span class="pre">request_region()</span></code> (inside the <code class="xref c c-func docutils literal"><span class="pre">kbd_init()</span></code> +function) to allocate the ports and the function <code class="xref c c-func docutils literal"><span class="pre">release_region()</span></code> +(inside the <code class="xref c c-func docutils literal"><span class="pre">kbd_exit()</span></code> function) to release the allocated memory.</p> +<p>This time we can load the module and <em>/proc/ioports</em> shows that the +owner of these ports is our module:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>root@qemux86:~# insmod skels/interrupts/kbd.ko +kbd: loading out-of-tree module taints kernel. +Driver kbd loaded +root@qemux86:~# cat /proc/ioports <span class="p">|</span> grep kbd +<span class="m">0061</span>-0061 : kbd +<span class="m">0065</span>-0065 : kbd +</pre></div> +</div> +<p>Let's remove the module and check that the I/O ports are released:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>root@qemux86:~# rmmod kbd +Driver kbd unloaded +root@qemux86:~# cat /proc/ioports <span class="p">|</span> grep kbd +root@qemux86:~# +</pre></div> +</div> +</div> +<div class="section" id="interrupt-handling-routine"> +<h3>2. Interrupt handling routine<a class="headerlink" href="#interrupt-handling-routine" title="Permalink to this headline">¶</a></h3> +<p>For this task we will implement and register an interrupt handler for +the keyboard interrupt. You can review the <a class="reference internal" href="#requesting-an-interrupt">Requesting an interrupt</a> +section before proceeding.</p> +<p>Follow the sections marked with <strong>TODO 2</strong> in the skeleton.</p> +<p>First, define an empty interrupt handling routine named +<code class="xref c c-func docutils literal"><span class="pre">kbd_interrupt_handler()</span></code>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Since we already have a driver that uses this interrupt we +should report the interrupt as not handled (i.e. return +<code class="xref c c-type docutils literal"><span class="pre">IRQ_NONE</span></code>) so that the original driver still has a +chance to process it.</p> +</div> +<p>Then register the interrupt handler routine using +<code class="xref c c-type docutils literal"><span class="pre">request_irq</span></code>. The interrupt number is defined by the +<cite>I8042_KBD_IRQ</cite> macro. The interrupt handling routine must be +requested with <code class="xref c c-type docutils literal"><span class="pre">IRQF_SHARED</span></code> to share the interrupt line with +the keyboard driver (i8042).</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>For shared interrupts, <em>dev_id</em> can not be NULL . Use +<code class="docutils literal"><span class="pre">&devs[0]</span></code>, that is pointer to <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">kbd</span></code>. This +structure contains all the information needed for device +management. To see the interrupt in <em>/proc/interrupts</em>, do +not use NULL for <em>dev_name</em> . You can use the MODULE_NAME +macro.</p> +<p class="last">If the interrupt requesting fails make sure to properly +cleanup by jumping to the right label, in this case the one +the releases the I/O ports and continues with unregistering +the character device driver.</p> +</div> +<p>Compile, copy and load module in the kernel. Check that the interrupt +line has been registered by looking at <em>/proc/interrupts</em> . Determine +the IRQ number from the source code (see <cite>I8042_KBD_IRQ</cite>) and verify +that there are two drivers registered at this interrupt line (which +means that we have a shared interrupt line): the i8042 initial driver +and our driver.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">More details about the format of the <em>/proc/interrupts</em> can +be found in the <a class="reference internal" href="#interrupt-statistics">Interrupt statistics</a> section.</p> +</div> +<p>Print a message inside the routine to make sure it is called. Compile +and reload the module into the kernel. Check that the interrupt handling +routine is called when you press the keyboard on the virtual machine, +using <strong class="command">dmesg</strong>. Also note that when you use the serial port no +keyboard interrupt is generated.</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">To get access to the keyboard on the virtual machine +boot with "QEMU_DISPLAY=gtk make boot".</p> +</div> +</div> +<div class="section" id="store-ascii-keys-to-buffer"> +<h3>3. Store ASCII keys to buffer<a class="headerlink" href="#store-ascii-keys-to-buffer" title="Permalink to this headline">¶</a></h3> +<p>Next, we want to collect the keystrokes in a buffer whose content we +will then send to the user space. For this routine we will add the +following in the interrupt handling:</p> +<ul class="simple"> +<li>capture the pressed keys (only pressed, ignore released)</li> +<li>identify the ASCII characters.</li> +<li>copy the ASCII characters corresponding to the keystrokes and store +them in the buffer of the device</li> +</ul> +<p>Follow the sections marked <strong>TODO 3</strong> in the skeleton.</p> +<div class="section" id="reading-the-data-register"> +<h4>Reading the data register<a class="headerlink" href="#reading-the-data-register" title="Permalink to this headline">¶</a></h4> +<p>First, fill in the <code class="xref c c-func docutils literal"><span class="pre">i8042_read_data()</span></code> function to read the +<code class="docutils literal"><span class="pre">I8042_DATA_REG</span></code> of the keyboard controller. The function +just needs to return the value of the register. The value of the +registry is also called scancode, which is what is generated at each +keystroke.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Read the <code class="docutils literal"><span class="pre">I8042_DATA_REG</span></code> register using <code class="xref c c-func docutils literal"><span class="pre">inb()</span></code> and +store the value in the local variable <code class="xref c c-type docutils literal"><span class="pre">val</span></code>. +Revisit the <a class="reference internal" href="#accessing-i-o-ports">Accessing I/O ports</a> section.</p> +</div> +<p>Call the <code class="xref c c-func docutils literal"><span class="pre">i8042_read_data()</span></code> in the +<code class="xref c c-func docutils literal"><span class="pre">kbd_interrupt_handler()</span></code> and print the value read.</p> +<p>Print information about the keystrokes in the following format:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">pr_info</span><span class="p">(</span><span class="s">"IRQ:% d, scancode = 0x%x (%u,%c)</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> + <span class="n">irq_no</span><span class="p">,</span> <span class="n">scancode</span><span class="p">,</span> <span class="n">scancode</span><span class="p">,</span> <span class="n">scancode</span><span class="p">);</span> +</pre></div> +</div> +<p>Where scancode is the value of the read register using the +<code class="xref c c-func docutils literal"><span class="pre">i8042_read_data()</span></code> function.</p> +<p>Notice that the scancode (reading of the read register) is not an ASCII +character of the pressed key. We'll have to understand the scancode.</p> +</div> +<div class="section" id="interpreting-the-scancode"> +<h4>Interpreting the scancode<a class="headerlink" href="#interpreting-the-scancode" title="Permalink to this headline">¶</a></h4> +<p>Note that the registry value is a scancode, not the ASCII value of the +character pressed. Also note that an interrupt is sent both when the +key is pressed and when the key is released. We only need to select +the code when the key is pressed and then and decode the ASCII +character.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>To check scancode, we can use the showkey command (showkey +-s).</p> +<p>In this form, the command will display the key scancodes for +10 seconds after the last pressed key end then it will +stop. If you press and release a key you will get two +scancodes: one for the pressed key and one for the released +key. E.g:</p> +<ul class="last"> +<li><p class="first">If you press the ENTER key, you will get the 0x1c ( 0x1c ) +and 0x9c (for the released key)</p> +</li> +<li><p class="first">If you press the key a you will get the 0x1e (key pressed) +and 0x9e (for the key release)</p> +</li> +<li><p class="first">If you press b you will get 0x30 (key pressed) and 0xb0 +(for the release key)</p> +</li> +<li><p class="first">If you press the c key, you will get the 0x2e (key +pressed) 0xae and 0xae (for the released key)</p> +</li> +<li><p class="first">If you press the Shift key you will get the 0x2a (key +pressed) 0xaa and 0xaa (for the released key)</p> +</li> +<li><p class="first">If you press the Ctrl key you will get the 0x1d (key +pressed) and 0x9d (for the release key)</p> +<p>As also indicated in this <a class="reference external" href="http://www.linuxjournal.com/article/1080">article</a>, a key +release scancode is 128 (0x80) higher then a key press +scancode. This is how we can distinguish between a press +key scancode and a release scancode.</p> +<p>A scancode is translated into a keycode that matches a +key. A pressed scanned keycode and a released scancode +have the same keycode. For the keys shown above we have +the following table:</p> +<table border="1" class="docutils"> +<colgroup> +<col width="25%" /> +<col width="25%" /> +<col width="25%" /> +<col width="25%" /> +</colgroup> +<tbody valign="top"> +<tr class="row-odd"><td>Key</td> +<td>Key Press Scancode</td> +<td>Key Release Scancode</td> +<td>Keycode</td> +</tr> +<tr class="row-even"><td>ENTER</td> +<td>0x1c</td> +<td>0x9c</td> +<td>0x1c (28)</td> +</tr> +<tr class="row-odd"><td>a</td> +<td>0x1e</td> +<td>0x9e</td> +<td>0x1e (30)</td> +</tr> +<tr class="row-even"><td>b</td> +<td>0x30</td> +<td>0xb0</td> +<td>0x30 (48)</td> +</tr> +<tr class="row-odd"><td>c</td> +<td>0x2e</td> +<td>0xae</td> +<td>0x2e (46)</td> +</tr> +<tr class="row-even"><td>Shift</td> +<td>0x2a</td> +<td>0xaa</td> +<td>0x2a (42)</td> +</tr> +<tr class="row-odd"><td>Ctrl</td> +<td>0x1d</td> +<td>0x9d</td> +<td>0x1d (29)</td> +</tr> +</tbody> +</table> +<p>The press / release key is performed in the is_key_press() +function and obtaining the ASCII character of a scancode +takes place in the get_ascii() function.</p> +</li> +</ul> +</div> +<p>In the interrupt handler check the scancode to see if the key is +pressed or released then determine the corresponding ASCII +character.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">To check for press / release, use <code class="xref c c-func docutils literal"><span class="pre">is_key_press()</span></code>. +Use <code class="xref c c-func docutils literal"><span class="pre">get_ascii()</span></code> function to get the corresponding +ASCII code. Both functions expect the scancode.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>To display the received information use the following +format.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">pr_info</span><span class="p">(</span><span class="s">"IRQ %d: scancode=0x%x (%u) pressed=%d ch=%c</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> + <span class="n">irq_no</span><span class="p">,</span> <span class="n">scancode</span><span class="p">,</span> <span class="n">scancode</span><span class="p">,</span> <span class="n">pressed</span><span class="p">,</span> <span class="n">ch</span><span class="p">);</span> +</pre></div> +</div> +<p class="last">Where scancode is the value of the data register, and ch is +the value returned by the get_ascii() function.</p> +</div> +</div> +<div class="section" id="store-characters-to-the-buffer"> +<h4>Store characters to the buffer<a class="headerlink" href="#store-characters-to-the-buffer" title="Permalink to this headline">¶</a></h4> +<p>We want to collect the pressed characters (not the other keys) into +a circular buffer that can be consumed from user space.</p> +<p>Update the interrupt handler to add a pressed ASCII character to the +end of the device buffer. If the buffer is full, the character will be +discarded.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>The device buffer is the field <code class="xref c c-type docutils literal"><span class="pre">buf</span></code> in the device's +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">kbd</span></code>. To get the device data from the interrupt handler +use the following construct:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">kbd</span> <span class="o">*</span><span class="n">data</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">kbd</span> <span class="o">*</span><span class="p">)</span> <span class="n">dev_id</span><span class="p">;</span> +</pre></div> +</div> +<p class="last">The buffer's dimension is located in <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">kbd</span></code>'s field, +<code class="xref c c-type docutils literal"><span class="pre">count</span></code>. The <code class="xref c c-type docutils literal"><span class="pre">put_idx</span></code> and <code class="xref c c-type docutils literal"><span class="pre">get_idx</span></code> fields +specify the next writing and reading index. Take a look at the +<code class="xref c c-func docutils literal"><span class="pre">put_char()</span></code> function's implementation to observe how the data is +added to the circular buffer.</p> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p>Synchronize the access to the buffer and the helper +indexes with a spinlock. +Define the spinlock in the device struct <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">kbd</span></code> +and initialize it in <code class="xref c c-func docutils literal"><span class="pre">kbd_init()</span></code>.</p> +<p>Use the <code class="xref c c-func docutils literal"><span class="pre">spin_lock()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">spin_unlock()</span></code> functions +to protect the buffer in the interrupt handler.</p> +<p class="last">Revisit the <a class="reference internal" href="#locking">Locking</a> section.</p> +</div> +</div> +</div> +<div class="section" id="reading-the-buffer"> +<h3>4. Reading the buffer<a class="headerlink" href="#reading-the-buffer" title="Permalink to this headline">¶</a></h3> +<p>In order to have access to the keylogger's data, we have to send it to +the user space. We will do this using the <em>/dev/kbd</em> character device. When +reading from this device, we will get the data from the buffer in the kernel +space, where we collected the keys pressed.</p> +<p>For this step +follow the sections marked with <strong>TODO 4</strong> in the <code class="xref c c-func docutils literal"><span class="pre">kbd_read()</span></code> function.</p> +<p>Implement <code class="xref c c-func docutils literal"><span class="pre">get_char()</span></code> in a similar way to <code class="xref c c-func docutils literal"><span class="pre">put_char()</span></code>. Be careful +when implementing the circular buffer.</p> +<p>In the <code class="xref c c-func docutils literal"><span class="pre">kbd_read()</span></code> function copy the data from the buffer to the +userspace buffer.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use <code class="xref c c-func docutils literal"><span class="pre">get_char()</span></code> to read a character from the buffer +and <code class="xref c c-func docutils literal"><span class="pre">put_user()</span></code> to store it to the user buffer.</p> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p>In the read function, use <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock_irqrestore()</span></code> for locking.</p> +<p class="last">Revisit the <a class="reference internal" href="#locking">Locking</a> section.</p> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p>We cannot use <code class="xref c c-func docutils literal"><span class="pre">put_user()</span></code> or <code class="xref c c-func docutils literal"><span class="pre">copy_to_user()</span></code> +while holding the lock, as userpace access is not permitted from +atomic contexts.</p> +<p class="last">For more info, read the <span class="xref std std-ref">Access to the address space of the +process section</span> in the +previous lab.</p> +</div> +<p>For testing, you will need to create the <em>/dev/kbd</em> character device +driver using the mknod before reading from it. The device master and +minor are defined as <code class="docutils literal"><span class="pre">KBD_MAJOR</span></code> and <code class="docutils literal"><span class="pre">KBD_MINOR</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">mknod</span> <span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">kbd</span> <span class="n">c</span> <span class="mi">42</span> <span class="mi">0</span> +</pre></div> +</div> +<p>Build, copy and boot the virtual machine and load the module. Test it +using the command:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">cat</span> <span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">kbd</span> +</pre></div> +</div> +</div> +<div class="section" id="reset-the-buffer"> +<h3>5. Reset the buffer<a class="headerlink" href="#reset-the-buffer" title="Permalink to this headline">¶</a></h3> +<p>Reset the buffer if the device is written to. For this step follow the +sections marked with <strong>TODO 5</strong> in the skeleton.</p> +<p>Implement <code class="xref c c-func docutils literal"><span class="pre">reset_buffer()</span></code> and add the write operation to <em>kbd_fops</em>.</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p>In the write function Use <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock_irqrestore()</span></code> for locking when resetting the +buffer.</p> +<p class="last">Revisit the <a class="reference internal" href="#locking">Locking</a> section.</p> +</div> +<p>For testing, you will need to create the <em>/dev/kbd</em> character device +driver using the mknod before reading from it. The device master and +minor are defined as <code class="docutils literal"><span class="pre">KBD_MAJOR</span></code> and <code class="docutils literal"><span class="pre">KBD_MINOR</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">mknod</span> <span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">kbd</span> <span class="n">c</span> <span class="mi">42</span> <span class="mi">0</span> +</pre></div> +</div> +<p>Build, copy and boot the virtual machine and load the module. +Test it using the command:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">cat</span> <span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">kbd</span> +</pre></div> +</div> +<p>Press some keys, then run the command <strong class="command">echo "clear" > /dev/kbd</strong>. +Check the buffer's content again. It should be reset.</p> +</div> +</div> +<div class="section" id="extra-exercises"> +<h2>Extra Exercises<a class="headerlink" href="#extra-exercises" title="Permalink to this headline">¶</a></h2> +<div class="section" id="kfifo"> +<h3>1. kfifo<a class="headerlink" href="#kfifo" title="Permalink to this headline">¶</a></h3> +<p>Implement a keylogger using the +<a class="reference external" href="https://elixir.bootlin.com/linux/v4.15/source/include/linux/kfifo.h">kfifo API</a>.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Follow the <a class="reference external" href="https://elixir.bootlin.com/linux/v4.15/source/samples/kfifo">API call examples from the kernel code</a>. +For example, the file <a class="reference external" href="https://elixir.bootlin.com/linux/v4.15/source/samples/kfifo/bytestream-example.c">bytestream-examples.c</a>.</p> +</div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="device_drivers.html" class="btn btn-neutral float-left" title="Character device drivers" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="deferred_work.html" class="btn btn-neutral float-right" title="Deferred work" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/labs/introduction.html b/refs/pull/405/merge/labs/introduction.html new file mode 100644 index 00000000..2c3de3f5 --- /dev/null +++ b/refs/pull/405/merge/labs/introduction.html @@ -0,0 +1,917 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Introduction — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Kernel modules" href="kernel_modules.html" /> + <link rel="prev" title="Infrastructure" href="infrastructure.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Introduction</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="#keywords">Keywords</a></li> +<li class="toctree-l2"><a class="reference internal" href="#about-this-laboratory">About this laboratory</a></li> +<li class="toctree-l2"><a class="reference internal" href="#references">References</a></li> +<li class="toctree-l2"><a class="reference internal" href="#source-code-navigation">Source code navigation</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#cscope">cscope</a></li> +<li class="toctree-l3"><a class="reference internal" href="#clangd">clangd</a></li> +<li class="toctree-l3"><a class="reference internal" href="#kscope">Kscope</a></li> +<li class="toctree-l3"><a class="reference internal" href="#lxr-cross-reference">LXR Cross-Reference</a></li> +<li class="toctree-l3"><a class="reference internal" href="#sourceweb">SourceWeb</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#kernel-debugging">Kernel Debugging</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#gdb-linux">gdb (Linux)</a></li> +<li class="toctree-l3"><a class="reference internal" href="#getting-a-stack-trace">Getting a stack trace</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#documentation">Documentation</a></li> +<li class="toctree-l2"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#remarks">Remarks</a></li> +<li class="toctree-l3"><a class="reference internal" href="#booting-the-virtual-machine">Booting the virtual machine</a></li> +<li class="toctree-l3"><a class="reference internal" href="#adding-and-using-a-virtual-disk">Adding and using a virtual disk</a></li> +<li class="toctree-l3"><a class="reference internal" href="#gdb-and-qemu">GDB and QEMU</a></li> +<li class="toctree-l3"><a class="reference internal" href="#gdb-spelunking">4. GDB spelunking</a></li> +<li class="toctree-l3"><a class="reference internal" href="#cscope-spelunking">5. Cscope spelunking</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Introduction</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/labs/introduction.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="introduction"> +<h1>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>presenting the rules and objectives of the Operating Systems 2 lab</li> +<li>introducing the lab documentation</li> +<li>introducing the Linux kernel and related resources</li> +</ul> +</div> +<div class="section" id="keywords"> +<h2>Keywords<a class="headerlink" href="#keywords" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>kernel, kernel programming</li> +<li>Linux, vanilla, <a class="reference external" href="http://www.kernel.org">http://www.kernel.org</a></li> +<li>cscope, LXR</li> +<li>gdb, /proc/kcore, addr2line, dump_stack</li> +</ul> +</div> +<div class="section" id="about-this-laboratory"> +<h2>About this laboratory<a class="headerlink" href="#about-this-laboratory" title="Permalink to this headline">¶</a></h2> +<p>The Operating Systems 2 lab is a kernel programming and driver development lab. +The objectives of the laboratory are:</p> +<ul class="simple"> +<li>deepening the notions presented in the course</li> +<li>presentation of kernel programming interfaces (kernel API)</li> +<li>gaining documenting, development and debugging skills on a freestanding +environment</li> +<li>acquiring knowledge and skills for drivers development</li> +</ul> +<p>A laboratory will present a set of concepts, applications and commands +specific to a given problem. The lab will start with a presentation +(each lab will have a set of slides) (15 minutes) and the remaining +time will be allocated to the lab exercises (80 minutes).</p> +<p>For best laboratory performance, we recommend that you read the related slides. +To fully understand a laboratory, we recommend going through the lab support. For +in-depth study, use the supporting documentation.</p> +</div> +<div class="section" id="references"> +<h2>References<a class="headerlink" href="#references" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>Linux<ul> +<li><a class="reference external" href="http://www.amazon.com/Linux-Kernel-Development-Robert-Love/dp/0672329468/">Linux Kernel Development, 3rd +Edition</a></li> +<li><a class="reference external" href="http://free-electrons.com/doc/books/ldd3.pdf">Linux Device Drivers, 3rd +Edition</a></li> +<li><a class="reference external" href="http://www.amazon.com/Essential-Device-Drivers-Sreekrishnan-Venkateswaran/dp/0132396556">Essential Linux Device +Drivers</a></li> +</ul> +</li> +<li>General<ul> +<li><a class="reference external" href="http://cursuri.cs.pub.ro/cgi-bin/mailman/listinfo/pso">mailing list</a> +(<a class="reference external" href="http://blog.gmane.org/gmane.education.region.romania.operating-systems-design">searching the mailing list</a>)</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="source-code-navigation"> +<h2>Source code navigation<a class="headerlink" href="#source-code-navigation" title="Permalink to this headline">¶</a></h2> +<div class="section" id="cscope"> +<span id="cscope-intro"></span><h3>cscope<a class="headerlink" href="#cscope" title="Permalink to this headline">¶</a></h3> +<p><a class="reference external" href="http://cscope.sourceforge.net/">Cscope</a> is a tool for +efficient navigation of C sources. To use it, a cscope database must +be generated from the existing sources. In a Linux tree, the command +<strong class="command">make ARCH=x86 cscope</strong> is sufficient. Specification of the +architecture through the ARCH variable is optional but recommended; +otherwise, some architecture dependent functions will appear multiple +times in the database.</p> +<p>You can build the cscope database with the command <strong class="command">make +ARCH=x86 COMPILED_SOURCE=1 cscope</strong>. This way, the cscope database will +only contain symbols that have already been used in the compile +process before, thus resulting in better performance when searching +for symbols.</p> +<p>Cscope can also be used as stand-alone, but it is more useful when +combined with an editor. To use cscope with <strong class="command">vim</strong>, it is necessary to +install both packages and add the following lines to the file +<code class="file docutils literal"><span class="pre">.vimrc</span></code> (the machine in the lab already has the settings):</p> +<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="k">if</span> has<span class="p">(</span><span class="s2">"cscope"</span><span class="p">)</span> +<span class="c"> " Look for a 'cscope.out' file starting from the current directory,</span> +<span class="c"> " going up to the root directory.</span> + <span class="k">let</span> s:dirs <span class="p">=</span> split<span class="p">(</span>getcwd<span class="p">(),</span> <span class="s2">"/"</span><span class="p">)</span> + <span class="k">while</span> s:dirs <span class="p">!=</span> [] + <span class="k">let</span> s:<span class="nb">path</span> <span class="p">=</span> <span class="s2">"/"</span> . <span class="k">join</span><span class="p">(</span>s:dirs<span class="p">,</span> <span class="s2">"/"</span><span class="p">)</span> + <span class="k">if</span> <span class="p">(</span>filereadable<span class="p">(</span>s:<span class="nb">path</span> . <span class="s2">"/cscope.out"</span><span class="p">))</span> + execute <span class="s2">"cs add "</span> . s:<span class="nb">path</span> . <span class="s2">"/cscope.out "</span> . s:<span class="nb">path</span> . <span class="s2">" -v"</span> + <span class="k">break</span> + <span class="k">endif</span> + <span class="k">let</span> s:dirs <span class="p">=</span> s:dirs[:<span class="m">-2</span>] + <span class="k">endwhile</span> + + <span class="k">set</span> <span class="nb">csto</span><span class="p">=</span><span class="m">0</span> <span class="c">" Use cscope first, then ctags</span> + <span class="k">set</span> <span class="nb">cst</span> <span class="c">" Only search cscope</span> + <span class="k">set</span> <span class="nb">csverb</span> <span class="c">" Make cs verbose</span> + + nmap `<span class="p"><</span>C<span class="p">-</span>\<span class="p">></span>`s :<span class="k">cs</span> find s `<span class="p"><</span>C<span class="p">-</span>R<span class="p">></span>`<span class="p">=</span>expand<span class="p">(</span><span class="s2">"`<cword>`"</span><span class="p">)</span>`<span class="p"><</span>CR<span class="p">></span>``<span class="p"><</span>CR<span class="p">></span>` + nmap `<span class="p"><</span>C<span class="p">-</span>\<span class="p">></span>`<span class="k">g</span> :<span class="k">cs</span> find <span class="k">g</span> `<span class="p"><</span>C<span class="p">-</span>R<span class="p">></span>`<span class="p">=</span>expand<span class="p">(</span><span class="s2">"`<cword>`"</span><span class="p">)</span>`<span class="p"><</span>CR<span class="p">></span>``<span class="p"><</span>CR<span class="p">></span>` + nmap `<span class="p"><</span>C<span class="p">-</span>\<span class="p">></span>`<span class="k">c</span> :<span class="k">cs</span> find <span class="k">c</span> `<span class="p"><</span>C<span class="p">-</span>R<span class="p">></span>`<span class="p">=</span>expand<span class="p">(</span><span class="s2">"`<cword>`"</span><span class="p">)</span>`<span class="p"><</span>CR<span class="p">></span>``<span class="p"><</span>CR<span class="p">></span>` + nmap `<span class="p"><</span>C<span class="p">-</span>\<span class="p">></span>`<span class="k">t</span> :<span class="k">cs</span> find <span class="k">t</span> `<span class="p"><</span>C<span class="p">-</span>R<span class="p">></span>`<span class="p">=</span>expand<span class="p">(</span><span class="s2">"`<cword>`"</span><span class="p">)</span>`<span class="p"><</span>CR<span class="p">></span>``<span class="p"><</span>CR<span class="p">></span>` + nmap `<span class="p"><</span>C<span class="p">-</span>\<span class="p">></span>`<span class="k">e</span> :<span class="k">cs</span> find <span class="k">e</span> `<span class="p"><</span>C<span class="p">-</span>R<span class="p">></span>`<span class="p">=</span>expand<span class="p">(</span><span class="s2">"`<cword>`"</span><span class="p">)</span>`<span class="p"><</span>CR<span class="p">></span>``<span class="p"><</span>CR<span class="p">></span>` + nmap `<span class="p"><</span>C<span class="p">-</span>\<span class="p">></span>`<span class="k">f</span> :<span class="k">cs</span> find <span class="k">f</span> `<span class="p"><</span>C<span class="p">-</span>R<span class="p">></span>`<span class="p">=</span>expand<span class="p">(</span><span class="s2">"`<cfile>`"</span><span class="p">)</span>`<span class="p"><</span>CR<span class="p">></span>``<span class="p"><</span>CR<span class="p">></span>` + nmap `<span class="p"><</span>C<span class="p">-</span>\<span class="p">></span>`<span class="k">i</span> :<span class="k">cs</span> find <span class="k">i</span> ^`<span class="p"><</span>C<span class="p">-</span>R<span class="p">></span>`<span class="p">=</span>expand<span class="p">(</span><span class="s2">"`<cfile>`"</span><span class="p">)</span>`<span class="p"><</span>CR<span class="p">></span>`$`<span class="p"><</span>CR<span class="p">></span>` + nmap `<span class="p"><</span>C<span class="p">-</span>\<span class="p">></span>`<span class="k">d</span> :<span class="k">cs</span> find <span class="k">d</span> `<span class="p"><</span>C<span class="p">-</span>R<span class="p">></span>`<span class="p">=</span>expand<span class="p">(</span><span class="s2">"`<cword>`"</span><span class="p">)</span>`<span class="p"><</span>CR<span class="p">></span>``<span class="p"><</span>CR<span class="p">></span>` + nmap <span class="p"><</span>F6<span class="p">></span> :cnext <span class="p"><</span>CR<span class="p">></span> + nmap <span class="p"><</span>F5<span class="p">></span> :cprev <span class="p"><</span>CR<span class="p">></span> + +<span class="c"> " Open a quickfix window for the following queries.</span> + <span class="k">set</span> <span class="nb">cscopequickfix</span><span class="p">=</span>s<span class="p">-,</span><span class="k">c</span><span class="p">-,</span><span class="k">d</span><span class="p">-,</span><span class="k">i</span><span class="p">-,</span><span class="k">t</span><span class="p">-,</span><span class="k">e</span><span class="p">-,</span><span class="k">g</span><span class="p">-</span> +<span class="k">endif</span> +</pre></div> +</div> +<p>The script searches for a file called <code class="file docutils literal"><span class="pre">cscope.out</span></code> in the current directory, or +in parent directories. If <strong class="command">vim</strong> finds this file, you can use the shortcut <code class="code docutils literal"><span class="pre">Ctrl</span> <span class="pre">+]</span></code> +or <code class="code docutils literal"><span class="pre">Ctrl+\</span> <span class="pre">g</span></code> (the combination control-\ followed by g) to jump directly to +the definition of the word under the cursor (function, variable, structure, etc.). +Similarly, you can use <code class="code docutils literal"><span class="pre">Ctrl+\</span> <span class="pre">s</span></code> to go where the word under the cursor is used.</p> +<p>You can take a cscope-enabled <code class="file docutils literal"><span class="pre">.vimrc</span></code> file (also contains other goodies) from +<a class="reference external" href="https://github.com/ddvlad/cfg/blob/master/_vimrc">https://github.com/ddvlad/cfg/blob/master/_vimrc</a>. +The following guidelines are based on this file, but also show basic <strong class="command">vim</strong> commands +that have the same effect.</p> +<p>If there are more than one results (usually there are) you can move between them +using <code class="code docutils literal"><span class="pre">F6</span></code> and <code class="code docutils literal"><span class="pre">F5</span></code> (<code class="code docutils literal"><span class="pre">:ccnext</span></code> and <code class="code docutils literal"><span class="pre">:cprev</span></code>). +You can also open a new panel showing the results using <code class="code docutils literal"><span class="pre">:copen</span></code>. To close +the panel, use the <code class="code docutils literal"><span class="pre">:cclose</span></code> command.</p> +<p>To return to the previous location, use <code class="code docutils literal"><span class="pre">Ctrl+o</span></code> (o, not zero). +The command can be used multiple times and works even if cscope changed the +file you are currently editing.</p> +<p>To go to a symbol definition directly when <strong class="command">vim</strong> starts, use <code class="code docutils literal"><span class="pre">vim</span> <span class="pre">-t</span> <span class="pre"><symbol_name></span></code> +(for example <code class="code docutils literal"><span class="pre">vim</span> <span class="pre">-t</span> <span class="pre">task_struct</span></code>). Otherwise, if you started <strong class="command">vim</strong> and want +to search for a symbol by name, use <code class="code docutils literal"><span class="pre">cs</span> <span class="pre">find</span> <span class="pre">g</span> <span class="pre"><symbol_name></span></code> (for example +<code class="code docutils literal"><span class="pre">cs</span> <span class="pre">find</span> <span class="pre">g</span> <span class="pre">task_struct</span></code>).</p> +<p>If you found more than one results and opened a panel showing all the matches +(using <code class="code docutils literal"><span class="pre">:copen</span></code>) and you want to find a symbol of type structure, +it is recommended to search in the results panel (using <code class="code docutils literal"><span class="pre">/</span></code> -- slash) +the character <code class="code docutils literal"><span class="pre">{</span></code> (opening brace).</p> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>You can get a summary of all the <strong class="command">cscope</strong> commands using <strong class="command">:cs help</strong>.</p> +<p class="last">For more info, use the <strong class="command">vim</strong> built-in help command: <strong class="command">:h cscope</strong> or <strong class="command">:h copen</strong>.</p> +</div> +<p>If you use <strong class="command">emacs</strong>, install the <code class="code docutils literal"><span class="pre">xcscope-el</span></code> package and +add the following lines in <code class="file docutils literal"><span class="pre">~/.emacs</span></code>.</p> +<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="p">(</span>require ‘xcscope<span class="p">)</span> +<span class="p">(</span><span class="k">cscope</span><span class="p">-</span>setup<span class="p">)</span> +</pre></div> +</div> +<p>These commands will activate cscope for the C and C++ modes automatically. +<code class="code docutils literal"><span class="pre">C-s</span> <span class="pre">s</span></code> is the key bindings prefix and <code class="code docutils literal"><span class="pre">C-s</span> <span class="pre">s</span> <span class="pre">s</span></code> is used to +search for a symbol (if you call it when the cursor is over a word, +it will use that). For more details, check <cite>https://github.com/dkogan/xcscope.el</cite></p> +</div> +<div class="section" id="clangd"> +<h3>clangd<a class="headerlink" href="#clangd" title="Permalink to this headline">¶</a></h3> +<p><a class="reference external" href="https://clangd.llvm.org/">Clangd</a> is a language server that provides tools +for navigating C and C++ code. +<a class="reference external" href="https://microsoft.github.io/language-server-protocol/">Language Server Protocol</a> +facilitates features like go-to-definition, find-references, hover, completion, etc., +using semantic whole project analysis.</p> +<p>Clangd requires a compilation database to understand the kernel source code. +It can be generated with:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>make defconfig +make +scripts/clang-tools/gen_compile_commands.py +</pre></div> +</div> +<p>LSP clients:</p> +<ul class="simple"> +<li>Vim/Neovim (<a class="reference external" href="https://github.com/neoclide/coc.nvim">coc.nvim</a>, <a class="reference external" href="https://github.com/neovim/nvim-lspconfig">nvim-lsp</a>, <a class="reference external" href="https://github.com/natebosch/vim-lsc">vim-lsc</a>, <a class="reference external" href="https://github.com/prabirshrestha/vim-lsp">vim-lsp</a>)</li> +<li>Emacs (<a class="reference external" href="https://github.com/emacs-lsp/lsp-mode">lsp-mode</a>)</li> +<li>VSCode (<a class="reference external" href="https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd">clangd extension</a>)</li> +</ul> +</div> +<div class="section" id="kscope"> +<h3>Kscope<a class="headerlink" href="#kscope" title="Permalink to this headline">¶</a></h3> +<p>For a simpler interface, <a class="reference external" href="http://sourceforge.net/projects/kscope/">Kscope</a> +is a cscope frontend which uses QT. It is lightweight, very fast and very +easy to use. It allows searching using regular expressions, call graphs, etc. +Kscope is no longer mantained.</p> +<p>There is also a <a class="reference external" href="https///opendesktop.org/content/show.php/Kscope4?content=156987">port</a> +of version 1.6 for Qt4 and KDE 4 which keeps the integration of the text +editor Kate and is easier to use than the last version on SourceForge.</p> +</div> +<div class="section" id="lxr-cross-reference"> +<h3>LXR Cross-Reference<a class="headerlink" href="#lxr-cross-reference" title="Permalink to this headline">¶</a></h3> +<p>LXR (LXR Cross-Reference) is a tool that allows indexing and +referencing the symbols in the source code of a program using +a web interface. The web interface shows links to +locations in files where a symbol is defined or used. Development website +for LXR is <a class="reference external" href="http://sourceforge.net/projects/lxr">http://sourceforge.net/projects/lxr</a>. Similar tools +are <a class="reference external" href="http://oracle.github.io/opengrok/">OpenGrok</a> and +<a class="reference external" href="http://en.wikipedia.org/wiki/Gonzui">Gonzui</a>.</p> +<p>Although LXR was originally intended for the Linux kernel sources, it is +also used in the sources of <a class="reference external" href="http://lxr.mozilla.org/">Mozilla</a>, +<a class="reference external" href="http://apache.wirebrain.de/lxr/">Apache HTTP Server</a> and +<a class="reference external" href="http://lxr.linux.no/freebsd/source">FreeBSD</a>.</p> +<p>There are a number of sites that use LXR for cross-referencing the +the sources of the Linux kernel, the main site being <a class="reference external" href="http://lxr.linux.no/linux/">the original site of +development</a> which does not work anymore. You can +use <a class="reference external" href="https://elixir.bootlin.com/">https://elixir.bootlin.com/</a>.</p> +<p>LXR allows searching for an identifier (symbol), after a free text +or after a file name. The main feature and, at the same +time, the main advantage provided is the ease of finding the declaration +of any global identifier. This way, it facilitates quick access to function +declarations, variables, macro definitions and the code can be easily +navigated. Also, the fact that it can detect what code areas are affected +when a variable or function is changed is a real advantage in the development +and debugging phase.</p> +</div> +<div class="section" id="sourceweb"> +<h3>SourceWeb<a class="headerlink" href="#sourceweb" title="Permalink to this headline">¶</a></h3> +<p><a class="reference external" href="http://rprichard.github.io/sourceweb/">SourceWeb</a> is a source code indexer +for C and C++. It uses the +<a class="reference external" href="http://clang.llvm.org/docs/IntroductionToTheClangAST.html">framework</a> +provided by the Clang compiler to index the code.</p> +<p>The main difference between cscope and SourceWeb is the fact that SourceWeb +is, in a way, a compiler pass. SourceWeb doesn't index all the code, but +only the code that was efectively compiled by the compiler. This way, some +problems are eliminated, such as ambiguities about which variant of a function +defined in multiple places is used. This also means that the indexing takes +more time, because the compiled files must pass one more time through +the indexer to generate the references.</p> +<p>Usage example:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>make oldconfig +sw-btrace make -j4 +sw-btrace-to-compile-db +sw-clang-indexer --index-project +sourceweb index +</pre></div> +</div> +<p><code class="file docutils literal"><span class="pre">sw-btrace</span></code> is a script that adds the <code class="file docutils literal"><span class="pre">libsw-btrace.so</span></code> +library to <code class="code docutils literal"><span class="pre">LD_PRELOAD</span></code>. This way, the library is loaded by +every process started by <code class="code docutils literal"><span class="pre">make</span></code> (basically, the compiler), +registers the commands used to start the processes and generates +a filed called <code class="file docutils literal"><span class="pre">btrace.log</span></code>. This file is then used by +<code class="code docutils literal"><span class="pre">sw-btrace-to-compile-db</span></code> which converts it to a format defined +by clang: <a class="reference external" href="http://clang.llvm.org/docs/JSONCompilationDatabase.html">JSON Compilation Database</a>. +This JSON Compilation Database resulted from the above steps is then +used by the indexer, which makes one more pass through the compiled +source files and generates the index used by the GUI.</p> +<p>Word of advice: don't index the sources you are working with, but use +a copy, because SourceWeb doesn't have, at this moment, the capability +to regenerate the index for a single file and you will have to regenerate +the complete index.</p> +</div> +</div> +<div class="section" id="kernel-debugging"> +<h2>Kernel Debugging<a class="headerlink" href="#kernel-debugging" title="Permalink to this headline">¶</a></h2> +<p>Debugging a kernel is a much more difficult process than the debugging +of a program, because there is no support from the operating system. +This is why this process is usually done using two computers, connected +on serial interfaces.</p> +<div class="section" id="gdb-linux"> +<span id="gdb-intro"></span><h3>gdb (Linux)<a class="headerlink" href="#gdb-linux" title="Permalink to this headline">¶</a></h3> +<p>A simpler debug method on Linux, but with many disadvantages, +is local debugging, using <a class="reference external" href="http://www.gnu.org/software/gdb/">gdb</a>, +the uncompressed kernel image (<code class="file docutils literal"><span class="pre">vmlinux</span></code>) and <code class="file docutils literal"><span class="pre">/proc/kcore</span></code> +(the real-time kernel image). This method is usually used to inspect +the kernel and detect certain inconsistencies while it runs. The +method is useful especially if the kernel was compiled using the +<code class="code docutils literal"><span class="pre">-g</span></code> option, which keeps debug information. Some well-known +debug techniques can't be used by this method, such as breakpoints +of data modification.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>Because <code class="file docutils literal"><span class="pre">/proc</span></code> is a virtual filesystem, <code class="file docutils literal"><span class="pre">/proc/kcore</span></code> +does not physically exist on the disk. It is generated on-the-fly +by the kernel when a program tries to access <code class="file docutils literal"><span class="pre">proc/kcore</span></code>.</p> +<p>It is used for debugging purposes.</p> +<p>From <strong class="command">man proc</strong>, we have:</p> +<div class="last highlight-none"><div class="highlight"><pre><span></span>/proc/kcore +This file represents the physical memory of the system and is stored in the ELF core file format. With this pseudo-file, and +an unstripped kernel (/usr/src/linux/vmlinux) binary, GDB can be used to examine the current state of any kernel data struc‐ +tures. +</pre></div> +</div> +</div> +<p>The uncompressed kernel image offers information about the data structures +and symbols it contains.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>student@eg106$ <span class="nb">cd</span> ~/src/linux +student@eg106$ file vmlinux +vmlinux: ELF <span class="m">32</span>-bit LSB executable, Intel <span class="m">80386</span>, ... +student@eg106$ nm vmlinux <span class="p">|</span> grep sys_call_table +c02e535c R sys_call_table +student@eg106$ cat System.map <span class="p">|</span> grep sys_call_table +c02e535c R sys_call_table +</pre></div> +</div> +<p>The <strong class="command">nm</strong> utility is used to show the symbols in an object or +executable file. In our case, <code class="file docutils literal"><span class="pre">vmlinux</span></code> is an ELF file. Alternately, +we can use the file <code class="file docutils literal"><span class="pre">System.map</span></code> to view information about the +symbols in kernel.</p> +<p>Then we use <strong class="command">gdb</strong> to inspect the symbols using the uncompressed +kernel image. A simple <strong class="command">gdb</strong> session is the following:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>student@eg106$ <span class="nb">cd</span> ~/src/linux +stduent@eg106$ gdb --quiet vmlinux +Using host libthread_db library <span class="s2">"/lib/tls/libthread_db.so.1"</span>. +<span class="o">(</span>gdb<span class="o">)</span> x/x 0xc02e535c +0xc02e535c <span class="sb">`</span><sys_call_table><span class="sb">`</span>: 0xc011bc58 +<span class="o">(</span>gdb<span class="o">)</span> x/16 0xc02e535c +0xc02e535c <span class="sb">`</span><sys_call_table><span class="sb">`</span>: 0xc011bc58 0xc011482a 0xc01013d3 0xc014363d +0xc02e536c <span class="sb">`</span><sys_call_table+16><span class="sb">`</span>: 0xc014369f 0xc0142d4e 0xc0142de5 0xc011548b +0xc02e537c <span class="sb">`</span><sys_call_table+32><span class="sb">`</span>: 0xc0142d7d 0xc01507a1 0xc015042c 0xc0101431 +0xc02e538c <span class="sb">`</span><sys_call_table+48><span class="sb">`</span>: 0xc014249e 0xc0115c6c 0xc014fee7 0xc0142725 +<span class="o">(</span>gdb<span class="o">)</span> x/x sys_call_table +0xc011bc58 <span class="sb">`</span><sys_restart_syscall><span class="sb">`</span>: 0xffe000ba +<span class="o">(</span>gdb<span class="o">)</span> x/x <span class="p">&</span>sys_call_table +0xc02e535c <span class="sb">`</span><sys_call_table><span class="sb">`</span>: 0xc011bc58 +<span class="o">(</span>gdb<span class="o">)</span> x/16 <span class="p">&</span>sys_call_table +0xc02e535c <span class="sb">`</span><sys_call_table><span class="sb">`</span>: 0xc011bc58 0xc011482a 0xc01013d3 0xc014363d +0xc02e536c <span class="sb">`</span><sys_call_table+16><span class="sb">`</span>: 0xc014369f 0xc0142d4e 0xc0142de5 0xc011548b +0xc02e537c <span class="sb">`</span><sys_call_table+32><span class="sb">`</span>: 0xc0142d7d 0xc01507a1 0xc015042c 0xc0101431 +0xc02e538c <span class="sb">`</span><sys_call_table+48><span class="sb">`</span>: 0xc014249e 0xc0115c6c 0xc014fee7 0xc0142725 +<span class="o">(</span>gdb<span class="o">)</span> x/x sys_fork +0xc01013d3 <span class="sb">`</span><sys_fork><span class="sb">`</span>: 0x3824548b +<span class="o">(</span>gdb<span class="o">)</span> disass sys_fork +Dump of assembler code <span class="k">for</span> <span class="k">function</span> sys_fork: +0xc01013d3 <span class="sb">`</span><sys_fork+0><span class="sb">`</span>: mov 0x38<span class="o">(</span>%esp<span class="o">)</span>,%edx +0xc01013d7 <span class="sb">`</span><sys_fork+4><span class="sb">`</span>: mov <span class="nv">$0</span>x11,%eax +0xc01013dc <span class="sb">`</span><sys_fork+9><span class="sb">`</span>: push <span class="nv">$0</span>x0 +0xc01013de <span class="sb">`</span><sys_fork+11><span class="sb">`</span>: push <span class="nv">$0</span>x0 +0xc01013e0 <span class="sb">`</span><sys_fork+13><span class="sb">`</span>: push <span class="nv">$0</span>x0 +0xc01013e2 <span class="sb">`</span><sys_fork+15><span class="sb">`</span>: lea 0x10<span class="o">(</span>%esp<span class="o">)</span>,%ecx +0xc01013e6 <span class="sb">`</span><sys_fork+19><span class="sb">`</span>: call 0xc0111aab <span class="sb">`</span><do_fork><span class="sb">`</span> +0xc01013eb <span class="sb">`</span><sys_fork+24><span class="sb">`</span>: add <span class="nv">$0</span>xc,%esp +0xc01013ee <span class="sb">`</span><sys_fork+27><span class="sb">`</span>: ret +End of assembler dump. +</pre></div> +</div> +<p>It can be noticed that the uncompressed kernel image was used as an argument +for <strong class="command">gdb</strong>. The image can be found in the root of the kernel sources +after compilation.</p> +<p>A few commands used for debugging using <strong class="command">gdb</strong> are:</p> +<ul class="simple"> +<li><strong class="command">x</strong> (examine) - Used to show the contents of the memory area +whose address is specified as an argument to the command (this address +can be the value of a physical address, a symbol or the address of a +symbol). It can take as arguments (preceded by <code class="code docutils literal"><span class="pre">/</span></code>): the format +to display the data in (<code class="code docutils literal"><span class="pre">x</span></code> for hexadecimal, <code class="code docutils literal"><span class="pre">d</span></code> for +decimal, etc.), how many memory units to display and the size of a +memory unit.</li> +<li><strong class="command">disassemble</strong> - Used to disassemble a function.</li> +<li><strong class="command">p</strong> (print) - Used to evaluate and show the value of an +expression. The format to show the data in can be specified as +an argument (<code class="code docutils literal"><span class="pre">/x</span></code> for hexadecimal, <code class="code docutils literal"><span class="pre">/d</span></code> for decimal, etc.).</li> +</ul> +<p>The analysis of the kernel image is a method of static analysis. If we +want to perform dynamic analysis (analyzing how the kernel runs, not +only its static image) we can use <code class="file docutils literal"><span class="pre">/proc/kcore</span></code>; this is a dynamic +image (in memory) of the kernel.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>student@eg106$ gdb ~/src/linux/vmlinux /proc/kcore +Core was generated by `root=/dev/hda3 ro'. +#0 0x00000000 in ?? () +(gdb) p sys_call_table +$1 = -1072579496 +(gdb) p /x sys_call_table +$2 = 0xc011bc58 +(gdb) p /x &sys_call_table +$3 = 0xc02e535c +(gdb) x/16 &sys_call_table +0xc02e535c `<sys_call_table>`: 0xc011bc58 0xc011482a 0xc01013d3 0xc014363d +0xc02e536c `<sys_call_table+16>`: 0xc014369f 0xc0142d4e 0xc0142de5 0xc011548b +0xc02e537c `<sys_call_table+32>`: 0xc0142d7d 0xc01507a1 0xc015042c 0xc0101431 +0xc02e538c `<sys_call_table+48>`: 0xc014249e 0xc0115c6c 0xc014fee7 0xc0142725 +</pre></div> +</div> +<p>Using the dynamic image of the kernel is useful for detecting <a class="reference external" href="http://en.wikipedia.org/wiki/Rootkit">rootkits</a>.</p> +<ul class="simple"> +<li><a class="reference external" href="http://linuxdriver.co.il/ldd3/linuxdrive3-CHP-4-SECT-6.html">Linux Device Drivers 3rd Edition - Debuggers and Related Tools</a></li> +<li><a class="reference external" href="http://www.securityfocus.com/infocus/1811">Detecting Rootkits and Kernel-level Compromises in Linux</a></li> +<li><a class="reference external" href="http://user-mode-linux.sf.net/">User-Mode Linux</a></li> +</ul> +</div> +<div class="section" id="getting-a-stack-trace"> +<h3>Getting a stack trace<a class="headerlink" href="#getting-a-stack-trace" title="Permalink to this headline">¶</a></h3> +<p>Sometimes, you will want information about the trace the execution +reaches a certain point. You can determine this information using +<strong class="command">cscope</strong> or LXR, but some function are called from many +execution paths, which makes this method difficult.</p> +<p>In these situations, it is useful to get a stack trace, which can be +simply done using the function <code class="code docutils literal"><span class="pre">dump_stack()</span></code>.</p> +</div> +</div> +<div class="section" id="documentation"> +<h2>Documentation<a class="headerlink" href="#documentation" title="Permalink to this headline">¶</a></h2> +<p>Kernel development is a difficult process, compared to user space +programming. The API is different and the complexity of the subsystems +in kernel requires additional preparation. The associated documentation +is heterogeneous, sometimes requiring the inspection of multiple sources +to have a more complete understanding of a certain aspect.</p> +<p>The main advantages of the Linux kernel are the access to sources and +the open development system. Because of this, the Internet offers a +larger number of documentation for the kernel.</p> +<p>A few links related to the Linux kernel are shown bellow:</p> +<ul class="simple"> +<li><a class="reference external" href="http://kernelnewbies.org">KernelNewbies</a></li> +<li><a class="reference external" href="http://kernelnewbies.org/KernelHacking">KernelNewbies - Kernel Hacking</a></li> +<li><a class="reference external" href="http://www.tldp.org/HOWTO/KernelAnalysis-HOWTO.html">Kernel Analysis - HOWTO</a></li> +<li><a class="reference external" href="http://web.archive.org/web/20090228191439/http://www.linuxhq.com/lkprogram.html">Linux Kernel Programming</a></li> +<li><a class="reference external" href="http://en.wikibooks.org/wiki/Linux_kernel">Linux kernel - Wikibooks</a></li> +</ul> +<p>The links are not comprehensive. Using <a class="reference external" href="http://www.google.com">The Internet</a> and +<a class="reference external" href="http://lxr.free-electrons.com/">kernel source code</a> is essential.</p> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="section" id="remarks"> +<h3>Remarks<a class="headerlink" href="#remarks" title="Permalink to this headline">¶</a></h3> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<ul class="last simple"> +<li>Usually, the steps used to develop a kernel module are the +following:<ul> +<li>editing the module source code (on the physical machine);</li> +<li>module compilation (on the physical machine);</li> +<li>generation of the minimal image for the virtual machine; +this image contains the kernel, your module, busybox and +eventually test programs;</li> +<li>starting the virtual machine using QEMU;</li> +<li>running the tests in the virtual machine.</li> +</ul> +</li> +<li>When using cscope, use <code class="file docutils literal"><span class="pre">~/src/linux</span></code>. +If there is no <code class="file docutils literal"><span class="pre">cscope.out</span></code> file, you can generate it using +the command <strong class="command">make ARCH=x86 cscope</strong>.</li> +<li>You can find more details about the virtual machine at +<a class="reference internal" href="../info/vm.html#vm-link"><span class="std std-ref">Recommended Setup</span></a>.</li> +</ul> +</div> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p class="last">Before solving an exercice, <strong>carefully</strong> read all its bullets.</p> +</div> +</div> +<div class="section" id="booting-the-virtual-machine"> +<h3>Booting the virtual machine<a class="headerlink" href="#booting-the-virtual-machine" title="Permalink to this headline">¶</a></h3> +<p>A summary of the virtual machine infrastructure:</p> +<ul class="simple"> +<li><code class="file docutils literal"><span class="pre">~/src/linux</span></code> - Linux kernel sources, needed to +compile modules. The directory contains the file <code class="file docutils literal"><span class="pre">cscope.out</span></code>, +used for navigation in the source tree.</li> +<li><code class="file docutils literal"><span class="pre">~/src/linux/tools/labs/qemu</span></code>- scripts and auxiliary +files used to generate and run the QEMU VM.</li> +</ul> +<p>To start the VM, run <strong class="command">make boot</strong> in the directory <code class="file docutils literal"><span class="pre">~/src/linux/tools/labs</span></code>:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>student@eg106:~$ <span class="nb">cd</span> ~/src/linux/tools/labs +student@eg106:~/src/linux/tools/labs$ make boot +</pre></div> +</div> +<p>By default, you will not get a prompt or any graphical interface, but you can connect to +a console exposed by the virtual machine using <strong class="command">minicom</strong> or <strong class="command">screen</strong>.</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>student@eg106:~/src/linux/tools/labs$ minicom -D serial.pts + +<press enter> + +qemux86 login: +Poky <span class="o">(</span>Yocto Project Reference Distro<span class="o">)</span> <span class="m">2</span>.3 qemux86 /dev/hvc0 +</pre></div> +</div> +<p>Alternatively, you can start the virtual machine with graphical interface support, using +the <strong class="command">QEMU_DISPLAY=gtk make boot</strong>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">To access the virtual machine, at the login prompt, enter the +username <code class="code docutils literal"><span class="pre">root</span></code>; there is no need to enter a password. +The virtual machine will start with the permissions of the +root account.</p> +</div> +</div> +<div class="section" id="adding-and-using-a-virtual-disk"> +<h3>Adding and using a virtual disk<a class="headerlink" href="#adding-and-using-a-virtual-disk" title="Permalink to this headline">¶</a></h3> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">If you don't have the file <code class="file docutils literal"><span class="pre">mydisk.img</span></code>, you can download +it from the address <a class="reference external" href="http://elf.cs.pub.ro/so2/res/laboratoare/mydisk.img">http://elf.cs.pub.ro/so2/res/laboratoare/mydisk.img</a>. +The file must be placed in <code class="file docutils literal"><span class="pre">tools/labs</span></code>.</p> +</div> +<p>In the <code class="file docutils literal"><span class="pre">~/src/linux/tools/labs</span></code> directory, you have a new virtual +machine disk, in the file <code class="file docutils literal"><span class="pre">mydisk.img</span></code>. We want to add the disk +to the virtual machine and use it within the virtual machine.</p> +<p>Edit <code class="file docutils literal"><span class="pre">qemu/Makefile</span></code> and add <code class="code docutils literal"><span class="pre">-drive</span> <span class="pre">file=mydisk.img,if=virtio,format=raw</span></code> +to the <code class="code docutils literal"><span class="pre">QEMU_OPTS</span></code> variable.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">There are already two disks added to qemu (disk1.img and disk2.img). You will need +to add the new one after them. In this case, the new disk can be accessed as +<code class="file docutils literal"><span class="pre">/dev/vdd</span></code> (vda is the root partition, vdb is disk1 and vdc is disk2).</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">You do not need to manually create the entry for the new disk in <code class="file docutils literal"><span class="pre">/dev</span></code> +because the virtual machine uses <strong class="command">devtmpfs</strong>.</p> +</div> +<p>Run <code class="code docutils literal"><span class="pre">make</span></code> in <code class="file docutils literal"><span class="pre">tools/labs</span></code> to boot the virtual machine. +Create <code class="file docutils literal"><span class="pre">/test</span></code> directory and try to mount the new disk:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>mkdir /test +mount /dev/vdd /test +</pre></div> +</div> +<p>The reason why we can not mount the virtual disk is because we do not have support in the +kernel for the filesystem with which the <code class="file docutils literal"><span class="pre">mydisk.img</span></code> is formatted. You will need +to identify the filesystem for <code class="file docutils literal"><span class="pre">mydisk.img</span></code> and compile kernel support for that filesystem.</p> +<p>Close the virtual machine (close the QEMU window, you do not need to use another command). +Use the <strong class="command">file</strong> command on the physical machine to find out with which filesystem +the <code class="file docutils literal"><span class="pre">mydisk.img</span></code> file is formatted. You will identify the <strong class="command">btrfs</strong> file system.</p> +<p>You will need to enable <strong class="command">btrfs</strong> support in the kernel and recompile the kernel image.</p> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>If you receive an error while executing the <strong class="command">make menuconfig</strong> +command, you probably do not have the <strong class="command">libncurses5-dev</strong> +package installed. Install it using the command:</p> +<div class="last highlight-none"><div class="highlight"><pre><span></span>sudo apt-get install libncurses5-dev +</pre></div> +</div> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>Enter the <code class="file docutils literal"><span class="pre">~/src/linux/</span></code> subdirectory. Run <strong class="command">make menuconfig</strong> +and go to the <em>File systems</em> section. Enable <em>Btrfs filesystem support</em>. +You will need to use the builtin option (not the module), i.e. <strong class="command"><*></strong> must appear +next to the option (<strong>not</strong> <strong class="command"><M></strong>).</p> +<p>Save the configuration you have made. Use the default configuration file (<code class="file docutils literal"><span class="pre">config</span></code>).</p> +<p>In the kernel source subdirectory (<code class="file docutils literal"><span class="pre">~/src/linux/</span></code>) recompile using the command:</p> +<div class="highlight-none"><div class="highlight"><pre><span></span>make +</pre></div> +</div> +<p>To wait less, you can use the <strong class="command">-j</strong> option run multiple jobs in parallel. +Generally, it is recommended to use <strong class="command">number of CPUs+1</strong>:</p> +<div class="last highlight-none"><div class="highlight"><pre><span></span>make -j5 +</pre></div> +</div> +</div> +<p>After the kernel recompilation finishes, <strong>restart</strong> the QEMU virtual machine: +that is, launch the <strong class="command">make</strong> command in the subdirectory. You +do not need to copy anything, because the <code class="file docutils literal"><span class="pre">bzImage</span></code> file is a symlink to the kernel +image you just recompiled.</p> +<p>Inside the QEMU virtual machine, repeat the <strong class="command">mkdir</strong> and <strong class="command">mount</strong> operations. +With support for the <strong class="command">btrfs</strong> filesystem, now <strong class="command">mount</strong> will finish successfully.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>When doing your homework, there is no need to recompile the kernel +because you will only use kernel modules. However, it is important +to be familiar with configuring and recompiling a kernel.</p> +<p class="last">If you still plan to recompile the kernel, make a backup of the bzImage +file (follow the link in ~/src/linux for the full path). This will allow +you to return to the initial setup in order to have an environment +identical to the one used by vmchecker.</p> +</div> +</div> +<div class="section" id="gdb-and-qemu"> +<h3>GDB and QEMU<a class="headerlink" href="#gdb-and-qemu" title="Permalink to this headline">¶</a></h3> +<p>We can investigate and troubleshoot the QEMU virtual machine in real time.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>You can also use the <strong class="command">GDB Dashboard</strong> plugin for a user-friendly interface. +<strong class="command">gdb</strong> must be compiled with Python support.</p> +<p>In order to install it, you can just run:</p> +<div class="last highlight-none"><div class="highlight"><pre><span></span>wget -P ~ git.io/.gdbinit +</pre></div> +</div> +</div> +<p>To do this, we start the QEMU virtual machine first. Then, we can connect +with <strong class="command">gdb</strong> to <strong>a running QEMU virtual machine</strong> using the command</p> +<div class="highlight-none"><div class="highlight"><pre><span></span>make gdb +</pre></div> +</div> +<p>We used the QEMU command with the <strong class="command">-s</strong> parameter, which means +listening to port <code class="code docutils literal"><span class="pre">1234</span></code> from <strong class="command">gdb</strong>. We can do debugging +using a <strong>remote target</strong> for <strong class="command">gdb</strong>. The existing <code class="file docutils literal"><span class="pre">Makefile</span></code> +takes care of the details.</p> +<p>When you attach a debugger to a process, the process is suspended. +You can add breakpoints and inspect the current status of the process.</p> +<p>Attach to the QEMU virtual machine (using the <strong class="command">make gdb</strong> command) +and place a breakpoint in the <code class="code docutils literal"><span class="pre">sys_access</span></code> function using the +following command in the <strong class="command">gdb</strong> console:</p> +<div class="highlight-none"><div class="highlight"><pre><span></span>break sys_access +</pre></div> +</div> +<p>At this time, the virtual machine is suspended. To continue executing it (up to the possible call +of the <code class="code docutils literal"><span class="pre">sys_access</span></code> function), use the command:</p> +<div class="highlight-none"><div class="highlight"><pre><span></span>continue +</pre></div> +</div> +<p>in the <strong class="command">gdb</strong> console.</p> +<p>At this time, the virtual machine is active and has a usable console. +To make a <code class="code docutils literal"><span class="pre">sys_access</span></code> call, issue a <strong class="command">ls</strong> command. +Note that the virtual machine was again suspended by <strong class="command">gdb</strong> +and the corresponding <code class="code docutils literal"><span class="pre">sys_access</span></code> callback message appeared within the <strong class="command">gdb</strong> console.</p> +<p>Trace code execution using <strong class="command">step</strong> instruction, <strong class="command">continue</strong> or <strong class="command">next</strong> +instruction. You probably do not understand everything that happens, so use commands +such as <strong class="command">list</strong> and <strong class="command">backtrace</strong> to trace the execution.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">At the <strong class="command">gdb</strong> prompt, you can press <strong class="command">Enter</strong> +(without anything else) to rerun the last command.</p> +</div> +</div> +<div class="section" id="gdb-spelunking"> +<h3>4. GDB spelunking<a class="headerlink" href="#gdb-spelunking" title="Permalink to this headline">¶</a></h3> +<p>Use <strong class="command">gdb</strong> to display the source code of the function that creates kernel threads +(<code class="code docutils literal"><span class="pre">kernel_thread</span></code>).</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>You can use GDB for static kernel analysis using, in the kernel source directory, +a command such as:</p> +<div class="highlight-none"><div class="highlight"><pre><span></span>gdb vmlinux +</pre></div> +</div> +<p class="last">Go over the <a class="reference external" href="#gdb-linux">gdb (Linux)</a> section of the lab.</p> +</div> +<p>Use <strong class="command">gdb</strong> to find the address of the <code class="code docutils literal"><span class="pre">jiffies</span></code> variable in memory and its contents. +The <code class="code docutils literal"><span class="pre">jiffies</span></code> variable holds the number of ticks (clock beats) since the system started.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>To track the value of the jiffies variable, use dynamic analysis in <strong class="command">gdb</strong> +by running the command:</p> +<div class="highlight-none"><div class="highlight"><pre><span></span>make gdb +</pre></div> +</div> +<p>as in the previous exercise.</p> +<p class="last">Go over the <a class="reference external" href="#gdb-linux">gdb (Linux)</a> section of the lab.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>The <code class="code docutils literal"><span class="pre">jiffies</span></code> is a 64-bit variable. +You can see that its address is the same as the <code class="code docutils literal"><span class="pre">jiffies_64</span></code> variable.</p> +<p>To explore the contents of a 64-bit variable, use in the <strong class="command">gdb</strong> console the command:</p> +<div class="highlight-none"><div class="highlight"><pre><span></span>x/gx & jiffies +</pre></div> +</div> +<p>If you wanted to display the contents of the 32-bit variable, +you would use in the <strong class="command">gdb</strong> console the command:</p> +<div class="last highlight-none"><div class="highlight"><pre><span></span>x/wx & jiffies +</pre></div> +</div> +</div> +</div> +<div class="section" id="cscope-spelunking"> +<h3>5. Cscope spelunking<a class="headerlink" href="#cscope-spelunking" title="Permalink to this headline">¶</a></h3> +<p>Use LXR or cscope in the <code class="file docutils literal"><span class="pre">~/src/linux/</span></code> directory to discover +the location of certain structures or functions.</p> +<p>Cscope index files are already generated. Use <strong class="command">vim</strong> and other related commands +to scroll through the source code. For example, use the command:</p> +<div class="highlight-none"><div class="highlight"><pre><span></span>vim +</pre></div> +</div> +<p>for opening the <strong class="command">vim</strong> editor. Afterwards, inside the editor, use commands such as:</p> +<p><strong class="command">:cs find g task_struct</strong>.</p> +<p>Find the file in which the following data types are defined:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code></li> +<li><code class="docutils literal"><span class="pre">struct</span> <span class="pre">semaphore</span></code></li> +<li><code class="docutils literal"><span class="pre">struct</span> <span class="pre">list_head</span></code></li> +<li><code class="docutils literal"><span class="pre">spinlock_t</span></code></li> +<li><code class="docutils literal"><span class="pre">struct</span> <span class="pre">file_system_type</span></code></li> +</ul> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>For a certain structure, only its name needs to be searched.</p> +<p class="last">For instance, in the case of <strong class="command">struct task_struct</strong>, +search for the <strong class="command">task_struct</strong> string.</p> +</div> +<p>Usually, you will get more matches. To locate the one you are interested in, do the following:</p> +<ol class="arabic simple"> +<li>List all matches by using, in <strong class="command">vim</strong>, <strong class="command">:copen</strong> command.</li> +<li>Look for the right match (where the structure is defined) by looking for an open character +(<strong class="command">{</strong>), a single character on the structure definition line. To search for the open +braid you use in <strong class="command">vim</strong> the construction <strong class="command">/{</strong>.</li> +<li>On the respective line, press <strong class="command">Enter</strong> to get into the source code where the variable +is defined.</li> +<li>Close the secondary window using the command: <strong class="command">:cclose</strong> command.</li> +</ol> +<p>Find the file in which the following global kernel variables are declared:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">sys_call_table</span></code></li> +<li><code class="docutils literal"><span class="pre">file_systems</span></code></li> +<li><code class="docutils literal"><span class="pre">current</span></code></li> +<li><code class="docutils literal"><span class="pre">chrdevs</span></code></li> +</ul> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>To do this, use a <strong class="command">vim</strong> command with the syntax:</p> +<p><strong class="command">:cs f g <symbol></strong></p> +<p class="last">where <strong class="command"><symbol></strong> is the name of the symbol being searched.</p> +</div> +<p>Find the file in which the following functions are declared:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">copy_from_user</span></code></li> +<li><code class="docutils literal"><span class="pre">vmalloc</span></code></li> +<li><code class="docutils literal"><span class="pre">schedule_timeout</span></code></li> +<li><code class="docutils literal"><span class="pre">add_timer</span></code></li> +</ul> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>To do this, use a <strong class="command">vim</strong> command with the syntax:</p> +<p><strong class="command">:cs f g <symbol></strong></p> +<p class="last">where <strong class="command"><symbol></strong> is the name of the symbol being searched.</p> +</div> +<p>Scroll through the following sequence of structures:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code></li> +<li><code class="docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code></li> +<li><code class="docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code></li> +<li><code class="docutils literal"><span class="pre">struct</span> <span class="pre">vm_operations_struct</span></code></li> +</ul> +<p>That is, you access a structure and then you find fields with the data type of the +next structure, access the respective fields and so on. +Note in which files these structures are defined; this will be useful to the following labs.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>In order to search for a symbol in <strong class="command">vim</strong> (with <strong class="command">cscope</strong> support) +when the cursor is placed on it, use the <strong class="command">Ctrl+]</strong> keyboard shortcut.</p> +<p>To return to the previous match (the one before search/jump), use the +<strong class="command">Ctrl+o</strong> keyboard shortcut.</p> +<p class="last">To move forward with the search (to return to matches before <strong class="command">Ctrl+o</strong>), +use the <strong class="command">Ctrl+i</strong> keyboard shortcut.</p> +</div> +<p>Following the above instructions, find and go through the function call sequence:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">bio_alloc</span></code></li> +<li><code class="docutils literal"><span class="pre">bio_alloc_bioset</span></code></li> +<li><code class="docutils literal"><span class="pre">bvec_alloc</span></code></li> +<li><code class="docutils literal"><span class="pre">kmem_cache_alloc</span></code></li> +<li><code class="docutils literal"><span class="pre">slab_alloc</span></code></li> +</ul> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Read <a class="reference external" href="#cscope">cscope</a> or <a class="reference external" href="#lxr-cross-reference">LXR Cross-Reference</a> sections of the lab.</p> +</div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="infrastructure.html" class="btn btn-neutral float-left" title="Infrastructure" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="kernel_modules.html" class="btn btn-neutral float-right" title="Kernel modules" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/labs/kernel_api.html b/refs/pull/405/merge/labs/kernel_api.html new file mode 100644 index 00000000..f14577df --- /dev/null +++ b/refs/pull/405/merge/labs/kernel_api.html @@ -0,0 +1,1093 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Kernel API — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Character device drivers" href="device_drivers.html" /> + <link rel="prev" title="Kernel modules" href="kernel_modules.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Kernel API</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="#overview">Overview</a></li> +<li class="toctree-l2"><a class="reference internal" href="#accessing-memory">Accessing memory</a></li> +<li class="toctree-l2"><a class="reference internal" href="#contexts-of-execution">Contexts of execution</a></li> +<li class="toctree-l2"><a class="reference internal" href="#locking">Locking</a></li> +<li class="toctree-l2"><a class="reference internal" href="#preemptivity">Preemptivity</a></li> +<li class="toctree-l2"><a class="reference internal" href="#linux-kernel-api">Linux Kernel API</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#convention-indicating-errors">Convention indicating errors</a></li> +<li class="toctree-l3"><a class="reference internal" href="#strings-of-characters">Strings of characters</a></li> +<li class="toctree-l3"><a class="reference internal" href="#printk">printk</a></li> +<li class="toctree-l3"><a class="reference internal" href="#memory-allocation">Memory allocation</a></li> +<li class="toctree-l3"><a class="reference internal" href="#lists">lists</a></li> +<li class="toctree-l3"><a class="reference internal" href="#spinlock">Spinlock</a></li> +<li class="toctree-l3"><a class="reference internal" href="#mutex">mutex</a></li> +<li class="toctree-l3"><a class="reference internal" href="#atomic-variables-1">Atomic variables</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#use-of-atomic-variables">Use of atomic variables</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#atomic-bitwise-operations">Atomic bitwise operations</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#intro">0. Intro</a></li> +<li class="toctree-l3"><a class="reference internal" href="#memory-allocation-in-linux-kernel">1. Memory allocation in Linux kernel</a></li> +<li class="toctree-l3"><a class="reference internal" href="#sleeping-in-atomic-context">2. Sleeping in atomic context</a></li> +<li class="toctree-l3"><a class="reference internal" href="#working-with-kernel-memory">3. Working with kernel memory</a></li> +<li class="toctree-l3"><a class="reference internal" href="#working-with-kernel-lists">4. Working with kernel lists</a></li> +<li class="toctree-l3"><a class="reference internal" href="#working-with-kernel-lists-for-process-handling">5. Working with kernel lists for process handling</a></li> +<li class="toctree-l3"><a class="reference internal" href="#synchronizing-list-work">6. Synchronizing list work</a></li> +<li class="toctree-l3"><a class="reference internal" href="#test-module-calling-in-our-list-module">7. Test module calling in our list module</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Kernel API</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/labs/kernel_api.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="kernel-api"> +<h1>Kernel API<a class="headerlink" href="#kernel-api" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<blockquote> +<div><ul class="simple"> +<li>Familiarize yourself with the basic Linux kernel API</li> +<li>Description of memory allocation mechanisms</li> +<li>Description of locking mechanisms</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="overview"> +<h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline">¶</a></h2> +<p>Inside the current lab we present a set of concepts and basic functions required +for starting Linux kernel programming. It is important to note that kernel +programming differs greatly from user space programming. The kernel is a +stand-alone entity that can not use libraries in user-space (not even libc). +As a result, the usual user-space functions (printf, malloc, free, open, read, +write, memcpy, strcpy, etc.) can no longer be used. In conclusion, kernel +programming is based on a totally new and independent API that is unrelated to +the user-space API, whether we refer to POSIX or ANSI C (standard C language +library functions).</p> +</div> +<div class="section" id="accessing-memory"> +<h2>Accessing memory<a class="headerlink" href="#accessing-memory" title="Permalink to this headline">¶</a></h2> +<p>An important difference in kernel programming is how to access and allocate +memory. Due to the fact that kernel programming is very close to the physical +machine, there are important rules for memory management. First, it works with +several types of memory:</p> +<blockquote> +<div><ul class="simple"> +<li>Physical memory</li> +<li>Virtual memory from the kernel address space</li> +<li>Virtual memory from a process's address space</li> +<li>Resident memory - we know for sure that the accessed pages are present in +physical memory</li> +</ul> +</div></blockquote> +<p>Virtual memory in a process's address space can not be considered resident due +to the virtual memory mechanisms implemented by the operating system: pages may +be swapped or simply may not be present in physical memory as a result of the +demand paging mechanism. The memory in the kernel address space can be resident +or not. Both the data and code segments of a module and the kernel stack of a +process are resident. Dynamic memory may or may not be resident, depending on +how it is allocated.</p> +<p>When working with resident memory, things are simple: memory can be accessed at +any time. But if working with non-resident memory, then it can only be accessed +from certain contexts. Non-resident memory can only be accessed from the +process context. Accessing non-resident memory from the context of an +interrupt has unpredictable results and, therefore, when the operating +system detects such access, it will take drastic measures: blocking or +resetting the system to prevent serious corruption.</p> +<p>The virtual memory of a process can not be accessed directly from the kernel. +In general, it is totally discouraged to access the address space of a process, +but there are situations where a device driver needs to do it. The typical case +is where the device driver needs to access a buffer from the user-space. In +this case, the device driver must use special features and not directly access +the buffer. This is necessary to prevent access to invalid memory areas.</p> +<p>Another difference from the user-space scheduling, relative to memory, is due to +the stack, a stack whose size is fixed and limited. A stack of 4K is used in +Linux, and a stack of 12K is used in Windows. For this reason, the +allocation of large structures on stack or the use of recursive calls should +be avoided.</p> +</div> +<div class="section" id="contexts-of-execution"> +<h2>Contexts of execution<a class="headerlink" href="#contexts-of-execution" title="Permalink to this headline">¶</a></h2> +<p>In relation to kernel execution, we distinguish two contexts: process context +and interrupt context. We are in the process context when we run code as a +result of a system call or when we run in the context of a kernel thread. When +we run in a routine to handle an interrupt or a deferrable action, we run in +an interrupt context.</p> +<p>Some of the kernel API calls can block the current process. Common examples are +using a semaphore or waiting for a condition. In this case, the process is +put into the <code class="docutils literal"><span class="pre">WAITING</span></code> state and another process is running. An interesting +situation occurs when a function that can lead to the current process to be +suspended, is called from an interrupt context. In this case, there is no +current process, and therefore the results are unpredictable. Whenever the +operating system detects this condition will generate an error condition that +will cause the operating system to shut down.</p> +</div> +<div class="section" id="locking"> +<h2>Locking<a class="headerlink" href="#locking" title="Permalink to this headline">¶</a></h2> +<p>One of the most important features of kernel programming is parallelism. Linux +supports SMP systems with multiple processors and kernel preemptivity. This +makes kernel programming more difficult because access to global variables must +be synchronized with either spinlock primitives or blocking primitives. Although +it is recommended to use blocking primitives, they can not be used in an +interrupt context, so the only locking solution in the context of an interrupt +is spinlocks.</p> +<p>Spinlocks are used in order to achieve mutual exclusion. When it can not get +access to the critical region, it does not suspend the current process, but it +uses the busy-waiting mechanism (waiting in a <code class="xref c c-func docutils literal"><span class="pre">while()</span></code> loop for the lock +to be released). +The code that runs in the critical region protected by a spinlock is not allowed +to suspend the current process (it must adhere to the execution conditions in +the interrupt context). Moreover, the CPU will not be released except for +the case of an interrupt. Due to the mechanism used, it is important that a +spinlock is being held as little time as possible.</p> +</div> +<div class="section" id="preemptivity"> +<h2>Preemptivity<a class="headerlink" href="#preemptivity" title="Permalink to this headline">¶</a></h2> +<p>Linux uses preemptive kernels. The notion of preemptive multitasking should not +be confused with the notion of a preemptive kernel. The notion of preemptive +multitasking refers to the fact that the operating system forcefully interrupts +a process running in user space when its quantum (time slice) expires, in order +to run another process. +A kernel is preemptive if a process running in kernel mode (as a result of a +system call) can be interrupted so that another process is being run.</p> +<p>Because of preemptivity, when we share resources between two portions of code +that can run from different process contexts, we need to protect ourselves with +synchronization primitives, even in the case of a single processor.</p> +</div> +<div class="section" id="linux-kernel-api"> +<h2>Linux Kernel API<a class="headerlink" href="#linux-kernel-api" title="Permalink to this headline">¶</a></h2> +<div class="section" id="convention-indicating-errors"> +<h3>Convention indicating errors<a class="headerlink" href="#convention-indicating-errors" title="Permalink to this headline">¶</a></h3> +<p>For Linux kernel programming, the convention used for calling functions to +indicate success is the same as in UNIX programming: 0 for success, or a value +other than 0 for failure. +For failures, negative values are returned as shown in the example below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="p">(</span><span class="n">alloc_memory</span><span class="p">()</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">return</span> <span class="o">-</span><span class="n">ENOMEM</span><span class="p">;</span> + +<span class="k">if</span> <span class="p">(</span><span class="n">user_parameter_valid</span><span class="p">()</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EINVAL</span><span class="p">;</span> +</pre></div> +</div> +<p>The exhaustive list of errors and a summary explanation can be found in +<code class="file docutils literal"><span class="pre">include/uapi/asm-generic/errno-base.h</span></code> and in +<code class="file docutils literal"><span class="pre">include/uapi/asm-generic/ernno.h</span></code>.</p> +</div> +<div class="section" id="strings-of-characters"> +<h3>Strings of characters<a class="headerlink" href="#strings-of-characters" title="Permalink to this headline">¶</a></h3> +<p>In Linux, the kernel programmer is provided with the usual routine functions: +<code class="xref c c-func docutils literal"><span class="pre">strcpy()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strncpy()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strlcpy()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strcat()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">strncat()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strlcat()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strcmp()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strncmp()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">strnicmp()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strchr()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strnchr()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strrchr()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">strstr()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strlen()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">memset()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">memmove()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">memcmp()</span></code>, etc. These functions are declared in the +<code class="file docutils literal"><span class="pre">include/linux/string.h</span></code> header and are implemented in the kernel in the +<code class="file docutils literal"><span class="pre">lib/string.c</span></code> file.</p> +</div> +<div class="section" id="printk"> +<h3>printk<a class="headerlink" href="#printk" title="Permalink to this headline">¶</a></h3> +<p>The printf equivalent in the kernel is printk, defined in +<code class="file docutils literal"><span class="pre">include/linux/printk.h</span></code>. The <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code> syntax is very similar +to <code class="xref c c-func docutils literal"><span class="pre">printf()</span></code>. The first +parameter of <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code> decides the log category in which the current log +falls into:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define KERN_EMERG "<0>" </span><span class="cm">/* system is unusable */</span><span class="cp"></span> +<span class="cp">#define KERN_ALERT "<1>" </span><span class="cm">/* action must be taken immediately */</span><span class="cp"></span> +<span class="cp">#define KERN_CRIT "<2>" </span><span class="cm">/* critical conditions */</span><span class="cp"></span> +<span class="cp">#define KERN_ERR "<3>" </span><span class="cm">/* error conditions */</span><span class="cp"></span> +<span class="cp">#define KERN_WARNING "<4>" </span><span class="cm">/* warning conditions */</span><span class="cp"></span> +<span class="cp">#define KERN_NOTICE "<5>" </span><span class="cm">/* normal but significant condition */</span><span class="cp"></span> +<span class="cp">#define KERN_INFO "<6>" </span><span class="cm">/* informational */</span><span class="cp"></span> +<span class="cp">#define KERN_DEBUG "<7>" </span><span class="cm">/* debug-level messages */</span><span class="cp"></span> +</pre></div> +</div> +<p>Thus, a warning message in the kernel would be sent with:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">printk</span><span class="p">(</span><span class="n">KERN_WARNING</span> <span class="s">"my_module input string %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">buff</span><span class="p">);</span> +</pre></div> +</div> +<p>If the logging level is missing from the <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code> call, logging is done +with the default level at the time of the call. One thing to keep in mind is +that messages sent with <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code> are only visible on the console if and +only if their level exceeds the default level set on the console.</p> +<p>To reduce the size of lines when using <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code>, it is recommended to +use the following help functions instead of directly using the <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code> +call:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">pr_emerg</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span> <span class="p">...);</span> <span class="cm">/* similar to printk(KERN_EMERG pr_fmt(fmt), ...); */</span> +<span class="n">pr_alert</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span> <span class="p">...);</span> <span class="cm">/* similar to printk(KERN_ALERT pr_fmt(fmt), ...); */</span> +<span class="n">pr_crit</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span> <span class="p">...);</span> <span class="cm">/* similar to printk(KERN_CRIT pr_fmt(fmt), ...); */</span> +<span class="n">pr_err</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span> <span class="p">...);</span> <span class="cm">/* similar to printk(KERN_ERR pr_fmt(fmt), ...); */</span> +<span class="n">pr_warn</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span> <span class="p">...);</span> <span class="cm">/* similar to printk(KERN_WARNING pr_fmt(fmt), ...); */</span> +<span class="n">pr_notice</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span> <span class="p">...);</span> <span class="cm">/* similar to printk(KERN_NOTICE pr_fmt(fmt), ...); */</span> +<span class="n">pr_info</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span> <span class="p">...);</span> <span class="cm">/* similar to printk(KERN_INFO pr_fmt(fmt), ...); */</span> +<span class="n">pr_debug</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span> <span class="p">...);</span> <span class="cm">/* similar to printk(KERN_DEBUG pr_fmt(fmt), ...); */</span> +</pre></div> +</div> +<p>A special case is <code class="xref c c-func docutils literal"><span class="pre">pr_debug()</span></code> that calls the <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code> function +only when the <code class="xref c c-macro docutils literal"><span class="pre">DEBUG</span></code> macro is defined or if dynamic debugging is used.</p> +</div> +<div class="section" id="memory-allocation"> +<h3>Memory allocation<a class="headerlink" href="#memory-allocation" title="Permalink to this headline">¶</a></h3> +<p>In Linux only resident memory can be allocated, using <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> call. +A typical <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> call is presented below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/slab.h></span><span class="cp"></span> + +<span class="n">string</span> <span class="o">=</span> <span class="n">kmalloc</span> <span class="p">(</span><span class="n">string_len</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">string</span><span class="p">)</span> <span class="p">{</span> + <span class="c1">//report error: -ENOMEM;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>As you can see, the first parameter indicates the size in bytes of the allocated +area. The function returns a pointer to a memory area that can be directly used +in the kernel, or <code class="xref c c-macro docutils literal"><span class="pre">NULL</span></code> if memory could not be allocated. The second +parameter specifies how allocation should be done and the most commonly used +values for this are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-data docutils literal"><span class="pre">GFP_KERNEL</span></code> - using this value may cause the current process to +be suspended. Thus, it can not be used in the interrupt context.</li> +<li><code class="xref c c-data docutils literal"><span class="pre">GFP_ATOMIC</span></code> - using this value it ensures that the +<code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> function does not suspend the current process. It can be +used anytime.</li> +</ul> +</div></blockquote> +<p>The counterpart to the <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> function is <code class="xref c c-func docutils literal"><span class="pre">kfree()</span></code>, a function +that receives as argument an area allocated by <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code>. This function +does not suspend the current process and can therefore be called from any +context.</p> +</div> +<div class="section" id="lists"> +<h3>lists<a class="headerlink" href="#lists" title="Permalink to this headline">¶</a></h3> +<p>Because linked lists are often used, the Linux kernel API provides a unified +way of defining and using lists. This involves using a +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">list_head</span></code> element in the structure we want to consider as a +list node. The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">list_head</span></code> is defined in +<code class="file docutils literal"><span class="pre">include/linux/list.h</span></code> along with all the other functions that manipulate +the lists. The following code shows the definition of +the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">list_head</span></code> and the use of an element of this type in another +well-known structure in the Linux kernel:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">list_head</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="o">*</span><span class="n">next</span><span class="p">,</span> <span class="o">*</span><span class="n">prev</span><span class="p">;</span> +<span class="p">};</span> + +<span class="k">struct</span> <span class="n">task_struct</span> <span class="p">{</span> + <span class="p">...</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="n">children</span><span class="p">;</span> + <span class="p">...</span> +<span class="p">};</span> +</pre></div> +</div> +<p>The usual routines for working with lists are the following:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-macro docutils literal"><span class="pre">LIST_HEAD(name)</span></code> is used to declare the sentinel of a list</li> +<li><code class="xref c c-func docutils literal"><span class="pre">INIT_LIST_HEAD(struct</span> <span class="pre">list_head</span> <span class="pre">*list)()</span></code> is used to initialize the +sentinel of a list when dynamic allocation is made, by setting the value of +the <code class="xref c c-data docutils literal"><span class="pre">next</span></code> and <code class="xref c c-data docutils literal"><span class="pre">prev</span></code> to list fields.</li> +<li><code class="xref c c-func docutils literal"><span class="pre">list_add(struct</span> <span class="pre">list_head</span> <span class="pre">*new,</span> <span class="pre">struct</span> <span class="pre">list_head</span> <span class="pre">*head)()</span></code> adds the +<code class="xref c c-data docutils literal"><span class="pre">new</span></code> element after the <code class="xref c c-data docutils literal"><span class="pre">head</span></code> element.</li> +<li><code class="xref c c-func docutils literal"><span class="pre">list_del(struct</span> <span class="pre">list_head</span> <span class="pre">*entry)()</span></code> deletes the item at the +<code class="xref c c-data docutils literal"><span class="pre">entry</span></code> address of the list it belongs to.</li> +<li><code class="xref c c-macro docutils literal"><span class="pre">list_entry(ptr,</span> <span class="pre">type,</span> <span class="pre">member)</span></code> returns the structure with the +type <code class="xref c c-type docutils literal"><span class="pre">type</span></code> that contains the element <code class="xref c c-data docutils literal"><span class="pre">ptr</span></code> from the list, +having the name <code class="xref c c-member docutils literal"><span class="pre">member</span></code> within the structure.</li> +<li><code class="xref c c-macro docutils literal"><span class="pre">list_for_each(pos,</span> <span class="pre">head)</span></code> iterates over a list using +<code class="xref c c-data docutils literal"><span class="pre">pos</span></code> as a cursor.</li> +<li><code class="xref c c-macro docutils literal"><span class="pre">list_for_each_safe(pos,</span> <span class="pre">n,</span> <span class="pre">head)</span></code> iterates over a list using +<code class="xref c c-data docutils literal"><span class="pre">pos</span></code> as a cursor and <code class="xref c c-data docutils literal"><span class="pre">n</span></code> as a temporary cursor. +This macro is used to delete an item from the list.</li> +</ul> +</div></blockquote> +<p>The following code shows how to use these routines:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/slab.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/list.h></span><span class="cp"></span> + +<span class="k">struct</span> <span class="n">pid_list</span> <span class="p">{</span> + <span class="kt">pid_t</span> <span class="n">pid</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="n">list</span><span class="p">;</span> +<span class="p">};</span> + +<span class="n">LIST_HEAD</span><span class="p">(</span><span class="n">my_list</span><span class="p">);</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">add_pid</span><span class="p">(</span><span class="kt">pid_t</span> <span class="n">pid</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">pid_list</span> <span class="o">*</span><span class="n">ple</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="k">sizeof</span> <span class="o">*</span><span class="n">ple</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">ple</span><span class="p">)</span> + <span class="k">return</span> <span class="o">-</span><span class="n">ENOMEM</span><span class="p">;</span> + + <span class="n">ple</span><span class="o">-></span><span class="n">pid</span> <span class="o">=</span> <span class="n">pid</span><span class="p">;</span> + <span class="n">list_add</span><span class="p">(</span><span class="o">&</span><span class="n">ple</span><span class="o">-></span><span class="n">list</span><span class="p">,</span> <span class="o">&</span><span class="n">my_list</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">del_pid</span><span class="p">(</span><span class="kt">pid_t</span> <span class="n">pid</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="o">*</span><span class="n">i</span><span class="p">,</span> <span class="o">*</span><span class="n">tmp</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">pid_list</span> <span class="o">*</span><span class="n">ple</span><span class="p">;</span> + + <span class="n">list_for_each_safe</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">tmp</span><span class="p">,</span> <span class="o">&</span><span class="n">my_list</span><span class="p">)</span> <span class="p">{</span> + <span class="n">ple</span> <span class="o">=</span> <span class="n">list_entry</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="k">struct</span> <span class="n">pid_list</span><span class="p">,</span> <span class="n">list</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">ple</span><span class="o">-></span><span class="n">pid</span> <span class="o">==</span> <span class="n">pid</span><span class="p">)</span> <span class="p">{</span> + <span class="n">list_del</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> + <span class="n">kfree</span><span class="p">(</span><span class="n">ple</span><span class="p">);</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> + <span class="p">}</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="o">-</span><span class="n">EINVAL</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">destroy_list</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="o">*</span><span class="n">i</span><span class="p">,</span> <span class="o">*</span><span class="n">n</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">pid_list</span> <span class="o">*</span><span class="n">ple</span><span class="p">;</span> + + <span class="n">list_for_each_safe</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="o">&</span><span class="n">my_list</span><span class="p">)</span> <span class="p">{</span> + <span class="n">ple</span> <span class="o">=</span> <span class="n">list_entry</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="k">struct</span> <span class="n">pid_list</span><span class="p">,</span> <span class="n">list</span><span class="p">);</span> + <span class="n">list_del</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> + <span class="n">kfree</span><span class="p">(</span><span class="n">ple</span><span class="p">);</span> + <span class="p">}</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The evolution of the list can be seen in the following figure:</p> +<a class="reference internal image-reference" href="../_images/list_evolution.png"><img alt="../_images/list_evolution.png" src="../_images/list_evolution.png" style="width: 85%;" /></a> +<p>You see the stack type behavior introduced by the <code class="xref c c-macro docutils literal"><span class="pre">list_add</span></code> macro, +and the use of a sentinel.</p> +<p>From the above example, it can be noticed that the way to define and use a list +(double-linked) is generic and, at the same time, it does not introduce an +additional overhead. The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">list_head</span></code> is used to maintain the +links between the list elements. It can be noticed that iterating over the list +is also done with this structure, and that retrieving a list element can be done +using <code class="xref c c-macro docutils literal"><span class="pre">list_entry</span></code>. This idea of implementing and using a list is not +new, as it has already been described in The Art of Computer Programming by +Donald Knuth in the 1980s.</p> +<p>Several kernel list functions and macro definitions are presented and explained +in the <code class="file docutils literal"><span class="pre">include/linux/list.h</span></code> header.</p> +</div> +<div class="section" id="spinlock"> +<h3>Spinlock<a class="headerlink" href="#spinlock" title="Permalink to this headline">¶</a></h3> +<p><code class="xref c c-type docutils literal"><span class="pre">spinlock_t</span></code> (defined in <code class="file docutils literal"><span class="pre">linux/spinlock.h</span></code>) is the basic type +that implements the spinlock concept in Linux. It describes a spinlock, and the +operations associated with a spinlock are <code class="xref c c-func docutils literal"><span class="pre">spin_lock_init()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">spin_lock()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">spin_unlock()</span></code>. An example of use is given below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/spinlock.h></span><span class="cp"></span> + +<span class="n">DEFINE_SPINLOCK</span><span class="p">(</span><span class="n">lock1</span><span class="p">);</span> +<span class="n">spinlock_t</span> <span class="n">lock2</span><span class="p">;</span> + +<span class="n">spin_lock_init</span><span class="p">(</span><span class="o">&</span><span class="n">lock2</span><span class="p">);</span> + +<span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock1</span><span class="p">);</span> +<span class="cm">/* critical region */</span> +<span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock1</span><span class="p">);</span> + +<span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock2</span><span class="p">);</span> +<span class="cm">/* critical region */</span> +<span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock2</span><span class="p">);</span> +</pre></div> +</div> +<p>In Linux, you can use reader-writer spinlocks, useful for readers-writers +problems. +These types of locks are identified by <code class="xref c c-type docutils literal"><span class="pre">rwlock_t</span></code>, and the functions +that can work on a reader-writer spinlock are +<code class="xref c c-func docutils literal"><span class="pre">rwlock_init()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">read_lock()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">write_lock()</span></code>. +An example of use:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/spinlock.h></span><span class="cp"></span> + +<span class="n">DEFINE_RWLOCK</span><span class="p">(</span><span class="n">lock</span><span class="p">);</span> + +<span class="k">struct</span> <span class="n">pid_list</span> <span class="p">{</span> + <span class="kt">pid_t</span> <span class="n">pid</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="n">list</span><span class="p">;</span> +<span class="p">};</span> + +<span class="kt">int</span> <span class="nf">have_pid</span><span class="p">(</span><span class="k">struct</span> <span class="n">list_head</span> <span class="o">*</span><span class="n">lh</span><span class="p">,</span> <span class="kt">int</span> <span class="n">pid</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="o">*</span><span class="n">i</span><span class="p">;</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">elem</span><span class="p">;</span> + + <span class="n">read_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> + <span class="n">list_for_each</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lh</span><span class="p">)</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">pid_list</span> <span class="o">*</span><span class="n">pl</span> <span class="o">=</span> <span class="n">list_entry</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="k">struct</span> <span class="n">pid_list</span><span class="p">,</span> <span class="n">list</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">pl</span><span class="o">-></span><span class="n">pid</span> <span class="o">==</span> <span class="n">pid</span><span class="p">)</span> <span class="p">{</span> + <span class="n">read_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> + <span class="k">return</span> <span class="mi">1</span><span class="p">;</span> + <span class="p">}</span> + <span class="p">}</span> + <span class="n">read_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">void</span> <span class="nf">add_pid</span><span class="p">(</span><span class="k">struct</span> <span class="n">list_head</span> <span class="o">*</span><span class="n">lh</span><span class="p">,</span> <span class="k">struct</span> <span class="n">pid_list</span> <span class="o">*</span><span class="n">pl</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">write_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> + <span class="n">list_add</span><span class="p">(</span><span class="o">&</span><span class="n">pl</span><span class="o">-></span><span class="n">list</span><span class="p">,</span> <span class="n">lh</span><span class="p">);</span> + <span class="n">write_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="mutex"> +<h3>mutex<a class="headerlink" href="#mutex" title="Permalink to this headline">¶</a></h3> +<p>A mutex is a variable of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mutex</span></code> type (defined in +<code class="file docutils literal"><span class="pre">linux/mutex.h</span></code>). +Functions and macros for working with mutexes are listed below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/mutex.h></span><span class="cp"></span> + +<span class="cm">/* functions for mutex initialization */</span> +<span class="kt">void</span> <span class="nf">mutex_init</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">mutex</span><span class="p">);</span> +<span class="n">DEFINE_MUTEX</span><span class="p">(</span><span class="n">name</span><span class="p">);</span> + +<span class="cm">/* functions for mutex acquire */</span> +<span class="kt">void</span> <span class="nf">mutex_lock</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">mutex</span><span class="p">);</span> + +<span class="cm">/* functions for mutex release */</span> +<span class="kt">void</span> <span class="nf">mutex_unlock</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">mutex</span><span class="p">);</span> +</pre></div> +</div> +<p>Operations are similar to classic mutex operations in user-space or spinlock +operations: the mutex is acquired before entering the critical region and it is +released after exiting the critical region. Unlike spinlocks, these operations +can only be used in process context.</p> +</div> +<div class="section" id="atomic-variables-1"> +<span id="atomic-variables"></span><h3>Atomic variables<a class="headerlink" href="#atomic-variables-1" title="Permalink to this headline">¶</a></h3> +<p>Often, you only need to synchronize access to a simple variable, such as a +counter. For this, an <code class="xref c c-type docutils literal"><span class="pre">atomic_t</span></code> type can be used (defined in +<code class="file docutils literal"><span class="pre">include/linux/atomic.h</span></code>), that holds an integer value. Below are some +operations that can be performed on an <code class="xref c c-type docutils literal"><span class="pre">atomic_t</span></code> variable.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><asm/atomic.h></span><span class="cp"></span> + +<span class="kt">void</span> <span class="nf">atomic_set</span><span class="p">(</span><span class="n">atomic_t</span> <span class="o">*</span><span class="n">v</span><span class="p">,</span> <span class="kt">int</span> <span class="n">i</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">atomic_read</span><span class="p">(</span><span class="n">atomic_t</span> <span class="o">*</span><span class="n">v</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">atomic_add</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="n">atomic_t</span> <span class="o">*</span><span class="n">v</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">atomic_sub</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="n">atomic_t</span> <span class="o">*</span><span class="n">v</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">atomic_inc</span><span class="p">(</span><span class="n">atomic_t</span> <span class="o">*</span><span class="n">v</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">atomic_dec</span><span class="p">(</span><span class="n">atomic_t</span> <span class="o">*</span><span class="n">v</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">atomic_inc_and_test</span><span class="p">(</span><span class="n">atomic_t</span> <span class="o">*</span><span class="n">v</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">atomic_dec_and_test</span><span class="p">(</span><span class="n">atomic_t</span> <span class="o">*</span><span class="n">v</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">atomic_cmpxchg</span><span class="p">(</span><span class="n">atomic_t</span> <span class="o">*</span><span class="n">v</span><span class="p">,</span> <span class="kt">int</span> <span class="n">old</span><span class="p">,</span> <span class="kt">int</span> <span class="n">new</span><span class="p">);</span> +</pre></div> +</div> +<div class="section" id="use-of-atomic-variables"> +<h4>Use of atomic variables<a class="headerlink" href="#use-of-atomic-variables" title="Permalink to this headline">¶</a></h4> +<p>A common way of using atomic variables is to store the status of an action +(e.g. a flag). So we can use an atomic variable to mark exclusive actions. For +example, we consider that an atomic variable can have the LOCKED and UNLOCKED +values, and if the respective variable equals LOCKED then a specific function +should return -EBUSY. +Such an usage is shown schematically in the code below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define LOCKED 0</span> +<span class="cp">#define UNLOCKED 1</span> + +<span class="k">static</span> <span class="n">atomic_t</span> <span class="n">flag</span><span class="p">;</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_acquire</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">initial_flag</span><span class="p">;</span> + + <span class="cm">/*</span> +<span class="cm"> * Check if flag is UNLOCKED; if so, lock it and do it atomically.</span> +<span class="cm"> *</span> +<span class="cm"> * This is the atomic equivalent of</span> +<span class="cm"> * if (flag == UNLOCKED)</span> +<span class="cm"> * flag = LOCKED;</span> +<span class="cm"> * else</span> +<span class="cm"> * return -EBUSY;</span> +<span class="cm"> */</span> + <span class="n">initial_flag</span> <span class="o">=</span> <span class="n">atomic_cmpxchg</span><span class="p">(</span><span class="o">&</span><span class="n">flag</span><span class="p">,</span> <span class="n">UNLOCKED</span><span class="p">,</span> <span class="n">LOCKED</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">initial_flag</span> <span class="o">==</span> <span class="n">LOCKED</span><span class="p">)</span> <span class="p">{</span> + <span class="n">printk</span><span class="p">(</span><span class="n">KERN_ALERT</span> <span class="s">"Already locked.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EBUSY</span><span class="p">;</span> + <span class="p">}</span> + + <span class="cm">/* Do your thing after getting the lock. */</span> + <span class="p">[...]</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">my_release</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="cm">/* Release flag; mark it as unlocked. */</span> + <span class="n">atomic_set</span><span class="p">(</span><span class="o">&</span><span class="n">flag</span><span class="p">,</span> <span class="n">UNLOCKED</span><span class="p">);</span> +<span class="p">}</span> + +<span class="kt">void</span> <span class="nf">my_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="p">[...]</span> + <span class="cm">/* Atomic variable is initially unlocked. */</span> + <span class="n">atomic_set</span><span class="p">(</span><span class="o">&</span><span class="n">flag</span><span class="p">,</span> <span class="n">UNLOCKED</span><span class="p">);</span> + + <span class="p">[...]</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The above code is the equivalent of using a trylock (such as +<code class="xref c c-func docutils literal"><span class="pre">pthread_mutex_trylock()</span></code>).</p> +<p>We can also use a variable to store the size of a buffer and for atomic +updates of the respective variable. The code below is such an example:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="n">MAX_SIZE</span><span class="p">];</span> +<span class="k">static</span> <span class="n">atomic_t</span> <span class="n">size</span><span class="p">;</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">add_to_buffer</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">value</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">buffer</span><span class="p">[</span><span class="n">atomic_read</span><span class="p">(</span><span class="o">&</span><span class="n">size</span><span class="p">)]</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span> + <span class="n">atomic_inc</span><span class="p">(</span><span class="o">&</span><span class="n">size</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="nf">remove_from_buffer</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">value</span><span class="p">;</span> + + <span class="n">value</span> <span class="o">=</span> <span class="n">buffer</span><span class="p">[</span><span class="n">atomic_read</span><span class="p">(</span><span class="o">&</span><span class="n">size</span><span class="p">)];</span> + <span class="n">atomic_dec</span><span class="p">(</span><span class="o">&</span><span class="n">size</span><span class="p">);</span> + + <span class="k">return</span> <span class="n">value</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">reset_buffer</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">atomic_set</span><span class="p">(</span><span class="o">&</span><span class="n">size</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> +<span class="p">}</span> + +<span class="kt">void</span> <span class="nf">my_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="p">[...]</span> + <span class="cm">/* Initialized buffer and size. */</span> + <span class="n">atomic_set</span><span class="p">(</span><span class="o">&</span><span class="n">size</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> + <span class="n">memset</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">buffer</span><span class="p">));</span> + + <span class="p">[...]</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="atomic-bitwise-operations"> +<h3>Atomic bitwise operations<a class="headerlink" href="#atomic-bitwise-operations" title="Permalink to this headline">¶</a></h3> +<p>The kernel provides a set of functions (in <code class="file docutils literal"><span class="pre">asm/bitops.h</span></code>) that modify or +test bits in an atomic way.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><asm/bitops.h></span><span class="cp"></span> + +<span class="kt">void</span> <span class="nf">set_bit</span><span class="p">(</span><span class="kt">int</span> <span class="n">nr</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">addr</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">clear_bit</span><span class="p">(</span><span class="kt">int</span> <span class="n">nr</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">addr</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">change_bit</span><span class="p">(</span><span class="kt">int</span> <span class="n">nr</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">addr</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">test_and_set_bit</span><span class="p">(</span><span class="kt">int</span> <span class="n">nr</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">addr</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">test_and_clear_bit</span><span class="p">(</span><span class="kt">int</span> <span class="n">nr</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">addr</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">test_and_change_bit</span><span class="p">(</span><span class="kt">int</span> <span class="n">nr</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">addr</span><span class="p">);</span> +</pre></div> +</div> +<p><code class="xref c c-data docutils literal"><span class="pre">Addr</span></code> represents the address of the memory area whose bits are being +modified or tested and <code class="xref c c-data docutils literal"><span class="pre">nr</span></code> is the bit on which the operation is +performed.</p> +</div> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is kernel_api. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/kernel_api/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="section" id="intro"> +<h3>0. Intro<a class="headerlink" href="#intro" title="Permalink to this headline">¶</a></h3> +<p>Using <a class="reference external" href="http://elixir.free-electrons.com/linux/latest/source">LXR</a> find the definitions of the following symbols in the Linux kernel:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">list_head</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">INIT_LIST_HEAD()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">list_add()</span></code></li> +<li><code class="xref c c-macro docutils literal"><span class="pre">list_for_each</span></code></li> +<li><code class="xref c c-macro docutils literal"><span class="pre">list_entry</span></code></li> +<li><code class="xref c c-macro docutils literal"><span class="pre">container_of</span></code></li> +<li><code class="xref c c-macro docutils literal"><span class="pre">offsetof</span></code></li> +</ul> +</div></blockquote> +</div> +<div class="section" id="memory-allocation-in-linux-kernel"> +<h3>1. Memory allocation in Linux kernel<a class="headerlink" href="#memory-allocation-in-linux-kernel" title="Permalink to this headline">¶</a></h3> +<p>Generate the skeleton for the task named <strong>1-mem</strong> and browse the +contents of the <code class="file docutils literal"><span class="pre">mem.c</span></code> file. Observe the use of <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> +call for memory allocation.</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Compile the source code and load the <code class="file docutils literal"><span class="pre">mem.ko</span></code> module using +<strong class="command">insmod</strong>.</li> +<li>View the kernel messages using the <strong class="command">dmesg</strong> command.</li> +<li>Unload the kernel module using the <strong class="command">rmmod mem</strong> command.</li> +</ol> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Review the <a class="reference internal" href="#memory-allocation">Memory Allocation</a> section in the lab.</p> +</div> +</div> +<div class="section" id="sleeping-in-atomic-context"> +<h3>2. Sleeping in atomic context<a class="headerlink" href="#sleeping-in-atomic-context" title="Permalink to this headline">¶</a></h3> +<p>Generate the skeleton for the task named <strong>2-sched-spin</strong> and browse +the contents of the <code class="file docutils literal"><span class="pre">sched-spin.c</span></code> file.</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Compile the source code and load the module, according the above info: +(<strong class="command">make build</strong> and <strong class="command">make copy</strong>)</li> +<li>Notice that it is waiting for 5 seconds until the insertion +order is complete.</li> +<li>Unload the kernel module.</li> +<li>Look for the lines marked with: <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">0</span></code> to create an atomic +section. Re-compile the source code and reload the module into +the kernel.</li> +</ol> +</div></blockquote> +<p>You should now get an error. Look at the stack trace. What is the +cause of the error?</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">In the error message, follow the line containing the <code class="xref c c-macro docutils literal"><span class="pre">BUG</span></code> +for a description of the error. You are not allowed to sleep in +atomic context. The atomic context is given by a section +between a lock operation and an unlock on a spinlock.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The +<code class="xref c c-func docutils literal"><span class="pre">schedule_timeout()</span></code> function, corroborated with the +<code class="xref c c-macro docutils literal"><span class="pre">set_current_state</span></code> macro, forces the current process to wait +for 5 seconds.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Review the <a class="reference internal" href="#contexts-of-execution">Contexts of execution</a>, <a class="reference internal" href="#locking">Locking</a> and <a class="reference internal" href="#spinlock">Spinlock</a> +sections.</p> +</div> +</div> +<div class="section" id="working-with-kernel-memory"> +<h3>3. Working with kernel memory<a class="headerlink" href="#working-with-kernel-memory" title="Permalink to this headline">¶</a></h3> +<p>Generate the skeleton for the task named <strong>3-memory</strong> directory and +browse the contents of the <code class="file docutils literal"><span class="pre">memory.c</span></code> file. Notice the comments +marked with <code class="docutils literal"><span class="pre">TODO</span></code>. You must allocate 4 structures of type <code class="xref c c-type docutils literal"><span class="pre">struct</span> +<span class="pre">task_info</span></code> and initialize them (in <code class="xref c c-func docutils literal"><span class="pre">memory_init()</span></code>), then print and +free them (in <code class="xref c c-func docutils literal"><span class="pre">memory_exit()</span></code>).</p> +<blockquote> +<div><ol class="arabic"> +<li><p class="first">(TODO 1) Allocate memory for <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_info</span></code> structure and +initialize its fields:</p> +<ul class="simple"> +<li>The <code class="xref c c-member docutils literal"><span class="pre">pid</span></code> field to the PID transmitted as a parameter;</li> +<li>The <code class="xref c c-member docutils literal"><span class="pre">timestamp</span></code> field to the value of the <code class="xref c c-data docutils literal"><span class="pre">jiffies</span></code> +variable, which holds the number of ticks that have occurred since the +system booted.</li> +</ul> +</li> +<li><p class="first">(TODO 2) Allocate <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_info</span></code> for the current process, +the parent process, the next process, the next process of the next +process, with the following information:</p> +<ul class="simple"> +<li>PID of the current process, which can be retrieved from +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code> structure, returned by <code class="xref c c-macro docutils literal"><span class="pre">current</span></code> +macro.</li> +</ul> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Search for <code class="xref c c-type docutils literal"><span class="pre">pid</span></code> in <code class="xref c c-type docutils literal"><span class="pre">task_struct</span></code>.</p> +</div> +<ul class="simple"> +<li>PID of the parent process of the current process.</li> +</ul> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Search for the relevant field from <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code> +structure. Look after "parent".</p> +</div> +<ul class="simple"> +<li>PID of the next process from the list of processes, relative to the +current process.</li> +</ul> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use <code class="xref c c-macro docutils literal"><span class="pre">next_task</span></code> macro, which returns a pointer to the next +process (i.e a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code> structure).</p> +</div> +<ul class="simple"> +<li>PID of the next process of the next process, relative to the current +process.</li> +</ul> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Call the <code class="xref c c-macro docutils literal"><span class="pre">next_task</span></code> macro 2 times.</p> +</div> +</li> +<li><p class="first">(TODO 3) Display the four structures.</p> +<ul class="simple"> +<li>Use <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code> to display their two fields:</li> +</ul> +<p><code class="xref c c-member docutils literal"><span class="pre">pid</span></code> and <code class="xref c c-member docutils literal"><span class="pre">timestamp</span></code>.</p> +</li> +<li><p class="first">(TODO 4) Release the memory occupied by the structures +(use <code class="xref c c-func docutils literal"><span class="pre">kfree()</span></code>).</p> +</li> +</ol> +</div></blockquote> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<ul class="last simple"> +<li>You can access the current process using <code class="xref c c-macro docutils literal"><span class="pre">current</span></code> +macro.</li> +<li>Look for the relevant fields in the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code> +structure (<code class="xref c c-member docutils literal"><span class="pre">pid</span></code>, <code class="xref c c-member docutils literal"><span class="pre">parent</span></code>).</li> +<li>Use the <code class="xref c c-macro docutils literal"><span class="pre">next_task</span></code> macro. The macro returns the pointer to +the next process (ie. a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct*</span></code> structure).</li> +</ul> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code> structure contains two fields to +designate the parent of a task:</p> +<ul class="simple"> +<li><code class="xref c c-member docutils literal"><span class="pre">real_parent</span></code> points to the process that created the +task or to process with pid 1 (init) if the parent +completed its execution.</li> +<li><code class="xref c c-member docutils literal"><span class="pre">parent</span></code> indicates to the current task parent (the +process that will be reported if the task completes +execution).</li> +</ul> +<p class="last">In general, the values of the two fields are the same, but +there are situations where they differ, for example when +using the <code class="xref c c-func docutils literal"><span class="pre">ptrace()</span></code> system call.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Review the <a class="reference internal" href="#memory-allocation">Memory allocation</a> section in the lab.</p> +</div> +</div> +<div class="section" id="working-with-kernel-lists"> +<h3>4. Working with kernel lists<a class="headerlink" href="#working-with-kernel-lists" title="Permalink to this headline">¶</a></h3> +<p>Generate the skeleton for the task named <strong>4-list</strong>. Browse the +contents of the <code class="file docutils literal"><span class="pre">list.c</span></code> file and notice the comments marked with +<code class="docutils literal"><span class="pre">TODO</span></code>. The current process will add the four structures from the +previous exercise into a list. The list will be built in the +<code class="xref c c-func docutils literal"><span class="pre">task_info_add_for_current()</span></code> function which is called when module is +loaded. The list will be printed and deleted in the <code class="xref c c-func docutils literal"><span class="pre">list_exit()</span></code> +function and the <code class="xref c c-func docutils literal"><span class="pre">task_info_purge_list()</span></code> function.</p> +<blockquote> +<div><ol class="arabic simple"> +<li>(TODO 1) Complete the <code class="xref c c-func docutils literal"><span class="pre">task_info_add_to_list()</span></code> function to allocate +a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_info</span></code> structure and add it to the list.</li> +<li>(TODO 2) Complete the <code class="xref c c-func docutils literal"><span class="pre">task_info_purge_list()</span></code> function to delete +all the elements in the list.</li> +<li>Compile the kernel module. Load and unload the module by +following the messages displayed by the kernel.</li> +</ol> +</div></blockquote> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Review the labs <a class="reference internal" href="#lists">Lists</a> section. When deleting items from +the list, you will need to use either the +<code class="xref c c-macro docutils literal"><span class="pre">list_for_each_safe</span></code> or <code class="xref c c-macro docutils literal"><span class="pre">list_for_each_entry_safe</span></code> +macros.</p> +</div> +</div> +<div class="section" id="working-with-kernel-lists-for-process-handling"> +<h3>5. Working with kernel lists for process handling<a class="headerlink" href="#working-with-kernel-lists-for-process-handling" title="Permalink to this headline">¶</a></h3> +<p>Generate the skeleton for the task named <strong>5-list-full</strong>. Browse the +contents of the <code class="file docutils literal"><span class="pre">list-full.c</span></code> and notice comments marked with +<code class="docutils literal"><span class="pre">TODO</span></code>. In addition to the <code class="file docutils literal"><span class="pre">4-list</span></code> functionality we add the +following:</p> +<blockquote> +<div><ul> +<li><p class="first">A <code class="xref c c-member docutils literal"><span class="pre">count</span></code> field showing how many times a process has been "added" +to the list.</p> +</li> +<li><p class="first">If a process is "added" several times, no new entry is created in +the list, but:</p> +<blockquote> +<div><ul class="simple"> +<li>Update the <code class="xref c c-member docutils literal"><span class="pre">timestamp</span></code> field.</li> +<li>Increment <code class="xref c c-member docutils literal"><span class="pre">count</span></code>.</li> +</ul> +</div></blockquote> +</li> +<li><p class="first">To implement the counter facility, add a <code class="xref c c-func docutils literal"><span class="pre">task_info_find_pid()</span></code> +function that searches for a pid in the existing list.</p> +</li> +<li><p class="first">If found, return the reference to the <code class="xref c c-type docutils literal"><span class="pre">task_info</span></code> struct. If +not, return <code class="xref c c-macro docutils literal"><span class="pre">NULL</span></code>.</p> +</li> +<li><p class="first">An expiration facility. If a process was added more than 3 +seconds ago and if it does not have a <code class="xref c c-member docutils literal"><span class="pre">count</span></code> greater than 5 then +it is considered expired and is removed from the list.</p> +</li> +<li><p class="first">The expiration facility is already implemented in the +<code class="xref c c-func docutils literal"><span class="pre">task_info_remove_expired()</span></code> function.</p> +</li> +</ul> +<ol class="arabic"> +<li><p class="first">(TODO 1) Implement the <code class="xref c c-func docutils literal"><span class="pre">task_info_find_pid()</span></code> function.</p> +</li> +<li><p class="first">(TODO 2) Change a field of an item in the list so it does not +expire. It must not satisfy a part of the expiration condition +from <code class="xref c c-func docutils literal"><span class="pre">task_info_remove_expired()</span></code>.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">For <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">2</span></code>, extract the first element from the list (the one +referred by <code class="xref c c-member docutils literal"><span class="pre">head.next</span></code>) and set the <code class="xref c c-member docutils literal"><span class="pre">count</span></code> +field to a large enough value. Use <code class="xref c c-func docutils literal"><span class="pre">atomic_set()</span></code> function.</p> +</div> +</li> +<li><p class="first">Compile, copy, load and unload the kernel module following the displayed +messages. +Kernel module loading will take some time, because <code class="xref c c-func docutils literal"><span class="pre">sleep()</span></code> is +being called by <code class="xref c c-func docutils literal"><span class="pre">schedule_timeout()</span></code> function.</p> +</li> +</ol> +</div></blockquote> +</div> +<div class="section" id="synchronizing-list-work"> +<h3>6. Synchronizing list work<a class="headerlink" href="#synchronizing-list-work" title="Permalink to this headline">¶</a></h3> +<p>Generate the skeleton for the task named <strong>6-list-sync</strong>.</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Browse the code and look for <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">1</span></code> string.</li> +<li>Use a spinlock or a read-write lock to synchronize access to the +list.</li> +<li>Compile, load and unload the kernel module.</li> +</ol> +</div></blockquote> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p class="last">Always lock data, not code!</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Read <a class="reference internal" href="#spinlock">Spinlock</a> section of the lab.</p> +</div> +</div> +<div class="section" id="test-module-calling-in-our-list-module"> +<h3>7. Test module calling in our list module<a class="headerlink" href="#test-module-calling-in-our-list-module" title="Permalink to this headline">¶</a></h3> +<p>Generate the skeleton for the task named <strong>7-list-test</strong> and browse +the contents of the <code class="file docutils literal"><span class="pre">list-test.c</span></code> file. We'll use it as a test +module. It will call functions exported by the <strong>6-list-sync</strong> +task. The exported functions are the ones marked with <strong>extern</strong> in +<code class="file docutils literal"><span class="pre">list-test.c</span></code> file.</p> +<p>Uncomment the commented code from <code class="file docutils literal"><span class="pre">7-list-test.c</span></code>. Look for <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">1</span></code>.</p> +<p>To export the above functions from the module located at <code class="file docutils literal"><span class="pre">6-list-sync/</span></code> +directory, the following steps are required:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Functions must not be static.</li> +<li>Use the <code class="xref c c-macro docutils literal"><span class="pre">EXPORT_SYMBOL</span></code> macro to export the kernel symbols. For +example: <code class="xref c c-macro docutils literal"><span class="pre">EXPORT_SYMBOL(task_info_remove_expired);</span></code>. The +macro must be used for each function after the function is defined. +Browse the code and look for the <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">2</span></code> string in the +<code class="file docutils literal"><span class="pre">list-sync.c</span></code>.</li> +<li>Remove from the module from <strong>6-list-sync</strong> the code that avoids the +expiration of a list item (it is in contradiction to our exercise).</li> +<li>Compile and load the module from <code class="file docutils literal"><span class="pre">6-list-sync/</span></code>. Once loaded, it +exposes exported functions and can be used by the test +module. You can check this by searching for the function names +in <code class="file docutils literal"><span class="pre">/proc/kallsyms</span></code> before and after loading the module.</li> +<li>Compile the test module and then load it.</li> +<li>Use <strong class="command">lsmod</strong> to check that the two modules have been loaded. +What do you notice?</li> +<li>Unload the kernel test module.</li> +</ol> +</div></blockquote> +<p>What should be the unload order of the two modules (the module from +<strong>6-list-sync</strong> and the test module)? What happens if you use another order?</p> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="kernel_modules.html" class="btn btn-neutral float-left" title="Kernel modules" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="device_drivers.html" class="btn btn-neutral float-right" title="Character device drivers" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/labs/kernel_modules.html b/refs/pull/405/merge/labs/kernel_modules.html new file mode 100644 index 00000000..13dc7fb1 --- /dev/null +++ b/refs/pull/405/merge/labs/kernel_modules.html @@ -0,0 +1,1391 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Kernel modules — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Kernel API" href="kernel_api.html" /> + <link rel="prev" title="Introduction" href="introduction.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Kernel modules</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="#kernel-modules-overview">Kernel Modules Overview</a></li> +<li class="toctree-l2"><a class="reference internal" href="#an-example-of-a-kernel-module">An example of a kernel module</a></li> +<li class="toctree-l2"><a class="reference internal" href="#compiling-kernel-modules">Compiling kernel modules</a></li> +<li class="toctree-l2"><a class="reference internal" href="#loading-unloading-a-kernel-module">Loading/unloading a kernel module</a></li> +<li class="toctree-l2"><a class="reference internal" href="#kernel-module-debugging">Kernel Module Debugging</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#objdump">objdump</a></li> +<li class="toctree-l3"><a class="reference internal" href="#addr2line">addr2line</a></li> +<li class="toctree-l3"><a class="reference internal" href="#minicom">minicom</a></li> +<li class="toctree-l3"><a class="reference internal" href="#netconsole">netconsole</a></li> +<li class="toctree-l3"><a class="reference internal" href="#printk-debugging">Printk debugging</a></li> +<li class="toctree-l3"><a class="reference internal" href="#dynamic-debugging">Dynamic debugging</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#dyndbg-options">Dyndbg Options</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#kdb-kernel-debugger">KDB: Kernel debugger</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#intro">0. Intro</a></li> +<li class="toctree-l3"><a class="reference internal" href="#kernel-module">1. Kernel module</a></li> +<li class="toctree-l3"><a class="reference internal" href="#printk">2. Printk</a></li> +<li class="toctree-l3"><a class="reference internal" href="#error">3. Error</a></li> +<li class="toctree-l3"><a class="reference internal" href="#sub-modules">4. Sub-modules</a></li> +<li class="toctree-l3"><a class="reference internal" href="#kernel-oops-1">5. Kernel oops</a></li> +<li class="toctree-l3"><a class="reference internal" href="#module-parameters">6. Module parameters</a></li> +<li class="toctree-l3"><a class="reference internal" href="#proc-info-1">7. Proc info</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#extra-exercises">Extra Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#kdb">1. KDB</a></li> +<li class="toctree-l3"><a class="reference internal" href="#ps-module">2. PS Module</a></li> +<li class="toctree-l3"><a class="reference internal" href="#memory-info">3. Memory Info</a></li> +<li class="toctree-l3"><a class="reference internal" href="#dynamic-debugging-1">4. Dynamic Debugging</a></li> +<li class="toctree-l3"><a class="reference internal" href="#dynamic-debugging-during-initialization">5. Dynamic Debugging During Initialization</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Kernel modules</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/labs/kernel_modules.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="kernel-modules"> +<h1>Kernel modules<a class="headerlink" href="#kernel-modules" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>creating simple modules</li> +<li>describing the process of kernel module compilation</li> +<li>presenting how a module can be used with a kernel</li> +<li>simple kernel debugging methods</li> +</ul> +</div> +<div class="section" id="kernel-modules-overview"> +<h2>Kernel Modules Overview<a class="headerlink" href="#kernel-modules-overview" title="Permalink to this headline">¶</a></h2> +<p>A monolithic kernel, though faster than a microkernel, has the disadvantage of +lack of modularity and extensibility. On modern monolithic kernels, this has +been solved by using kernel modules. A kernel module (or loadable kernel mode) +is an object file that contains code that can extend the kernel functionality +at runtime (it is loaded as needed); When a kernel module is no longer needed, +it can be unloaded. Most of the device drivers are used in the form of kernel +modules.</p> +<p>For the development of Linux device drivers, it is recommended to download the +kernel sources, configure and compile them and then install the compiled version +on the test /development tool machine.</p> +</div> +<div class="section" id="an-example-of-a-kernel-module"> +<h2>An example of a kernel module<a class="headerlink" href="#an-example-of-a-kernel-module" title="Permalink to this headline">¶</a></h2> +<p>Below is a very simple example of a kernel module. When loading into the kernel, +it will generate the message <code class="code docutils literal"><span class="pre">"Hi"</span></code>. When unloading the kernel module, the +<code class="code docutils literal"><span class="pre">"Bye"</span></code> message will be generated.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/kernel.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/init.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/module.h></span><span class="cp"></span> + +<span class="n">MODULE_DESCRIPTION</span><span class="p">(</span><span class="s">"My kernel module"</span><span class="p">);</span> +<span class="n">MODULE_AUTHOR</span><span class="p">(</span><span class="s">"Me"</span><span class="p">);</span> +<span class="n">MODULE_LICENSE</span><span class="p">(</span><span class="s">"GPL"</span><span class="p">);</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">dummy_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_debug</span><span class="p">(</span><span class="s">"Hi</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">dummy_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_debug</span><span class="p">(</span><span class="s">"Bye</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> +<span class="p">}</span> + +<span class="n">module_init</span><span class="p">(</span><span class="n">dummy_init</span><span class="p">);</span> +<span class="n">module_exit</span><span class="p">(</span><span class="n">dummy_exit</span><span class="p">);</span> +</pre></div> +</div> +<p>The generated messages will not be displayed on the console but will be saved +in a specially reserved memory area for this, from where they will be extracted +by the logging daemon (syslog). To display kernel messages, you can use the +<strong class="command">dmesg</strong> command or inspect the logs:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># cat /var/log/syslog | tail -2</span> +Feb <span class="m">20</span> <span class="m">13</span>:57:38 asgard kernel: Hi +Feb <span class="m">20</span> <span class="m">13</span>:57:43 asgard kernel: Bye + +<span class="c1"># dmesg | tail -2</span> +Hi +Bye +</pre></div> +</div> +</div> +<div class="section" id="compiling-kernel-modules"> +<h2>Compiling kernel modules<a class="headerlink" href="#compiling-kernel-modules" title="Permalink to this headline">¶</a></h2> +<p>Compiling a kernel module differs from compiling an user program. First, other +headers should be used. Also, the module should not be linked to libraries. +And, last but not least, the module must be compiled with the same options as +the kernel in which we load the module. For these reasons, there is a standard +compilation method (<code class="code docutils literal"><span class="pre">kbuild</span></code>). This method requires the use of two files: +a <code class="file docutils literal"><span class="pre">Makefile</span></code> and a <code class="file docutils literal"><span class="pre">Kbuild</span></code> file.</p> +<p>Below is an example of a <code class="file docutils literal"><span class="pre">Makefile</span></code>:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nv">KDIR</span> <span class="o">=</span> /lib/modules/<span class="sb">`</span>uname -r<span class="sb">`</span>/build + +kbuild: + make -C <span class="k">$(</span>KDIR<span class="k">)</span> <span class="nv">M</span><span class="o">=</span><span class="sb">`</span><span class="nb">pwd</span><span class="sb">`</span> + +clean: + make -C <span class="k">$(</span>KDIR<span class="k">)</span> <span class="nv">M</span><span class="o">=</span><span class="sb">`</span><span class="nb">pwd</span><span class="sb">`</span> clean +</pre></div> +</div> +<p>And the example of a <code class="file docutils literal"><span class="pre">Kbuild</span></code> file used to compile a module:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nv">EXTRA_CFLAGS</span> <span class="o">=</span> -Wall -g + +obj-m <span class="o">=</span> modul.o +</pre></div> +</div> +<p>As you can see, calling <strong class="command">make</strong> on the <code class="file docutils literal"><span class="pre">Makefile</span></code> file in the +example shown will result in the <strong class="command">make</strong> invocation in the kernel +source directory (<code class="docutils literal"><span class="pre">/lib/modules/`uname</span> <span class="pre">-r`/build</span></code>) and referring to the +current directory (<code class="docutils literal"><span class="pre">M</span> <span class="pre">=</span> <span class="pre">`pwd`</span></code>). This process ultimately leads to reading +the <code class="file docutils literal"><span class="pre">Kbuild</span></code> file from the current directory and compiling the module +as instructed in this file.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>For labs we will configure different <strong class="command">KDIR</strong>, according to +the virtual machine specifications:</p> +<div class="last highlight-bash"><div class="highlight"><pre><span></span><span class="nv">KDIR</span> <span class="o">=</span> /home/student/src/linux +<span class="o">[</span>...<span class="o">]</span> +</pre></div> +</div> +</div> +<p>A <code class="file docutils literal"><span class="pre">Kbuild</span></code> file contains one or more directives for compiling a kernel +module. The easiest example of such a directive is <code class="docutils literal"><span class="pre">obj-m</span> <span class="pre">=</span> +<span class="pre">module.o</span></code>. Following this directive, a kernel module (<code class="code docutils literal"><span class="pre">ko</span></code> - kernel +object) will be created, starting from the <code class="docutils literal"><span class="pre">module.o</span></code> file. <code class="docutils literal"><span class="pre">module.o</span></code> will +be created starting from <code class="docutils literal"><span class="pre">module.c</span></code> or <code class="docutils literal"><span class="pre">module.S</span></code>. All of these files can +be found in the <code class="file docutils literal"><span class="pre">Kbuild</span></code>'s directory.</p> +<p>An example of a <code class="file docutils literal"><span class="pre">Kbuild</span></code> file that uses several sub-modules is shown +below:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nv">EXTRA_CFLAGS</span> <span class="o">=</span> -Wall -g + +obj-m <span class="o">=</span> supermodule.o +supermodule-y <span class="o">=</span> module-a.o module-b.o +</pre></div> +</div> +<p>For the example above, the steps to compile are:</p> +<blockquote> +<div><ul class="simple"> +<li>compile the <code class="file docutils literal"><span class="pre">module-a.c</span></code> and <code class="file docutils literal"><span class="pre">module-b.c</span></code> sources, +resulting in module-a.o and module-b.o objects</li> +<li><code class="file docutils literal"><span class="pre">module-a.o</span></code> and <code class="file docutils literal"><span class="pre">module-b.o</span></code> will then be linked +in <code class="file docutils literal"><span class="pre">supermodule.o</span></code></li> +<li>from <code class="file docutils literal"><span class="pre">supermodule.o</span></code> will be created <code class="file docutils literal"><span class="pre">supermodule.ko</span></code> +module</li> +</ul> +</div></blockquote> +<p>The suffix of targets in <code class="file docutils literal"><span class="pre">Kbuild</span></code> determines how they are used, as +follows:</p> +<blockquote> +<div><ul class="simple"> +<li>M (modules) is a target for loadable kernel modules</li> +<li>Y (yes) represents a target for object files to be compiled and then +linked to a module (<code class="docutils literal"><span class="pre">$(mode_name)-y</span></code>) or within the kernel (<code class="docutils literal"><span class="pre">obj-y</span></code>)</li> +<li>any other target suffix will be ignored by <code class="file docutils literal"><span class="pre">Kbuild</span></code> and will not be +compiled</li> +</ul> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">These suffixes are used to easily configure the kernel by running the +<strong class="command">make menuconfig</strong> command or directly editing the +<code class="file docutils literal"><span class="pre">.config</span></code> file. This file sets a series of variables that are +used to determine which features are added to the kernel at build +time. For example, when adding BTRFS support with <strong class="command">make +menuconfig</strong>, add the line <code class="code docutils literal"><span class="pre">CONFIG_BTRFS_FS</span> <span class="pre">=</span> <span class="pre">y</span></code> to the +<code class="file docutils literal"><span class="pre">.config</span></code> file. The BTRFS kbuild contains the line +<code class="docutils literal"><span class="pre">obj-$(CONFIG_BTRFS_FS):=</span> <span class="pre">btrfs.o</span></code>, which becomes <code class="docutils literal"><span class="pre">obj-y:=</span> +<span class="pre">btrfs.o</span></code>. This will compile the <code class="file docutils literal"><span class="pre">btrfs.o</span></code> object and will be +linked to the kernel. Before the variable was set, the line became +<code class="docutils literal"><span class="pre">obj:=btrfs.o</span></code> and so it was ignored, and the kernel was build +without BTRFS support.</p> +</div> +<p>For more details, see the <code class="file docutils literal"><span class="pre">Documentation/kbuild/makefiles.txt</span></code> and +<code class="file docutils literal"><span class="pre">Documentation/kbuild/modules.txt</span></code> files within the kernel sources.</p> +</div> +<div class="section" id="loading-unloading-a-kernel-module"> +<h2>Loading/unloading a kernel module<a class="headerlink" href="#loading-unloading-a-kernel-module" title="Permalink to this headline">¶</a></h2> +<p>To load a kernel module, use the <strong class="command">insmod</strong> utility. This utility +receives as a parameter the path to the <code class="file docutils literal"><span class="pre">*.ko</span></code> file in which the module +was compiled and linked. Unloading the module from the kernel is done using +the <strong class="command">rmmod</strong> command, which receives the module name as a parameter.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ insmod module.ko +$ rmmod module.ko +</pre></div> +</div> +<p>When loading the kernel module, the routine specified as a parameter of the +<code class="docutils literal"><span class="pre">module_init</span></code> macro will be executed. Similarly, when the module is unloaded +the routine specified as a parameter of the <code class="docutils literal"><span class="pre">module_exit</span></code> will be executed.</p> +<p>A complete example of compiling and loading/unloading a kernel module is +presented below:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>faust:~/lab-01/modul-lin# ls +Kbuild Makefile modul.c + +faust:~/lab-01/modul-lin# make +make -C /lib/modules/<span class="sb">`</span>uname -r<span class="sb">`</span>/build <span class="nv">M</span><span class="o">=</span><span class="sb">`</span><span class="nb">pwd</span><span class="sb">`</span> +make<span class="o">[</span><span class="m">1</span><span class="o">]</span>: Entering directory <span class="sb">`</span>/usr/src/linux-2.6.28.4<span class="s1">'</span> +<span class="s1"> LD /root/lab-01/modul-lin/built-in.o</span> +<span class="s1"> CC [M] /root/lab-01/modul-lin/modul.o</span> +<span class="s1"> Building modules, stage 2.</span> +<span class="s1"> MODPOST 1 modules</span> +<span class="s1"> CC /root/lab-01/modul-lin/modul.mod.o</span> +<span class="s1"> LD [M] /root/lab-01/modul-lin/modul.ko</span> +<span class="s1">make[1]: Leaving directory `/usr/src/linux-2.6.28.4'</span> + +faust:~/lab-01/modul-lin# ls +built-in.o Kbuild Makefile modul.c Module.markers +modules.order Module.symvers modul.ko modul.mod.c +modul.mod.o modul.o + +faust:~/lab-01/modul-lin# insmod modul.ko + +faust:~/lab-01/modul-lin# dmesg <span class="p">|</span> tail -1 +Hi + +faust:~/lab-01/modul-lin# rmmod modul + +faust:~/lab-01/modul-lin# dmesg <span class="p">|</span> tail -2 +Hi +Bye +</pre></div> +</div> +<p>Information about modules loaded into the kernel can be found using the +<strong class="command">lsmod</strong> command or by inspecting the <code class="file docutils literal"><span class="pre">/proc/modules</span></code>, +<code class="file docutils literal"><span class="pre">/sys/module</span></code> directories.</p> +</div> +<div class="section" id="kernel-module-debugging"> +<h2>Kernel Module Debugging<a class="headerlink" href="#kernel-module-debugging" title="Permalink to this headline">¶</a></h2> +<p>Troubleshooting a kernel module is much more complicated than debugging a +regular program. First, a mistake in a kernel module can lead to blocking the +entire system. Troubleshooting is therefore much slowed down. To avoid reboot, +it is recommended to use a virtual machine (qemu, virtualbox, vmware).</p> +<p>When a module containing bugs is inserted into the kernel, it will eventually +generate a <a class="reference external" href="https://en.wikipedia.org/wiki/Linux_kernel_oops">kernel oops</a>. +A kernel oops is an invalid operation detected by the kernel and can only +be generated by the kernel. For a stable kernel version, it almost certainly +means that the module contains a bug. After the oops appears, the kernel will +continue to work.</p> +<p>Very important to the appearance of a kernel oops is saving the generated +message. As noted above, messages generated by the kernel are saved in logs and +can be displayed with the <strong class="command">dmesg</strong> command. To make sure that no kernel +message is lost, it is recommended to insert/test the kernel directly from the +console, or periodically check the kernel messages. Noteworthy is that an oops +can occur because of a programming error, but also a because of hardware error.</p> +<p>If a fatal error occurs, after which the system can not return to a stable +state, a <a class="reference external" href="https://en.wikipedia.org/wiki/Linux_kernel_panic">kernel panic</a> is +generated.</p> +<p>Look at the kernel module below that contains a bug that generates an oops:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/*</span> +<span class="cm"> * Oops generating kernel module</span> +<span class="cm"> */</span> + +<span class="cp">#include</span> <span class="cpf"><linux/kernel.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/module.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/init.h></span><span class="cp"></span> + +<span class="n">MODULE_DESCRIPTION</span> <span class="p">(</span><span class="s">"Oops"</span><span class="p">);</span> +<span class="n">MODULE_LICENSE</span> <span class="p">(</span><span class="s">"GPL"</span><span class="p">);</span> +<span class="n">MODULE_AUTHOR</span> <span class="p">(</span><span class="s">"PSO"</span><span class="p">);</span> + +<span class="cp">#define OP_READ 0</span> +<span class="cp">#define OP_WRITE 1</span> +<span class="cp">#define OP_OOPS OP_WRITE</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_oops_init</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="o">*</span><span class="n">a</span><span class="p">;</span> + + <span class="n">a</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span> <span class="o">*</span><span class="p">)</span> <span class="mh">0x00001234</span><span class="p">;</span> +<span class="cp">#if OP_OOPS == OP_WRITE</span> + <span class="o">*</span><span class="n">a</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span> +<span class="cp">#elif OP_OOPS == OP_READ</span> + <span class="n">printk</span> <span class="p">(</span><span class="n">KERN_ALERT</span> <span class="s">"value = %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="o">*</span><span class="n">a</span><span class="p">);</span> +<span class="cp">#else</span> +<span class="cp">#error "Unknown op for oops!"</span> +<span class="cp">#endif</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">my_oops_exit</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> +<span class="p">}</span> + +<span class="n">module_init</span> <span class="p">(</span><span class="n">my_oops_init</span><span class="p">);</span> +<span class="n">module_exit</span> <span class="p">(</span><span class="n">my_oops_exit</span><span class="p">);</span> +</pre></div> +</div> +<p>Inserting this module into the kernel will generate an oops:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>faust:~/lab-01/modul-oops# insmod oops.ko +<span class="o">[</span>...<span class="o">]</span> + +faust:~/lab-01/modul-oops# dmesg <span class="p">|</span> tail -32 +BUG: unable to handle kernel paging request at <span class="m">00001234</span> +IP: <span class="o">[</span><c89d4005><span class="o">]</span> my_oops_init+0x5/0x20 <span class="o">[</span>oops<span class="o">]</span> + *de <span class="o">=</span> <span class="m">00000000</span> +Oops: <span class="m">0002</span> <span class="o">[</span><span class="c1">#1] PREEMPT DEBUG_PAGEALLOC</span> +last sysfs file: /sys/devices/virtual/net/lo/operstate +Modules linked in: oops<span class="o">(</span>+<span class="o">)</span> netconsole ide_cd_mod pcnet32 crc32 cdrom <span class="o">[</span>last unloaded: modul<span class="o">]</span> + +Pid: <span class="m">4157</span>, comm: insmod Not tainted <span class="o">(</span><span class="m">2</span>.6.28.4 <span class="c1">#2) VMware Virtual Platform</span> +EIP: <span class="m">0060</span>:<span class="o">[</span><c89d4005><span class="o">]</span> EFLAGS: <span class="m">00010246</span> CPU: <span class="m">0</span> +EIP is at my_oops_init+0x5/0x20 <span class="o">[</span>oops<span class="o">]</span> +EAX: <span class="m">00000000</span> EBX: fffffffc ECX: c89d4300 EDX: <span class="m">00000001</span> +ESI: c89d4000 EDI: <span class="m">00000000</span> EBP: c5799e24 ESP: c5799e24 + DS: 007b ES: 007b FS: <span class="m">0000</span> GS: <span class="m">0033</span> SS: <span class="m">0068</span> +Process insmod <span class="o">(</span>pid: <span class="m">4157</span>, <span class="nv">ti</span><span class="o">=</span>c5799000 <span class="nv">task</span><span class="o">=</span>c665c780 task.ti<span class="o">=</span>c5799000<span class="o">)</span> +Stack: + c5799f8c c010102d c72b51d8 0000000c c5799e58 c01708e4 <span class="m">00000124</span> <span class="m">00000000</span> + c89d4300 c5799e58 c724f448 <span class="m">00000001</span> c89d4300 c5799e60 c0170981 c5799f8c + c014b698 <span class="m">00000000</span> <span class="m">00000000</span> c5799f78 c5799f20 <span class="m">00000500</span> c665cb00 c89d4300 +Call Trace: + <span class="o">[</span><c010102d><span class="o">]</span> ? _stext+0x2d/0x170 + <span class="o">[</span><c01708e4><span class="o">]</span> ? __vunmap+0xa4/0xf0 + <span class="o">[</span><c0170981><span class="o">]</span> ? vfree+0x21/0x30 + <span class="o">[</span><c014b698><span class="o">]</span> ? load_module+0x19b8/0x1a40 + <span class="o">[</span><c035e965><span class="o">]</span> ? __mutex_unlock_slowpath+0xd5/0x140 + <span class="o">[</span><c0140da6><span class="o">]</span> ? trace_hardirqs_on_caller+0x106/0x150 + <span class="o">[</span><c014b7aa><span class="o">]</span> ? sys_init_module+0x8a/0x1b0 + <span class="o">[</span><c0140da6><span class="o">]</span> ? trace_hardirqs_on_caller+0x106/0x150 + <span class="o">[</span><c0240a08><span class="o">]</span> ? trace_hardirqs_on_thunk+0xc/0x10 + <span class="o">[</span><c0103407><span class="o">]</span> ? sysenter_do_call+0x12/0x43 +Code: <c7> <span class="m">05</span> <span class="m">34</span> <span class="m">12</span> <span class="m">00</span> <span class="m">00</span> <span class="m">03</span> <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> 5d c3 eb 0d <span class="m">90</span> <span class="m">90</span> <span class="m">90</span> <span class="m">90</span> <span class="m">90</span> <span class="m">90</span> <span class="m">90</span> <span class="m">90</span> +EIP: <span class="o">[</span><c89d4005><span class="o">]</span> my_oops_init+0x5/0x20 <span class="o">[</span>oops<span class="o">]</span> SS:ESP <span class="m">0068</span>:c5799e24 +---<span class="o">[</span> end trace 2981ce73ae801363 <span class="o">]</span>--- +</pre></div> +</div> +<p>Although relatively cryptic, the message provided by the kernel to the +appearance of an oops provides valuable information about the error. First line:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>BUG: unable to handle kernel paging request at <span class="m">00001234</span> +EIP: <span class="o">[</span><c89d4005><span class="o">]</span> my_oops_init + 0x5 / 0x20 <span class="o">[</span>oops<span class="o">]</span> +</pre></div> +</div> +<p>Tells us the cause and the address of the instruction that generated the error. +In our case this is an invalid access to memory.</p> +<p>Next line</p> +<blockquote> +<div><code class="docutils literal"><span class="pre">Oops:</span> <span class="pre">0002</span> <span class="pre">[#</span> <span class="pre">1]</span> <span class="pre">PREEMPT</span> <span class="pre">DEBUG_PAGEALLOC</span></code></div></blockquote> +<p>Tells us that it's the first oops (#1). This is important in the context that +an oops can lead to other oopses. Usually only the first oops is relevant. +Furthermore, the oops code (<code class="docutils literal"><span class="pre">0002</span></code>) provides information about the error type +(see <code class="file docutils literal"><span class="pre">arch/x86/include/asm/trap_pf.h</span></code>):</p> +<blockquote> +<div><ul class="simple"> +<li>Bit 0 == 0 means no page found, 1 means protection fault</li> +<li>Bit 1 == 0 means read, 1 means write</li> +<li>Bit 2 == 0 means kernel, 1 means user mode</li> +</ul> +</div></blockquote> +<p>In this case, we have a write access that generated the oops (bit 1 is 1).</p> +<p>Below is a dump of the registers. It decodes the instruction pointer (<code class="docutils literal"><span class="pre">EIP</span></code>) +value and notes that the bug appeared in the <code class="code docutils literal"><span class="pre">my_oops_init</span></code> function with +a 5-byte offset (<code class="docutils literal"><span class="pre">EIP:</span> <span class="pre">[<c89d4005>]</span> <span class="pre">my_oops_init+0x5</span></code>). The message also +shows the stack content and a backtrace of calls until then.</p> +<p>If an invalid read call is generated (<code class="docutils literal"><span class="pre">#define</span> <span class="pre">OP_OOPS</span> <span class="pre">OP_READ</span></code>), the message +will be the same, but the oops code will differ, which would now be <code class="docutils literal"><span class="pre">0000</span></code>:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>faust:~/lab-01/modul-oops# dmesg <span class="p">|</span> tail -33 +BUG: unable to handle kernel paging request at <span class="m">00001234</span> +IP: <span class="o">[</span><c89c3016><span class="o">]</span> my_oops_init+0x6/0x20 <span class="o">[</span>oops<span class="o">]</span> + *de <span class="o">=</span> <span class="m">00000000</span> +Oops: <span class="m">0000</span> <span class="o">[</span><span class="c1">#1] PREEMPT DEBUG_PAGEALLOC</span> +last sysfs file: /sys/devices/virtual/net/lo/operstate +Modules linked in: oops<span class="o">(</span>+<span class="o">)</span> netconsole pcnet32 crc32 ide_cd_mod cdrom + +Pid: <span class="m">2754</span>, comm: insmod Not tainted <span class="o">(</span><span class="m">2</span>.6.28.4 <span class="c1">#2) VMware Virtual Platform</span> +EIP: <span class="m">0060</span>:<span class="o">[</span><c89c3016><span class="o">]</span> EFLAGS: <span class="m">00010292</span> CPU: <span class="m">0</span> +EIP is at my_oops_init+0x6/0x20 <span class="o">[</span>oops<span class="o">]</span> +EAX: <span class="m">00000000</span> EBX: fffffffc ECX: c89c3380 EDX: <span class="m">00000001</span> +ESI: c89c3010 EDI: <span class="m">00000000</span> EBP: c57cbe24 ESP: c57cbe1c + DS: 007b ES: 007b FS: <span class="m">0000</span> GS: <span class="m">0033</span> SS: <span class="m">0068</span> +Process insmod <span class="o">(</span>pid: <span class="m">2754</span>, <span class="nv">ti</span><span class="o">=</span>c57cb000 <span class="nv">task</span><span class="o">=</span>c66ec780 task.ti<span class="o">=</span>c57cb000<span class="o">)</span> +Stack: + c57cbe34 <span class="m">00000282</span> c57cbf8c c010102d c57b9280 0000000c c57cbe58 c01708e4 + <span class="m">00000124</span> <span class="m">00000000</span> c89c3380 c57cbe58 c5db1d38 <span class="m">00000001</span> c89c3380 c57cbe60 + c0170981 c57cbf8c c014b698 <span class="m">00000000</span> <span class="m">00000000</span> c57cbf78 c57cbf20 <span class="m">00000580</span> +Call Trace: + <span class="o">[</span><c010102d><span class="o">]</span> ? _stext+0x2d/0x170 + <span class="o">[</span><c01708e4><span class="o">]</span> ? __vunmap+0xa4/0xf0 + <span class="o">[</span><c0170981><span class="o">]</span> ? vfree+0x21/0x30 + <span class="o">[</span><c014b698><span class="o">]</span> ? load_module+0x19b8/0x1a40 + <span class="o">[</span><c035d083><span class="o">]</span> ? printk+0x0/0x1a + <span class="o">[</span><c035e965><span class="o">]</span> ? __mutex_unlock_slowpath+0xd5/0x140 + <span class="o">[</span><c0140da6><span class="o">]</span> ? trace_hardirqs_on_caller+0x106/0x150 + <span class="o">[</span><c014b7aa><span class="o">]</span> ? sys_init_module+0x8a/0x1b0 + <span class="o">[</span><c0140da6><span class="o">]</span> ? trace_hardirqs_on_caller+0x106/0x150 + <span class="o">[</span><c0240a08><span class="o">]</span> ? trace_hardirqs_on_thunk+0xc/0x10 + <span class="o">[</span><c0103407><span class="o">]</span> ? sysenter_do_call+0x12/0x43 +Code: <a1> <span class="m">34</span> <span class="m">12</span> <span class="m">00</span> <span class="m">00</span> c7 <span class="m">04</span> <span class="m">24</span> <span class="m">54</span> <span class="m">30</span> 9c c8 <span class="m">89</span> <span class="m">44</span> <span class="m">24</span> <span class="m">04</span> e8 <span class="m">58</span> a0 <span class="m">99</span> f7 <span class="m">31</span> +EIP: <span class="o">[</span><c89c3016><span class="o">]</span> my_oops_init+0x6/0x20 <span class="o">[</span>oops<span class="o">]</span> SS:ESP <span class="m">0068</span>:c57cbe1c +---<span class="o">[</span> end trace 45eeb3d6ea8ff1ed <span class="o">]</span>--- +</pre></div> +</div> +<div class="section" id="objdump"> +<h3>objdump<a class="headerlink" href="#objdump" title="Permalink to this headline">¶</a></h3> +<p>Detailed information about the instruction that generated the oops can be found +using the <strong class="command">objdump</strong> utility. Useful options to use are <strong class="command">-d</strong> +to disassemble the code and <strong class="command">-S</strong> for interleaving C code in assembly +language code. For efficient decoding, however, we need the address where the +kernel module was loaded. This can be found in <code class="file docutils literal"><span class="pre">/proc/modules</span></code>.</p> +<p>Here's an example of using <strong class="command">objdump</strong> on the above module to identify +the instruction that generated the oops:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>faust:~/lab-01/modul-oops# cat /proc/modules +oops <span class="m">1280</span> <span class="m">1</span> - Loading 0xc89d4000 +netconsole <span class="m">8352</span> <span class="m">0</span> - Live 0xc89ad000 +pcnet32 <span class="m">33412</span> <span class="m">0</span> - Live 0xc895a000 +ide_cd_mod <span class="m">34952</span> <span class="m">0</span> - Live 0xc8903000 +crc32 <span class="m">4224</span> <span class="m">1</span> pcnet32, Live 0xc888a000 +cdrom <span class="m">34848</span> <span class="m">1</span> ide_cd_mod, Live 0xc886d000 + +faust:~/lab-01/modul-oops# objdump -dS --adjust-vma<span class="o">=</span>0xc89d4000 oops.ko + +oops.ko: file format elf32-i386 + + +Disassembly of section .text: + +c89d4000 <init_module>: +<span class="c1">#define OP_READ 0</span> +<span class="c1">#define OP_WRITE 1</span> +<span class="c1">#define OP_OOPS OP_WRITE</span> + +static int my_oops_init <span class="o">(</span>void<span class="o">)</span> +<span class="o">{</span> +c89d4000: <span class="m">55</span> push %ebp +<span class="c1">#else</span> +<span class="c1">#error "Unknown op for oops!"</span> +<span class="c1">#endif</span> + + <span class="k">return</span> <span class="m">0</span><span class="p">;</span> +<span class="o">}</span> +c89d4001: <span class="m">31</span> c0 xor %eax,%eax +<span class="c1">#define OP_READ 0</span> +<span class="c1">#define OP_WRITE 1</span> +<span class="c1">#define OP_OOPS OP_WRITE</span> + +static int my_oops_init <span class="o">(</span>void<span class="o">)</span> +<span class="o">{</span> +c89d4003: <span class="m">89</span> e5 mov %esp,%ebp + int *a<span class="p">;</span> + + <span class="nv">a</span> <span class="o">=</span> <span class="o">(</span>int *<span class="o">)</span> 0x00001234<span class="p">;</span> +<span class="c1">#if OP_OOPS == OP_WRITE</span> + *a <span class="o">=</span> <span class="m">3</span><span class="p">;</span> +c89d4005: c7 <span class="m">05</span> <span class="m">34</span> <span class="m">12</span> <span class="m">00</span> <span class="m">00</span> <span class="m">03</span> movl <span class="nv">$0</span>x3,0x1234 +c89d400c: <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> +<span class="c1">#else</span> +<span class="c1">#error "Unknown op for oops!"</span> +<span class="c1">#endif</span> + + <span class="k">return</span> <span class="m">0</span><span class="p">;</span> +<span class="o">}</span> +c89d400f: 5d pop %ebp +c89d4010: c3 ret +c89d4011: eb 0d jmp c89c3020 <cleanup_module> +c89d4013: <span class="m">90</span> nop +c89d4014: <span class="m">90</span> nop +c89d4015: <span class="m">90</span> nop +c89d4016: <span class="m">90</span> nop +c89d4017: <span class="m">90</span> nop +c89d4018: <span class="m">90</span> nop +c89d4019: <span class="m">90</span> nop +c89d401a: <span class="m">90</span> nop +c89d401b: <span class="m">90</span> nop +c89d401c: <span class="m">90</span> nop +c89d401d: <span class="m">90</span> nop +c89d401e: <span class="m">90</span> nop +c89d401f: <span class="m">90</span> nop + +c89d4020 <cleanup_module>: + +static void my_oops_exit <span class="o">(</span>void<span class="o">)</span> +<span class="o">{</span> +c89d4020: <span class="m">55</span> push %ebp +c89d4021: <span class="m">89</span> e5 mov %esp,%ebp +<span class="o">}</span> +c89d4023: 5d pop %ebp +c89d4024: c3 ret +c89d4025: <span class="m">90</span> nop +c89d4026: <span class="m">90</span> nop +c89d4027: <span class="m">90</span> nop +</pre></div> +</div> +<p>Note that the instruction that generated the oops (<code class="docutils literal"><span class="pre">c89d4005</span></code> identified +earlier) is:</p> +<blockquote> +<div><code class="docutils literal"><span class="pre">C89d4005:</span> <span class="pre">c7</span> <span class="pre">05</span> <span class="pre">34</span> <span class="pre">12</span> <span class="pre">00</span> <span class="pre">00</span> <span class="pre">03</span> <span class="pre">movl</span> <span class="pre">$</span> <span class="pre">0x3,0x1234</span></code></div></blockquote> +<p>That is exactly what was expected - storing value 3 at 0x0001234.</p> +<p>The <code class="file docutils literal"><span class="pre">/proc/modules</span></code> is used to find the address where a kernel module is +loaded. The <strong class="command">--adjust-vma</strong> option allows you to display instructions +relative to <code class="docutils literal"><span class="pre">0xc89d4000</span></code>. The <strong class="command">-l</strong> option displays the number of +each line in the source code interleaved with the assembly language code.</p> +</div> +<div class="section" id="addr2line"> +<h3>addr2line<a class="headerlink" href="#addr2line" title="Permalink to this headline">¶</a></h3> +<p>A more simplistic way to find the code that generated an oops is to use the +<strong class="command">addr2line</strong> utility:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>faust:~/lab-01/modul-oops# addr2line -e oops.o 0x5 +/root/lab-01/modul-oops/oops.c:23 +</pre></div> +</div> +<p>Where <code class="docutils literal"><span class="pre">0x5</span></code> is the value of the program counter (<code class="docutils literal"><span class="pre">EIP</span> <span class="pre">=</span> <span class="pre">c89d4005</span></code>) that +generated the oops, minus the base address of the module (<code class="docutils literal"><span class="pre">0xc89d4000</span></code>) +according to <code class="file docutils literal"><span class="pre">/proc/modules</span></code></p> +</div> +<div class="section" id="minicom"> +<h3>minicom<a class="headerlink" href="#minicom" title="Permalink to this headline">¶</a></h3> +<p><strong class="command">Minicom</strong> (or other equivalent utilities, eg <strong class="command">picocom</strong>, +<strong class="command">screen</strong>) is a utility that can be used to connect and interact with a +serial port. The serial port is the basic method for analyzing kernel messages +or interacting with an embedded system in the development phase. There are two +more common ways to connect:</p> +<ul class="simple"> +<li>a serial port where the device we are going to use is <code class="file docutils literal"><span class="pre">/dev/ttyS0</span></code></li> +<li>a serial USB port (FTDI) in which case the device we are going to use is +<code class="file docutils literal"><span class="pre">/dev/ttyUSB</span></code>.</li> +</ul> +<p>For the virtual machine used in the lab, the device that we need to use is +displayed after the virtual machine starts:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>char device redirected to /dev/pts/20 <span class="o">(</span>label virtiocon0<span class="o">)</span> +</pre></div> +</div> +<p>Minicom use:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1">#for connecting via COM1 and using a speed of 115,200 characters per second</span> +minicom -b <span class="m">115200</span> -D /dev/ttyS0 + +<span class="c1">#For USB serial port connection</span> +minicom -D /dev/ttyUSB0 + +<span class="c1">#To connect to the serial port of the virtual machine</span> +minicom -D /dev/pts/20 +</pre></div> +</div> +</div> +<div class="section" id="netconsole"> +<h3>netconsole<a class="headerlink" href="#netconsole" title="Permalink to this headline">¶</a></h3> +<p><strong class="command">Netconsole</strong> is a utility that allows logging of kernel debugging +messages over the network. This is useful when the disk logging system does not +work or when serial ports are not available or when the terminal does not +respond to commands. <strong class="command">Netconsole</strong> comes in the form of a kernel +module.</p> +<p>To work, it needs the following parameters:</p> +<blockquote> +<div><ul class="simple"> +<li>port, IP address, and the source interface name of the debug station</li> +<li>port, MAC address, and IP address of the machine to which the debug +messages will be sent</li> +</ul> +</div></blockquote> +<p>These parameters can be configured when the module is inserted into the kernel, +or even while the module is inserted if it has been compiled with the +<code class="docutils literal"><span class="pre">CONFIG_NETCONSOLE_DYNAMIC</span></code> option.</p> +<p>An example configuration when inserting <strong class="command">netconsole</strong> kernel module is +as follows:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>alice:~# modprobe netconsole <span class="nv">netconsole</span><span class="o">=</span><span class="m">6666</span>@192.168.191.130/eth0,6000@192.168.191.1/00:50:56:c0:00:08 +</pre></div> +</div> +<p>Thus, the debug messages on the station that has the address +<code class="docutils literal"><span class="pre">192.168.191.130</span></code> will be sent to the <code class="docutils literal"><span class="pre">eth0</span></code> interface, having source port +<code class="docutils literal"><span class="pre">6666</span></code>. The messages will be sent to <code class="docutils literal"><span class="pre">192.168.191.1</span></code> with the MAC address +<code class="docutils literal"><span class="pre">00:50:56:c0:00:08</span></code>, on port <code class="docutils literal"><span class="pre">6000</span></code>.</p> +<p>Messages can be played on the destination station using <strong class="command">netcat</strong>:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>bob:~ <span class="c1"># nc -l -p 6000 -u</span> +</pre></div> +</div> +<p>Alternatively, the destination station can configure <strong class="command">syslogd</strong> to +intercept these messages. More information can be found in +<code class="file docutils literal"><span class="pre">Documentation/networking/netconsole.txt</span></code>.</p> +</div> +<div class="section" id="printk-debugging"> +<h3>Printk debugging<a class="headerlink" href="#printk-debugging" title="Permalink to this headline">¶</a></h3> +<p><code class="docutils literal"><span class="pre">The</span> <span class="pre">two</span> <span class="pre">oldest</span> <span class="pre">and</span> <span class="pre">most</span> <span class="pre">useful</span> <span class="pre">debugging</span> <span class="pre">aids</span> <span class="pre">are</span> <span class="pre">Your</span> <span class="pre">Brain</span> <span class="pre">and</span> <span class="pre">Printf</span></code>.</p> +<p>For debugging, a primitive way is often used, but it is quite effective: +<code class="code docutils literal"><span class="pre">printk</span></code> debugging. Although a debugger can also be used, it is generally +not very useful: simple bugs (uninitialized variables, memory management +problems, etc.) can be easily localized by control messages and the +kernel-decoded oop message.</p> +<p>For more complex bugs, even a debugger can not help us too much unless the +operating system structure is very well understood. When debugging a kernel +module, there are a lot of unknowns in the equation: multiple contexts (we have +multiple processes and threads running at a time), interruptions, virtual +memory, etc.</p> +<p>You can use <code class="code docutils literal"><span class="pre">printk</span></code> to display kernel messages to user space. It is +similar to <code class="code docutils literal"><span class="pre">printf</span></code>'s functionality; the only difference is that the +transmitted message can be prefixed with a string of <code class="code docutils literal"><span class="pre">"<n>"</span></code>, where +<code class="code docutils literal"><span class="pre">n</span></code> indicates the error level (loglevel) and has values between <code class="docutils literal"><span class="pre">0</span></code> and +<code class="docutils literal"><span class="pre">7</span></code>. Instead of <code class="code docutils literal"><span class="pre">"<n>"</span></code>, the levels can also be coded by symbolic +constants:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">KERN_EMERG</span> <span class="o">-</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">0</span> +<span class="n">KERN_ALERT</span> <span class="o">-</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">1</span> +<span class="n">KERN_CRIT</span> <span class="o">-</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">2</span> +<span class="n">KERN_ERR</span> <span class="o">-</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">3</span> +<span class="n">KERN_WARNING</span> <span class="o">-</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">4</span> +<span class="n">KERN_NOTICE</span> <span class="o">-</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">5</span> +<span class="n">KERN_INFO</span> <span class="o">-</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">6</span> +<span class="n">KERN_DEBUG</span> <span class="o">-</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">7</span> +</pre></div> +</div> +<p>The definitions of all log levels are found in <code class="file docutils literal"><span class="pre">linux/kern_levels.h</span></code>. +Basically, these log levels are used by the system to route messages sent to +various outputs: console, log files in <code class="file docutils literal"><span class="pre">/var/log</span></code> etc.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>To display <code class="code docutils literal"><span class="pre">printk</span></code> messages in user space, the <code class="code docutils literal"><span class="pre">printk</span></code> +log level must be of higher priority than <cite>console_loglevel</cite> +variable. The default console log level can be configured from +<code class="file docutils literal"><span class="pre">/proc/sys/kernel/printk</span></code>.</p> +<p>For instance, the command:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nb">echo</span> <span class="m">8</span> > /proc/sys/kernel/printk +</pre></div> +</div> +<p class="last">will enable all the kernel log messages to be displayed in the +console. That is, the logging level has to be strictly less than the +<code class="code docutils literal"><span class="pre">console_loglevel</span></code> variable. For example, if the +<code class="code docutils literal"><span class="pre">console_loglevel</span></code> has a value of <code class="docutils literal"><span class="pre">5</span></code> (specific to +<code class="code docutils literal"><span class="pre">KERN_NOTICE</span></code>), only messages with loglevel stricter than <code class="docutils literal"><span class="pre">5</span></code> +(i.e <code class="code docutils literal"><span class="pre">KERN_EMERG</span></code>, <code class="code docutils literal"><span class="pre">KERN_ALERT</span></code>, <code class="code docutils literal"><span class="pre">KERN_CRIT</span></code>, +<code class="code docutils literal"><span class="pre">KERN_ERR</span></code>, <code class="code docutils literal"><span class="pre">KERN_WARNING</span></code>) will be shown.</p> +</div> +<p>Console-redirected messages can be useful for quickly viewing the effect of +executing the kernel code, but they are no longer so useful if the kernel +encounters an irreparable error and the system freezes. In this case, the logs +of the system must be consulted, as they keep the information between system +restarts. These are found in <code class="file docutils literal"><span class="pre">/var/log</span></code> and are text files, populated by +<code class="code docutils literal"><span class="pre">syslogd</span></code> and <code class="code docutils literal"><span class="pre">klogd</span></code> during the kernel run. <code class="code docutils literal"><span class="pre">syslogd</span></code> and +<code class="code docutils literal"><span class="pre">klogd</span></code> take the information from the virtual file system mounted in +<code class="file docutils literal"><span class="pre">/proc</span></code>. In principle, with <code class="code docutils literal"><span class="pre">syslogd</span></code> and <code class="code docutils literal"><span class="pre">klogd</span></code> turned on, +all messages coming from the kernel will go to <code class="file docutils literal"><span class="pre">/var/log/kern.log</span></code>.</p> +<p>A simpler version for debugging is using the <code class="file docutils literal"><span class="pre">/var/log/debug</span></code> file. It +is populated only with the <code class="code docutils literal"><span class="pre">printk</span></code> messages from the kernel with the +<code class="code docutils literal"><span class="pre">KERN_DEBUG</span></code> log level.</p> +<p>Given that a production kernel (similar to the one we're probably running with) +contains only release code, our module is among the few that send messages +prefixed with KERN_DEBUG . In this way, we can easily navigate through the +<code class="file docutils literal"><span class="pre">/var/log/debug</span></code> information by finding the messages corresponding to a +debugging session for our module.</p> +<p>Such an example would be the following:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># Clear the debug file of previous information (or possibly a backup)</span> +$ <span class="nb">echo</span> <span class="s2">"New debug session"</span> > /var/log/debug +<span class="c1"># Run the tests</span> +<span class="c1"># If there is no critical error causing a panic kernel, check the output</span> +<span class="c1"># if a critical error occurs and the machine only responds to a restart,</span> + restart the system and check /var/log/debug. +</pre></div> +</div> +<p>The format of the messages must obviously contain all the information of +interest in order to detect the error, but inserting in the code <code class="code docutils literal"><span class="pre">printk</span></code> +to provide detailed information can be as time-consuming as writing the code to +solve the problem. This is usually a trade-off between the completeness of the +debugging messages displayed using <code class="code docutils literal"><span class="pre">printk</span></code> and the time it takes to +insert these messages into the text.</p> +<p>A very simple way, less time-consuming for inserting <code class="code docutils literal"><span class="pre">printk</span></code> and +providing the possibility to analyze the flow of instructions for tests is the +use of the predefined constants <code class="code docutils literal"><span class="pre">__FILE__</span></code>, <code class="code docutils literal"><span class="pre">__LINE__</span></code> and +<code class="code docutils literal"><span class="pre">__func__</span></code>:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">__FILE__</span></code> is replaced by the compiler with the name of the source file +it is currently being compiled.</li> +<li><code class="docutils literal"><span class="pre">__LINE__</span></code> is replaced by the compiler with the line number on which the +current instruction is found in the current source file.</li> +<li><code class="docutils literal"><span class="pre">__func__</span></code> /<code class="docutils literal"><span class="pre">__FUNCTION__</span></code> is replaced by the compiler with the name +of the function in which the current instruction is found.</li> +</ul> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last"><code class="code docutils literal"><span class="pre">__FILE__</span></code> and <code class="code docutils literal"><span class="pre">__LINE__</span></code> are part of the ANSI C specifications: +<code class="code docutils literal"><span class="pre">__func__</span></code> is part of specification C99; <code class="code docutils literal"><span class="pre">__FUNCTION__</span></code> is a GNU +<code class="code docutils literal"><span class="pre">C</span></code> extension and is not portable; However, since we write code for the +<code class="code docutils literal"><span class="pre">Linux</span></code> kernel, we can use it without any problems.</p> +</div> +<p>The following macro definition can be used in this case:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define PRINT_DEBUG \</span> +<span class="cp"> printk (KERN_DEBUG "[% s]: FUNC:% s: LINE:% d \ n", __FILE__,</span> + <span class="n">__FUNCTION__</span><span class="p">,</span> <span class="n">__LINE__</span><span class="p">)</span> +</pre></div> +</div> +<p>Then, at each point where we want to see if it is "reached" in execution, +insert PRINT_DEBUG; This is a simple and quick way, and can yield by carefully +analyzing the output.</p> +<p>The <strong class="command">dmesg</strong> command is used to view the messages printed with +<code class="code docutils literal"><span class="pre">printk</span></code> but not appearing on the console.</p> +<p>To delete all previous messages from a log file, run:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>cat /dev/null > /var/log/debug +</pre></div> +</div> +<p>To delete messages displayed by the <strong class="command">dmesg</strong> command, run:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>dmesg -c +</pre></div> +</div> +</div> +<div class="section" id="dynamic-debugging"> +<h3>Dynamic debugging<a class="headerlink" href="#dynamic-debugging" title="Permalink to this headline">¶</a></h3> +<p>Dynamic <a class="reference external" href="https://www.kernel.org/doc/html/v4.15/admin-guide/dynamic-debug-howto.html">dyndbg</a> +debugging enables dynamic debugging activation/deactivation. +Unlike <code class="code docutils literal"><span class="pre">printk</span></code>, it offers more advanced <code class="code docutils literal"><span class="pre">printk</span></code> options for the +messages we want to display; it is very useful for complex modules or +troubleshooting subsystems. +This significantly reduces the amount of messages displayed, leaving only +those relevant for the debug context. To enable <code class="docutils literal"><span class="pre">dyndbg</span></code>, the kernel must be +compiled with the <code class="docutils literal"><span class="pre">CONFIG_DYNAMIC_DEBUG</span></code> option. Once configured, +<code class="code docutils literal"><span class="pre">pr_debug()</span></code>, <code class="code docutils literal"><span class="pre">dev_dbg()</span></code> and <code class="code docutils literal"><span class="pre">print_hex_dump_debug()</span></code>, +<code class="code docutils literal"><span class="pre">print_hex_dump_bytes()</span></code> can be dynamically enabled per call.</p> +<p>The <code class="file docutils literal"><span class="pre">/sys/kernel/debug/dynamic_debug/control</span></code> file from the debugfs (where +<code class="file docutils literal"><span class="pre">/sys/kernel/debug</span></code> is the path to which debugfs was mounted) is used to +filter messages or to view existing filters.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">mount</span> <span class="o">-</span><span class="n">t</span> <span class="n">debugfs</span> <span class="n">none</span> <span class="o">/</span><span class="n">debug</span> +</pre></div> +</div> +<p><a class="reference external" href="http://opensourceforu.com/2010/10/debugging-linux-kernel-with-debugfs/">Debugfs</a> +is a simple file system, used as a kernel-space interface and +user-space interface to configure different debug options. Any debug utility +can create and use its own files /folders in debugfs.</p> +<p>For example, to display existing filters in <code class="docutils literal"><span class="pre">dyndbg</span></code>, you will use:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>cat /debug/dynamic_debug/control +</pre></div> +</div> +<p>And to enable the debug message from line <code class="docutils literal"><span class="pre">1603</span></code> in the <code class="file docutils literal"><span class="pre">svcsock.c</span></code> file:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nb">echo</span> <span class="s1">'file svcsock.c line 1603 +p'</span> > /debug/dynamic_debug/control +</pre></div> +</div> +<p>The <code class="file docutils literal"><span class="pre">/debug/dynamic_debug/control</span></code> file is not a regular file. It shows +the <code class="docutils literal"><span class="pre">dyndbg</span></code> settings on the filters. Writing in it with an echo will change +these settings (it will not actually make a write). Be aware that the file +contains settings for <code class="docutils literal"><span class="pre">dyndbg</span></code> debugging messages. Do not log in this file.</p> +<div class="section" id="dyndbg-options"> +<h4>Dyndbg Options<a class="headerlink" href="#dyndbg-options" title="Permalink to this headline">¶</a></h4> +<ul> +<li><p class="first"><code class="docutils literal"><span class="pre">func</span></code> - just the debug messages from the functions that have the same +name as the one defined in the filter.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nb">echo</span> <span class="s1">'func svc_tcp_accept +p'</span> > /debug/dynamic_debug/control +</pre></div> +</div> +</li> +<li><p class="first"><code class="docutils literal"><span class="pre">file</span></code> - the name of the file(s) for which we want to display the debug +messages. It can be just the source name, but also the absolute path or +kernel-tree path.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>file svcsock.c +file kernel/freezer.c +file /usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c +</pre></div> +</div> +</li> +<li><p class="first"><code class="docutils literal"><span class="pre">module</span></code> - module name.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>module sunrpc +</pre></div> +</div> +</li> +<li><p class="first"><code class="docutils literal"><span class="pre">format</span></code> - only messages whose display format contains the specified string.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>format <span class="s2">"nfsd: SETATTR"</span> +</pre></div> +</div> +</li> +<li><p class="first"><code class="docutils literal"><span class="pre">line</span></code> - the line or lines for which we want to enable debug calls.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># Triggers debug messages between lines 1603 and 1605 in the svcsock.c file</span> +$ <span class="nb">echo</span> <span class="s1">'file svcsock.c line 1603-1605 +p'</span> > /sys/kernel/debug/dynamic_debug/control +<span class="c1"># Enables debug messages from the beginning of the file to line 1605</span> +$ <span class="nb">echo</span> <span class="s1">'file svcsock.c line -1605 +p'</span> > /sys/kernel/debug/dynamic_debug/control +</pre></div> +</div> +</li> +</ul> +<p>In addition to the above options, a series of flags can be added, removed, or set +with operators <code class="docutils literal"><span class="pre">+</span></code>, <code class="docutils literal"><span class="pre">-</span></code> or <code class="docutils literal"><span class="pre">=</span></code>:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">p</span></code> activates the pr_debug() .</li> +<li><code class="docutils literal"><span class="pre">f</span></code> includes the name of the function in the printed message.</li> +<li><code class="docutils literal"><span class="pre">l</span></code> includes the line number in the printed message.</li> +<li><code class="docutils literal"><span class="pre">m</span></code> includes the module name in the printed message.</li> +<li><code class="docutils literal"><span class="pre">t</span></code> includes the thread id if it is not called from interrupt context</li> +<li><code class="docutils literal"><span class="pre">_</span></code> no flag is set.</li> +</ul> +</div></blockquote> +</div> +</div> +<div class="section" id="kdb-kernel-debugger"> +<h3>KDB: Kernel debugger<a class="headerlink" href="#kdb-kernel-debugger" title="Permalink to this headline">¶</a></h3> +<p>The kernel debugger has proven to be very useful to facilitate the development and +debugging process. One of its main advantages is the possibility to perform live debugging. +This allows us to monitor, in real time, the accesses to memory or even modify the memory +while debugging. +The debugger has been integrated in the mainline kernel starting with version 2.6.26-rci. +KDB is not a <em>source debugger</em>, but for a complete analysis it can be used in parallel with +gdb and symbol files -- see <a class="reference internal" href="../so2/lab1-intro.html#gdb-intro"><span class="std std-ref">the GDB debugging section</span></a></p> +<p>To use KDB, you have the following options:</p> +<blockquote> +<div><ul class="simple"> +<li>non-usb keyboard + VGA text console</li> +<li>serial port console</li> +<li>USB EHCI debug port</li> +</ul> +</div></blockquote> +<p>For the lab, we will use a serial interface connected to the host. +The following command will activate GDB over the serial port:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nb">echo</span> hvc0 > /sys/module/kgdboc/parameters/kgdboc +</pre></div> +</div> +<p>KDB is a <em>stop mode debugger</em>, which means that, while it is active, all the other processes +are stopped. The kernel can be <em>forced</em> to enter KDB during execution using the following +<a class="reference external" href="http://en.wikipedia.org/wiki/Magic_SysRq_key">SysRq</a> command</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nb">echo</span> g > /proc/sysrq-trigger +</pre></div> +</div> +<p>or by using the key combination <code class="docutils literal"><span class="pre">Ctrl+O</span> <span class="pre">g</span></code> in a terminal connected to the serial port +(for example using <strong class="command">minicom</strong>).</p> +<p>KDB has various commands to control and define the context of the debugged system:</p> +<blockquote> +<div><ul class="simple"> +<li>lsmod, ps, kill, dmesg, env, bt (backtrace)</li> +<li>dump trace logs</li> +<li>hardware breakpoints</li> +<li>modifying memory</li> +</ul> +</div></blockquote> +<p>For a better description of the available commands you can use the <code class="docutils literal"><span class="pre">help</span></code> command in +the KDB shell. +In the next example, you can notice a simple KDB usage example which sets a hardware +breakpoint to monitor the changes of the <code class="docutils literal"><span class="pre">mVar</span></code> variable.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># trigger KDB</span> +<span class="nb">echo</span> g > /proc/sysrq-trigger +<span class="c1"># or if we are connected to the serial port issue</span> +Ctrl-O g +<span class="c1"># breakpoint on write access to the mVar variable</span> +kdb> bph mVar dataw +<span class="c1"># return from KDB</span> +kdb> go +</pre></div> +</div> +</div> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important" id="exercises-summary"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is kernel_modules. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/kernel_modules/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="section" id="intro"> +<h3>0. Intro<a class="headerlink" href="#intro" title="Permalink to this headline">¶</a></h3> +<p>Using <strong class="command">cscope</strong> or <a class="reference external" href="http://elixir.free-electrons.com/linux/latest/source">LXR</a> find the definitions of the following symbols +in the Linux kernel source code:</p> +<ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">module_init()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">module_exit()</span></code><ul> +<li>what do the two macros do? What is <code class="docutils literal"><span class="pre">init_module</span></code> and <code class="docutils literal"><span class="pre">cleanup_module</span></code>?</li> +</ul> +</li> +<li><code class="xref c c-data docutils literal"><span class="pre">ignore_loglevel</span></code><ul> +<li>What is this variable used for?</li> +</ul> +</li> +</ul> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>If you have problems using <strong class="command">cscope</strong>, it is possible that the database +is not generated. To generate it, use the following command in the kernel +directory:</p> +<div class="last highlight-bash"><div class="highlight"><pre><span></span>make <span class="nv">ARCH</span><span class="o">=</span>x86 cscope +</pre></div> +</div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>When searching for a structure using <strong class="command">cscope</strong>, use only the +structure name (without <code class="code docutils literal"><span class="pre">struct</span></code>). So, to search for the +structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">module</span></code>, you will use the command</p> +<blockquote> +<div><div class="highlight-bash"><div class="highlight"><pre><span></span>vim -t module +</pre></div> +</div> +</div></blockquote> +<p>or, in <strong class="command">vim</strong>, the command</p> +<blockquote class="last"> +<div><div class="highlight-bash"><div class="highlight"><pre><span></span>:cs f g module +</pre></div> +</div> +</div></blockquote> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">For more info on using <strong class="command">cscope</strong>, read the +<a class="reference internal" href="../so2/lab1-intro.html#cscope-intro"><span class="std std-ref">cscope section</span></a> in the previous lab.</p> +</div> +</div> +<div class="section" id="kernel-module"> +<h3>1. Kernel module<a class="headerlink" href="#kernel-module" title="Permalink to this headline">¶</a></h3> +<p>To work with the kernel modules, we will follow the steps described +<a class="reference internal" href="../so2/lab1-intro.html#exercises-summary"><span class="std std-ref">above</span></a>.</p> +<dl class="docutils"> +<dt>Generate the skeleton for the task named <strong>1-2-test-mod</strong> then build the module,</dt> +<dd>by running the following command in <code class="file docutils literal"><span class="pre">tools/labs</span></code>.</dd> +</dl> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nv">LABS</span><span class="o">=</span>kernel_modules make skels +$ make build +</pre></div> +</div> +<p>These command will build all the modules in the current +lab skeleton.</p> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p class="last">Until after solving exercise 3, you will get a compilation error for +<code class="docutils literal"><span class="pre">3-error-mod</span></code>. To avoid this issue, remove the directory +<code class="file docutils literal"><span class="pre">skels/kernel_modules/3-error-mod/</span></code> and remove the corresponding +line from <code class="docutils literal"><span class="pre">skels/Kbuild</span></code>.</p> +</div> +<p>Start the VM using <strong class="command">make console</strong>, and perform the following tasks:</p> +<ul class="simple"> +<li>load the kernel module.</li> +<li>list the kernel modules and check if current module is present</li> +<li>unload the kernel module</li> +<li>view the messages displayed at loading/unloading the kernel module using +<strong class="command">dmesg</strong> command</li> +</ul> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Read <a class="reference internal" href="#loading-unloading-a-kernel-module">Loading/unloading a kernel module</a> section. When unloading +a kernel module, you can specify only the module name +(without extension).</p> +</div> +</div> +<div class="section" id="printk"> +<h3>2. Printk<a class="headerlink" href="#printk" title="Permalink to this headline">¶</a></h3> +<p>Watch the virtual machine console. Why were the messages displayed directly +to the virtual machine console?</p> +<p>Configure the system such that the messages are not displayed directly +on the serial console, and they can only be inspected using <code class="docutils literal"><span class="pre">dmesg</span></code>.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">One option is to set the console log level by writting +the desired level to <code class="docutils literal"><span class="pre">/proc/sys/kernel/printk</span></code>. +Use a value smaller than the level used for the prints in +the source code of the module.</p> +</div> +<p>Load/unload the module again. +The messages should not be printed to the virtual machine console, +but they should be visible when running <code class="docutils literal"><span class="pre">dmesg</span></code>.</p> +</div> +<div class="section" id="error"> +<h3>3. Error<a class="headerlink" href="#error" title="Permalink to this headline">¶</a></h3> +<p>Generate the skeleton for the task named <strong>3-error-mod</strong>. Compile the +sources and get the corresponding kernel module.</p> +<p>Why have compilation +errors occurred? <strong>Hint:</strong> How does this module differ from the previous module?</p> +<p>Modify the module to solve the cause of those errors, then compile and test +the module.</p> +</div> +<div class="section" id="sub-modules"> +<h3>4. Sub-modules<a class="headerlink" href="#sub-modules" title="Permalink to this headline">¶</a></h3> +<p>Inspect the C source files <code class="docutils literal"><span class="pre">mod1.c</span></code> and <code class="docutils literal"><span class="pre">mod2.c</span></code> in <code class="file docutils literal"><span class="pre">4-multi-mod/</span></code>. +Module 2 contains only the definition of a function used by module 1.</p> +<p>Change the <code class="file docutils literal"><span class="pre">Kbuild</span></code> file to create the <code class="docutils literal"><span class="pre">multi_mod.ko</span></code> module from the +two C source files.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Read the <a class="reference internal" href="#compiling-kernel-modules">Compiling kernel modules</a> section of the lab.</p> +</div> +<p>Compile, copy, boot the VM, load and unload the kernel module. Make sure messages +are properly displayed on the console.</p> +</div> +<div class="section" id="kernel-oops-1"> +<h3>5. Kernel oops<a class="headerlink" href="#kernel-oops-1" title="Permalink to this headline">¶</a></h3> +<p>Enter the directory for the task <strong>5-oops-mod</strong> and inspect the +C source file. Notice where the problem will occur. Add the compilation flag +<code class="docutils literal"><span class="pre">-g</span></code> in the Kbuild file.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Read <a class="reference internal" href="#compiling-kernel-modules">Compiling kernel modules</a> section of the lab.</p> +</div> +<p>Compile the corresponding module and load it into the kernel. Identify the memory +address at which the oops appeared.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Read <a href="#system-message-1"><span class="problematic" id="problematic-1">`Debugging`_</span></a> section of the lab. To identify the +address, follow the oops message and extract the value of +the instructions pointer (<code class="docutils literal"><span class="pre">EIP</span></code>) register.</p> +</div> +<p>Determine which instruction has triggered the oops.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use the <code class="file docutils literal"><span class="pre">proc/modules</span></code> information to get the load address of +the kernel module. Use, on the physical machine, objdump +and/or addr2line . Objdump needs debugging support for +compilation! Read the lab's <a class="reference internal" href="#objdump">objdump</a> and <a class="reference internal" href="#addr2line">addr2line</a> +sections.</p> +</div> +<p>Try to unload the kernel module. Notice that the operation does not +work because there are references from the kernel module within the +kernel since the oops; Until the release of those references (which is +almost impossible in the case of an oops), the module can not be +unloaded.</p> +</div> +<div class="section" id="module-parameters"> +<h3>6. Module parameters<a class="headerlink" href="#module-parameters" title="Permalink to this headline">¶</a></h3> +<p>Enter the directory for the task <strong>6-cmd-mod</strong> and inspect the C +<code class="docutils literal"><span class="pre">cmd_mod.c</span></code> source file. Compile and copy the associated module and +load the kernel module to see the printk message. Then unload the +module from the kernel.</p> +<p>Without modifying the sources, load the kernel module so that the +message shown is <code class="docutils literal"><span class="pre">Early</span> <span class="pre">bird</span> <span class="pre">gets</span> <span class="pre">tired</span></code>.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">The str variable can be changed by passing a parameter to +the module. Find more information <a class="reference external" href="http://tldp.org/LDP/lkmpg/2.6/html/x323.html">here</a>.</p> +</div> +<span class="target" id="proc-info"></span></div> +<div class="section" id="proc-info-1"> +<h3>7. Proc info<a class="headerlink" href="#proc-info-1" title="Permalink to this headline">¶</a></h3> +<p>Check the skeleton for the task named <strong>7-list-proc</strong>. Add code to +display the Process ID (<code class="docutils literal"><span class="pre">PID</span></code>) and the executable name for the current +process.</p> +<p>Follow the commands marked with <code class="docutils literal"><span class="pre">TODO</span></code>. +The information must be displayed both when loading and unloading the +module.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<ul class="last simple"> +<li>In the Linux kernel, a process is described by the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>. Use <a class="reference external" href="http://elixir.free-electrons.com/linux/latest/source">LXR</a> or <code class="docutils literal"><span class="pre">cscope</span></code> to find the +definition of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>.</li> +<li>To find the structure field that contains the name of the +executable, look for the "executable" comment.</li> +<li>The pointer to the structure of the current process +running at a given time in the kernel is given by the +<code class="xref c c-macro docutils literal"><span class="pre">current</span></code> variable (of the type +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct*</span></code>).</li> +</ul> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">To use <code class="xref c c-macro docutils literal"><span class="pre">current</span></code> you'll need to include the header +in which the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code> is defined, i.e +<code class="docutils literal"><span class="pre">linux/sched.h</span></code>.</p> +</div> +<p>Compile, copy, boot the VM and load the module. Unload the kernel module.</p> +<p>Repeat the loading/unloading operation. Note that the PIDs of the +displayed processes differ. This is because a process is created +from the executable <code class="file docutils literal"><span class="pre">/sbin/insmod</span></code> when the module is loaded and +when the module is unloaded a process is created from the executable +<code class="file docutils literal"><span class="pre">/sbin/rmmod</span></code>.</p> +</div> +</div> +<div class="section" id="extra-exercises"> +<h2>Extra Exercises<a class="headerlink" href="#extra-exercises" title="Permalink to this headline">¶</a></h2> +<div class="section" id="kdb"> +<h3>1. KDB<a class="headerlink" href="#kdb" title="Permalink to this headline">¶</a></h3> +<p>Go to the <strong>8-kdb</strong> directory. Activate KDB over the serial port and enter KDB +mode using <strong class="command">SysRq</strong>. Connect to the pseudo-terminal linked to virtiocon0 +using <strong class="command">minicom</strong>, configure KDB to use the hvc0 serial port:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nb">echo</span> hvc0 > /sys/module/kgdboc/parameters/kgdboc +</pre></div> +</div> +<p>and enable it using SysRq (<strong class="command">Ctrl + O g</strong>). +Review the current system status (<strong class="command">help</strong> to see the available KDB +commands). Continue the kernel execution using the <strong class="command">go</strong> command.</p> +<p>Load the <code class="file docutils literal"><span class="pre">hello_kdb</span></code> module. +The module will simulate a bug when writing to the <code class="file docutils literal"><span class="pre">/proc/hello_kdb_bug</span></code> +file. To simulate a bug, use the below command:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nb">echo</span> <span class="m">1</span> > /proc/hello_kdb_bug +</pre></div> +</div> +<p>After running the above command, at every oops/panic the kernel stops the +execution and enters debug mode.</p> +<p>Analyze the stacktrace and determine the code that generated the bug. +How can we find out from KDB the address where the module was loaded?</p> +<p>In parallel, use GDB in a new window to view the code based on KDB information.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Load the symbol file. Use <strong class="command">info line</strong>.</p> +</div> +<p>When writing to <code class="file docutils literal"><span class="pre">/proc/hello_kdb_break</span></code>, the module will increment the +<code class="xref c c-data docutils literal"><span class="pre">kdb_write_address</span></code> variable. Enter KDB and set a breakpoint for each +write access of the <code class="xref c c-data docutils literal"><span class="pre">kdb_write_address</span></code> variable. +Return to kernel to trigger a write using:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nb">echo</span> <span class="m">1</span> > /proc/hello_kdb_break +</pre></div> +</div> +</div> +<div class="section" id="ps-module"> +<h3>2. PS Module<a class="headerlink" href="#ps-module" title="Permalink to this headline">¶</a></h3> +<p>Update the created kernel module at <span class="xref std std-ref">proc-info</span> in order to display +information about all the processes in the system, when inserting the kernel +module, not just about the current process. Afterwards, compare the obtained +result with the output of the <strong class="command">ps</strong> command.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<ul class="last simple"> +<li>Processes in the system are structured in a circular list.</li> +<li><code class="xref c c-macro docutils literal"><span class="pre">for_each</span> <span class="pre">_...</span></code> macros (such as <code class="xref c c-macro docutils literal"><span class="pre">for_each_process</span></code>) are +useful when you want to navigate the items in a list.</li> +<li>To understand how to use a feature or a macro, use <a class="reference external" href="http://elixir.free-electrons.com/linux/latest/source">LXR</a> or Vim and +<strong class="command">cscope</strong> and search for usage scenarios.</li> +</ul> +</div> +</div> +<div class="section" id="memory-info"> +<h3>3. Memory Info<a class="headerlink" href="#memory-info" title="Permalink to this headline">¶</a></h3> +<p>Create a kernel module that displays the virtual memory areas of the current +process; for each memory area it will display the start address and the end +address.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<ul class="last simple"> +<li>Start from an existing kernel module.</li> +<li>Investigate the structures <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>, +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code> and <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code>. A +memory area is indicated by a structure of type <code class="xref c c-type docutils literal"><span class="pre">struct</span> +<span class="pre">vm_area_struct</span></code>.</li> +<li>Don't forget to include the headers where the necessary structures are +defined.</li> +</ul> +</div> +</div> +<div class="section" id="dynamic-debugging-1"> +<h3>4. Dynamic Debugging<a class="headerlink" href="#dynamic-debugging-1" title="Permalink to this headline">¶</a></h3> +<p>Go to the <strong>9-dyndbg</strong> directory and compile the <code class="code docutils literal"><span class="pre">dyndbg.ko</span></code> module.</p> +<p>Familiarize yourself with the <code class="code docutils literal"><span class="pre">debugfs</span></code> file system mounted in +<code class="file docutils literal"><span class="pre">/debug</span></code> and analyze the contents of the file +<code class="file docutils literal"><span class="pre">/debug/dynamic_debug/control</span></code>. Insert the <code class="code docutils literal"><span class="pre">dyndbg.ko</span></code> module and +notice the new content of the <code class="file docutils literal"><span class="pre">dynamic_debug/control</span></code> file.</p> +<p>What appears extra in the respective file? Run the following command:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>grep dyndbg /debug/dynamic_debug/control +</pre></div> +</div> +<p>Configure <strong class="command">dyndbg</strong> so that only messages marked as "Important" in +<code class="xref c c-func docutils literal"><span class="pre">my_debug_func()</span></code> function are displayed when the module is unloaded. +The exercise will only filter out the <code class="xref c c-func docutils literal"><span class="pre">pr_debug()</span></code> calls; <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code> +calls being always displayed.</p> +<p>Specify two ways to filter.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Read the <a class="reference internal" href="#dynamic-debugging">Dynamic debugging</a> section and look at the <strong class="command">dyndbg</strong> +options (for example, <strong class="command">line</strong>, <strong class="command">format</strong>).</p> +</div> +<p>Perform the filtering and revise the <code class="file docutils literal"><span class="pre">dynamic_debug/control</span></code> file. What +has changed? How do you know which calls are activated?</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Check the <strong class="command">dyndbg</strong> flags. Unload the kernel module and observe the +log messages.</p> +</div> +</div> +<div class="section" id="dynamic-debugging-during-initialization"> +<h3>5. Dynamic Debugging During Initialization<a class="headerlink" href="#dynamic-debugging-during-initialization" title="Permalink to this headline">¶</a></h3> +<p>As you have noticed, <code class="xref c c-func docutils literal"><span class="pre">pr_debug()</span></code> calls can only be activated /filtered +after module insertion. In some situations, it might be helpful to view the +messages from the initialization of the module. This can be done by using a +default (fake) parameter called <strong class="command">dyndbg</strong> that can be passed as an +argument to initialize the module. With this parameter you can add /delete +<strong class="command">dyndbg</strong> flags.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Read the last part of the <a class="reference internal" href="#dynamic-debugging">Dynamic debugging</a> section and see the available +flags (e.g.: <strong class="command">+/- p</strong>).</p> +</div> +<p>Read the <a class="reference external" href="https://01.org/linuxgraphics/gfx-docs/drm/admin-guide/dynamic-debug-howto.html#debug-messages-at-module-initialization-time">Debug Messages section at Module Initialization Time</a> +and insert the module so that the messages in <code class="xref c c-func docutils literal"><span class="pre">my_debug_func()</span></code> (called +<code class="xref c c-func docutils literal"><span class="pre">dyndbg_init()</span></code>) are also displayed during initialization.</p> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p class="last">In the VM from the lab, you will need to use <strong class="command">insmod</strong> instead of +<strong class="command">modprobe</strong>.</p> +</div> +<p>Without unloading the module, deactivate <code class="xref c c-func docutils literal"><span class="pre">pr_debug()</span></code> calls.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">You can delete the set flags. Unload the kernel module.</p> +</div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="introduction.html" class="btn btn-neutral float-left" title="Introduction" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="kernel_api.html" class="btn btn-neutral float-right" title="Kernel API" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/labs/kernel_profiling.html b/refs/pull/405/merge/labs/kernel_profiling.html new file mode 100644 index 00000000..80c42a4a --- /dev/null +++ b/refs/pull/405/merge/labs/kernel_profiling.html @@ -0,0 +1,645 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Kernel Profiling — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Recommended Setup" href="../info/vm.html" /> + <link rel="prev" title="Linux Device Model" href="device_model.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_model.html">Linux Device Model</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Kernel Profiling</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lab-objectives">Lab Objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="#overview">Overview</a></li> +<li class="toctree-l2"><a class="reference internal" href="#profiling-tools">Profiling Tools</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#perf">perf</a></li> +<li class="toctree-l3"><a class="reference internal" href="#ps">ps</a></li> +<li class="toctree-l3"><a class="reference internal" href="#time">time</a></li> +<li class="toctree-l3"><a class="reference internal" href="#top">top</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#profiling-methodology">Profiling Methodology</a></li> +<li class="toctree-l2"><a class="reference internal" href="#exercises">Exercises</a></li> +<li class="toctree-l2"><a class="reference internal" href="#demo-profiling-i-o-problems">0. Demo: Profiling I/O Problems</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#investigating-reduced-responsiveness">1. Investigating Reduced Responsiveness</a></li> +<li class="toctree-l3"><a class="reference internal" href="#launching-new-threads">2. Launching New Threads</a></li> +<li class="toctree-l3"><a class="reference internal" href="#tuning-cp">3. Tuning <code class="docutils literal"><span class="pre">cp</span></code></a></li> +<li class="toctree-l3"><a class="reference internal" href="#i-o-latency">4. I/O Latency</a></li> +<li class="toctree-l3"><a class="reference internal" href="#bad-elf">5. Bad ELF</a></li> +</ul> +</li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Kernel Profiling</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/labs/kernel_profiling.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="kernel-profiling"> +<h1>Kernel Profiling<a class="headerlink" href="#kernel-profiling" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab Objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<blockquote> +<div><ul class="simple"> +<li>Familiarize yourself with the basics of Linux kernel profiling</li> +<li>Understanding basic profiling tools</li> +<li>Learning profiling methodologies and good practices</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="overview"> +<h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline">¶</a></h2> +<p>Up until now we have studied how the different components of the Linux kernel +work, and how to write drivers that interface with them in order to provide +support for devices or protocols. This has helped us understand how the Linux +kernel works, but most people will not get to write kernel drivers.</p> +<p>Nonetheless, the skills learned will help us to write applications that better +integrate with the whole operating system. In order to do this, one has to have +a good view of both the user space and the kernel space.</p> +<p>This session aims to merge the work we have done up until now in the kernel +space with real world use cases where we do not write kernel space code, but we +look through the kernel using profiling tools, in order to debug issues that +we're having when writing regular, low-level, applications.</p> +<p>Another focus of this session will be learning a general methodology for +debugging software issues, and we will approach some tools that give us insight +from the kernel on the way our application runs.</p> +</div> +<div class="section" id="profiling-tools"> +<h2>Profiling Tools<a class="headerlink" href="#profiling-tools" title="Permalink to this headline">¶</a></h2> +<p>The main tool that we will focus our attention on is <code class="docutils literal"><span class="pre">perf</span></code>, which offers +support for tracing applications, and also inspecting general aspects of the +system. We will also be using debugging tools that most people have used in +their day to day life, such as <code class="docutils literal"><span class="pre">htop</span></code>, <code class="docutils literal"><span class="pre">ps</span></code>, <code class="docutils literal"><span class="pre">lsof</span></code> and others.</p> +<div class="section" id="perf"> +<h3>perf<a class="headerlink" href="#perf" title="Permalink to this headline">¶</a></h3> +<p><code class="docutils literal"><span class="pre">perf</span></code> is a tool that instruments the CPU using +tracepoints, kprobes and uprobes. This tool allows us to take a look at what +functions are being called at a given point. This allows us to take a peak at +where the kernel is pending the most time, print out call stacks of functions, +and in general log what the CPU is running.</p> +<p><code class="docutils literal"><span class="pre">perf</span></code> integrates modules such as: +* static tracing +* dynamic tracing +* resource monitoring</p> +<p>The tracing interface that is offered by perf can be used by itself, using the +<code class="docutils literal"><span class="pre">perf</span></code> command together with its subcommands.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~# ./skels/kernel_profiling/perf + + usage: perf [--version] [--help] [OPTIONS] COMMAND [ARGS] + + The most commonly used perf commands are: + annotate Read perf.data (created by perf record) and display annotated code + archive Create archive with object files with build-ids found in perf.data file + bench General framework for benchmark suites + buildid-cache Manage build-id cache. + buildid-list List the buildids in a perf.data file + c2c Shared Data C2C/HITM Analyzer. + config Get and set variables in a configuration file. + data Data file related processing + diff Read perf.data files and display the differential profile + evlist List the event names in a perf.data file + ftrace simple wrapper for kernel's ftrace functionality + inject Filter to augment the events stream with additional information + kallsyms Searches running kernel for symbols + kmem Tool to trace/measure kernel memory properties + kvm Tool to trace/measure kvm guest os + list List all symbolic event types + lock Analyze lock events + mem Profile memory accesses + record Run a command and record its profile into perf.data + report Read perf.data (created by perf record) and display the profile + sched Tool to trace/measure scheduler properties (latencies) + script Read perf.data (created by perf record) and display trace output + stat Run a command and gather performance counter statistics + test Runs sanity tests. + timechart Tool to visualize total system behavior during a workload + top System profiling tool. + version display the version of perf binary + probe Define new dynamic tracepoints + + See 'perf help COMMAND' for more information on a specific command. +</pre></div> +</div> +<p>In the output above we can see all of perf's subcommands together with a +description of their functionality, the most significant of which are:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">stat</span></code> - displays statistics such as the number of context switches and page +faults;</li> +<li><code class="docutils literal"><span class="pre">top</span></code> - an interactive interface where we can inspect the most frequent +function calls and their caller. This interface allows us direct feedback +while profiling;</li> +<li><code class="docutils literal"><span class="pre">list</span></code> - lists the static trace point that we can instrument inside the +kernel. These are useful when trying to get an insight from inside the kernel;</li> +<li><code class="docutils literal"><span class="pre">probe</span></code> - add a dynamic trace point that instruments a function call in +order to be recorded by perf;</li> +<li><code class="docutils literal"><span class="pre">record</span></code> - records function calls and stack traces based on tracing points +defined by the user; It can also record specific function calls and their +stack traces. The record is saved in a file, named <code class="docutils literal"><span class="pre">perf.data</span></code> by default;</li> +<li><code class="docutils literal"><span class="pre">report</span></code> - displays the information saved in a perf recording.</li> +</ul> +<p>Another way to use perf's interface is through scripts that wrap over perf that +offer a higher level way of looking at events or data, without needing to know +the intricacies of the command. An example of this is the <code class="docutils literal"><span class="pre">iosnoop.sh</span></code> script, +which displays what I/O transfers are taking place.</p> +</div> +<div class="section" id="ps"> +<h3>ps<a class="headerlink" href="#ps" title="Permalink to this headline">¶</a></h3> +<p><code class="docutils literal"><span class="pre">ps</span></code> is the Linux tool that allows us to monitor the processes that are +running at a given time on the machine, including the kernel threads. This is a +simple and easy to use way of checking at a glance what processes are running on +the CPU, and what is their CPU and memory usage.</p> +<p>In order to list all the processes running, we use to <code class="docutils literal"><span class="pre">ps</span> <span class="pre">aux</span></code> command in the +following way:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span>TODO +root@qemux86:~/skels/kernel_profiling/0-demo# cd + root@qemux86:~# ps aux + USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND + root 1 0.0 0.5 2004 1256 ? Ss 12:06 0:12 init [5] + root 2 0.0 0.0 0 0 ? S 12:06 0:00 [kthreadd] + [...] + root 350 4.5 4.4 11132 10688 hvc0 T 12:07 17:21 ./io-app + root 1358 0.0 0.0 0 0 ? I 14:30 0:00 [kworker/u2:1-e + root 2293 0.1 1.5 5516 3704 ? Ss 18:18 0:00 sshd: root@pts/ + root 2295 0.0 1.3 3968 3232 pts/0 Ss+ 18:19 0:00 -sh + root 2307 0.0 0.0 0 0 ? I 18:19 0:00 [kworker/u2:2-e + root 2350 0.0 0.7 3032 1792 hvc0 R+ 18:26 0:00 ps aux + root 2392 2.6 0.0 0 0 ? D 18:31 0:00 test-script +</pre></div> +</div> +<p>One information of note is that the 7th column represents the that of the +process, <code class="docutils literal"><span class="pre">S</span></code> meaning suspended, <code class="docutils literal"><span class="pre">D</span></code> suspended due to I/O, and <code class="docutils literal"><span class="pre">R</span></code> meaning +running.</p> +</div> +<div class="section" id="time"> +<h3>time<a class="headerlink" href="#time" title="Permalink to this headline">¶</a></h3> +<p>The <code class="docutils literal"><span class="pre">time</span></code> command allows us to inspect the amount of time spent by a +process in I/O, running the application code, or running code in kernel space. +This can be useful in order to find out whether an application's issue comes +from running too much in kernel space, so it has some overhead when it does +system calls, or the issue is in the user code.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span>root@qemux86:~# time dd if=/dev/urandom of=./test-file bs=1K count=10 +10+0 records in +10+0 records out +10240 bytes (10 kB, 10 KiB) copied, 0.00299749 s, 3.4 MB/s + +real 0m0.020s +user 0m0.001s +sys 0m0.015s +</pre></div> +</div> +<p>In the output above we timed the generation of a file using <code class="docutils literal"><span class="pre">dd</span></code>. The result +of the timing is displayed at the bottom of output. The values outputted by the +tool are the following:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">real</span></code> - the amount of time has passed from the start of the application to +its finishing;</li> +<li><code class="docutils literal"><span class="pre">user</span></code> - time spent running the <code class="docutils literal"><span class="pre">dd</span></code> code;</li> +<li><code class="docutils literal"><span class="pre">sys</span></code> - time spent running kernel code on behalf of the process.</li> +</ul> +<p>We see that the sum of the <code class="docutils literal"><span class="pre">user</span></code> and <code class="docutils literal"><span class="pre">sys</span></code> values doesn't add up to the +<code class="docutils literal"><span class="pre">real</span></code> value. This happens either when the application runs on multiple cores, +in which case the sum might be higher, or the application sleeps, in which case +the sum is lower.</p> +</div> +<div class="section" id="top"> +<h3>top<a class="headerlink" href="#top" title="Permalink to this headline">¶</a></h3> +<p><code class="docutils literal"><span class="pre">top</span></code> is an application that is found on most systems which lists in real time +the applications that are running on the system. <code class="docutils literal"><span class="pre">top</span></code> runs interactively, and +it auto-refreshes its output, as opposed to <code class="docutils literal"><span class="pre">ps</span></code>. We use this tool when we +want a high level of continuous monitoring.</p> +</div> +</div> +<div class="section" id="profiling-methodology"> +<h2>Profiling Methodology<a class="headerlink" href="#profiling-methodology" title="Permalink to this headline">¶</a></h2> +<p>When doing profiling, our goal is to identify the cause of a problem. Usually +this problem is observed by someone when their application doesn't work as +expected. When we say that an application did not work as expected, this can +mean different things for different people. For example, one person might +complain that the application has a slowdown, while another might say that the +application runs on the CPU, but it doesn't output anything.</p> +<p>The first step in any problem solving context is to understand the default +behaviour of the application we're trying to debug, and to make sure that it is +now not running in the expected parameters.</p> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is kernel_profiling. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/kernel_profiling/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">This session will require us to use the <code class="docutils literal"><span class="pre">perf</span></code> tracing tool. When running +natively on our systems, we have to install the +<code class="docutils literal"><span class="pre">linux-tools-<version>-generic</span></code> package using a package manager in order +to run it. Because in our visual machine we don't have access to a package +manager, we will be downloading the <code class="docutils literal"><span class="pre">perf</span></code> binary from <a class="reference external" href="http://swarm.cs.pub.ro/~sweisz/perf">this</a> link. Download the application in +the <code class="docutils literal"><span class="pre">skels/kernel_profiling</span></code> directory, and grant in execution +permissions.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p class="last">When running <code class="docutils literal"><span class="pre">perf</span></code>, make sure that you're running the downloaded version, +not the version in the <code class="docutils literal"><span class="pre">PATH</span></code> variable.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">When going through this session's exercises, we will have to run command in +parallel. In order to do this, we will have to connect to the virtual machine +using SSH. We recommend using the <code class="docutils literal"><span class="pre">core-image-sato-sdk-qemu</span></code> image, since it +has the tools that we need. To run the virtual machine using the +<code class="docutils literal"><span class="pre">core-image-sato-sdk-qemu</span></code> file system, uncomment line 16 in the +<code class="docutils literal"><span class="pre">qemu/Makefile</span></code> file.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">If you wish to run the <code class="docutils literal"><span class="pre">perf-tools</span></code> based scripts that we have included in +the repository, such as <code class="docutils literal"><span class="pre">iosnoop.sh</span></code>, you will have to grant it execution +privilleges, in order to be copied to the virtual machine file system.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>In order to improve the course of SO2, its components and the way it is +conducted, your opinions are very useful to us. Please fill the feedback form +on <a class="reference external" href="https://curs.upb.ro/2022/mod/feedbackadm/view.php?id=15292">curs.upb.ro platform</a>.</p> +<p>The form is anonymous and is active between May 22 and June 2, 2023. The +results will be visible to the SO2 team after all the grades have been +marked.</p> +<p>We invite you to evaluate the activity of the SO2 team and specify its +strengths and weaknesses and your suggestions for improving the subject. +Your feedback is very important to us to increase the quality of the subject +in the coming years.</p> +<p>We are particularly interested in:</p> +<blockquote class="last"> +<div><ul class="simple"> +<li>What did you not like and what do you think did not go well?</li> +<li>Why didn't you like it and why do you think it didn't go well?</li> +<li>What should we do to make things better?</li> +</ul> +</div></blockquote> +</div> +</div> +<div class="section" id="demo-profiling-i-o-problems"> +<h2>0. Demo: Profiling I/O Problems<a class="headerlink" href="#demo-profiling-i-o-problems" title="Permalink to this headline">¶</a></h2> +<p>When working with I/O, we have to keep in mind that it is one of the slowest +systems in the operating system, compared to memory, which is an order of +magnitude faster, and scheduling, which deals with what is currently running on +the CPU.</p> +<p>Because of this, I/O operations have do be thought out, because you might starve +you application by saturating the system with requests. Another issue that you +might face is that the I/O's slow speed might affect your application's +responsiveness, if it waits for the I/O operations to finish.</p> +<p>Let's take a look at an application and debug its issues.</p> +<p>We are going to run the <code class="docutils literal"><span class="pre">io-app</span></code> application, from the <code class="docutils literal"><span class="pre">0-demo</span></code> directory.</p> +<p>In order to inspect what is running on the CPU, and look at the stack of the +process, we can use the <code class="docutils literal"><span class="pre">perf</span> <span class="pre">record</span></code> subcommand in the following way:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~# ./perf record -a -g +Couldn't synthesize bpf events. +^C[ perf record: Woken up 7 times to write data ] +[ perf record: Captured and wrote 1.724 MB perf.data (8376 samples) ] +</pre></div> +</div> +<p>perf will record values indefinitely, but we can close it using the <code class="docutils literal"><span class="pre">Ctrl+c</span></code> +hotkey. We used the <code class="docutils literal"><span class="pre">-a</span></code> option in order to probe all CPUs, and <code class="docutils literal"><span class="pre">-g</span></code> option, +which record the whole call stack.</p> +<p>To visualize the recorded information, we will use the <code class="docutils literal"><span class="pre">perf</span> <span class="pre">report</span></code> command, +which will bring up a pager which will display the most frequent function calls +that were found on the CPU, and their call stack.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~# ./perf report --header -F overhead,comm,parent +<span class="c1"># Total Lost Samples: 0</span> +<span class="c1">#</span> +<span class="c1"># Samples: 8K of event 'cpu-clock:pppH'</span> +<span class="c1"># Event count (approx.): 2094000000</span> +<span class="c1">#</span> +<span class="c1"># Overhead Command Parent symbol</span> +<span class="c1"># ........ ............... .............</span> +<span class="c1">#</span> + <span class="m">58</span>.63% io-app <span class="o">[</span>other<span class="o">]</span> + <span class="p">|</span> + --58.62%--__libc_start_main + main + __kernel_vsyscall + <span class="p">|</span> + --58.61%--__irqentry_text_end + do_SYSENTER_32 + do_fast_syscall_32 + __noinstr_text_start + __ia32_sys_write + ksys_write + vfs_write + <span class="p">|</span> + --58.60%--ext4_file_write_iter + ext4_buffered_write_iter +<span class="o">[</span>...<span class="o">]</span> +</pre></div> +</div> +<p>We have used the <code class="docutils literal"><span class="pre">--header</span></code> in order to print the table header, and <code class="docutils literal"><span class="pre">-F</span> +<span class="pre">overhead,comm,parent</span></code>, in order to print the percentage of time where the call +stack, the command and the caller.</p> +<p>We can see that the <code class="docutils literal"><span class="pre">io-app</span></code> command is doing some writes in the file system, +and this contributes to much of the load on the system.</p> +<p>Armed with this information, we know that there are many I/O calls being done by +the application. In order to look at the size of these requests, we can use the +<code class="docutils literal"><span class="pre">iosnoop.sh</span></code> script in order to see how big these requests are.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~/skels/kernel_profiling# ./iosnoop.sh <span class="m">1</span> +Tracing block I/O. Ctrl-C to end. +COMM PID TYPE DEV BLOCK BYTES LATms +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">4800512</span> <span class="m">1310720</span> <span class="m">2</span>.10 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">4803072</span> <span class="m">1310720</span> <span class="m">2</span>.04 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">4805632</span> <span class="m">1310720</span> <span class="m">2</span>.03 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">4808192</span> <span class="m">1310720</span> <span class="m">2</span>.43 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">4810752</span> <span class="m">1310720</span> <span class="m">3</span>.48 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">4813312</span> <span class="m">1310720</span> <span class="m">3</span>.46 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">4815872</span> <span class="m">524288</span> <span class="m">1</span>.03 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">5029888</span> <span class="m">1310720</span> <span class="m">5</span>.82 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">5032448</span> <span class="m">786432</span> <span class="m">5</span>.80 +jbd2/vda-43 <span class="m">43</span> WS <span class="m">254</span>,0 <span class="m">2702392</span> <span class="m">8192</span> <span class="m">0</span>.22 +kworker/0:1H <span class="m">34</span> WS <span class="m">254</span>,0 <span class="m">2702408</span> <span class="m">4096</span> <span class="m">0</span>.40 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">4800512</span> <span class="m">1310720</span> <span class="m">2</span>.60 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">4803072</span> <span class="m">1310720</span> <span class="m">2</span>.58 +<span class="o">[</span>...<span class="o">]</span> +</pre></div> +</div> +<p>From this output we see that the <code class="docutils literal"><span class="pre">io-app</span></code> is reading in a loop from the fact +that the first block <code class="docutils literal"><span class="pre">4800512</span></code> is repeating, and that it is doing big reads, +since it is reading one megabyte fer request. This constant looping adds the +load to the system that we're experiencing.</p> +<div class="section" id="investigating-reduced-responsiveness"> +<h3>1. Investigating Reduced Responsiveness<a class="headerlink" href="#investigating-reduced-responsiveness" title="Permalink to this headline">¶</a></h3> +<p>The <code class="docutils literal"><span class="pre">io.ko</span></code> module, located in the <code class="docutils literal"><span class="pre">kernel_profiling/1-io</span></code> directory, +decreases the system's responsiveness when inserted. We see that the command +line stutters when typing commands, but when running top, we see that the +system's load is not high, and there aren't any processes that are hogging +resources.</p> +<p>Find out what the <code class="docutils literal"><span class="pre">io.ko</span></code> module is doing and why is it leading to the +stuttering effect that we experience.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Trace all the functions being called and check where the CPU is +spending most of its time. In order to do this, you can run either <code class="docutils literal"><span class="pre">perf</span> +<span class="pre">record</span></code> and <code class="docutils literal"><span class="pre">perf</span> <span class="pre">report</span></code> to view the output, or <code class="docutils literal"><span class="pre">perf</span> <span class="pre">top</span></code>.</p> +</div> +</div> +<div class="section" id="launching-new-threads"> +<h3>2. Launching New Threads<a class="headerlink" href="#launching-new-threads" title="Permalink to this headline">¶</a></h3> +<p>We want to run the same function in a loop 100 times in parallel. We have +implemented two solutions inside the <code class="docutils literal"><span class="pre">scheduling</span></code> binary file, located in the +<code class="docutils literal"><span class="pre">kernel_profiling/2-scheduling</span></code> directory.</p> +<p>When executing the <code class="docutils literal"><span class="pre">scheduling</span></code> binary, it prints a message in parallel from +100 running instances. We can tune this execution by running the application +either with the first parameter <code class="docutils literal"><span class="pre">0</span></code> or <code class="docutils literal"><span class="pre">1</span></code>.</p> +<p>Find out which solution is better, and why.</p> +</div> +<div class="section" id="tuning-cp"> +<h3>3. Tuning <code class="docutils literal"><span class="pre">cp</span></code><a class="headerlink" href="#tuning-cp" title="Permalink to this headline">¶</a></h3> +<p>Our goal is to write a copy of the <code class="docutils literal"><span class="pre">cp</span></code> tool integrated in Linux, which has +been implemented by the <code class="docutils literal"><span class="pre">memory</span></code> binary, in the <code class="docutils literal"><span class="pre">kernel_profiling/3-memory</span></code> +directory. It implements two approaches that we can take for the copy operation:</p> +<ul class="simple"> +<li>reading the contents of the source file in a buffer in memory using the +<code class="docutils literal"><span class="pre">read()</span></code> system call, and writing that buffer to the destination file using +the <code class="docutils literal"><span class="pre">write()</span></code> system call;</li> +<li>mapping the source and destination files to memory using the <code class="docutils literal"><span class="pre">mmap</span></code> system +call, and copying the contents of the source file to the destination in +memory.</li> +</ul> +<p>Another tunable parameter that we're going to use is the block size of to copies +that we're going to make, either through reads/writes or in memory.</p> +<p>1) Investigate which of the two copying mechanisms is faster. For this step, you +will use the 1024 block size.</p> +<p>2) Once you have found which copying mechanism is faster, change the block size +parameter and see which value gives you the best copies. Why?</p> +</div> +<div class="section" id="i-o-latency"> +<h3>4. I/O Latency<a class="headerlink" href="#i-o-latency" title="Permalink to this headline">¶</a></h3> +<p>We have written a module that reads the content of a disk. Insert the <code class="docutils literal"><span class="pre">bio.ko</span></code> +module, located in the <code class="docutils literal"><span class="pre">4-bio</span></code> module, we see a large spike in the system's +load, as can be seen in the <code class="docutils literal"><span class="pre">top</span></code> command, but we see that the system is still +responsive.</p> +<p>Investigate what is causing the increased load to the system. Is it an I/O issue, +or is it a scheduling issue?</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Try to trace the I/O operations using <code class="docutils literal"><span class="pre">perf</span></code>, or use the +<code class="docutils literal"><span class="pre">iosnoop.sh</span></code> script in order to inspect what I/O is happening at a +certain point.</p> +</div> +</div> +<div class="section" id="bad-elf"> +<h3>5. Bad ELF<a class="headerlink" href="#bad-elf" title="Permalink to this headline">¶</a></h3> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">This is a bonus exercise that has been tested on a native Linux system. +It may run under the QEMU virtual machine, but the behavior was weird in our testing. +We recommend you used a native (or VirtualBox or VMware) Linux system.</p> +</div> +<p>We managed to build (as part of a <a class="reference external" href="https://github.com/unikraft/unikraft">Unikraft</a> build) an ELF file that is valid when doing static analysis, but that can't be executed. +The file is <code class="docutils literal"><span class="pre">bad_elf</span></code>, located in the <code class="docutils literal"><span class="pre">5-bad-elf/</span></code> folder.</p> +<p>Running it triggers a <em>segmentation fault</em> message. +Running it using <code class="docutils literal"><span class="pre">strace</span></code> show an error with <code class="docutils literal"><span class="pre">execve()</span></code>.</p> +<div class="code highlight-none"><div class="highlight"><pre><span></span>... skels/kernel_profiling/5-bad-elf$ ./bad_elf +Segmentation fault + +... skels/kernel_profiling/5-bad-elf$ strace ./bad_elf +execve("./bad_elf", ["./bad_elf"], 0x7ffc3349ba50 /* 70 vars \*/) = -1 EINVAL (Invalid argument) +--- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=NULL} --- ++++ killed by SIGSEGV +++ +Segmentation fault (core dumped) +</pre></div> +</div> +<p>The ELF file itself is valid:</p> +<div class="code highlight-none"><div class="highlight"><pre><span></span>... skels/kernel_profiling/5-bad-elf$ readelf -a bad_elf +</pre></div> +</div> +<p>The issue is to be detected in the kernel.</p> +<p>Use either <code class="docutils literal"><span class="pre">perf</span></code>, or, better yet <a class="reference external" href="https://jvns.ca/blog/2017/03/19/getting-started-with-ftrace/">ftrace</a> to inspect the kernel function calls done by the program. +Identify the function call that sends out the <code class="docutils literal"><span class="pre">SIGSEGV</span></code> signal. +Identify the cause of the issue. +Find that cause in the <a class="reference external" href="https://linux.die.net/man/5/elf">manual page elf(5)</a>.</p> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="device_model.html" class="btn btn-neutral float-left" title="Linux Device Model" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../info/vm.html" class="btn btn-neutral float-right" title="Recommended Setup" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/labs/memory_mapping.html b/refs/pull/405/merge/labs/memory_mapping.html new file mode 100644 index 00000000..8587a6d6 --- /dev/null +++ b/refs/pull/405/merge/labs/memory_mapping.html @@ -0,0 +1,674 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Memory mapping — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Linux Device Model" href="device_model.html" /> + <link rel="prev" title="Kernel Development on ARM" href="arm_kernel_development.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Memory mapping</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="#overview">Overview</a></li> +<li class="toctree-l2"><a class="reference internal" href="#structures-used-for-memory-mapping">Structures used for memory mapping</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#struct-page"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code></a></li> +<li class="toctree-l3"><a class="reference internal" href="#struct-vm-area-struct"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code></a></li> +<li class="toctree-l3"><a class="reference internal" href="#struct-mm-struct"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code></a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#device-driver-memory-mapping">Device driver memory mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="#further-reading">Further reading</a></li> +<li class="toctree-l2"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#mapping-contiguous-physical-memory-to-userspace">1. Mapping contiguous physical memory to userspace</a></li> +<li class="toctree-l3"><a class="reference internal" href="#mapping-non-contiguous-physical-memory-to-userspace">2. Mapping non-contiguous physical memory to userspace</a></li> +<li class="toctree-l3"><a class="reference internal" href="#read-write-operations-in-mapped-memory">3. Read / write operations in mapped memory</a></li> +<li class="toctree-l3"><a class="reference internal" href="#display-memory-mapped-in-procfs">4. Display memory mapped in procfs</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Memory mapping</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/labs/memory_mapping.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="memory-mapping"> +<h1>Memory mapping<a class="headerlink" href="#memory-mapping" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>Understand address space mapping mechanisms</li> +<li>Learn about the most important structures related to memory management</li> +</ul> +<p>Keywords:</p> +<ul class="simple"> +<li>address space</li> +<li><code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_struct</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">remap_pfn_range</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">SetPageReserved()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">ClearPageReserved()</span></code></li> +</ul> +</div> +<div class="section" id="overview"> +<h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline">¶</a></h2> +<p>In the Linux kernel it is possible to map a kernel address space to a +user address space. This eliminates the overhead of copying user space +information into the kernel space and vice versa. This can be done +through a device driver and the user space device interface +(<code class="file docutils literal"><span class="pre">/dev</span></code>).</p> +<p>This feature can be used by implementing the <code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> operation +in the device driver's <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code> and using the +<code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> system call in user space.</p> +<p>The basic unit for virtual memory management is a page, which size is +usually 4K, but it can be up to 64K on some platforms. Whenever we +work with virtual memory we work with two types of addresses: virtual +address and physical address. All CPU access (including from kernel +space) uses virtual addresses that are translated by the MMU into +physical addresses with the help of page tables.</p> +<p>A physical page of memory is identified by the Page Frame Number +(PFN). The PFN can be easily computed from the physical address by +dividing it with the size of the page (or by shifting the physical +address with PAGE_SHIFT bits to the right).</p> +<a class="reference internal image-reference" href="../_images/paging.png"><img alt="../_images/paging.png" src="../_images/paging.png" style="width: 49%;" /></a> +<p>For efficiency reasons, the virtual address space is divided into +user space and kernel space. For the same reason, the kernel space +contains a memory mapped zone, called <strong>lowmem</strong>, which is contiguously +mapped in physical memory, starting from the lowest possible physical +address (usually 0). The virtual address where lowmem is mapped is +defined by <code class="xref c c-macro docutils literal"><span class="pre">PAGE_OFFSET</span></code>.</p> +<p>On a 32bit system, not all available memory can be mapped in lowmem and +because of that there is a separate zone in kernel space called +<strong>highmem</strong> which can be used to arbitrarily map physical memory.</p> +<p>Memory allocated by <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> resides in lowmem and it is +physically contiguous. Memory allocated by <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code> is not +contiguous and does not reside in lowmem (it has a dedicated zone in +highmem).</p> +<a class="reference internal image-reference" href="../_images/kernel-virtmem-map.png"><img alt="../_images/kernel-virtmem-map.png" src="../_images/kernel-virtmem-map.png" style="width: 49%;" /></a> +</div> +<div class="section" id="structures-used-for-memory-mapping"> +<h2>Structures used for memory mapping<a class="headerlink" href="#structures-used-for-memory-mapping" title="Permalink to this headline">¶</a></h2> +<p>Before discussing about the memory mapping mechanism over a device, +we will present some of the basic structures used by the Linux memory +management subsystem. +Some of the basic structures are: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code>, +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code>, <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code>.</p> +<div class="section" id="struct-page"> +<h3><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code><a class="headerlink" href="#struct-page" title="Permalink to this headline">¶</a></h3> +<p><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code> is used to embed information about all physical +pages in the system. The kernel has a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code> structure +for all pages in the system.</p> +<p>There are many functions that interact with this structure:</p> +<ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">virt_to_page()</span></code> returns the page associated with a virtual +address</li> +<li><code class="xref c c-func docutils literal"><span class="pre">pfn_to_page()</span></code> returns the page associated with a page frame +number</li> +<li><code class="xref c c-func docutils literal"><span class="pre">page_to_pfn()</span></code> return the page frame number associated with a +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">page_address()</span></code> returns the virtual address of a +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code>; this functions can be called only for pages from +lowmem</li> +<li><code class="xref c c-func docutils literal"><span class="pre">kmap()</span></code> creates a mapping in kernel for an arbitrary physical +page (can be from highmem) and returns a virtual address that can be +used to directly reference the page</li> +</ul> +</div> +<div class="section" id="struct-vm-area-struct"> +<h3><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code><a class="headerlink" href="#struct-vm-area-struct" title="Permalink to this headline">¶</a></h3> +<p><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code> holds information about a contiguous +virtual memory area. The memory areas of a process can be viewed by +inspecting the <em>maps</em> attribute of the process via procfs:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>root@qemux86:~# cat /proc/1/maps +<span class="c1">#address perms offset device inode pathname</span> +<span class="m">08048000</span>-08050000 r-xp <span class="m">00000000</span> fe:00 <span class="m">761</span> /sbin/init.sysvinit +<span class="m">08050000</span>-08051000 r--p <span class="m">00007000</span> fe:00 <span class="m">761</span> /sbin/init.sysvinit +<span class="m">08051000</span>-08052000 rw-p <span class="m">00008000</span> fe:00 <span class="m">761</span> /sbin/init.sysvinit +092e1000-09302000 rw-p <span class="m">00000000</span> <span class="m">00</span>:00 <span class="m">0</span> <span class="o">[</span>heap<span class="o">]</span> +4480c000-4482e000 r-xp <span class="m">00000000</span> fe:00 <span class="m">576</span> /lib/ld-2.25.so +4482e000-4482f000 r--p <span class="m">00021000</span> fe:00 <span class="m">576</span> /lib/ld-2.25.so +4482f000-44830000 rw-p <span class="m">00022000</span> fe:00 <span class="m">576</span> /lib/ld-2.25.so +<span class="m">44832000</span>-449a9000 r-xp <span class="m">00000000</span> fe:00 <span class="m">581</span> /lib/libc-2.25.so +449a9000-449ab000 r--p <span class="m">00176000</span> fe:00 <span class="m">581</span> /lib/libc-2.25.so +449ab000-449ac000 rw-p <span class="m">00178000</span> fe:00 <span class="m">581</span> /lib/libc-2.25.so +449ac000-449af000 rw-p <span class="m">00000000</span> <span class="m">00</span>:00 <span class="m">0</span> +b7761000-b7763000 rw-p <span class="m">00000000</span> <span class="m">00</span>:00 <span class="m">0</span> +b7763000-b7766000 r--p <span class="m">00000000</span> <span class="m">00</span>:00 <span class="m">0</span> <span class="o">[</span>vvar<span class="o">]</span> +b7766000-b7767000 r-xp <span class="m">00000000</span> <span class="m">00</span>:00 <span class="m">0</span> <span class="o">[</span>vdso<span class="o">]</span> +bfa15000-bfa36000 rw-p <span class="m">00000000</span> <span class="m">00</span>:00 <span class="m">0</span> <span class="o">[</span>stack<span class="o">]</span> +</pre></div> +</div> +<p>A memory area is characterized by a start address, a stop address, +length, permissions.</p> +<p>A <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code> is created at each <code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> +call issued from user space. A driver that supports the <code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> +operation must complete and initialize the associated +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code>. The most important fields of this +structure are:</p> +<ul class="simple"> +<li><code class="xref c c-member docutils literal"><span class="pre">vm_start</span></code>, <code class="xref c c-member docutils literal"><span class="pre">vm_end</span></code> - the beginning and the end of +the memory area, respectively (these fields also appear in +<code class="file docutils literal"><span class="pre">/proc/<pid>/maps</span></code>);</li> +<li><code class="xref c c-member docutils literal"><span class="pre">vm_file</span></code> - the pointer to the associated file structure (if any);</li> +<li><code class="xref c c-member docutils literal"><span class="pre">vm_pgoff</span></code> - the offset of the area within the file;</li> +<li><code class="xref c c-member docutils literal"><span class="pre">vm_flags</span></code> - a set of flags;</li> +<li><code class="xref c c-member docutils literal"><span class="pre">vm_ops</span></code> - a set of working functions for this area</li> +<li><code class="xref c c-member docutils literal"><span class="pre">vm_next</span></code>, <code class="xref c c-member docutils literal"><span class="pre">vm_prev</span></code> - the areas of the same process +are chained by a list structure</li> +</ul> +</div> +<div class="section" id="struct-mm-struct"> +<h3><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code><a class="headerlink" href="#struct-mm-struct" title="Permalink to this headline">¶</a></h3> +<p><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code> encompasses all memory areas associated +with a process. The <code class="xref c c-member docutils literal"><span class="pre">mm</span></code> field of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code> +is a pointer to the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code> of the current process.</p> +</div> +</div> +<div class="section" id="device-driver-memory-mapping"> +<h2>Device driver memory mapping<a class="headerlink" href="#device-driver-memory-mapping" title="Permalink to this headline">¶</a></h2> +<p>Memory mapping is one of the most interesting features of a Unix +system. From a driver's point of view, the memory-mapping facility +allows direct memory access to a user space device.</p> +<p>To assign a <code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> operation to a driver, the <code class="xref c c-member docutils literal"><span class="pre">mmap</span></code> +field of the device driver's <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code> must be +implemented. If that is the case, the user space process can then use +the <code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> system call on a file descriptor associated with +the device.</p> +<p>The mmap system call takes the following parameters:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="o">*</span><span class="nf">mmap</span><span class="p">(</span><span class="n">caddr_t</span> <span class="n">addr</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">len</span><span class="p">,</span> <span class="kt">int</span> <span class="n">prot</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">flags</span><span class="p">,</span> <span class="kt">int</span> <span class="n">fd</span><span class="p">,</span> <span class="kt">off_t</span> <span class="n">offset</span><span class="p">);</span> +</pre></div> +</div> +<p>To map memory between a device and user space, the user process must +open the device and issue the <code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> system call with the resulting +file descriptor.</p> +<p>The device driver <code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> operation has the following signature:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">mmap</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">filp</span><span class="p">,</span> <span class="k">struct</span> <span class="n">vm_area_struct</span> <span class="o">*</span><span class="n">vma</span><span class="p">);</span> +</pre></div> +</div> +<p>The <em>filp</em> field is a pointer to a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file</span></code> created when +the device is opened from user space. The <em>vma</em> field is used to +indicate the virtual address space where the memory should be mapped +by the device. A driver should allocate memory (using +<code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">alloc_pages()</span></code>) and then +map it to the user address space as indicated by the <em>vma</em> parameter +using helper functions such as <code class="xref c c-func docutils literal"><span class="pre">remap_pfn_range()</span></code>.</p> +<p><code class="xref c c-func docutils literal"><span class="pre">remap_pfn_range()</span></code> will map a contiguous physical address space +into the virtual space represented by <code class="xref c c-type docutils literal"><span class="pre">vm_area_struct</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="nf">remap_pfn_range</span> <span class="p">(</span><span class="n">structure</span> <span class="n">vm_area_struct</span> <span class="o">*</span><span class="n">vma</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">addr</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">pfn</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">size</span><span class="p">,</span> <span class="n">pgprot_t</span> <span class="n">prot</span><span class="p">);</span> +</pre></div> +</div> +<p><code class="xref c c-func docutils literal"><span class="pre">remap_pfn_range()</span></code> expects the following parameters:</p> +<ul class="simple"> +<li><em>vma</em> - the virtual memory space in which mapping is made;</li> +<li><em>addr</em> - the virtual address space from where remapping begins; page +tables for the virtual address space between addr and addr + size +will be formed as needed</li> +<li><em>pfn</em> - the page frame number to which the virtual address should be +mapped</li> +<li><em>size</em> - the size (in bytes) of the memory to be mapped</li> +<li><em>prot</em> - protection flags for this mapping</li> +</ul> +<p>Here is an example of using this function that contiguously maps the +physical memory starting at page frame number <em>pfn</em> (memory that was +previously allocated) to the <em>vma->vm_start</em> virtual address:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">vm_area_struct</span> <span class="o">*</span><span class="n">vma</span><span class="p">;</span> +<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">len</span> <span class="o">=</span> <span class="n">vma</span><span class="o">-></span><span class="n">vm_end</span> <span class="o">-</span> <span class="n">vma</span><span class="o">-></span><span class="n">vm_start</span><span class="p">;</span> +<span class="kt">int</span> <span class="n">ret</span> <span class="p">;</span> + +<span class="n">ret</span> <span class="o">=</span> <span class="n">remap_pfn_range</span><span class="p">(</span><span class="n">vma</span><span class="p">,</span> <span class="n">vma</span><span class="o">-></span><span class="n">vm_start</span><span class="p">,</span> <span class="n">pfn</span><span class="p">,</span> <span class="n">len</span><span class="p">,</span> <span class="n">vma</span><span class="o">-></span><span class="n">vm_page_prot</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="n">ret</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="n">pr_err</span><span class="p">(</span><span class="s">"could not map the address area</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EIO</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>To obtain the page frame number of the physical memory we must +consider how the memory allocation was performed. For each +<code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">alloc_pages()</span></code>, we must +used a different approach. For <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> we can use something +like:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">char</span> <span class="o">*</span><span class="n">kmalloc_area</span><span class="p">;</span> + +<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">pfn</span> <span class="o">=</span> <span class="n">virt_to_phys</span><span class="p">((</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">kmalloc_area</span><span class="p">)</span><span class="o">>></span><span class="n">PAGE_SHIFT</span><span class="p">;</span> +</pre></div> +</div> +<p>while for <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">char</span> <span class="o">*</span><span class="n">vmalloc_area</span><span class="p">;</span> + +<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">pfn</span> <span class="o">=</span> <span class="n">vmalloc_to_pfn</span><span class="p">(</span><span class="n">vmalloc_area</span><span class="p">);</span> +</pre></div> +</div> +<p>and finally for <code class="xref c c-func docutils literal"><span class="pre">alloc_pages()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">;</span> + +<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">pfn</span> <span class="o">=</span> <span class="n">page_to_pfn</span><span class="p">(</span><span class="n">page</span><span class="p">);</span> +</pre></div> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">Note that memory allocated with <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code> is not +physically contiguous so if we want to map a range allocated +with <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code>, we have to map each page individually +and compute the physical address for each page.</p> +</div> +<p>Since the pages are mapped to user space, they might be swapped +out. To avoid this we must set the PG_reserved bit on the page. +Enabling is done using <code class="xref c c-func docutils literal"><span class="pre">SetPageReserved()</span></code> while reseting it +(which must be done before freeing the memory) is done with +<code class="xref c c-func docutils literal"><span class="pre">ClearPageReserved()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">alloc_mmap_pages</span><span class="p">(</span><span class="kt">int</span> <span class="n">npages</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">i</span><span class="p">;</span> + <span class="kt">char</span> <span class="o">*</span><span class="n">mem</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="n">PAGE_SIZE</span> <span class="o">*</span> <span class="n">npages</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">mem</span><span class="p">)</span> + <span class="k">return</span> <span class="n">mem</span><span class="p">;</span> + + <span class="k">for</span><span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">npages</span> <span class="o">*</span> <span class="n">PAGE_SIZE</span><span class="p">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="n">PAGE_SIZE</span><span class="p">)</span> + <span class="n">SetPageReserved</span><span class="p">(</span><span class="n">virt_to_page</span><span class="p">(((</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)</span><span class="n">mem</span><span class="p">)</span> <span class="o">+</span> <span class="n">i</span><span class="p">));</span> + + <span class="k">return</span> <span class="n">mem</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">void</span> <span class="nf">free_mmap_pages</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">mem</span><span class="p">,</span> <span class="kt">int</span> <span class="n">npages</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">i</span><span class="p">;</span> + + <span class="k">for</span><span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">npages</span> <span class="o">*</span> <span class="n">PAGE_SIZE</span><span class="p">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="n">PAGE_SIZE</span><span class="p">)</span> + <span class="n">ClearPageReserved</span><span class="p">(</span><span class="n">virt_to_page</span><span class="p">(((</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)</span><span class="n">mem</span><span class="p">)</span> <span class="o">+</span> <span class="n">i</span><span class="p">));</span> + + <span class="n">kfree</span><span class="p">(</span><span class="n">mem</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="further-reading"> +<h2>Further reading<a class="headerlink" href="#further-reading" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li><a class="reference external" href="http://lwn.net/images/pdf/LDD3/ch15.pdf">Linux Device Drivers 3rd Edition - Chapter 15. Memory Mapping and DMA</a></li> +<li><a class="reference external" href="http://www.xml.com/ldd/chapter/book/ch13.html">Linux Device Driver mmap Skeleton</a></li> +<li><a class="reference external" href="http://lwn.net/Articles/28746/">Driver porting: supporting mmap ()</a></li> +<li><a class="reference external" href="http://www.linuxjournal.com/article/1287">Device Drivers Concluded</a></li> +<li><a class="reference external" href="http://en.wikipedia.org/wiki/Mmap">mmap</a></li> +</ul> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is memory_mapping. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/memory_mapping/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="section" id="mapping-contiguous-physical-memory-to-userspace"> +<h3>1. Mapping contiguous physical memory to userspace<a class="headerlink" href="#mapping-contiguous-physical-memory-to-userspace" title="Permalink to this headline">¶</a></h3> +<p>Implement a device driver that maps contiguous physical memory +(e.g. obtained via <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code>) to userspace.</p> +<p>Review the <a class="reference internal" href="#device-driver-memory-mapping">Device driver memory mapping</a> section, generate the +skeleton for the task named <strong>kmmap</strong> and fill in the areas marked +with <strong>TODO 1</strong>.</p> +<p>Start with allocating a NPAGES+2 memory area page using <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> +in the module init function and find the first address in the area that is +aligned to a page boundary.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>The size of a page is <em>PAGE_SIZE</em>.</p> +<p>Store the allocated area in <em>kmalloc_ptr</em> and the page +aligned address in <em>kmalloc_area</em>:</p> +<p class="last">Use <code class="xref c c-func docutils literal"><span class="pre">PAGE_ALIGN()</span></code> to determine <em>kmalloc_area</em>.</p> +</div> +<p>Enable the PG_reserved bit of each page with +<code class="xref c c-func docutils literal"><span class="pre">SetPageReserved()</span></code>. Clear the bit with +<code class="xref c c-func docutils literal"><span class="pre">ClearPageReserved()</span></code> before freeing the memory.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use <code class="xref c c-func docutils literal"><span class="pre">virt_to_page()</span></code> to translate virtual pages into +physical pages, as required by <code class="xref c c-func docutils literal"><span class="pre">SetPageReserved()</span></code> +and <code class="xref c c-func docutils literal"><span class="pre">ClearPageReserved()</span></code>.</p> +</div> +<p>For verification purpose (using the test below), fill in the first 4 +bytes of each page with the following values: 0xaa, 0xbb, 0xcc, 0xdd.</p> +<p>Implement the <code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> driver function.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>For mapping, use <code class="xref c c-func docutils literal"><span class="pre">remap_pfn_range()</span></code>. The third +argument for <code class="xref c c-func docutils literal"><span class="pre">remap_pfn_range()</span></code> is a page frame number (PFN).</p> +<p>To convert from virtual kernel address to physical address, +use <code class="xref c c-func docutils literal"><span class="pre">virt_to_phys()</span></code>.</p> +<p class="last">To convert a physical address to its PFN, shift the address +with PAGE_SHIFT bits to the right.</p> +</div> +<p>For testing, load the kernel module and run:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>root@qemux86:~# skels/memory_mapping/test/mmap-test <span class="m">1</span> +</pre></div> +</div> +<p>If everything goes well, the test will show "matched" messages.</p> +</div> +<div class="section" id="mapping-non-contiguous-physical-memory-to-userspace"> +<h3>2. Mapping non-contiguous physical memory to userspace<a class="headerlink" href="#mapping-non-contiguous-physical-memory-to-userspace" title="Permalink to this headline">¶</a></h3> +<p>Implement a device driver that maps non-contiguous physical memory +(e.g. obtained via <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code>) to userspace.</p> +<p>Review the <a class="reference internal" href="#device-driver-memory-mapping">Device driver memory mapping</a> section, generate the +skeleton for the task named <strong>vmmap</strong> and fill in the areas marked +with <strong>TODO 1</strong>.</p> +<p>Allocate a memory area of NPAGES with <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code>.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">The size of a page is <em>PAGE_SIZE</em>. +Store the allocated area in <em>vmalloc_area</em>. +Memory allocated by <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code> is paged aligned.</p> +</div> +<p>Enable the PG_reserved bit of each page with +<code class="xref c c-func docutils literal"><span class="pre">SetPageReserved()</span></code>. Clear the bit with +<code class="xref c c-func docutils literal"><span class="pre">ClearPageReserved()</span></code> before freeing the memory.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use <code class="xref c c-func docutils literal"><span class="pre">vmalloc_to_page()</span></code> to translate virtual pages +into physical pages used by the functions +<code class="xref c c-func docutils literal"><span class="pre">SetPageReserved()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">ClearPageReserved()</span></code>.</p> +</div> +<p>For verification purpose (using the test below), fill in the first 4 +bytes of each page with the following values: 0xaa, 0xbb, 0xcc, 0xdd.</p> +<p>Implement the mmap driver function.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">To convert from virtual vmalloc address to physical address, +use <code class="xref c c-func docutils literal"><span class="pre">vmalloc_to_pfn()</span></code> which returns a PFN directly.</p> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p>vmalloc pages are not physically contiguous so it is +needed to use <code class="xref c c-func docutils literal"><span class="pre">remap_pfn_range()</span></code> for each page.</p> +<p>Loop through all virtual pages and for each: +* determine the physical address +* map it with <code class="xref c c-func docutils literal"><span class="pre">remap_pfn_range()</span></code></p> +<p class="last">Make sure that you determine the physical address +each time and that you use a range of one page for mapping.</p> +</div> +<p>For testing, load the kernel module and run:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>root@qemux86:~# skels/memory_mapping/test/mmap-test <span class="m">1</span> +</pre></div> +</div> +<p>If everything goes well, the test will show "matched" messages.</p> +</div> +<div class="section" id="read-write-operations-in-mapped-memory"> +<h3>3. Read / write operations in mapped memory<a class="headerlink" href="#read-write-operations-in-mapped-memory" title="Permalink to this headline">¶</a></h3> +<p>Modify one of the previous modules to allow read / write operations on +your device. This is a didactic exercise to see that the same space +can also be used with the <code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> call and with <code class="xref c c-func docutils literal"><span class="pre">read()</span></code> +and <code class="xref c c-func docutils literal"><span class="pre">write()</span></code> calls.</p> +<p>Fill in areas marked with <strong>TODO 2</strong>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The offset parameter sent to the read / write operation can +be ignored as all reads / writes from the test program will +be done with 0 offsets.</p> +</div> +<p>For testing, load the kernel module and run:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>root@qemux86:~# skels/memory_mapping/test/mmap-test <span class="m">2</span> +</pre></div> +</div> +</div> +<div class="section" id="display-memory-mapped-in-procfs"> +<h3>4. Display memory mapped in procfs<a class="headerlink" href="#display-memory-mapped-in-procfs" title="Permalink to this headline">¶</a></h3> +<p>Using one of the previous modules, create a procfs file in which you +display the total memory mapped by the calling process.</p> +<p>Fill in the areas marked with <strong>TODO 3</strong>.</p> +<p>Create a new entry in procfs (<code class="xref c c-macro docutils literal"><span class="pre">PROC_ENTRY_NAME</span></code>, defined in +<code class="file docutils literal"><span class="pre">mmap-test.h</span></code>) that will show the total memory mapped by the process +that called the <code class="xref c c-func docutils literal"><span class="pre">read()</span></code> on that file.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use <code class="xref c c-func docutils literal"><span class="pre">proc_create()</span></code>. For the mode parameter, use 0, +and for the parent parameter use NULL. Use +<code class="xref c c-func docutils literal"><span class="pre">my_proc_file_ops()</span></code> for operations.</p> +</div> +<p>In the module exit function, delete the <code class="xref c c-macro docutils literal"><span class="pre">PROC_ENTRY_NAME</span></code> entry +using <code class="xref c c-func docutils literal"><span class="pre">remove_proc_entry()</span></code>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>A (complex) use and description of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> +<span class="pre">seq_file</span></code> interface can be found here in this <a class="reference external" href="http://tldp.org/LDP/lkmpg/2.6/html/x861.html">example</a> .</p> +<p class="last">For this exercise, just a simple use of the interface +described <a class="reference external" href="http://lwn.net/Articles/22355/">here</a> is +sufficient. Check the "extra-simple" API described there.</p> +</div> +<p>In the <code class="xref c c-func docutils literal"><span class="pre">my_seq_show()</span></code> function you will need to:</p> +<ul> +<li><p class="first">Obtain the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code> structure of the current process +using the <code class="xref c c-func docutils literal"><span class="pre">get_task_mm()</span></code> function.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">The current process is available via the <em>current</em> variable +of type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct*</span></code>.</p> +</div> +</li> +<li><p class="first">Iterate through the entire <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code> list +associated with the process.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use the variable <code class="xref c c-data docutils literal"><span class="pre">vma_iterator</span></code> and start from +<code class="xref c c-data docutils literal"><span class="pre">mm->mmap</span></code>. Use the <code class="xref c c-member docutils literal"><span class="pre">vm_next</span></code> field of +the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code> to navigate through +the list of memory areas. Stop when you reach <code class="xref c c-macro docutils literal"><span class="pre">NULL</span></code>.</p> +</div> +</li> +<li><p class="first">Use <em>vm_start</em> and <em>vm_end</em> for each area to compute the total size.</p> +</li> +<li><p class="first">Use <code class="xref c c-func docutils literal"><span class="pre">pr_info("%lx</span> <span class="pre">%lxn,</span> <span class="pre">...)()</span></code> to print <em>vm_start</em> and <em>vm_end</em> for +each area.</p> +</li> +<li><p class="first">To release <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code>, decrement the reference +counter of the structure using <code class="xref c c-func docutils literal"><span class="pre">mmput()</span></code>.</p> +</li> +<li><p class="first">Use <code class="xref c c-func docutils literal"><span class="pre">seq_printf()</span></code> to write to the file. Show only the total count, +no other messages. Do not even show newline (n).</p> +</li> +</ul> +<p>In <code class="xref c c-func docutils literal"><span class="pre">my_seq_open()</span></code> register the display function +(<code class="xref c c-func docutils literal"><span class="pre">my_seq_show()</span></code>) using <code class="xref c c-func docutils literal"><span class="pre">single_open()</span></code>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last"><code class="xref c c-func docutils literal"><span class="pre">single_open()</span></code> can use <code class="xref c c-macro docutils literal"><span class="pre">NULL</span></code> as its third argument.</p> +</div> +<p>For testing, load the kernel module and run:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>root@qemux86:~# skels/memory_mapping/test/mmap-test <span class="m">3</span> +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The test waits for a while (it has an internal sleep +instruction). As long as the test waits, use the +<strong class="command">pmap</strong> command in another console to see the +mappings of the test and compare those to the test results.</p> +</div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="arm_kernel_development.html" class="btn btn-neutral float-left" title="Kernel Development on ARM" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="device_model.html" class="btn btn-neutral float-right" title="Linux Device Model" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/labs/networking.html b/refs/pull/405/merge/labs/networking.html new file mode 100644 index 00000000..b4a3e42b --- /dev/null +++ b/refs/pull/405/merge/labs/networking.html @@ -0,0 +1,1387 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Networking — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Kernel Development on ARM" href="arm_kernel_development.html" /> + <link rel="prev" title="File system drivers (Part 2)" href="filesystems_part2.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Networking</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="#overview">Overview</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#networking-in-user-space">Networking in user space</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#linux-networking">Linux networking</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#the-struct-socket-structure">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> structure</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#operations-on-the-socket-structure">Operations on the socket structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="#the-struct-socket-fields">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> fields</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#the-struct-sock-structure">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">sock</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="#the-struct-sk-buff-structure">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">sk_buff</span></code> structure</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#conversions-1">Conversions</a></li> +<li class="toctree-l2"><a class="reference internal" href="#netfilter-1">netfilter</a></li> +<li class="toctree-l2"><a class="reference internal" href="#netcat">netcat</a></li> +<li class="toctree-l2"><a class="reference internal" href="#further-reading">Further reading</a></li> +<li class="toctree-l2"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#displaying-packets-in-kernel-space">1. Displaying packets in kernel space</a></li> +<li class="toctree-l3"><a class="reference internal" href="#filtering-by-destination-address">2. Filtering by destination address</a></li> +<li class="toctree-l3"><a class="reference internal" href="#listening-on-a-tcp-socket">3. Listening on a TCP socket</a></li> +<li class="toctree-l3"><a class="reference internal" href="#accepting-connections-in-kernel-space">4. Accepting connections in kernel space</a></li> +<li class="toctree-l3"><a class="reference internal" href="#udp-socket-sender">5. UDP socket sender</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Networking</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/labs/networking.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="networking"> +<h1>Networking<a class="headerlink" href="#networking" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<blockquote> +<div><ul class="simple"> +<li>Understanding the Linux kernel networking architecture</li> +<li>Acquiring practical IP packet management skills using a packet filter or +firewall</li> +<li>Familiarize yourself with how to use sockets at the Linux kernel level</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="overview"> +<h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline">¶</a></h2> +<p>The development of the Internet has led to an exponential increase in network +applications and, as a consequence, to increasing the speed and productivity +requirements of an operating system's networking subsystem. The networking +subsystem is not an essential component of an operating system kernel (the Linux +kernel can be compiled without networking support). It is, however, quite +unlikely for a computing system (or even an embedded device) to have a +non-networked operating system due to the need for connectivity. Modern operating +systems use the <a class="reference external" href="https://en.wikipedia.org/wiki/Internet_protocol_suite">TCP/IP stack</a>. Their kernel +implements protocols up to the transport layer, while application layer protocols +are typically implemented in user space (HTTP, FTP, SSH, etc.).</p> +<div class="section" id="networking-in-user-space"> +<h3>Networking in user space<a class="headerlink" href="#networking-in-user-space" title="Permalink to this headline">¶</a></h3> +<p>In user space the abstraction of network communication is the socket. The +socket abstracts a communication channel and is the kernel-based TCP/IP stack +interaction interface. An IP socket is associated with an IP address, the +transport layer protocol used (TCP, UDP etc) and a port. Common function calls +that use sockets are: creation (<code class="docutils literal"><span class="pre">socket</span></code>), initialization +(<code class="docutils literal"><span class="pre">bind</span></code>), connecting (<code class="docutils literal"><span class="pre">connect</span></code>), waiting for a connection +(<code class="docutils literal"><span class="pre">listen</span></code>, <code class="docutils literal"><span class="pre">accept</span></code>), closing a socket (<code class="docutils literal"><span class="pre">close</span></code>).</p> +<p>Network communication is accomplished via <code class="docutils literal"><span class="pre">read</span></code>/<code class="docutils literal"><span class="pre">write</span></code> or <code class="docutils literal"><span class="pre">recv</span></code>/<code class="docutils literal"><span class="pre">send</span></code> calls +for TCP sockets and <code class="docutils literal"><span class="pre">recvfrom</span></code>/<code class="docutils literal"><span class="pre">sendto</span></code> for UDP sockets. Transmission and +reception operations are transparent to the application, leaving encapsulation +and transmission over network at the kernel's discretion. However, it is +possible to implement the TCP/IP stack in user space using raw sockets (the +<code class="docutils literal"><span class="pre">PF_PACKET</span></code> option when creating a socket), or implementing an application +layer protocol in kernel (<a class="reference external" href="http://en.wikipedia.org/wiki/TUX_web_server">TUX web server</a>).</p> +<p>For more details about user space programming using sockets, see <a class="reference external" href="https://www.beej.us/guide/bgnet/">Beej's Guide to +Network Programming Using Internet +Sockets</a>.</p> +</div> +</div> +<div class="section" id="linux-networking"> +<h2>Linux networking<a class="headerlink" href="#linux-networking" title="Permalink to this headline">¶</a></h2> +<p>The Linux kernel provides three basic structures for working with network +packets: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code>, <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sock</span></code> and <code class="xref c c-type docutils literal"><span class="pre">struct</span> +<span class="pre">sk_buff</span></code>.</p> +<p>The first two are abstractions of a socket:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> is an abstraction very close to user space, ie <a class="reference external" href="http://en.wikipedia.org/wiki/Berkeley_sockets">BSD +sockets</a> used to program +network applications;</li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sock</span></code> or <em>INET socket</em> in Linux terminology is the network +representation of a socket.</li> +</ul> +</div></blockquote> +<p>The two structures are related: the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> contains an INET +socket field, and the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sock</span></code> has a BSD socket that holds it.</p> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sk_buff</span></code> structure is the representation of a network packet +and its status. The structure is created when a kernel packet is received, +either from the user space or from the network interface.</p> +<div class="section" id="the-struct-socket-structure"> +<h3>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> structure<a class="headerlink" href="#the-struct-socket-structure" title="Permalink to this headline">¶</a></h3> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> structure is the kernel representation of a BSD +socket, the operations that can be executed on it are similar to those offered +by the kernel (through system calls). Common operations with sockets +(creation, initialization/bind, closing, etc.) result in specific system +calls; they work with the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> structure.</p> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> operations are described in <code class="file docutils literal"><span class="pre">net/socket.c</span></code> and +are independent of the protocol type. The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> structure is thus +a generic interface over particular network operations implementations. +Typically, the names of these operations begin with the <code class="docutils literal"><span class="pre">sock_</span></code> prefix.</p> +<div class="section" id="operations-on-the-socket-structure"> +<span id="socketstructops"></span><h4>Operations on the socket structure<a class="headerlink" href="#operations-on-the-socket-structure" title="Permalink to this headline">¶</a></h4> +<p>Socket operations are:</p> +<div class="section" id="creation"> +<h5>Creation<a class="headerlink" href="#creation" title="Permalink to this headline">¶</a></h5> +<p>Creation is similar to calling the <code class="xref c c-func docutils literal"><span class="pre">socket()</span></code> function in user space, but the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> created will be stored in the <code class="docutils literal"><span class="pre">res</span></code> parameter:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">int</span> <span class="pre">sock_create(int</span> <span class="pre">family,</span> <span class="pre">int</span> <span class="pre">type,</span> <span class="pre">int</span> <span class="pre">protocol,</span> <span class="pre">struct</span> <span class="pre">socket</span> <span class="pre">**res)</span></code> +creates a socket after the <code class="xref c c-func docutils literal"><span class="pre">socket()</span></code> system call;</li> +<li><code class="docutils literal"><span class="pre">int</span> <span class="pre">sock_create_kern(struct</span> <span class="pre">net</span> <span class="pre">*net,</span> <span class="pre">int</span> <span class="pre">family,</span> <span class="pre">int</span> <span class="pre">type,</span> <span class="pre">int</span> <span class="pre">protocol,</span> +<span class="pre">struct</span> <span class="pre">socket</span> <span class="pre">**res)</span></code> creates a kernel socket;</li> +<li><code class="docutils literal"><span class="pre">int</span> <span class="pre">sock_create_lite(int</span> <span class="pre">family,</span> <span class="pre">int</span> <span class="pre">type,</span> <span class="pre">int</span> <span class="pre">protocol,</span> <span class="pre">struct</span> <span class="pre">socket</span> <span class="pre">**res)</span></code> +creates a kernel socket without parameter sanity checks.</li> +</ul> +</div></blockquote> +<p>The parameters of these calls are as follows:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">net</span></code>, where it is present, used as reference to the network namespace used; +we will usually initialize it with <code class="docutils literal"><span class="pre">init_net</span></code>;</li> +<li><code class="docutils literal"><span class="pre">family</span></code> represents the family of protocols used in the transfer of +information; they usually begin with the <code class="docutils literal"><span class="pre">PF_</span></code> (Protocol Family) string; +the constants representing the family of protocols used are found in +<code class="file docutils literal"><span class="pre">linux/socket.h</span></code>, of which the most commonly used is <code class="docutils literal"><span class="pre">PF_INET</span></code>, for +TCP/IP protocols;</li> +<li><code class="docutils literal"><span class="pre">type</span></code> is the type of socket; the constants used for this parameter are +found in <code class="file docutils literal"><span class="pre">linux/net.h</span></code>, of which the most used are <code class="docutils literal"><span class="pre">SOCK_STREAM</span></code> for +a connection based source-to-destination communication and <code class="docutils literal"><span class="pre">SOCK_DGRAM</span></code> +for connectionless communication;</li> +<li><code class="docutils literal"><span class="pre">protocol</span></code> represents the protocol used and is closely related to the +<code class="docutils literal"><span class="pre">type</span></code> parameter; the constants used for this parameter are found in +<code class="file docutils literal"><span class="pre">linux/in.h</span></code>, of which the most used are <code class="docutils literal"><span class="pre">IPPROTO_TCP</span></code> for TCP and +<code class="docutils literal"><span class="pre">IPPROTO_UDP</span></code> for UDP.</li> +</ul> +</div></blockquote> +<p>To create a TCP socket in kernel space, you must call:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">;</span> +<span class="kt">int</span> <span class="n">err</span><span class="p">;</span> + +<span class="n">err</span> <span class="o">=</span> <span class="n">sock_create_kern</span><span class="p">(</span><span class="o">&</span><span class="n">init_net</span><span class="p">,</span> <span class="n">PF_INET</span><span class="p">,</span> <span class="n">SOCK_STREAM</span><span class="p">,</span> <span class="n">IPPROTO_TCP</span><span class="p">,</span> <span class="o">&</span><span class="n">sock</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> +<span class="p">}</span> +</pre></div> +</div> +<p>and for creating UDP sockets:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">;</span> +<span class="kt">int</span> <span class="n">err</span><span class="p">;</span> + +<span class="n">err</span> <span class="o">=</span> <span class="n">sock_create_kern</span><span class="p">(</span><span class="o">&</span><span class="n">init_net</span><span class="p">,</span> <span class="n">PF_INET</span><span class="p">,</span> <span class="n">SOCK_DGRAM</span><span class="p">,</span> <span class="n">IPPROTO_UDP</span><span class="p">,</span> <span class="o">&</span><span class="n">sock</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> +<span class="p">}</span> +</pre></div> +</div> +<p>A usage sample is part of the <code class="xref c c-func docutils literal"><span class="pre">sys_socket()</span></code> system call handler:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">SYSCALL_DEFINE3</span><span class="p">(</span><span class="n">socket</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span> <span class="n">family</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span> <span class="n">type</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span> <span class="n">protocol</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">retval</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">flags</span><span class="p">;</span> + + <span class="cm">/* Check the SOCK_* constants for consistency. */</span> + <span class="n">BUILD_BUG_ON</span><span class="p">(</span><span class="n">SOCK_CLOEXEC</span> <span class="o">!=</span> <span class="n">O_CLOEXEC</span><span class="p">);</span> + <span class="n">BUILD_BUG_ON</span><span class="p">((</span><span class="n">SOCK_MAX</span> <span class="o">|</span> <span class="n">SOCK_TYPE_MASK</span><span class="p">)</span> <span class="o">!=</span> <span class="n">SOCK_TYPE_MASK</span><span class="p">);</span> + <span class="n">BUILD_BUG_ON</span><span class="p">(</span><span class="n">SOCK_CLOEXEC</span> <span class="o">&</span> <span class="n">SOCK_TYPE_MASK</span><span class="p">);</span> + <span class="n">BUILD_BUG_ON</span><span class="p">(</span><span class="n">SOCK_NONBLOCK</span> <span class="o">&</span> <span class="n">SOCK_TYPE_MASK</span><span class="p">);</span> + + <span class="n">flags</span> <span class="o">=</span> <span class="n">type</span> <span class="o">&</span> <span class="o">~</span><span class="n">SOCK_TYPE_MASK</span><span class="p">;</span> + <span class="k">if</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&</span> <span class="o">~</span><span class="p">(</span><span class="n">SOCK_CLOEXEC</span> <span class="o">|</span> <span class="n">SOCK_NONBLOCK</span><span class="p">))</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EINVAL</span><span class="p">;</span> + <span class="n">type</span> <span class="o">&=</span> <span class="n">SOCK_TYPE_MASK</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">SOCK_NONBLOCK</span> <span class="o">!=</span> <span class="n">O_NONBLOCK</span> <span class="o">&&</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&</span> <span class="n">SOCK_NONBLOCK</span><span class="p">))</span> + <span class="n">flags</span> <span class="o">=</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&</span> <span class="o">~</span><span class="n">SOCK_NONBLOCK</span><span class="p">)</span> <span class="o">|</span> <span class="n">O_NONBLOCK</span><span class="p">;</span> + + <span class="n">retval</span> <span class="o">=</span> <span class="n">sock_create</span><span class="p">(</span><span class="n">family</span><span class="p">,</span> <span class="n">type</span><span class="p">,</span> <span class="n">protocol</span><span class="p">,</span> <span class="o">&</span><span class="n">sock</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">retval</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">goto</span> <span class="n">out</span><span class="p">;</span> + + <span class="k">return</span> <span class="nf">sock_map_fd</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="n">flags</span> <span class="o">&</span> <span class="p">(</span><span class="n">O_CLOEXEC</span> <span class="o">|</span> <span class="n">O_NONBLOCK</span><span class="p">));</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="closing"> +<h5>Closing<a class="headerlink" href="#closing" title="Permalink to this headline">¶</a></h5> +<p>Close connection (for sockets using connection) and release associated +resources:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">void</span> <span class="pre">sock_release(struct</span> <span class="pre">socket</span> <span class="pre">*sock)</span></code> calls the <code class="docutils literal"><span class="pre">release</span></code> function in +the <code class="docutils literal"><span class="pre">ops</span></code> field of the socket structure:</li> +</ul> +</div></blockquote> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">sock_release</span><span class="p">(</span><span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">sock</span><span class="o">-></span><span class="n">ops</span><span class="p">)</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">owner</span> <span class="o">=</span> <span class="n">sock</span><span class="o">-></span><span class="n">ops</span><span class="o">-></span><span class="n">owner</span><span class="p">;</span> + + <span class="n">sock</span><span class="o">-></span><span class="n">ops</span><span class="o">-></span><span class="n">release</span><span class="p">(</span><span class="n">sock</span><span class="p">);</span> + <span class="n">sock</span><span class="o">-></span><span class="n">ops</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="n">module_put</span><span class="p">(</span><span class="n">owner</span><span class="p">);</span> + <span class="p">}</span> + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="sending-receiving-messages"> +<h5>Sending/receiving messages<a class="headerlink" href="#sending-receiving-messages" title="Permalink to this headline">¶</a></h5> +<p>The messages are sent/received using the following functions:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">int</span> <span class="pre">sock_recvmsg(struct</span> <span class="pre">socket</span> <span class="pre">*sock,</span> <span class="pre">struct</span> <span class="pre">msghdr</span> <span class="pre">*msg,</span> <span class="pre">int</span> <span class="pre">flags);</span></code></li> +<li><code class="docutils literal"><span class="pre">int</span> <span class="pre">kernel_recvmsg(struct</span> <span class="pre">socket</span> <span class="pre">*sock,</span> <span class="pre">struct</span> <span class="pre">msghdr</span> <span class="pre">*msg,</span> <span class="pre">struct</span> <span class="pre">kvec</span> <span class="pre">*vec,</span> <span class="pre">size_t</span> <span class="pre">num,</span> <span class="pre">size_t</span> <span class="pre">size,</span> <span class="pre">int</span> <span class="pre">flags);</span></code></li> +<li><code class="docutils literal"><span class="pre">int</span> <span class="pre">sock_sendmsg(struct</span> <span class="pre">socket</span> <span class="pre">*sock,</span> <span class="pre">struct</span> <span class="pre">msghdr</span> <span class="pre">*msg);</span></code></li> +<li><code class="docutils literal"><span class="pre">int</span> <span class="pre">kernel_sendmsg(struct</span> <span class="pre">socket</span> <span class="pre">*sock,</span> <span class="pre">struct</span> <span class="pre">msghdr</span> <span class="pre">*msg,</span> <span class="pre">struct</span> <span class="pre">kvec</span> <span class="pre">*vec,</span> <span class="pre">size_t</span> <span class="pre">num,</span> <span class="pre">size_t</span> <span class="pre">size);</span></code></li> +</ul> +</div></blockquote> +<p>The message sending/receiving functions will then call the <code class="docutils literal"><span class="pre">sendmsg</span></code>/ +<code class="docutils literal"><span class="pre">recvmsg</span></code> function in the <code class="docutils literal"><span class="pre">ops</span></code> field of the socket. Functions +containing <code class="docutils literal"><span class="pre">kernel_</span></code> as a prefix are used when the socket is used in the +kernel.</p> +<p>The parameters are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">msg</span></code>, a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">msghdr</span></code> structure, containing the message to be +sent/received. Among the important components of this structure are <code class="docutils literal"><span class="pre">msg_name</span></code> +and <code class="docutils literal"><span class="pre">msg_namelen</span></code>, which, for UDP sockets, must be filled in with the address +to which the message is sent (<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sockaddr_in</span></code>);</li> +<li><code class="docutils literal"><span class="pre">vec</span></code>, a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">kvec</span></code> structure, containing a pointer to the buffer +containing its data and size; as can be seen, it has a similar structure to the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">iovec</span></code> structure (the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">iovec</span></code> structure +corresponds to the user space data, and the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">kvec</span></code> structure +corresponds to kernel space data).</li> +</ul> +</div></blockquote> +<p>A usage example can be seen in the <code class="xref c c-func docutils literal"><span class="pre">sys_sendto()</span></code> system call handler:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">SYSCALL_DEFINE6</span><span class="p">(</span><span class="n">sendto</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span> <span class="n">fd</span><span class="p">,</span> <span class="kt">void</span> <span class="n">__user</span> <span class="o">*</span><span class="p">,</span> <span class="n">buff</span><span class="p">,</span> <span class="kt">size_t</span><span class="p">,</span> <span class="n">len</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">,</span> <span class="n">flags</span><span class="p">,</span> <span class="k">struct</span> <span class="n">sockaddr</span> <span class="n">__user</span> <span class="o">*</span><span class="p">,</span> <span class="n">addr</span><span class="p">,</span> + <span class="kt">int</span><span class="p">,</span> <span class="n">addr_len</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">sockaddr_storage</span> <span class="n">address</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">err</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">msghdr</span> <span class="n">msg</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">iovec</span> <span class="n">iov</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">fput_needed</span><span class="p">;</span> + + <span class="n">err</span> <span class="o">=</span> <span class="n">import_single_range</span><span class="p">(</span><span class="n">WRITE</span><span class="p">,</span> <span class="n">buff</span><span class="p">,</span> <span class="n">len</span><span class="p">,</span> <span class="o">&</span><span class="n">iov</span><span class="p">,</span> <span class="o">&</span><span class="n">msg</span><span class="p">.</span><span class="n">msg_iter</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">unlikely</span><span class="p">(</span><span class="n">err</span><span class="p">))</span> + <span class="k">return</span> <span class="n">err</span><span class="p">;</span> + <span class="n">sock</span> <span class="o">=</span> <span class="n">sockfd_lookup_light</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="o">&</span><span class="n">err</span><span class="p">,</span> <span class="o">&</span><span class="n">fput_needed</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">sock</span><span class="p">)</span> + <span class="k">goto</span> <span class="n">out</span><span class="p">;</span> + + <span class="n">msg</span><span class="p">.</span><span class="n">msg_name</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="n">msg</span><span class="p">.</span><span class="n">msg_control</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="n">msg</span><span class="p">.</span><span class="n">msg_controllen</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="n">msg</span><span class="p">.</span><span class="n">msg_namelen</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="k">if</span> <span class="p">(</span><span class="n">addr</span><span class="p">)</span> <span class="p">{</span> + <span class="n">err</span> <span class="o">=</span> <span class="n">move_addr_to_kernel</span><span class="p">(</span><span class="n">addr</span><span class="p">,</span> <span class="n">addr_len</span><span class="p">,</span> <span class="o">&</span><span class="n">address</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">goto</span> <span class="n">out_put</span><span class="p">;</span> + <span class="n">msg</span><span class="p">.</span><span class="n">msg_name</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="p">)</span><span class="o">&</span><span class="n">address</span><span class="p">;</span> + <span class="n">msg</span><span class="p">.</span><span class="n">msg_namelen</span> <span class="o">=</span> <span class="n">addr_len</span><span class="p">;</span> + <span class="p">}</span> + <span class="k">if</span> <span class="p">(</span><span class="n">sock</span><span class="o">-></span><span class="n">file</span><span class="o">-></span><span class="n">f_flags</span> <span class="o">&</span> <span class="n">O_NONBLOCK</span><span class="p">)</span> + <span class="n">flags</span> <span class="o">|=</span> <span class="n">MSG_DONTWAIT</span><span class="p">;</span> + <span class="n">msg</span><span class="p">.</span><span class="n">msg_flags</span> <span class="o">=</span> <span class="n">flags</span><span class="p">;</span> + <span class="n">err</span> <span class="o">=</span> <span class="n">sock_sendmsg</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="o">&</span><span class="n">msg</span><span class="p">);</span> + +<span class="nl">out_put</span><span class="p">:</span> + <span class="n">fput_light</span><span class="p">(</span><span class="n">sock</span><span class="o">-></span><span class="n">file</span><span class="p">,</span> <span class="n">fput_needed</span><span class="p">);</span> +<span class="nl">out</span><span class="p">:</span> + <span class="k">return</span> <span class="n">err</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="the-struct-socket-fields"> +<h4>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> fields<a class="headerlink" href="#the-struct-socket-fields" title="Permalink to this headline">¶</a></h4> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/**</span> +<span class="cm"> * struct socket - general BSD socket</span> +<span class="cm"> * @state: socket state (%SS_CONNECTED, etc)</span> +<span class="cm"> * @type: socket type (%SOCK_STREAM, etc)</span> +<span class="cm"> * @flags: socket flags (%SOCK_NOSPACE, etc)</span> +<span class="cm"> * @ops: protocol specific socket operations</span> +<span class="cm"> * @file: File back pointer for gc</span> +<span class="cm"> * @sk: internal networking protocol agnostic socket representation</span> +<span class="cm"> * @wq: wait queue for several uses</span> +<span class="cm"> */</span> +<span class="k">struct</span> <span class="n">socket</span> <span class="p">{</span> + <span class="n">socket_state</span> <span class="n">state</span><span class="p">;</span> + + <span class="kt">short</span> <span class="n">type</span><span class="p">;</span> + + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + + <span class="k">struct</span> <span class="n">socket_wq</span> <span class="n">__rcu</span> <span class="o">*</span><span class="n">wq</span><span class="p">;</span> + + <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">;</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">proto_ops</span> <span class="o">*</span><span class="n">ops</span><span class="p">;</span> +<span class="p">};</span> +</pre></div> +</div> +<p>The noteworthy fields are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">ops</span></code> - the structure that stores pointers to protocol-specific functions;</li> +<li><code class="docutils literal"><span class="pre">sk</span></code> - The <code class="docutils literal"><span class="pre">INET</span> <span class="pre">socket</span></code> associated with it.</li> +</ul> +</div></blockquote> +<div class="section" id="the-struct-proto-ops-structure"> +<h5>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">proto_ops</span></code> structure<a class="headerlink" href="#the-struct-proto-ops-structure" title="Permalink to this headline">¶</a></h5> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">proto_ops</span></code> structure contains the implementations of the specific +operations implemented (TCP, UDP, etc.); these functions will be called from +generic functions through <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> (<code class="xref c c-func docutils literal"><span class="pre">sock_release()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">sock_sendmsg()</span></code>, etc.)</p> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">proto_ops</span></code> structure therefore contains a number of function +pointers for specific protocol implementations:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">proto_ops</span> <span class="p">{</span> + <span class="kt">int</span> <span class="n">family</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">owner</span><span class="p">;</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">release</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">bind</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="n">myaddr</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">sockaddr_len</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">connect</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="n">vaddr</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">sockaddr_len</span><span class="p">,</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">socketpair</span><span class="p">)(</span><span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock1</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock2</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">accept</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">newsock</span><span class="p">,</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">kern</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">getname</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="n">addr</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">peer</span><span class="p">);</span> + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The initialization of the <code class="docutils literal"><span class="pre">ops</span></code> field from <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> is done in +the <code class="xref c c-func docutils literal"><span class="pre">__sock_create()</span></code> function, by calling the <code class="xref c c-func docutils literal"><span class="pre">create()</span></code> function, +specific to each protocol; an equivalent call is the implementation of the +<code class="xref c c-func docutils literal"><span class="pre">__sock_create()</span></code> function:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="c1">//...</span> + <span class="n">err</span> <span class="o">=</span> <span class="n">pf</span><span class="o">-></span><span class="n">create</span><span class="p">(</span><span class="n">net</span><span class="p">,</span> <span class="n">sock</span><span class="p">,</span> <span class="n">protocol</span><span class="p">,</span> <span class="n">kern</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">goto</span> <span class="n">out_module_put</span><span class="p">;</span> +<span class="c1">//...</span> +</pre></div> +</div> +<p>This will instantiate the function pointers with calls specific to the protocol +type associated with the socket. The <code class="xref c c-func docutils literal"><span class="pre">sock_register()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">sock_unregister()</span></code> calls are used to fill the <code class="docutils literal"><span class="pre">net_families</span></code> vector.</p> +<p>For the rest of the socket operations (other than creating, closing, and +sending/receiving a message as described above in the <a class="reference internal" href="#operations-on-the-socket-structure">Operations on the socket +structure</a> section), the functions sent via pointers in this structure will be +called. For example, for <code class="docutils literal"><span class="pre">bind</span></code>, which associates a socket with a socket on +the local machine, we will have the following code sequence:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define MY_PORT 60000</span> + +<span class="k">struct</span> <span class="n">sockaddr_in</span> <span class="n">addr</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">sin_family</span> <span class="o">=</span> <span class="n">AF_INET</span><span class="p">,</span> + <span class="p">.</span><span class="n">sin_port</span> <span class="o">=</span> <span class="n">htons</span> <span class="p">(</span><span class="n">MY_PORT</span><span class="p">),</span> + <span class="p">.</span><span class="n">sin_addr</span> <span class="o">=</span> <span class="p">{</span> <span class="n">htonl</span> <span class="p">(</span><span class="n">INADDR_LOOPBACK</span><span class="p">)</span> <span class="p">}</span> +<span class="p">};</span> + +<span class="c1">//...</span> + <span class="n">err</span> <span class="o">=</span> <span class="n">sock</span><span class="o">-></span><span class="n">ops</span><span class="o">-></span><span class="n">bind</span> <span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="p">)</span> <span class="o">&</span><span class="n">addr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">addr</span><span class="p">));</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> + <span class="p">}</span> +<span class="c1">//...</span> +</pre></div> +</div> +<p>As you can see, for transmitting the address and port information that +will be associated with the socket, a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sockaddr_in</span></code> is filled.</p> +</div> +</div> +</div> +<div class="section" id="the-struct-sock-structure"> +<h3>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sock</span></code> structure<a class="headerlink" href="#the-struct-sock-structure" title="Permalink to this headline">¶</a></h3> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sock</span></code> describes an <code class="docutils literal"><span class="pre">INET</span></code> socket. Such a structure is +associated with a user space socket and implicitly with a <code class="xref c c-type docutils literal"><span class="pre">struct</span> +<span class="pre">socket</span></code> structure. The structure is used to store information about the status +of a connection. The structure's fields and associated operations usually begin +with the <code class="docutils literal"><span class="pre">sk_</span></code> string. Some fields are listed below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">sock</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="nl">sk_padding</span> <span class="p">:</span> <span class="mi">1</span><span class="p">,</span> + <span class="nl">sk_no_check_tx</span> <span class="p">:</span> <span class="mi">1</span><span class="p">,</span> + <span class="nl">sk_no_check_rx</span> <span class="p">:</span> <span class="mi">1</span><span class="p">,</span> + <span class="nl">sk_userlocks</span> <span class="p">:</span> <span class="mi">4</span><span class="p">,</span> + <span class="nl">sk_protocol</span> <span class="p">:</span> <span class="mi">8</span><span class="p">,</span> + <span class="nl">sk_type</span> <span class="p">:</span> <span class="mi">16</span><span class="p">;</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sk_socket</span><span class="p">;</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">sk_send_head</span><span class="p">;</span> + <span class="c1">//...</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">sk_state_change</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">sk_data_ready</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">sk_write_space</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">sk_error_report</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">sk_backlog_rcv</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">sk_destruct</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">);</span> +<span class="p">};</span> +</pre></div> +</div> +<p></p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">sk_protocol</span></code> is the type of protocol used by the socket;</li> +<li><code class="docutils literal"><span class="pre">sk_type</span></code> is the socket type (<code class="docutils literal"><span class="pre">SOCK_STREAM</span></code>, <code class="docutils literal"><span class="pre">SOCK_DGRAM</span></code>, etc.);</li> +<li><code class="docutils literal"><span class="pre">sk_socket</span></code> is the BSD socket that holds it;</li> +<li><code class="docutils literal"><span class="pre">sk_send_head</span></code> is the list of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sk_buff</span></code> structures for +transmission;</li> +<li>the function pointers at the end are callbacks for different situations.</li> +</ul> +</div></blockquote> +<p>Initializing the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sock</span></code> and attaching it to a BSD socket is done +using the callback created from <code class="docutils literal"><span class="pre">net_families</span></code> (called +<code class="xref c c-func docutils literal"><span class="pre">__sock_create()</span></code>). Here's how to initialize the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sock</span></code> +structure for the IP protocol, in the <code class="xref c c-func docutils literal"><span class="pre">inet_create()</span></code> function:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/*</span> +<span class="cm"> * Create an inet socket.</span> +<span class="cm"> */</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">inet_create</span><span class="p">(</span><span class="k">struct</span> <span class="n">net</span> <span class="o">*</span><span class="n">net</span><span class="p">,</span> <span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">,</span> <span class="kt">int</span> <span class="n">protocol</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">kern</span><span class="p">)</span> +<span class="p">{</span> + + <span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">;</span> + + <span class="c1">//...</span> + <span class="n">err</span> <span class="o">=</span> <span class="o">-</span><span class="n">ENOBUFS</span><span class="p">;</span> + <span class="n">sk</span> <span class="o">=</span> <span class="n">sk_alloc</span><span class="p">(</span><span class="n">net</span><span class="p">,</span> <span class="n">PF_INET</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">,</span> <span class="n">answer_prot</span><span class="p">,</span> <span class="n">kern</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">sk</span><span class="p">)</span> + <span class="k">goto</span> <span class="n">out</span><span class="p">;</span> + + <span class="n">err</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="k">if</span> <span class="p">(</span><span class="n">INET_PROTOSW_REUSE</span> <span class="o">&</span> <span class="n">answer_flags</span><span class="p">)</span> + <span class="n">sk</span><span class="o">-></span><span class="n">sk_reuse</span> <span class="o">=</span> <span class="n">SK_CAN_REUSE</span><span class="p">;</span> + + + <span class="c1">//...</span> + <span class="n">sock_init_data</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="n">sk</span><span class="p">);</span> + + <span class="n">sk</span><span class="o">-></span><span class="n">sk_destruct</span> <span class="o">=</span> <span class="n">inet_sock_destruct</span><span class="p">;</span> + <span class="n">sk</span><span class="o">-></span><span class="n">sk_protocol</span> <span class="o">=</span> <span class="n">protocol</span><span class="p">;</span> + <span class="n">sk</span><span class="o">-></span><span class="n">sk_backlog_rcv</span> <span class="o">=</span> <span class="n">sk</span><span class="o">-></span><span class="n">sk_prot</span><span class="o">-></span><span class="n">backlog_rcv</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="the-struct-sk-buff-structure"> +<span id="structskbuff"></span><h3>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sk_buff</span></code> structure<a class="headerlink" href="#the-struct-sk-buff-structure" title="Permalink to this headline">¶</a></h3> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sk_buff</span></code> (socket buffer) describes a network packet. The +structure fields contain information about both the header and packet contents, +the protocols used, the network device used, and pointers to the other +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sk_buff</span></code>. A summary description of the content of the structure +is presented below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="p">{</span> + <span class="k">union</span> <span class="p">{</span> + <span class="k">struct</span> <span class="p">{</span> + <span class="cm">/* These two members must be first. */</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">prev</span><span class="p">;</span> + + <span class="k">union</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">net_device</span> <span class="o">*</span><span class="n">dev</span><span class="p">;</span> + <span class="cm">/* Some protocols might use this space to store information,</span> +<span class="cm"> * while device pointer would be NULL.</span> +<span class="cm"> * UDP receive path is one user.</span> +<span class="cm"> */</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">dev_scratch</span><span class="p">;</span> + <span class="p">};</span> + <span class="p">};</span> + + <span class="k">struct</span> <span class="n">rb_node</span> <span class="n">rbnode</span><span class="p">;</span> <span class="cm">/* used in netem & tcp stack */</span> + <span class="p">};</span> + <span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">;</span> + + <span class="k">union</span> <span class="p">{</span> + <span class="n">ktime_t</span> <span class="n">tstamp</span><span class="p">;</span> + <span class="n">u64</span> <span class="n">skb_mstamp</span><span class="p">;</span> + <span class="p">};</span> + + <span class="cm">/*</span> +<span class="cm"> * This is the control buffer. It is free to use for every</span> +<span class="cm"> * layer. Please put your private variables there. If you</span> +<span class="cm"> * want to keep them across layers you have to do a skb_clone()</span> +<span class="cm"> * first. This is owned by whoever has the skb queued ATM.</span> +<span class="cm"> */</span> + <span class="kt">char</span> <span class="n">cb</span><span class="p">[</span><span class="mi">48</span><span class="p">]</span> <span class="n">__aligned</span><span class="p">(</span><span class="mi">8</span><span class="p">);</span> + + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">_skb_refdst</span><span class="p">;</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">destructor</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + <span class="k">union</span> <span class="p">{</span> + <span class="k">struct</span> <span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">_skb_refdst</span><span class="p">;</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">destructor</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + <span class="p">};</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="n">tcp_tsorted_anchor</span><span class="p">;</span> + <span class="p">};</span> + <span class="cm">/* ... */</span> + + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">,</span> + <span class="n">data_len</span><span class="p">;</span> + <span class="n">__u16</span> <span class="n">mac_len</span><span class="p">,</span> + <span class="n">hdr_len</span><span class="p">;</span> + + <span class="cm">/* ... */</span> + + <span class="n">__be16</span> <span class="n">protocol</span><span class="p">;</span> + <span class="n">__u16</span> <span class="n">transport_header</span><span class="p">;</span> + <span class="n">__u16</span> <span class="n">network_header</span><span class="p">;</span> + <span class="n">__u16</span> <span class="n">mac_header</span><span class="p">;</span> + + <span class="cm">/* private: */</span> + <span class="n">__u32</span> <span class="n">headers_end</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> + <span class="cm">/* public: */</span> + + <span class="cm">/* These elements must be at the end, see alloc_skb() for details. */</span> + <span class="n">sk_buff_data_t</span> <span class="n">tail</span><span class="p">;</span> + <span class="n">sk_buff_data_t</span> <span class="n">end</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">head</span><span class="p">,</span> + <span class="o">*</span><span class="n">data</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">truesize</span><span class="p">;</span> + <span class="n">refcount_t</span> <span class="n">users</span><span class="p">;</span> +<span class="p">};</span> +</pre></div> +</div> +<p>where:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">next</span></code> and <code class="docutils literal"><span class="pre">prev</span></code> are pointers to the next, and previous element in the +buffer list;</li> +<li><code class="docutils literal"><span class="pre">dev</span></code> is the device which sends or receives the buffer;</li> +<li><code class="docutils literal"><span class="pre">sk</span></code> is the socket associated with the buffer;</li> +<li><code class="docutils literal"><span class="pre">destructor</span></code> is the callback that deallocates the buffer;</li> +<li><code class="docutils literal"><span class="pre">transport_header</span></code>, <code class="docutils literal"><span class="pre">network_header</span></code>, and <code class="docutils literal"><span class="pre">mac_header</span></code> are offsets +between the beginning of the packet and the beginning of the various headers +in the packets. They are internally maintained by the various processing +layers through which the packet passes. To get pointers to the headers, use +one of the following functions: <code class="xref c c-func docutils literal"><span class="pre">tcp_hdr()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">udp_hdr()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">ip_hdr()</span></code>, etc. In principle, each protocol provides a function to +get a reference to the header of that protocol within a received packet. +Keep in mind that the <code class="docutils literal"><span class="pre">network_header</span></code> field is not set until the packet +reaches the network layer and the <code class="docutils literal"><span class="pre">transport_header</span></code> field is not set +until the packet reaches the transport layer.</li> +</ul> +</div></blockquote> +<p>The structure of an <a class="reference external" href="https://en.wikipedia.org/wiki/IPv4#Header">IP header</a> +(<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">iphdr</span></code>) has the following fields:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">iphdr</span> <span class="p">{</span> +<span class="cp">#if defined(__LITTLE_ENDIAN_BITFIELD)</span> + <span class="n">__u8</span> <span class="nl">ihl</span><span class="p">:</span><span class="mi">4</span><span class="p">,</span> + <span class="nl">version</span><span class="p">:</span><span class="mi">4</span><span class="p">;</span> +<span class="cp">#elif defined (__BIG_ENDIAN_BITFIELD)</span> + <span class="n">__u8</span> <span class="nl">version</span><span class="p">:</span><span class="mi">4</span><span class="p">,</span> + <span class="nl">ihl</span><span class="p">:</span><span class="mi">4</span><span class="p">;</span> +<span class="cp">#else</span> +<span class="cp">#error "Please fix <asm/byteorder.h>"</span> +<span class="cp">#endif</span> + <span class="n">__u8</span> <span class="n">tos</span><span class="p">;</span> + <span class="n">__be16</span> <span class="n">tot_len</span><span class="p">;</span> + <span class="n">__be16</span> <span class="n">id</span><span class="p">;</span> + <span class="n">__be16</span> <span class="n">frag_off</span><span class="p">;</span> + <span class="n">__u8</span> <span class="n">ttl</span><span class="p">;</span> + <span class="n">__u8</span> <span class="n">protocol</span><span class="p">;</span> + <span class="n">__sum16</span> <span class="n">check</span><span class="p">;</span> + <span class="n">__be32</span> <span class="n">saddr</span><span class="p">;</span> + <span class="n">__be32</span> <span class="n">daddr</span><span class="p">;</span> + <span class="cm">/*The options start here. */</span> +<span class="p">};</span> +</pre></div> +</div> +<p>where:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">protocol</span></code> is the transport layer protocol used;</li> +<li><code class="docutils literal"><span class="pre">saddr</span></code> is the source IP address;</li> +<li><code class="docutils literal"><span class="pre">daddr</span></code> is the destination IP address.</li> +</ul> +</div></blockquote> +<p>The structure of a <a class="reference external" href="https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_segment_structure">TCP header</a> +(<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">tcphdr</span></code>) has the following fields:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">tcphdr</span> <span class="p">{</span> + <span class="n">__be16</span> <span class="n">source</span><span class="p">;</span> + <span class="n">__be16</span> <span class="n">dest</span><span class="p">;</span> + <span class="n">__be32</span> <span class="n">seq</span><span class="p">;</span> + <span class="n">__be32</span> <span class="n">ack_seq</span><span class="p">;</span> +<span class="cp">#if defined(__LITTLE_ENDIAN_BITFIELD)</span> + <span class="n">__u16</span> <span class="nl">res1</span><span class="p">:</span><span class="mi">4</span><span class="p">,</span> + <span class="nl">doff</span><span class="p">:</span><span class="mi">4</span><span class="p">,</span> + <span class="nl">fin</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">syn</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">rst</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">psh</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">ack</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">urg</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">ece</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">cwr</span><span class="p">:</span><span class="mi">1</span><span class="p">;</span> +<span class="cp">#elif defined(__BIG_ENDIAN_BITFIELD)</span> + <span class="n">__u16</span> <span class="nl">doff</span><span class="p">:</span><span class="mi">4</span><span class="p">,</span> + <span class="nl">res1</span><span class="p">:</span><span class="mi">4</span><span class="p">,</span> + <span class="nl">cwr</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">ece</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">urg</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">ack</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">psh</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">rst</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">syn</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">fin</span><span class="p">:</span><span class="mi">1</span><span class="p">;</span> +<span class="cp">#else</span> +<span class="cp">#error "Adjust your <asm/byteorder.h> defines"</span> +<span class="cp">#endif</span> + <span class="n">__be16</span> <span class="n">window</span><span class="p">;</span> + <span class="n">__sum16</span> <span class="n">check</span><span class="p">;</span> + <span class="n">__be16</span> <span class="n">urg_ptr</span><span class="p">;</span> +<span class="p">};</span> +</pre></div> +</div> +<p>where:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">source</span></code> is the source port;</li> +<li><code class="docutils literal"><span class="pre">dest</span></code> is the destination port;</li> +<li><code class="docutils literal"><span class="pre">syn</span></code>, <code class="docutils literal"><span class="pre">ack</span></code>, <code class="docutils literal"><span class="pre">fin</span></code> are the TCP flags used; for a more detailed view, +see this <a class="reference external" href="http://www.eventhelix.com/Realtimemantra/Networking/Tcp.pdf">diagram</a>.</li> +</ul> +</div></blockquote> +<p>The structure of a <a class="reference external" href="https://en.wikipedia.org/wiki/User_Datagram_Protocol#Packet_structure">UDP header</a> +(<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">udphdr</span></code>) has the following fields:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">udphdr</span> <span class="p">{</span> + <span class="n">__be16</span> <span class="n">source</span><span class="p">;</span> + <span class="n">__be16</span> <span class="n">dest</span><span class="p">;</span> + <span class="n">__be16</span> <span class="n">len</span><span class="p">;</span> + <span class="n">__sum16</span> <span class="n">check</span><span class="p">;</span> +<span class="p">};</span> +</pre></div> +</div> +<p>where:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">source</span></code> is the source port;</li> +<li><code class="docutils literal"><span class="pre">dest</span></code> is the destination port.</li> +</ul> +</div></blockquote> +<p>An example of accessing the information present in the headers of a network +packet is as follows:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">;</span> + +<span class="k">struct</span> <span class="n">iphdr</span> <span class="o">*</span><span class="n">iph</span> <span class="o">=</span> <span class="n">ip_hdr</span><span class="p">(</span><span class="n">skb</span><span class="p">);</span> <span class="cm">/* IP header */</span> +<span class="cm">/* iph->saddr - source IP address */</span> +<span class="cm">/* iph->daddr - destination IP address */</span> +<span class="k">if</span> <span class="p">(</span><span class="n">iph</span><span class="o">-></span><span class="n">protocol</span> <span class="o">==</span> <span class="n">IPPROTO_TCP</span><span class="p">)</span> <span class="p">{</span> <span class="cm">/* TCP protocol */</span> + <span class="k">struct</span> <span class="n">tcphdr</span> <span class="o">*</span><span class="n">tcph</span> <span class="o">=</span> <span class="n">tcp_hdr</span><span class="p">(</span><span class="n">skb</span><span class="p">);</span> <span class="cm">/* TCP header */</span> + <span class="cm">/* tcph->source - source TCP port */</span> + <span class="cm">/* tcph->dest - destination TCP port */</span> +<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">iph</span><span class="o">-></span><span class="n">protocol</span> <span class="o">==</span> <span class="n">IPPROTO_UDP</span><span class="p">)</span> <span class="p">{</span> <span class="cm">/* UDP protocol */</span> + <span class="k">struct</span> <span class="n">udphdr</span> <span class="o">*</span><span class="n">udph</span> <span class="o">=</span> <span class="n">udp_hdr</span><span class="p">(</span><span class="n">skb</span><span class="p">);</span> <span class="cm">/* UDP header */</span> + <span class="cm">/* udph->source - source UDP port */</span> + <span class="cm">/* udph->dest - destination UDP port */</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="conversions-1"> +<span id="conversions"></span><h2>Conversions<a class="headerlink" href="#conversions-1" title="Permalink to this headline">¶</a></h2> +<p>In different systems, there are several ways of ordering bytes in a word +(<a class="reference external" href="http://en.wikipedia.org/wiki/Endianness">Endianness</a>), including: <a class="reference external" href="http://en.wikipedia.org/wiki/Endianness#Big-endian">Big +Endian</a> (the most +significant byte first) and <a class="reference external" href="http://en.wikipedia.org/wiki/Endianness#Little-endian">Little +Endian</a> (the least +significant byte first). Since a network interconnects systems with different +platforms, the Internet has imposed a standard sequence for the storage of +numerical data, called <a class="reference external" href="http://en.wikipedia.org/wiki/Endianness#Endianness_in_networking">network byte-order</a>. In +contrast, the byte sequence for the representation of numerical data on the host +computer is called host byte-order. Data received/sent from/to the network is in +the network byte-order format and should be converted between this format and +the host byte-order.</p> +<p>For converting we use the following macros:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">u16</span> <span class="pre">htons(u16</span> <span class="pre">x)</span></code> converts a 16 bit integer from host byte-order to +network byte-order (host to network short);</li> +<li><code class="docutils literal"><span class="pre">u32</span> <span class="pre">htonl(u32</span> <span class="pre">x)</span></code> converts a 32 bit integer from host byte-order to +network byte-order (host to network long);</li> +<li><code class="docutils literal"><span class="pre">u16</span> <span class="pre">ntohs(u16</span> <span class="pre">x)</span></code> converts a 16 bit integer from network byte-order to +host byte-order (network to host short);</li> +<li><code class="docutils literal"><span class="pre">u32</span> <span class="pre">ntohl(u32</span> <span class="pre">x)</span></code> converts a 32 bit integer from network byte-order to +host byte-order (network to host long).</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="netfilter-1"> +<span id="netfilter"></span><h2>netfilter<a class="headerlink" href="#netfilter-1" title="Permalink to this headline">¶</a></h2> +<p>Netfilter is the name of the kernel interface for capturing network packets for +modifying/analyzing them (for filtering, NAT, etc.). <a class="reference external" href="http://www.netfilter.org/">The netfilter</a> interface is used in user space by <a class="reference external" href="http://www.frozentux.net/documents/iptables-tutorial/">iptables</a>.</p> +<p>In the Linux kernel, packet capture using netfilter is done by attaching hooks. +Hooks can be specified in different locations in the path followed by a kernel +network packet, as needed. An organization chart with the route followed by a +package and the possible areas for a hook can be found <a class="reference external" href="http://linux-ip.net/nf/nfk-traversal.png">here</a>.</p> +<p>The header included when using netfilter is <code class="file docutils literal"><span class="pre">linux/netfilter.h</span></code>.</p> +<p>A hook is defined through the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">nf_hook_ops</span></code> structure:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">nf_hook_ops</span> <span class="p">{</span> + <span class="cm">/* User fills in from here down. */</span> + <span class="n">nf_hookfn</span> <span class="o">*</span><span class="n">hook</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">net_device</span> <span class="o">*</span><span class="n">dev</span><span class="p">;</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">priv</span><span class="p">;</span> + <span class="n">u_int8_t</span> <span class="n">pf</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">hooknum</span><span class="p">;</span> + <span class="cm">/* Hooks are ordered in ascending priority. */</span> + <span class="kt">int</span> <span class="n">priority</span><span class="p">;</span> +<span class="p">};</span> +</pre></div> +</div> +<p>where:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">pf</span></code> is the package type (<code class="docutils literal"><span class="pre">PF_INET</span></code>, etc.);</li> +<li><dl class="first docutils"> +<dt><code class="docutils literal"><span class="pre">priority</span></code> is the priority; priorities are defined in</dt> +<dd><code class="file docutils literal"><span class="pre">uapi/linux/netfilter_ipv4.h</span></code> as follows:</dd> +</dl> +</li> +</ul> +</div></blockquote> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">enum</span> <span class="n">nf_ip_hook_priorities</span> <span class="p">{</span> + <span class="n">NF_IP_PRI_FIRST</span> <span class="o">=</span> <span class="n">INT_MIN</span><span class="p">,</span> + <span class="n">NF_IP_PRI_CONNTRACK_DEFRAG</span> <span class="o">=</span> <span class="o">-</span><span class="mi">400</span><span class="p">,</span> + <span class="n">NF_IP_PRI_RAW</span> <span class="o">=</span> <span class="o">-</span><span class="mi">300</span><span class="p">,</span> + <span class="n">NF_IP_PRI_SELINUX_FIRST</span> <span class="o">=</span> <span class="o">-</span><span class="mi">225</span><span class="p">,</span> + <span class="n">NF_IP_PRI_CONNTRACK</span> <span class="o">=</span> <span class="o">-</span><span class="mi">200</span><span class="p">,</span> + <span class="n">NF_IP_PRI_MANGLE</span> <span class="o">=</span> <span class="o">-</span><span class="mi">150</span><span class="p">,</span> + <span class="n">NF_IP_PRI_NAT_DST</span> <span class="o">=</span> <span class="o">-</span><span class="mi">100</span><span class="p">,</span> + <span class="n">NF_IP_PRI_FILTER</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> + <span class="n">NF_IP_PRI_SECURITY</span> <span class="o">=</span> <span class="mi">50</span><span class="p">,</span> + <span class="n">NF_IP_PRI_NAT_SRC</span> <span class="o">=</span> <span class="mi">100</span><span class="p">,</span> + <span class="n">NF_IP_PRI_SELINUX_LAST</span> <span class="o">=</span> <span class="mi">225</span><span class="p">,</span> + <span class="n">NF_IP_PRI_CONNTRACK_HELPER</span> <span class="o">=</span> <span class="mi">300</span><span class="p">,</span> + <span class="n">NF_IP_PRI_CONNTRACK_CONFIRM</span> <span class="o">=</span> <span class="n">INT_MAX</span><span class="p">,</span> + <span class="n">NF_IP_PRI_LAST</span> <span class="o">=</span> <span class="n">INT_MAX</span><span class="p">,</span> +<span class="p">};</span> +</pre></div> +</div> +<p></p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">dev</span></code> is the device (network interface) on which the capture is +intended;</li> +<li><code class="docutils literal"><span class="pre">hooknum</span></code> is the type of hook used. When a packet is captured, the +processing mode is defined by the <code class="docutils literal"><span class="pre">hooknum</span></code> and <code class="docutils literal"><span class="pre">hook</span></code> fields. For IP, +hook types are defined in <code class="file docutils literal"><span class="pre">linux/netfilter.h</span></code>:</li> +</ul> +</div></blockquote> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">enum</span> <span class="n">nf_inet_hooks</span> <span class="p">{</span> + <span class="n">NF_INET_PRE_ROUTING</span><span class="p">,</span> + <span class="n">NF_INET_LOCAL_IN</span><span class="p">,</span> + <span class="n">NF_INET_FORWARD</span><span class="p">,</span> + <span class="n">NF_INET_LOCAL_OUT</span><span class="p">,</span> + <span class="n">NF_INET_POST_ROUTING</span><span class="p">,</span> + <span class="n">NF_INET_NUMHOOKS</span> +<span class="p">};</span> +</pre></div> +</div> +<p></p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">hook</span></code> is the handler called when capturing a network packet (packet sent +as a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sk_buff</span></code> structure). The <code class="docutils literal"><span class="pre">private</span></code> field is private information +handed to the handler. The capture handler prototype is defined by the +<code class="xref c c-type docutils literal"><span class="pre">nf_hookfn</span></code> type:</li> +</ul> +</div></blockquote> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">nf_hook_state</span> <span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">hook</span><span class="p">;</span> + <span class="n">u_int8_t</span> <span class="n">pf</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">net_device</span> <span class="o">*</span><span class="n">in</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">net_device</span> <span class="o">*</span><span class="n">out</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">net</span> <span class="o">*</span><span class="n">net</span><span class="p">;</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">okfn</span><span class="p">)(</span><span class="k">struct</span> <span class="n">net</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="p">);</span> +<span class="p">};</span> + +<span class="k">typedef</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="nf">nf_hookfn</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">priv</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">nf_hook_state</span> <span class="o">*</span><span class="n">state</span><span class="p">);</span> +</pre></div> +</div> +<p>For the <code class="xref c c-func docutils literal"><span class="pre">nf_hookfn()</span></code> capture function, the <code class="docutils literal"><span class="pre">priv</span></code> parameter is the +private information with which the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">nf_hook_ops</span></code> was +initialized. <code class="docutils literal"><span class="pre">skb</span></code> is the pointer to the captured network packet. Based on +<code class="docutils literal"><span class="pre">skb</span></code> information, packet filtering decisions are made. The function's +<code class="docutils literal"><span class="pre">state</span></code> parameter is the status information related to the packet capture, +including the input interface, the output interface, the priority, the hook +number. Priority and hook number are useful for allowing the same function to +be called by several hooks.</p> +<p>A capture handler can return one of the constants <code class="docutils literal"><span class="pre">NF_*</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* Responses from hook functions. */</span> +<span class="cp">#define NF_DROP 0</span> +<span class="cp">#define NF_ACCEPT 1</span> +<span class="cp">#define NF_STOLEN 2</span> +<span class="cp">#define NF_QUEUE 3</span> +<span class="cp">#define NF_REPEAT 4</span> +<span class="cp">#define NF_STOP 5</span> +<span class="cp">#define NF_MAX_VERDICT NF_STOP</span> +</pre></div> +</div> +<p><code class="docutils literal"><span class="pre">NF_DROP</span></code> is used to filter (ignore) a packet, and <code class="docutils literal"><span class="pre">NF_ACCEPT</span></code> is used to +accept a packet and forward it.</p> +<p>Registering/unregistering a hook is done using the functions defined in +<code class="file docutils literal"><span class="pre">linux/netfilter.h</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* Function to register/unregister hook points. */</span> +<span class="kt">int</span> <span class="nf">nf_register_net_hook</span><span class="p">(</span><span class="k">struct</span> <span class="n">net</span> <span class="o">*</span><span class="n">net</span><span class="p">,</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">nf_hook_ops</span> <span class="o">*</span><span class="n">ops</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">nf_unregister_net_hook</span><span class="p">(</span><span class="k">struct</span> <span class="n">net</span> <span class="o">*</span><span class="n">net</span><span class="p">,</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">nf_hook_ops</span> <span class="o">*</span><span class="n">ops</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">nf_register_net_hooks</span><span class="p">(</span><span class="k">struct</span> <span class="n">net</span> <span class="o">*</span><span class="n">net</span><span class="p">,</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">nf_hook_ops</span> <span class="o">*</span><span class="n">reg</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">n</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">nf_unregister_net_hooks</span><span class="p">(</span><span class="k">struct</span> <span class="n">net</span> <span class="o">*</span><span class="n">net</span><span class="p">,</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">nf_hook_ops</span> <span class="o">*</span><span class="n">reg</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">n</span><span class="p">);</span> +</pre></div> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p>Prior to version 3.11-rc2 of the Linux kernel, +there are some restrictions related to the use of header extraction functions +from a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sk_buff</span></code> structure set as a parameter in a netfilter +hook. While the IP header can be obtained each time using <code class="xref c c-func docutils literal"><span class="pre">ip_hdr()</span></code>, +the TCP and UDP headers can be obtained with <code class="xref c c-func docutils literal"><span class="pre">tcp_hdr()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">udp_hdr()</span></code> only for packages that come from inside the system rather +than the ones that are received from outside the system. In the latter case, +you must manually calculate the header offset in the package:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="c1">// For TCP packets (iph->protocol == IPPROTO_TCP)</span> +<span class="n">tcph</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">tcphdr</span><span class="o">*</span><span class="p">)((</span><span class="n">__u32</span><span class="o">*</span><span class="p">)</span><span class="n">iph</span> <span class="o">+</span> <span class="n">iph</span><span class="o">-></span><span class="n">ihl</span><span class="p">);</span> +<span class="c1">// For UDP packets (iph->protocol == IPPROTO_UDP)</span> +<span class="n">udph</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">udphdr</span><span class="o">*</span><span class="p">)((</span><span class="n">__u32</span><span class="o">*</span><span class="p">)</span><span class="n">iph</span> <span class="o">+</span> <span class="n">iph</span><span class="o">-></span><span class="n">ihl</span><span class="p">);</span> +</pre></div> +</div> +<p class="last">This code works in all filtering situations, so it's recommended to use it +instead of header access functions.</p> +</div> +<p>A usage example for a netfilter hook is shown below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/netfilter.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/netfilter_ipv4.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/net.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/in.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/skbuff.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/ip.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/tcp.h></span><span class="cp"></span> + +<span class="k">static</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="nf">my_nf_hookfn</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">priv</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">nf_hook_state</span> <span class="o">*</span><span class="n">state</span><span class="p">)</span> +<span class="p">{</span> + <span class="cm">/* process packet */</span> + <span class="c1">//...</span> + + <span class="k">return</span> <span class="n">NF_ACCEPT</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">nf_hook_ops</span> <span class="n">my_nfho</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">hook</span> <span class="o">=</span> <span class="n">my_nf_hookfn</span><span class="p">,</span> + <span class="p">.</span><span class="n">hooknum</span> <span class="o">=</span> <span class="n">NF_INET_LOCAL_OUT</span><span class="p">,</span> + <span class="p">.</span><span class="n">pf</span> <span class="o">=</span> <span class="n">PF_INET</span><span class="p">,</span> + <span class="p">.</span><span class="n">priority</span> <span class="o">=</span> <span class="n">NF_IP_PRI_FIRST</span> +<span class="p">};</span> + +<span class="kt">int</span> <span class="n">__init</span> <span class="nf">my_hook_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="n">nf_register_net_hook</span><span class="p">(</span><span class="o">&</span><span class="n">init_net</span><span class="p">,</span> <span class="o">&</span><span class="n">my_nfho</span><span class="p">);</span> +<span class="p">}</span> + +<span class="kt">void</span> <span class="n">__exit</span> <span class="nf">my_hook_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">nf_unregister_net_hook</span><span class="p">(</span><span class="o">&</span><span class="n">init_net</span><span class="p">,</span> <span class="o">&</span><span class="n">my_nfho</span><span class="p">);</span> +<span class="p">}</span> + +<span class="n">module_init</span><span class="p">(</span><span class="n">my_hook_init</span><span class="p">);</span> +<span class="n">module_exit</span><span class="p">(</span><span class="n">my_hook_exit</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="netcat"> +<h2>netcat<a class="headerlink" href="#netcat" title="Permalink to this headline">¶</a></h2> +<p>When developing applications that include networking code, one of the most +used tools is netcat. Also nicknamed "Swiss-army knife for TCP / IP". It allows:</p> +<blockquote> +<div><ul class="simple"> +<li>Initiating TCP connections;</li> +<li>Waiting for a TCP connection;</li> +<li>Sending and receiving UDP packets;</li> +<li>Displaying traffic in hexdump format;</li> +<li>Run a program after establishing a connection (eg, a shell);</li> +<li>Set special options in sent packages.</li> +</ul> +</div></blockquote> +<p>Initiating TCP connections:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">nc hostname port</span> +</pre></div> +</div> +<p>Listening to a TCP port:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">nc -l -p port</span> +</pre></div> +</div> +<p>Sending and receiving UDP packets is done adding the <code class="docutils literal"><span class="pre">-u</span></code> command line option.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The command is <strong class="command">nc</strong>; often <strong class="command">netcat</strong> is an alias for this +command. There are other implementations of the netcat command, some of which +have slightly different parameters than the classic implementation. Run +<strong class="command">man nc</strong> or <strong class="command">nc -h</strong> to check how to use it.</p> +</div> +<p>For more information on netcat, check the following <a class="reference external" href="https://www.win.tue.nl/~aeb/linux/hh/netcat_tutorial.pdf">tutorial</a>.</p> +</div> +<div class="section" id="further-reading"> +<h2>Further reading<a class="headerlink" href="#further-reading" title="Permalink to this headline">¶</a></h2> +<ol class="arabic simple"> +<li>Understanding Linux Network Internals</li> +<li><a class="reference external" href="http://www.cs.unh.edu/cnrg/gherrin/">Linux IP networking</a></li> +<li><a class="reference external" href="http://www.stllinux.org/meeting_notes/2001/0719/myTUX/">The TUX Web Server</a></li> +<li><a class="reference external" href="https://www.beej.us/guide/bgnet/">Beej's Guide to Network Programming Using Internet Sockets</a></li> +<li><a class="reference external" href="http://www.linuxjournal.com/article/7660">Kernel Korner - Network Programming in the Kernel</a></li> +<li><a class="reference external" href="http://phrack.org/issues/61/13.html">Hacking the Linux Kernel Network Stack</a></li> +<li><a class="reference external" href="http://www.netfilter.org/">The netfilter.org project</a></li> +<li><a class="reference external" href="https://www.digitalocean.com/community/tutorials/a-deep-dive-into-iptables-and-netfilter-architecture">A Deep Dive Into Iptables and Netfilter Architecture</a></li> +<li><a class="reference external" href="http://www.linuxfoundation.org/en/Net:Main_Page">Linux Foundation Networking Page</a></li> +</ol> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is networking. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/networking/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p class="last">You need to make sure that the <code class="docutils literal"><span class="pre">netfilter</span></code> support is active in kernel. It +is enabled via <code class="docutils literal"><span class="pre">CONFIG_NETFILTER</span></code>. To activate it, run <strong class="command">make menuconfig</strong> in +the <code class="file docutils literal"><span class="pre">linux</span></code> directory and check the <code class="docutils literal"><span class="pre">Network</span> <span class="pre">packet</span> <span class="pre">filtering</span> <span class="pre">framework</span> +<span class="pre">(Netfilter)</span></code> option in <code class="docutils literal"><span class="pre">Networking</span> <span class="pre">support</span> <span class="pre">-></span> <span class="pre">Networking</span> <span class="pre">options</span></code>. If it +was not enabled, enable it (as builtin, not external module - it must be +marked with <code class="docutils literal"><span class="pre">*</span></code>).</p> +</div> +<div class="section" id="displaying-packets-in-kernel-space"> +<h3>1. Displaying packets in kernel space<a class="headerlink" href="#displaying-packets-in-kernel-space" title="Permalink to this headline">¶</a></h3> +<p>Write a kernel module that displays the source address and port for TCP packets +that initiate an outbound connection. Start from the code in +<code class="file docutils literal"><span class="pre">1-2-netfilter</span></code> and fill in the areas marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">1</span></code>, taking into +account the comments below.</p> +<p>You will need to register a netfilter hook of type <code class="docutils literal"><span class="pre">NF_INET_LOCAL_OUT</span></code> as explained +in the <a class="reference internal" href="#netfilter">netfilter</a> section.</p> +<p><a class="reference internal" href="#the-struct-sk-buff-structure">The struct sk_buff structure</a> lets you access the packet headers using +specific functions. The <code class="xref c c-func docutils literal"><span class="pre">ip_hdr()</span></code> function returns the IP header as a +pointer to a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">iphdr</span></code> structure. The <code class="xref c c-func docutils literal"><span class="pre">tcp_hdr()</span></code> function +returns the TCP header as a pointer to a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">tcphdr</span></code> structure.</p> +<p>The <a class="reference external" href="http://www.eventhelix.com/Realtimemantra/Networking/Tcp.pdf">diagram</a> explains how to make a TCP connection. The connection initiation +packet has the <code class="docutils literal"><span class="pre">SYN</span></code> flag set in the TCP header and the <code class="docutils literal"><span class="pre">ACK</span></code> flag cleared.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>To display the source IP address, use the <code class="docutils literal"><span class="pre">%pI4</span></code> format of the printk +function. Details can be found in the <a class="reference external" href="https://www.kernel.org/doc/Documentation/printk-formats.txt">kernel documentation</a> (<code class="docutils literal"><span class="pre">IPv4</span> +<span class="pre">addresses</span></code> section). The following is an example code snippet that uses +<code class="docutils literal"><span class="pre">%pI4</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">printk</span><span class="p">(</span><span class="s">"IP address is %pI4</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="o">&</span><span class="n">iph</span><span class="o">-></span><span class="n">saddr</span><span class="p">);</span> +</pre></div> +</div> +<p class="last">When using the <code class="docutils literal"><span class="pre">%pI4</span></code> format, the argument to printk is a pointer. Hence the +construction <code class="docutils literal"><span class="pre">&iph->saddr</span></code> (with operator & - ampersand) instead of +<code class="docutils literal"><span class="pre">iph->saddr</span></code>.</p> +</div> +<p>The source TCP port is, in the TCP header, in the <a class="reference external" href="http://en.wikipedia.org/wiki/Endianness#Endianness_in_networking">network byte-order</a> format. +Read through the <a class="reference internal" href="../so2/lab10-networking.html#conversions"><span class="std std-ref">Conversions</span></a> section. Use <code class="xref c c-func docutils literal"><span class="pre">ntohs()</span></code> to convert.</p> +<p>For testing, use the <code class="file docutils literal"><span class="pre">1-2-netfilter/user/test-1.sh</span></code> file. The test creates +a connection to the localhost, a connection that will be intercepted and +displayed by the kernel module. The script is copied on the virtual machine by +the <strong class="command">make copy</strong> command only if it is marked as executable. The script +uses the statically compiled <strong class="command">netcat</strong> tool stored in +<code class="file docutils literal"><span class="pre">skels/networking/netcat</span></code>; this program must have execution +permissions.</p> +<p>After running the checker the output should be similar to the one bellow:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp"># ./test-1.sh</span> +<span class="p">[</span> <span class="mf">229.783512</span><span class="p">]</span> <span class="n">TCP</span> <span class="n">connection</span> <span class="n">initiated</span> <span class="n">from</span> <span class="mf">127.0.0.1</span><span class="o">:</span><span class="mi">44716</span> +<span class="n">Should</span> <span class="n">show</span> <span class="n">up</span> <span class="n">in</span> <span class="n">filter</span><span class="p">.</span> +<span class="n">Check</span> <span class="n">dmesg</span> <span class="n">output</span><span class="p">.</span> +</pre></div> +</div> +</div> +<div class="section" id="filtering-by-destination-address"> +<h3>2. Filtering by destination address<a class="headerlink" href="#filtering-by-destination-address" title="Permalink to this headline">¶</a></h3> +<p>Extend the module from exercise 1 so that you can specify a destination address +by means of a <code class="docutils literal"><span class="pre">MY_IOCTL_FILTER_ADDRESS</span></code> ioctl call. You'll only show packages +containing the specified destination address. To solve this task, fill in the +areas marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">2</span></code> and follow the specifications below.</p> +<p>To implement the ioctl routine, you must fill out the <code class="docutils literal"><span class="pre">my_ioctl</span></code> function. +Review the section in <a class="reference internal" href="../so2/lab3-device-drivers.html#ioctl"><span class="std std-ref">ioctl</span></a>. The address sent from user space is in +<a class="reference external" href="http://en.wikipedia.org/wiki/Endianness#Endianness_in_networking">network byte-order</a>, so there will be <strong>NO need</strong> for conversion.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The IP address sent via <code class="docutils literal"><span class="pre">ioctl</span></code> is sent by address, not by value. The +address must be stored in the <code class="docutils literal"><span class="pre">ioctl_set_addr</span></code> variable. For copying use +<code class="xref c c-func docutils literal"><span class="pre">copy_from_user()</span></code>.</p> +</div> +<p>To compare the addresses, fill out the <code class="docutils literal"><span class="pre">test_daddr</span></code> function. Addresses in +network byte-order will be used without having to convert addresses (if they +are equal from left to right they will be equal if reversed too).</p> +<p>The <code class="docutils literal"><span class="pre">test_daddr</span></code> function must be called from the netfilter hook to display +the connection initialization packets for which the destination address is the +one sent through the ioctl routine. The connection initiation packet has the +<code class="docutils literal"><span class="pre">SYN</span></code> flag set in the TCP header and the <code class="docutils literal"><span class="pre">ACK</span></code> flag cleared. You have to +check two things:</p> +<blockquote> +<div><ul class="simple"> +<li>the TCP flags;</li> +<li>the destination address of the packet (using <code class="docutils literal"><span class="pre">test_addr</span></code>).</li> +</ul> +</div></blockquote> +<p>For testing, use the <code class="file docutils literal"><span class="pre">1-2-netfilter/user/test-2.sh</span></code> script. This script +needs to compile the <code class="file docutils literal"><span class="pre">1-2-netfilter/user/test.c</span></code> file in the test +executable. Compilation is done automatically on the physical system when +running the <strong class="command">make build</strong> command. The test script is copied to the +virtual machine only if it is marked as executable. The script uses the +statically compiled <strong class="command">netcat</strong> tool in <code class="file docutils literal"><span class="pre">skels/networking/netcat</span></code>; +this executable must have execution permissions.</p> +<p>After running the checker the output should be similar to the one bellow:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ./test-2.sh +<span class="go">[ 797.673535] TCP connection initiated from 127.0.0.1:44721</span> +<span class="go">Should show up in filter.</span> +<span class="go">Should NOT show up in filter.</span> +<span class="go">Check dmesg output.</span> +</pre></div> +</div> +<p>The test ask for packet filtering first for the <code class="docutils literal"><span class="pre">127.0.0.1</span></code> IP address and +then for the <code class="docutils literal"><span class="pre">127.0.0.2</span></code> IP address. The first connection initiation packet +(to <code class="docutils literal"><span class="pre">127.0.0.1</span></code>) is intercepted and displayed by the filter, while the second +(to <code class="docutils literal"><span class="pre">127.0.0.2</span></code>) is not intercepted.</p> +</div> +<div class="section" id="listening-on-a-tcp-socket"> +<h3>3. Listening on a TCP socket<a class="headerlink" href="#listening-on-a-tcp-socket" title="Permalink to this headline">¶</a></h3> +<p>Write a kernel module that creates a TCP socket that listens to connections on +port <code class="docutils literal"><span class="pre">60000</span></code> on the loopback interface (in <code class="docutils literal"><span class="pre">init_module</span></code>). Start from the +code in <code class="file docutils literal"><span class="pre">3-4-tcp-sock</span></code> fill in the areas marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">1</span></code> taking +into account the observations below.</p> +<p>Read the <a class="reference internal" href="#operations-on-the-socket-structure">Operations on the socket structure</a> and <a class="reference internal" href="#the-struct-proto-ops-structure">The struct proto_ops +structure</a> sections.</p> +<p>The <code class="docutils literal"><span class="pre">sock</span></code> socket is a <code class="docutils literal"><span class="pre">server</span> <span class="pre">socket</span></code> and must be put in the listening +state. That is, the <code class="docutils literal"><span class="pre">bind</span></code> and <code class="docutils literal"><span class="pre">listen</span></code> operations must be applied to the +socket. For the <code class="docutils literal"><span class="pre">bind</span></code> and <code class="docutils literal"><span class="pre">listen</span></code> equivalent, in kernel space you will +need to call <code class="docutils literal"><span class="pre">sock->ops->...;</span></code> examples of such functions you can call are +<code class="docutils literal"><span class="pre">sock->ops->bind</span></code>, <code class="docutils literal"><span class="pre">sock->ops->listen</span></code> etc.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>For example, call <code class="docutils literal"><span class="pre">sock->ops->bind</span></code>, or <code class="docutils literal"><span class="pre">sock->ops->listen</span></code> functions, see +how they are called in the <code class="xref c c-func docutils literal"><span class="pre">sys_bind()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">sys_listen()</span></code> system +call handlers.</p> +<p class="last">Look for the system call handlers in the <code class="docutils literal"><span class="pre">net/socket.c</span></code> file in the Linux +kernel source code tree.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">For the second argument of the <code class="docutils literal"><span class="pre">listen</span></code> (backlog) call, use the +<code class="docutils literal"><span class="pre">LISTEN_BACKLOG</span></code>.</p> +</div> +<p>Remember to release the socket in the module's exit function and in the area +marked with error labels; use <code class="xref c c-func docutils literal"><span class="pre">sock_release()</span></code>.</p> +<p>For testing, run the <strong class="command">3-4-tcp_sock/test-3.sh</strong> script. The script is +copied on the virtual machine by <strong class="command">make copy</strong> only if it is marked as +executable.</p> +<p>After running the test, a TCP socket will be displayed by listening to +connections on port <code class="docutils literal"><span class="pre">60000</span></code>.</p> +</div> +<div class="section" id="accepting-connections-in-kernel-space"> +<h3>4. Accepting connections in kernel space<a class="headerlink" href="#accepting-connections-in-kernel-space" title="Permalink to this headline">¶</a></h3> +<p>Expand the module from the previous exercise to allow an external connection (no +need to send any message, only accept new connections). Fill in the areas marked +with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">2</span></code>.</p> +<p>Read the <a class="reference internal" href="#operations-on-the-socket-structure">Operations on the socket structure</a> and <a class="reference internal" href="#the-struct-proto-ops-structure">The struct proto_ops +structure</a> sections.</p> +<p>For the kernel space <code class="docutils literal"><span class="pre">accept</span></code> equivalent, see the system call handler for +<code class="xref c c-func docutils literal"><span class="pre">sys_accept4()</span></code>. Follow the <a class="reference external" href="https://elixir.bootlin.com/linux/v4.17/source/drivers/staging/lustre/lnet/lnet/lib-socket.c#L511">lnet_sock_accept</a> +implementation, and how the <code class="docutils literal"><span class="pre">sock->ops->accept</span></code> call is used. Use <code class="docutils literal"><span class="pre">0</span></code> as +the value for the second to last argument (<code class="docutils literal"><span class="pre">flags</span></code>), and <code class="docutils literal"><span class="pre">true</span></code> for the +last argument (<code class="docutils literal"><span class="pre">kern</span></code>).</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Look for the system call handlers in the <code class="docutils literal"><span class="pre">net/socket.c</span></code> file in the Linux +kernel source code tree.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The new socket (<code class="docutils literal"><span class="pre">new_sock</span></code>) must be created with the +<code class="xref c c-func docutils literal"><span class="pre">sock_create_lite()</span></code> function and then its operations must be configured +using</p> +<div class="last highlight-console"><div class="highlight"><pre><span></span><span class="go">newsock->ops = sock->ops;</span> +</pre></div> +</div> +</div> +<p>Print the address and port of the destination socket. To find the peer name of a +socket (its address), refer to the <code class="xref c c-func docutils literal"><span class="pre">sys_getpeername()</span></code> system call handler.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The first argument for the <code class="docutils literal"><span class="pre">sock->ops->getname</span></code> function will be the +connection socket, ie <code class="docutils literal"><span class="pre">new_sock</span></code>, the one initialized with by the <code class="docutils literal"><span class="pre">accept</span></code> +call.</p> +<p>The last argument of the <code class="docutils literal"><span class="pre">sock->ops->getname</span></code> function will be <code class="docutils literal"><span class="pre">1</span></code>, +meaning that we want to know about the endpoint or the peer (<em>remote end</em> or +<em>peer</em>).</p> +<p class="last">Display the peer address (indicated by the <code class="docutils literal"><span class="pre">raddr</span></code> variable) using the +<code class="docutils literal"><span class="pre">print_sock_address</span></code> macro defined in the file.</p> +</div> +<p>Release the newly created socket (after accepting the connection) in the module +exit function and after the error label. After adding the <code class="docutils literal"><span class="pre">accept</span></code> code to the +module initialization function, the <strong class="command">insmod</strong> operation will lock until +a connection is established. You can unlock using <strong class="command">netcat</strong> on that +port. Consequently, the test script from the previous exercise will not work.</p> +<p>For testing, run the <code class="file docutils literal"><span class="pre">3-4-tcp_sock/test-4.sh</span></code> script. The script is copied on +the virtual machine by <strong class="command">make copy</strong> only if it is marked as executable.</p> +<p>Nothing special will be displayed (in the kernel buffer). The success of the +test will be defined by the connection establishment. Then use <code class="docutils literal"><span class="pre">Ctrl+c</span></code> to +stop the test script, and then you can remove the kernel module.</p> +</div> +<div class="section" id="udp-socket-sender"> +<h3>5. UDP socket sender<a class="headerlink" href="#udp-socket-sender" title="Permalink to this headline">¶</a></h3> +<p>Write a kernel module that creates a UDP socket and sends the message from the +<code class="docutils literal"><span class="pre">MY_TEST_MESSAGE</span></code> macro on the socket to the loopback address on port +<code class="docutils literal"><span class="pre">60001</span></code>.</p> +<p>Start from the code in <code class="file docutils literal"><span class="pre">5-udp-sock</span></code>.</p> +<p>Read the <a class="reference internal" href="#operations-on-the-socket-structure">Operations on the socket structure</a> and <a class="reference internal" href="#the-struct-proto-ops-structure">The struct proto_ops +structure</a> sections.</p> +<p>To see how to send messages in the kernel space, see the <code class="xref c c-func docutils literal"><span class="pre">sys_send()</span></code> +system call handler or <a class="reference internal" href="#sending-receiving-messages">Sending/receiving messages</a>.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>The <code class="docutils literal"><span class="pre">msg_name</span></code> field of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">msghdr</span></code> structure must be +initialized to the destination address (pointer to <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sockaddr</span></code>) +and the <code class="docutils literal"><span class="pre">msg_namelen</span></code> field to the address size.</p> +<p>Initialize the <code class="docutils literal"><span class="pre">msg_flags</span></code> field of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">msghdr</span></code> structure +to <code class="docutils literal"><span class="pre">0</span></code>.</p> +<p class="last">Initialize the <code class="docutils literal"><span class="pre">msg_control</span></code> and <code class="docutils literal"><span class="pre">msg_controllen</span></code> fields of the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">msghdr</span></code> structure to <code class="docutils literal"><span class="pre">NULL</span></code> and <code class="docutils literal"><span class="pre">0</span></code> respectively.</p> +</div> +<p>For sending the message use <code class="xref c c-func docutils literal"><span class="pre">kernel_sendmsg()</span></code>.</p> +<p>The message transmission parameters are retrieved from the kernel space. Cast +the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">iovec</span></code> structure pointer to a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">kvec</span></code> pointer +in the <code class="xref c c-func docutils literal"><span class="pre">kernel_sendmsg()</span></code> call.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">The last two parameters of <code class="xref c c-func docutils literal"><span class="pre">kernel_sendmsg()</span></code> are <code class="docutils literal"><span class="pre">1</span></code> (number of I/O +vectors) and <code class="docutils literal"><span class="pre">len</span></code> (message size).</p> +</div> +<p>For testing, use the <code class="file docutils literal"><span class="pre">test-5.sh</span></code> file. The script is copied on the virtual +machine by the <strong class="command">make copy</strong> command only if it is marked as executable. +The script uses the statically compiled <code class="docutils literal"><span class="pre">netcat</span></code> tool stored in +<code class="file docutils literal"><span class="pre">skels/networking/netcat</span></code>; this executable must have execution +permissions.</p> +<p>For a correct implementation, running the <code class="file docutils literal"><span class="pre">test-5.sh</span></code> script will cause +the <code class="docutils literal"><span class="pre">kernelsocket</span></code> message to be displayed like in the output below:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">/root # ./test-5.sh</span> +<span class="go">+ pid=1059</span> +<span class="go">+ sleep 1</span> +<span class="go">+ nc -l -u -p 60001</span> +<span class="go">+ insmod udp_sock.ko</span> +<span class="go">kernelsocket</span> +<span class="go">+ rmmod udp_sock</span> +<span class="go">+ kill 1059</span> +</pre></div> +</div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="filesystems_part2.html" class="btn btn-neutral float-left" title="File system drivers (Part 2)" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="arm_kernel_development.html" class="btn btn-neutral float-right" title="Kernel Development on ARM" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/address-space-slides.html b/refs/pull/405/merge/lectures/address-space-slides.html new file mode 100644 index 00000000..fef6d4b7 --- /dev/null +++ b/refs/pull/405/merge/lectures/address-space-slides.html @@ -0,0 +1,709 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Address Space — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="next" title="Memory Management" href="memory-management.html" /> + <link rel="prev" title="Symmetric Multi-Processing" href="smp.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-address-space slide level-2"> + +<h2>Address Space</h2> + +<ul class="simple"> +<li>x86 MMU<ul> +<li>Segmentation</li> +<li>Paging</li> +<li>TLB</li> +</ul> +</li> +<li>Linux Address Space<ul> +<li>User</li> +<li>Kernel</li> +<li>High memory</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-x86-mmu slide level-2"> + +<h2>x86 MMU</h2> + +<p> </p> +<img alt="../_images/ditaa-f3703e3f627a948c59f6f960518d5f68eb7becec.png" src="../_images/ditaa-f3703e3f627a948c59f6f960518d5f68eb7becec.png" /> + + + + +</article> +<article class="admonition-selectors slide level-2"> + +<h2>Selectors</h2> + +<p> </p> +<img alt="../_images/ditaa-d6845a04f0ec792beec598d2a9f4c5b92c65529e.png" src="../_images/ditaa-d6845a04f0ec792beec598d2a9f4c5b92c65529e.png" /> +<ul class="simple"> +<li>Selectors: CS, DS, SS, ES, FS, GS</li> +<li>Index: indexes the segment descriptor table</li> +<li>TI: selects either the GDT or LDT</li> +<li>RPL: for CS only indicates the running (current) priviledge level</li> +<li>GDTR and LDTR registers points to the base of GDP and LDT</li> +</ul> + + + + +</article> +<article class="admonition-segment-descriptor slide level-2"> + +<h2>Segment descriptor</h2> + +<p> </p> +<img alt="../_images/ditaa-5cd4a8fa1ad97cff4bb1f64da13ce9ebfcfc4562.png" src="../_images/ditaa-5cd4a8fa1ad97cff4bb1f64da13ce9ebfcfc4562.png" /> +<ul class="simple"> +<li>Base: linear address for the start of the segment</li> +<li>Limit: size of the segment</li> +<li>G: granularity bit: if set the size is in bytes otherwise in 4K pages</li> +<li>B/D: data/code</li> +<li>Type: code segment, data/stack, TSS, LDT, GDT</li> +<li>Protection: the minimum priviledge level required to access the +segment (RPL is checked against DPL)</li> +</ul> + + + + +</article> +<article class="admonition-segmentation-in-linux slide level-2"> + +<h2>Segmentation in Linux</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/*</span> +<span class="cm"> * The layout of the per-CPU GDT under Linux:</span> +<span class="cm"> *</span> +<span class="cm"> * 0 - null <=== cacheline #1</span> +<span class="cm"> * 1 - reserved</span> +<span class="cm"> * 2 - reserved</span> +<span class="cm"> * 3 - reserved</span> +<span class="cm"> *</span> +<span class="cm"> * 4 - unused <=== cacheline #2</span> +<span class="cm"> * 5 - unused</span> +<span class="cm"> *</span> +<span class="cm"> * ------- start of TLS (Thread-Local Storage) segments:</span> +<span class="cm"> *</span> +<span class="cm"> * 6 - TLS segment #1 [ glibc's TLS segment ]</span> +<span class="cm"> * 7 - TLS segment #2 [ Wine's %fs Win32 segment ]</span> +<span class="cm"> * 8 - TLS segment #3 <=== cacheline #3</span> +<span class="cm"> * 9 - reserved</span> +<span class="cm"> * 10 - reserved</span> +<span class="cm"> * 11 - reserved</span> +<span class="cm"> *</span> +<span class="cm"> * ------- start of kernel segments:</span> +<span class="cm"> *</span> +<span class="cm"> * 12 - kernel code segment <=== cacheline #4</span> +<span class="cm"> * 13 - kernel data segment</span> +<span class="cm"> * 14 - default user CS</span> +<span class="cm"> * 15 - default user DS</span> +<span class="cm"> * 16 - TSS <=== cacheline #5</span> +<span class="cm"> * 17 - LDT</span> +<span class="cm"> * 18 - PNPBIOS support (16->32 gate)</span> +<span class="cm"> * 19 - PNPBIOS support</span> +<span class="cm"> * 20 - PNPBIOS support <=== cacheline #6</span> +<span class="cm"> * 21 - PNPBIOS support</span> +<span class="cm"> * 22 - PNPBIOS support</span> +<span class="cm"> * 23 - APM BIOS support</span> +<span class="cm"> * 24 - APM BIOS support <=== cacheline #7</span> +<span class="cm"> * 25 - APM BIOS support</span> +<span class="cm"> *</span> +<span class="cm"> * 26 - ESPFIX small SS</span> +<span class="cm"> * 27 - per-cpu [ offset to per-cpu data area ]</span> +<span class="cm"> * 28 - stack_canary-20 [ for stack protector ] <=== cacheline #8</span> +<span class="cm"> * 29 - unused</span> +<span class="cm"> * 30 - unused</span> +<span class="cm"> * 31 - TSS for double fault handler</span> +<span class="cm"> */</span> + + <span class="n">DEFINE_PER_CPU_PAGE_ALIGNED</span><span class="p">(</span><span class="k">struct</span> <span class="n">gdt_page</span><span class="p">,</span> <span class="n">gdt_page</span><span class="p">)</span> <span class="o">=</span> <span class="p">{</span> <span class="p">.</span><span class="n">gdt</span> <span class="o">=</span> <span class="p">{</span> + <span class="cp">#ifdef CONFIG_X86_64</span> + <span class="cm">/*</span> +<span class="cm"> * We need valid kernel segments for data and code in long mode too</span> +<span class="cm"> * IRET will check the segment types kkeil 2000/10/28</span> +<span class="cm"> * Also sysret mandates a special GDT layout</span> +<span class="cm"> *</span> +<span class="cm"> * TLS descriptors are currently at a different place compared to i386.</span> +<span class="cm"> * Hopefully nobody expects them at a fixed place (Wine?)</span> +<span class="cm"> */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL32_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc09b</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xa09b</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc093</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER32_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0fb</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0f3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xa0fb</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="cp">#else</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc09a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0fa</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0f2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="cm">/*</span> +<span class="cm"> * Segments used for calling PnP BIOS have byte granularity.</span> +<span class="cm"> * They code segments and data segments have fixed 64k limits,</span> +<span class="cm"> * the transfer segment sizes are set at run time.</span> +<span class="cm"> */</span> + <span class="cm">/* 32-bit code */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_CS32</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x409a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* 16-bit code */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_CS16</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x009a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* 16-bit data */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x0092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* 16-bit data */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_TS1</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x0092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> + <span class="cm">/* 16-bit data */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_TS2</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x0092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> + <span class="cm">/*</span> +<span class="cm"> * The APM segments have byte granularity and their bases</span> +<span class="cm"> * are set at run time. All have 64k limits.</span> +<span class="cm"> */</span> + <span class="cm">/* 32-bit code */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_APMBIOS_BASE</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x409a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* 16-bit code */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_APMBIOS_BASE</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x009a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* data */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_APMBIOS_BASE</span><span class="o">+</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x4092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + + <span class="p">[</span><span class="n">GDT_ENTRY_ESPFIX_SS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PERCPU</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="n">GDT_STACK_CANARY_INIT</span> + <span class="cp">#endif</span> + <span class="p">}</span> <span class="p">};</span> + <span class="n">EXPORT_PER_CPU_SYMBOL_GPL</span><span class="p">(</span><span class="n">gdt_page</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-inspecting-selectors-and-segments slide level-2"> + +<h2>Inspecting selectors and segments</h2> + +<p> </p> +<asciinema-player src="../_images/selectors-and-segments.cast"></asciinema-player> + + + +</article> +<article class="admonition-regular-paging slide level-2"> + +<h2>Regular paging</h2> + +<p> </p> +<img alt="../_images/ditaa-def299abebe530d760a6c8f16c791bbb016f9238.png" src="../_images/ditaa-def299abebe530d760a6c8f16c791bbb016f9238.png" /> + + + + +</article> +<article class="admonition-extended-paging slide level-2"> + +<h2>Extended paging</h2> + +<img alt="../_images/ditaa-709c2e7a68bfcdcfe9c1938d6ef2a0c9b5627931.png" src="../_images/ditaa-709c2e7a68bfcdcfe9c1938d6ef2a0c9b5627931.png" /> + + + + +</article> +<article class="admonition-page-tables slide level-2"> + +<h2>Page tables</h2> + +<ul class="simple"> +<li>Both page directory and page table have 1024 entries</li> +<li>Each entry has 4 bytes</li> +<li>The special CR3 register point to the base of the page directory</li> +<li>Page directory entries points to the base of the page table</li> +<li>All tables are stored in memory</li> +<li>All table addresses are physical addresses</li> +</ul> + + + + +</article> +<article class="admonition-page-table-entry-fields slide level-2"> + +<h2>Page table entry fields</h2> + +<ul class="simple"> +<li>Present/Absent</li> +<li>PFN (Page Frame Number): the most 20 significant bits of the physical address</li> +<li>Accessed - not updated by hardware (can be used by OS for housekeeping)</li> +<li>Dirty - not updated by hardware (can be used by OS for housekeeping)</li> +<li>Access rights: Read/Write</li> +<li>Privilege: User/Supervisor</li> +<li>Page size - only for page directory; if set extended paging is used</li> +<li>PCD (page cache disable), PWT (page write through)</li> +</ul> + + + + +</article> +<article class="admonition-linux-paging slide level-2"> + +<h2>Linux paging</h2> + +<img alt="../_images/ditaa-5e4d73e3fcb24db9d1f8c16daddf98694c063fe6.png" src="../_images/ditaa-5e4d73e3fcb24db9d1f8c16daddf98694c063fe6.png" /> + + + + +</article> +<article class="admonition-linux-apis-for-page-table-handling slide level-2"> + +<h2>Linux APIs for page table handling</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="o">*</span> <span class="n">page</span><span class="p">;</span> +<span class="n">pgd_t</span> <span class="n">pgd</span><span class="p">;</span> +<span class="n">pmd_t</span> <span class="n">pmd</span><span class="p">;</span> +<span class="n">pud_t</span> <span class="n">pud</span><span class="p">;</span> +<span class="n">pte_t</span> <span class="n">pte</span><span class="p">;</span> +<span class="kt">void</span> <span class="o">*</span><span class="n">laddr</span><span class="p">,</span> <span class="o">*</span><span class="n">paddr</span><span class="p">;</span> + +<span class="n">pgd</span> <span class="o">=</span> <span class="n">pgd_offset</span><span class="p">(</span><span class="n">mm</span><span class="p">,</span> <span class="n">vaddr</span><span class="p">);</span> +<span class="n">pud</span> <span class="o">=</span> <span class="n">pud_offet</span><span class="p">(</span><span class="n">pgd</span><span class="p">,</span> <span class="n">vaddr</span><span class="p">);</span> +<span class="n">pmd</span> <span class="o">=</span> <span class="n">pmd_offset</span><span class="p">(</span><span class="n">pud</span><span class="p">,</span> <span class="n">vaddr</span><span class="p">);</span> +<span class="n">pte</span> <span class="o">=</span> <span class="n">pte_offset</span><span class="p">(</span><span class="n">pmd</span><span class="p">,</span> <span class="n">vaddr</span><span class="p">);</span> +<span class="n">page</span> <span class="o">=</span> <span class="n">pte_page</span><span class="p">(</span><span class="n">pte</span><span class="p">);</span> +<span class="n">laddr</span> <span class="o">=</span> <span class="n">page_address</span><span class="p">(</span><span class="n">page</span><span class="p">);</span> +<span class="n">paddr</span> <span class="o">=</span> <span class="n">virt_to_phys</span><span class="p">(</span><span class="n">laddr</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-what-about-platforms-with-less-then-4-levels-of-pagination slide level-2"> + +<h2>What about platforms with less then 4 levels of pagination?</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kr">inline</span> <span class="n">pud_t</span> <span class="o">*</span> <span class="nf">pud_offset</span><span class="p">(</span><span class="n">pgd_t</span> <span class="o">*</span> <span class="n">pgd</span><span class="p">,</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">address</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="p">(</span><span class="n">pud_t</span> <span class="o">*</span><span class="p">)</span><span class="n">pgd</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kr">inline</span> <span class="n">pmd_t</span> <span class="o">*</span> <span class="nf">pmd_offset</span><span class="p">(</span><span class="n">pud_t</span> <span class="o">*</span> <span class="n">pud</span><span class="p">,</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">address</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="p">(</span><span class="n">pmd_t</span> <span class="o">*</span><span class="p">)</span><span class="n">pud</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-translation-look-aside-buffer slide level-2"> + +<h2>Translation Look-aside Buffer</h2> + +<ul class="simple"> +<li>Caches paging information (PFN, rights, privilege)</li> +<li>Content Addressable Memory / Associative Memory<ul> +<li>Very small (64-128)</li> +<li>Very fast (single cycle due to parallel search implementation)</li> +</ul> +</li> +<li>CPUs usually have two TLBs: i-TLB (code) and d-TLB (data)</li> +<li>TLB miss penalty: up hundreds of cycles</li> +</ul> + + + + +</article> +<article class="admonition-tlb-invalidation slide level-2"> + +<h2>TLB invalidation</h2> + +<p>Single address invalidation:</p> +<div class="highlight-asm"><div class="highlight"><pre><span></span>mov $addr, %eax +invlpg %(eax) +</pre></div> +</div> +<p>Full invalidation:</p> +<div class="highlight-asm"><div class="highlight"><pre><span></span><span class="nf">mov</span> <span class="nv">%cr3</span><span class="p">,</span> <span class="nv">%eax</span> +<span class="nf">mov</span> <span class="nv">%eax</span><span class="p">,</span> <span class="nv">%cr3</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-address-space-options-for-32bit-systems slide level-2"> + +<h2>Address space options for 32bit systems</h2> + +<p> </p> +<img alt="../_images/ditaa-d5d1129b0298a2ea5f116c9d4b246eb1b888db6b.png" src="../_images/ditaa-d5d1129b0298a2ea5f116c9d4b246eb1b888db6b.png" /> + + + + +</article> +<article class="admonition-advantages-and-disadvantages slide level-2"> + +<h2>Advantages and disadvantages</h2> + +<ul class="simple"> +<li>Disadvantages for dedicated kernel space:<ul> +<li>Fully invalidating the TLB for every system call</li> +</ul> +</li> +<li>Disadvantages for shared address space<ul> +<li>Less address space for both kernel and user processes</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-linux-address-space-for-32bit-systems slide level-2"> + +<h2>Linux address space for 32bit systems</h2> + +<p> </p> +<img alt="../_images/ditaa-3985c420def8f30934a72ea8c738a00ed629c298.png" src="../_images/ditaa-3985c420def8f30934a72ea8c738a00ed629c298.png" /> + + + + +</article> +<article class="admonition-virtual-to-physical-address-translations-for-i-o-transfers slide level-2"> + +<h2>Virtual to physical address translations for I/O transfers</h2> + +<ul class="simple"> +<li>Use the virtual address of a kernel buffer in order to copy to +data from from user space</li> +<li>Walk the page tables to transform the kernel buffer virtual +address to a physical address</li> +<li>Use the physical address of the kernel buffer to start a DMA +transfer</li> +</ul> + + + + +</article> +<article class="admonition-linear-mappings slide level-2"> + +<h2>Linear mappings</h2> + +<ul class="simple"> +<li>Virtual to physical address space translation is reduced to one +operation (instead of walking the page tables)</li> +<li>Less memory is used to create the page tables</li> +<li>Less TLB entries are used for the kernel memory</li> +</ul> + + + + +</article> +<article class="admonition-highmem slide level-2"> + +<h2>Highmem</h2> + +<p> </p> +<img alt="../_images/ditaa-bb8455a43088bf800eece11869f6ff857574605d.png" src="../_images/ditaa-bb8455a43088bf800eece11869f6ff857574605d.png" /> + + + + +</article> +<article class="admonition-multi-page-permanent-mappings slide level-2"> + +<h2>Multi-page permanent mappings</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="o">*</span> <span class="nf">vmalloc</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">size</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">vfree</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span> <span class="n">addr</span><span class="p">);</span> + +<span class="kt">void</span> <span class="o">*</span><span class="nf">ioremap</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">offset</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">size</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">iounmap</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span> <span class="n">addr</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-fixed-mapped-linear-addresses slide level-2"> + +<h2>Fixed-mapped linear addresses</h2> + +<ul class="simple"> +<li>Reserved virtual addresses (constants)</li> +<li>Mapped to physical addresses during boot</li> +</ul> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">set_fixmap</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="n">phys_addr</span><span class="p">)</span> +<span class="n">set_fixmap_nocache</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="n">phys_addr</span><span class="p">)</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-fixed-mapped-linear-addresses slide level-2"> + +<h2>Fixed-mapped linear addresses</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/*</span> +<span class="cm"> * Here we define all the compile-time 'special' virtual</span> +<span class="cm"> * addresses. The point is to have a constant address at</span> +<span class="cm"> * compile time, but to set the physical address only</span> +<span class="cm"> * in the boot process.</span> +<span class="cm"> * for x86_32: We allocate these special addresses</span> +<span class="cm"> * from the end of virtual memory (0xfffff000) backwards.</span> +<span class="cm"> * Also this lets us do fail-safe vmalloc(), we</span> +<span class="cm"> * can guarantee that these special addresses and</span> +<span class="cm"> * vmalloc()-ed addresses never overlap.</span> +<span class="cm"> *</span> +<span class="cm"> * These 'compile-time allocated' memory buffers are</span> +<span class="cm"> * fixed-size 4k pages (or larger if used with an increment</span> +<span class="cm"> * higher than 1). Use set_fixmap(idx,phys) to associate</span> +<span class="cm"> * physical memory with fixmap indices.</span> +<span class="cm"> *</span> +<span class="cm"> * TLB entries of such buffers will not be flushed across</span> +<span class="cm"> * task switches.</span> +<span class="cm"> */</span> + +<span class="k">enum</span> <span class="n">fixed_addresses</span> <span class="p">{</span> +<span class="cp">#ifdef CONFIG_X86_32</span> + <span class="n">FIX_HOLE</span><span class="p">,</span> +<span class="cp">#else</span> +<span class="cp">#ifdef CONFIG_X86_VSYSCALL_EMULATION</span> + <span class="n">VSYSCALL_PAGE</span> <span class="o">=</span> <span class="p">(</span><span class="n">FIXADDR_TOP</span> <span class="o">-</span> <span class="n">VSYSCALL_ADDR</span><span class="p">)</span> <span class="o">>></span> <span class="n">PAGE_SHIFT</span><span class="p">,</span> +<span class="cp">#endif</span> +<span class="cp">#endif</span> + <span class="n">FIX_DBGP_BASE</span><span class="p">,</span> + <span class="n">FIX_EARLYCON_MEM_BASE</span><span class="p">,</span> +<span class="cp">#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT</span> + <span class="n">FIX_OHCI1394_BASE</span><span class="p">,</span> +<span class="cp">#endif</span> +<span class="cp">#ifdef CONFIG_X86_LOCAL_APIC</span> + <span class="n">FIX_APIC_BASE</span><span class="p">,</span> <span class="cm">/* local (CPU) APIC) -- required for SMP or not */</span> +<span class="cp">#endif</span> +<span class="cp">#ifdef CONFIG_X86_IO_APIC</span> + <span class="n">FIX_IO_APIC_BASE_0</span><span class="p">,</span> + <span class="n">FIX_IO_APIC_BASE_END</span> <span class="o">=</span> <span class="n">FIX_IO_APIC_BASE_0</span> <span class="o">+</span> <span class="n">MAX_IO_APICS</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> +<span class="cp">#endif</span> +<span class="cp">#ifdef CONFIG_X86_32</span> + <span class="n">FIX_KMAP_BEGIN</span><span class="p">,</span> <span class="cm">/* reserved pte's for temporary kernel mappings */</span> + <span class="n">FIX_KMAP_END</span> <span class="o">=</span> <span class="n">FIX_KMAP_BEGIN</span><span class="o">+</span><span class="p">(</span><span class="n">KM_TYPE_NR</span><span class="o">*</span><span class="n">NR_CPUS</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> +<span class="cp">#ifdef CONFIG_PCI_MMCONFIG</span> + <span class="n">FIX_PCIE_MCFG</span><span class="p">,</span> +<span class="cp">#endif</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-conversion-between-virtual-address-fixed-address-indexes slide level-2"> + +<h2>Conversion between virtual address fixed address indexes</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))</span> +<span class="cp">#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)</span> + +<span class="cp">#ifndef __ASSEMBLY__</span> +<span class="cm">/*</span> +<span class="cm"> * 'index to address' translation. If anyone tries to use the idx</span> +<span class="cm"> * directly without translation, we catch the bug with a NULL-deference</span> +<span class="cm"> * kernel oops. Illegal ranges of incoming indices are caught too.</span> +<span class="cm"> */</span> + <span class="k">static</span> <span class="n">__always_inline</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="nf">fix_to_virt</span><span class="p">(</span><span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">idx</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">BUILD_BUG_ON</span><span class="p">(</span><span class="n">idx</span> <span class="o">>=</span> <span class="n">__end_of_fixed_addresses</span><span class="p">);</span> + <span class="k">return</span> <span class="n">__fix_to_virt</span><span class="p">(</span><span class="n">idx</span><span class="p">);</span> + <span class="p">}</span> + + <span class="k">static</span> <span class="kr">inline</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="nf">virt_to_fix</span><span class="p">(</span><span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">vaddr</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">BUG_ON</span><span class="p">(</span><span class="n">vaddr</span> <span class="o">>=</span> <span class="n">FIXADDR_TOP</span> <span class="o">||</span> <span class="n">vaddr</span> <span class="o"><</span> <span class="n">FIXADDR_START</span><span class="p">);</span> + <span class="k">return</span> <span class="n">__virt_to_fix</span><span class="p">(</span><span class="n">vaddr</span><span class="p">);</span> + <span class="p">}</span> + + + <span class="kr">inline</span> <span class="kt">long</span> <span class="nf">fix_to_virt</span><span class="p">(</span><span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">idx</span><span class="p">)</span> + <span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">idx</span> <span class="o">>=</span> <span class="n">__end_of_fixed_addresses</span><span class="p">)</span> + <span class="n">__this_fixmap_does_not_exist</span><span class="p">();</span> + <span class="k">return</span> <span class="p">(</span><span class="mh">0xffffe000UL</span> <span class="o">-</span> <span class="p">(</span><span class="n">idx</span> <span class="o"><<</span> <span class="n">PAGE_SHIFT</span><span class="p">));</span> + <span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-temporary-mappings slide level-2"> + +<h2>Temporary mappings</h2> + +<ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">kmap_atomic()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">kunmap_atomic()</span></code></li> +<li>No context switch is permitted in atomic kmap section</li> +<li>Can be used in interrupt context</li> +<li>No locking required</li> +<li>Only invalidates on TLB entry</li> +</ul> + + + + +</article> +<article class="admonition-temporary-mappings-implementation slide level-2"> + +<h2>Temporary mappings implementation</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define kmap_atomic(page) kmap_atomic_prot(page, kmap_prot)</span> + +<span class="kt">void</span> <span class="o">*</span><span class="nf">kmap_atomic_high_prot</span><span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">,</span> <span class="n">pgprot_t</span> <span class="n">prot</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">vaddr</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">idx</span><span class="p">,</span> <span class="n">type</span><span class="p">;</span> + + <span class="n">type</span> <span class="o">=</span> <span class="n">kmap_atomic_idx_push</span><span class="p">();</span> + <span class="n">idx</span> <span class="o">=</span> <span class="n">type</span> <span class="o">+</span> <span class="n">KM_TYPE_NR</span><span class="o">*</span><span class="n">smp_processor_id</span><span class="p">();</span> + <span class="n">vaddr</span> <span class="o">=</span> <span class="n">__fix_to_virt</span><span class="p">(</span><span class="n">FIX_KMAP_BEGIN</span> <span class="o">+</span> <span class="n">idx</span><span class="p">);</span> + <span class="n">BUG_ON</span><span class="p">(</span><span class="o">!</span><span class="n">pte_none</span><span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="n">kmap_pte</span><span class="o">-</span><span class="n">idx</span><span class="p">)));</span> + <span class="n">set_pte</span><span class="p">(</span><span class="n">kmap_pte</span><span class="o">-</span><span class="n">idx</span><span class="p">,</span> <span class="n">mk_pte</span><span class="p">(</span><span class="n">page</span><span class="p">,</span> <span class="n">prot</span><span class="p">));</span> + <span class="n">arch_flush_lazy_mmu_mode</span><span class="p">();</span> + + <span class="k">return</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">vaddr</span><span class="p">;</span> +<span class="p">}</span> +<span class="n">EXPORT_SYMBOL</span><span class="p">(</span><span class="n">kmap_atomic_high_prot</span><span class="p">);</span> + +<span class="k">static</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="nf">kmap_atomic_idx_push</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">idx</span> <span class="o">=</span> <span class="n">__this_cpu_inc_return</span><span class="p">(</span><span class="n">__kmap_atomic_idx</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> + +<span class="cp">#ifdef CONFIG_DEBUG_HIGHMEM</span> + <span class="n">WARN_ON_ONCE</span><span class="p">(</span><span class="n">in_irq</span><span class="p">()</span> <span class="o">&&</span> <span class="o">!</span><span class="n">irqs_disabled</span><span class="p">());</span> + <span class="n">BUG_ON</span><span class="p">(</span><span class="n">idx</span> <span class="o">>=</span> <span class="n">KM_TYPE_NR</span><span class="p">);</span> +<span class="cp">#endif</span> + <span class="k">return</span> <span class="n">idx</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-implementation-of-temporary-mappings slide level-2"> + +<h2>Implementation of temporary mappings</h2> + +<ul class="simple"> +<li>Use the fixed-mapped linear addresses</li> +<li>Every CPU has KM_TYPE_NR reserved entries to be used for +temporary mappings</li> +<li>Stack like selection: every user picks the current entry and +increments the "stack" counter</li> +</ul> + + + + +</article> +<article class="admonition-permanent-mappings slide level-2"> + +<h2>Permanent mappings</h2> + +<ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">kmap()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">kunmap()</span></code></li> +<li>Context switches are allowed</li> +<li>Only available in process context</li> +<li>One page table is reserved for permanent mappings</li> +<li>Page counter<ul> +<li>0 - page is not mapped, free and ready to use</li> +<li>1 - page is not mapped, may be present in TLB needs flushing before using</li> +<li>N - page is mapped N-1 times</li> +</ul> +</li> +</ul> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/address-space.html b/refs/pull/405/merge/lectures/address-space.html new file mode 100644 index 00000000..c314c4dd --- /dev/null +++ b/refs/pull/405/merge/lectures/address-space.html @@ -0,0 +1,767 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Address Space — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Memory Management" href="memory-management.html" /> + <link rel="prev" title="Symmetric Multi-Processing" href="smp.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Address Space</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="#x86-mmu">x86 MMU</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#selectors">Selectors</a></li> +<li class="toctree-l3"><a class="reference internal" href="#segment-descriptor">Segment descriptor</a></li> +<li class="toctree-l3"><a class="reference internal" href="#segmentation-in-linux">Segmentation in Linux</a></li> +<li class="toctree-l3"><a class="reference internal" href="#inspecting-selectors-and-segments">Inspecting selectors and segments</a></li> +<li class="toctree-l3"><a class="reference internal" href="#x86-paging">x86 Paging</a></li> +<li class="toctree-l3"><a class="reference internal" href="#page-tables">Page tables</a></li> +<li class="toctree-l3"><a class="reference internal" href="#linux-paging">Linux paging</a></li> +<li class="toctree-l3"><a class="reference internal" href="#translation-look-aside-buffer">Translation Look-aside Buffer</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#linux-address-space">Linux address space</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#address-space-options-for-32bit-systems">Address space options for 32bit systems</a></li> +<li class="toctree-l3"><a class="reference internal" href="#linear-mappings">Linear mappings</a></li> +<li class="toctree-l3"><a class="reference internal" href="#highmem">Highmem</a></li> +<li class="toctree-l3"><a class="reference internal" href="#fixed-mapped-linear-addresses">Fixed-mapped linear addresses</a></li> +<li class="toctree-l3"><a class="reference internal" href="#temporary-mappings">Temporary mappings</a></li> +<li class="toctree-l3"><a class="reference internal" href="#permanent-mappings">Permanent mappings</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Address Space</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/lectures/address-space.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="address-space"> +<h1>Address Space<a class="headerlink" href="#address-space" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="address-space-slides.html">View slides</a></p> +<div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-address-space simple"> +<li>x86 MMU<ul> +<li>Segmentation</li> +<li>Paging</li> +<li>TLB</li> +</ul> +</li> +<li>Linux Address Space<ul> +<li>User</li> +<li>Kernel</li> +<li>High memory</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="x86-mmu"> +<h2>x86 MMU<a class="headerlink" href="#x86-mmu" title="Permalink to this headline">¶</a></h2> +<p>The x86 MMU has a segmentation and a pagination unit. The segmentation +unit can be used to define logical memory segments defined by a +logical (virtual) start address, a base linear (mapped) address and a +size. A segment can also restrict access based on the access type +(read, execute, write) or the privilege level (we can define some +segments to be accessible only by kernel for example).</p> +<p>When the CPU makes a memory access, it will use the segmentation unit +to translate the logical address to a linear address, based on the +information in the segment descriptor.</p> +<p>If pagination is enabled the linear address will be further +transformed into a physical address, using the information from the +page tables.</p> +<p>Note that the segmentation unit can not be disabled, so if the MMU has +been enabled, segmentation will always be used.</p> +<p class="admonition-x86-mmu"> </p> +<img alt="../_images/ditaa-f3703e3f627a948c59f6f960518d5f68eb7becec.png" src="../_images/ditaa-f3703e3f627a948c59f6f960518d5f68eb7becec.png" /> +<div class="section" id="selectors"> +<h3>Selectors<a class="headerlink" href="#selectors" title="Permalink to this headline">¶</a></h3> +<p>A program can use multiple segments and in order to determine which +segment to use, special registers (named selectors) are used. The +basic selectors that are typically used are CS - "Code Selector", DS - +"Data Selector" and SS - "Stack Selector".</p> +<p>Instruction fetches will by default use CS, while data access will by +default use DS unless the stack is used (e.g. data access through the +pop and push instructions) in which case SS will be used by default.</p> +<p>Selectors have three main fields: the index, the table index and the +running privilege level:</p> +<p class="admonition-selectors"> </p> +<img alt="../_images/ditaa-d6845a04f0ec792beec598d2a9f4c5b92c65529e.png" src="../_images/ditaa-d6845a04f0ec792beec598d2a9f4c5b92c65529e.png" /> +<p>The index will be used to determine which entry of the descriptor +table should be used. <cite>TI</cite> is used to select either the Global +Descriptor Table (GDT) or the Local Descriptor Table (LDT). The tables +are effectively arrays that start at the location specified in the +special registers <cite>GDTR</cite> (for GDT) and <cite>LDTR</cite> (for LDT).</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">LDT was designed so that applications can define their own +particular segments. Although not many applications use this +feature, Linux (and Windows) provide system calls that +allows an application to create their own segments.</p> +</div> +<p><cite>RPL</cite> is only used for CS and it represents the current privilege +level. There are 4 privilege levels, the highest level being 0 (and +typically used by the kernel) and the lowest is 3 (and typically used +by user applications).</p> +</div> +<div class="section" id="segment-descriptor"> +<h3>Segment descriptor<a class="headerlink" href="#segment-descriptor" title="Permalink to this headline">¶</a></h3> +<p>The CPU will use the <cite>index</cite> field of the selector to access an 8 byte +descriptor:</p> +<p class="admonition-segment-descriptor"> </p> +<img alt="../_images/ditaa-5cd4a8fa1ad97cff4bb1f64da13ce9ebfcfc4562.png" src="../_images/ditaa-5cd4a8fa1ad97cff4bb1f64da13ce9ebfcfc4562.png" /> +<ul class="simple"> +<li>Base: linear address for the start of the segment</li> +<li>Limit: size of the segment</li> +<li>G: granularity bit: if set the size is in bytes otherwise in 4K pages</li> +<li>B/D: data/code</li> +<li>Type: code segment, data/stack, TSS, LDT, GDT</li> +<li>Protection: the minimum priviledge level required to access the +segment (RPL is checked against DPL)</li> +</ul> +<p>Some of the descriptor fields should be familiar. And that is because +there is some resemblance with Interrupt Descriptors we looked at +previously.</p> +</div> +<div class="section" id="segmentation-in-linux"> +<h3>Segmentation in Linux<a class="headerlink" href="#segmentation-in-linux" title="Permalink to this headline">¶</a></h3> +<p>In Linux, segments are not used to define the stack, code or +data. These will be setup using the paging unit as it allows better +granularity and more importantly it allows Linux to use a generic +approach that works on other architectures (that don't have +segmentation support).</p> +<p>However, because the segmentation unit can not be disabled Linux must +create 4 generic 0 - 4GB segments for: kernel code, kernel data, user +code and user data.</p> +<p>Besides these, Linux uses segments for implementing Thread Local +Storage (TLS) together with the <cite>set_thread_area</cite> system call.</p> +<p>It also uses the TSS segment in order to define the kernel stack to +use when a change of privilege (e.g. system call, interrupt while +running in user-space) occurs.</p> +<div class="admonition-segmentation-in-linux highlight-c"><div class="highlight"><pre><span></span><span class="cm">/*</span> +<span class="cm"> * The layout of the per-CPU GDT under Linux:</span> +<span class="cm"> *</span> +<span class="cm"> * 0 - null <=== cacheline #1</span> +<span class="cm"> * 1 - reserved</span> +<span class="cm"> * 2 - reserved</span> +<span class="cm"> * 3 - reserved</span> +<span class="cm"> *</span> +<span class="cm"> * 4 - unused <=== cacheline #2</span> +<span class="cm"> * 5 - unused</span> +<span class="cm"> *</span> +<span class="cm"> * ------- start of TLS (Thread-Local Storage) segments:</span> +<span class="cm"> *</span> +<span class="cm"> * 6 - TLS segment #1 [ glibc's TLS segment ]</span> +<span class="cm"> * 7 - TLS segment #2 [ Wine's %fs Win32 segment ]</span> +<span class="cm"> * 8 - TLS segment #3 <=== cacheline #3</span> +<span class="cm"> * 9 - reserved</span> +<span class="cm"> * 10 - reserved</span> +<span class="cm"> * 11 - reserved</span> +<span class="cm"> *</span> +<span class="cm"> * ------- start of kernel segments:</span> +<span class="cm"> *</span> +<span class="cm"> * 12 - kernel code segment <=== cacheline #4</span> +<span class="cm"> * 13 - kernel data segment</span> +<span class="cm"> * 14 - default user CS</span> +<span class="cm"> * 15 - default user DS</span> +<span class="cm"> * 16 - TSS <=== cacheline #5</span> +<span class="cm"> * 17 - LDT</span> +<span class="cm"> * 18 - PNPBIOS support (16->32 gate)</span> +<span class="cm"> * 19 - PNPBIOS support</span> +<span class="cm"> * 20 - PNPBIOS support <=== cacheline #6</span> +<span class="cm"> * 21 - PNPBIOS support</span> +<span class="cm"> * 22 - PNPBIOS support</span> +<span class="cm"> * 23 - APM BIOS support</span> +<span class="cm"> * 24 - APM BIOS support <=== cacheline #7</span> +<span class="cm"> * 25 - APM BIOS support</span> +<span class="cm"> *</span> +<span class="cm"> * 26 - ESPFIX small SS</span> +<span class="cm"> * 27 - per-cpu [ offset to per-cpu data area ]</span> +<span class="cm"> * 28 - stack_canary-20 [ for stack protector ] <=== cacheline #8</span> +<span class="cm"> * 29 - unused</span> +<span class="cm"> * 30 - unused</span> +<span class="cm"> * 31 - TSS for double fault handler</span> +<span class="cm"> */</span> + + <span class="n">DEFINE_PER_CPU_PAGE_ALIGNED</span><span class="p">(</span><span class="k">struct</span> <span class="n">gdt_page</span><span class="p">,</span> <span class="n">gdt_page</span><span class="p">)</span> <span class="o">=</span> <span class="p">{</span> <span class="p">.</span><span class="n">gdt</span> <span class="o">=</span> <span class="p">{</span> + <span class="cp">#ifdef CONFIG_X86_64</span> + <span class="cm">/*</span> +<span class="cm"> * We need valid kernel segments for data and code in long mode too</span> +<span class="cm"> * IRET will check the segment types kkeil 2000/10/28</span> +<span class="cm"> * Also sysret mandates a special GDT layout</span> +<span class="cm"> *</span> +<span class="cm"> * TLS descriptors are currently at a different place compared to i386.</span> +<span class="cm"> * Hopefully nobody expects them at a fixed place (Wine?)</span> +<span class="cm"> */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL32_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc09b</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xa09b</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc093</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER32_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0fb</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0f3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xa0fb</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="cp">#else</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc09a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0fa</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0f2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="cm">/*</span> +<span class="cm"> * Segments used for calling PnP BIOS have byte granularity.</span> +<span class="cm"> * They code segments and data segments have fixed 64k limits,</span> +<span class="cm"> * the transfer segment sizes are set at run time.</span> +<span class="cm"> */</span> + <span class="cm">/* 32-bit code */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_CS32</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x409a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* 16-bit code */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_CS16</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x009a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* 16-bit data */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x0092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* 16-bit data */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_TS1</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x0092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> + <span class="cm">/* 16-bit data */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_TS2</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x0092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> + <span class="cm">/*</span> +<span class="cm"> * The APM segments have byte granularity and their bases</span> +<span class="cm"> * are set at run time. All have 64k limits.</span> +<span class="cm"> */</span> + <span class="cm">/* 32-bit code */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_APMBIOS_BASE</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x409a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* 16-bit code */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_APMBIOS_BASE</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x009a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* data */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_APMBIOS_BASE</span><span class="o">+</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x4092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + + <span class="p">[</span><span class="n">GDT_ENTRY_ESPFIX_SS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PERCPU</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="n">GDT_STACK_CANARY_INIT</span> + <span class="cp">#endif</span> + <span class="p">}</span> <span class="p">};</span> + <span class="n">EXPORT_PER_CPU_SYMBOL_GPL</span><span class="p">(</span><span class="n">gdt_page</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="inspecting-selectors-and-segments"> +<h3>Inspecting selectors and segments<a class="headerlink" href="#inspecting-selectors-and-segments" title="Permalink to this headline">¶</a></h3> +<p class="admonition-inspecting-selectors-and-segments"> </p> +<asciinema-player src="../_images/selectors-and-segments.cast"></asciinema-player></div> +<div class="section" id="x86-paging"> +<h3>x86 Paging<a class="headerlink" href="#x86-paging" title="Permalink to this headline">¶</a></h3> +<p>The x86 paging unit support two types of paging: regular and extended paging.</p> +<p>Regular paging has 2 levels and a fixed page size of 4KB. The linear +address is split in three fields:</p> +<ul class="simple"> +<li>Directory (the 10 most significant bits)</li> +<li>Table (the next 10 most bits)</li> +<li>Offset (the least significant 12 bits)</li> +</ul> +<p class="admonition-regular-paging"> </p> +<img alt="../_images/ditaa-def299abebe530d760a6c8f16c791bbb016f9238.png" src="../_images/ditaa-def299abebe530d760a6c8f16c791bbb016f9238.png" /> +<p>When extended paging is enabled, a single level is used and pages are +4MB. The linear address is split in two fields:</p> +<ul class="simple"> +<li>Directory (10 most significant bits)</li> +<li>Offset (least significant 22 bits)</li> +</ul> +<img alt="../_images/ditaa-709c2e7a68bfcdcfe9c1938d6ef2a0c9b5627931.png" class="admonition-extended-paging" src="../_images/ditaa-709c2e7a68bfcdcfe9c1938d6ef2a0c9b5627931.png" /> +</div> +<div class="section" id="page-tables"> +<h3>Page tables<a class="headerlink" href="#page-tables" title="Permalink to this headline">¶</a></h3> +<p>We can mix regular and extended paging, the directory page has a bit +that specifies if extended or regular paging should be used. The +special CR3 register points to the base of the page directory and page +directory entries point to the base of the page table.</p> +<p>Both page directory and page table have 1024 entries and each entry +has 4 bytes.</p> +<p>All tables are stored in memory and the page table addresses are +physical addresses.</p> +<span class="admonition-page-tables"></span><p>Page table entry fields:</p> +<ul class="admonition-page-table-entry-fields simple"> +<li>Present/Absent</li> +<li>PFN (Page Frame Number): the most 20 significant bits of the physical address</li> +<li>Accessed - not updated by hardware (can be used by OS for housekeeping)</li> +<li>Dirty - not updated by hardware (can be used by OS for housekeeping)</li> +<li>Access rights: Read/Write</li> +<li>Privilege: User/Supervisor</li> +<li>Page size - only for page directory; if set extended paging is used</li> +<li>PCD (page cache disable), PWT (page write through)</li> +</ul> +</div> +<div class="section" id="linux-paging"> +<h3>Linux paging<a class="headerlink" href="#linux-paging" title="Permalink to this headline">¶</a></h3> +<p>Linux paging uses 4 levels in order to support 64bit +architectures. The diagram below shows how the various virtual address +chunks are used to index the page tables and compute the physical +address.</p> +<img alt="../_images/ditaa-5e4d73e3fcb24db9d1f8c16daddf98694c063fe6.png" class="admonition-linux-paging" src="../_images/ditaa-5e4d73e3fcb24db9d1f8c16daddf98694c063fe6.png" /> +<p>Linux has a common API for creating and walking page tables. Creating +and modifying address spaces for kernel and processes is done using +the same generic code which relies on macros and functions to +translate these generic operations in code that runs on different +architectures.</p> +<p>Here is an example of how we can translate a virtual address to a +physical address, using the Linux page table APIs:</p> +<div class="admonition-linux-apis-for-page-table-handling highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="o">*</span> <span class="n">page</span><span class="p">;</span> +<span class="n">pgd_t</span> <span class="n">pgd</span><span class="p">;</span> +<span class="n">pmd_t</span> <span class="n">pmd</span><span class="p">;</span> +<span class="n">pud_t</span> <span class="n">pud</span><span class="p">;</span> +<span class="n">pte_t</span> <span class="n">pte</span><span class="p">;</span> +<span class="kt">void</span> <span class="o">*</span><span class="n">laddr</span><span class="p">,</span> <span class="o">*</span><span class="n">paddr</span><span class="p">;</span> + +<span class="n">pgd</span> <span class="o">=</span> <span class="n">pgd_offset</span><span class="p">(</span><span class="n">mm</span><span class="p">,</span> <span class="n">vaddr</span><span class="p">);</span> +<span class="n">pud</span> <span class="o">=</span> <span class="n">pud_offet</span><span class="p">(</span><span class="n">pgd</span><span class="p">,</span> <span class="n">vaddr</span><span class="p">);</span> +<span class="n">pmd</span> <span class="o">=</span> <span class="n">pmd_offset</span><span class="p">(</span><span class="n">pud</span><span class="p">,</span> <span class="n">vaddr</span><span class="p">);</span> +<span class="n">pte</span> <span class="o">=</span> <span class="n">pte_offset</span><span class="p">(</span><span class="n">pmd</span><span class="p">,</span> <span class="n">vaddr</span><span class="p">);</span> +<span class="n">page</span> <span class="o">=</span> <span class="n">pte_page</span><span class="p">(</span><span class="n">pte</span><span class="p">);</span> +<span class="n">laddr</span> <span class="o">=</span> <span class="n">page_address</span><span class="p">(</span><span class="n">page</span><span class="p">);</span> +<span class="n">paddr</span> <span class="o">=</span> <span class="n">virt_to_phys</span><span class="p">(</span><span class="n">laddr</span><span class="p">);</span> +</pre></div> +</div> +<p>In order to support architectures with less than 4 levels of +pagination (such as for x86 32bits) some macros and / or functions are +0 / empty:</p> +<div class="admonition-what-about-platforms-with-less-then-4-levels-of-pagination highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kr">inline</span> <span class="n">pud_t</span> <span class="o">*</span> <span class="nf">pud_offset</span><span class="p">(</span><span class="n">pgd_t</span> <span class="o">*</span> <span class="n">pgd</span><span class="p">,</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">address</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="p">(</span><span class="n">pud_t</span> <span class="o">*</span><span class="p">)</span><span class="n">pgd</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kr">inline</span> <span class="n">pmd_t</span> <span class="o">*</span> <span class="nf">pmd_offset</span><span class="p">(</span><span class="n">pud_t</span> <span class="o">*</span> <span class="n">pud</span><span class="p">,</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">address</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="p">(</span><span class="n">pmd_t</span> <span class="o">*</span><span class="p">)</span><span class="n">pud</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="translation-look-aside-buffer"> +<h3>Translation Look-aside Buffer<a class="headerlink" href="#translation-look-aside-buffer" title="Permalink to this headline">¶</a></h3> +<p>When using virtual memory, due to the table page organization, we may +need an extra 1 (x86 extended paging), 2 (x86 regular paging) or 3 +(x86 64bit) memory access(es).</p> +<p>A special cache, called Translation Look-aside Buffer (TLB) is used to +speed up translations from virtual address to physical addresses.</p> +<p>The TLB has the following properties:</p> +<ul class="admonition-translation-look-aside-buffer simple"> +<li>Caches paging information (PFN, rights, privilege)</li> +<li>Content Addressable Memory / Associative Memory<ul> +<li>Very small (64-128)</li> +<li>Very fast (single cycle due to parallel search implementation)</li> +</ul> +</li> +<li>CPUs usually have two TLBs: i-TLB (code) and d-TLB (data)</li> +<li>TLB miss penalty: up hundreds of cycles</li> +</ul> +<p>As with other caches, we must be careful to not create consistency +issues.</p> +<p>For example, when changing the mapping of one page to point to a +different physical memory location in the page tables, we must +invalidate the associated TLB entry. Otherwise, the MMU will do the +translation to the old physical address instead of the new physical +address.</p> +<p>The x86 platform supports TLB invalidation through two types of +operations.</p> +<p class="admonition-tlb-invalidation">Single address invalidation:</p> +<div class="highlight-asm"><div class="highlight"><pre><span></span>mov $addr, %eax +invlpg %(eax) +</pre></div> +</div> +<p>Full invalidation:</p> +<div class="highlight-asm"><div class="highlight"><pre><span></span><span class="nf">mov</span> <span class="nv">%cr3</span><span class="p">,</span> <span class="nv">%eax</span> +<span class="nf">mov</span> <span class="nv">%eax</span><span class="p">,</span> <span class="nv">%cr3</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="linux-address-space"> +<h2>Linux address space<a class="headerlink" href="#linux-address-space" title="Permalink to this headline">¶</a></h2> +<div class="section" id="address-space-options-for-32bit-systems"> +<h3>Address space options for 32bit systems<a class="headerlink" href="#address-space-options-for-32bit-systems" title="Permalink to this headline">¶</a></h3> +<p>There are two main options for implementing kernel and user space: +either dedicated address spaces for each, or split a shared address +space.</p> +<p class="admonition-address-space-options-for-32bit-systems"> </p> +<img alt="../_images/ditaa-d5d1129b0298a2ea5f116c9d4b246eb1b888db6b.png" src="../_images/ditaa-d5d1129b0298a2ea5f116c9d4b246eb1b888db6b.png" /> +<p>Each has advantages and disadvantages:</p> +<ul class="admonition-advantages-and-disadvantages simple"> +<li>Disadvantages for dedicated kernel space:<ul> +<li>Fully invalidating the TLB for every system call</li> +</ul> +</li> +<li>Disadvantages for shared address space<ul> +<li>Less address space for both kernel and user processes</li> +</ul> +</li> +</ul> +<p>Linux is using a split address space for 32 bit systems, although in +the past there were options for supporting 4/4s split or dedicated +kernel address space (on those architecture that supports it, +e.g. x86). Linux always uses split address space for 64 bit systems.</p> +<p>On overview of the Linux address space is presented below:</p> +<p class="admonition-linux-address-space-for-32bit-systems"> </p> +<img alt="../_images/ditaa-3985c420def8f30934a72ea8c738a00ed629c298.png" src="../_images/ditaa-3985c420def8f30934a72ea8c738a00ed629c298.png" /> +</div> +<div class="section" id="linear-mappings"> +<h3>Linear mappings<a class="headerlink" href="#linear-mappings" title="Permalink to this headline">¶</a></h3> +<p>Linear mappings refer to particular way of mapping virtual pages to +physical pages, where virtual page V, V + 1, ... V + n is mapped to +physical pages P, P + 1, ..., P + n.</p> +<p>To understand the necessity of linear mappings, we should look at +common kernel operations that involves using both the virtual and +physical address of a page such as an I/O transfer:</p> +<ul class="admonition-virtual-to-physical-address-translations-for-i-o-transfers simple"> +<li>Use the virtual address of a kernel buffer in order to copy to +data from from user space</li> +<li>Walk the page tables to transform the kernel buffer virtual +address to a physical address</li> +<li>Use the physical address of the kernel buffer to start a DMA +transfer</li> +</ul> +<p>However, if we use linear mappings and the kernel buffers are in the +linear mapping area, then:</p> +<ul class="admonition-linear-mappings simple"> +<li>Virtual to physical address space translation is reduced to one +operation (instead of walking the page tables)</li> +<li>Less memory is used to create the page tables</li> +<li>Less TLB entries are used for the kernel memory</li> +</ul> +</div> +<div class="section" id="highmem"> +<h3>Highmem<a class="headerlink" href="#highmem" title="Permalink to this headline">¶</a></h3> +<p>The "highmem" part of the virtual address space is used to create +arbitrary mappings (as opposed to linear mappings in lowmem). On 32bit +systems the highmem area is absolutely required in order to access +physical memory outside of lowmem. However, highmem is also used on +64bit systems but the use-case there is mainly to allow arbitrary +mappings in kernel space.</p> +<p class="admonition-highmem"> </p> +<img alt="../_images/ditaa-bb8455a43088bf800eece11869f6ff857574605d.png" src="../_images/ditaa-bb8455a43088bf800eece11869f6ff857574605d.png" /> +<p>There are multiple types of mappings in the highmem area:</p> +<ul class="simple"> +<li>Multi-page permanent mappings (vmalloc, ioremap)</li> +<li>Temporary 1 page mappings (atomic_kmap)</li> +<li>Permanent 1 page mappings (kmap, fix-mapped linear addresses)</li> +</ul> +<p>Multiple page mappings allows mapping of ranges of physical memory +into the highmem area. Each such mapping is guarded by a +non-accessible page to catch buffer overflow and underflow errors.</p> +<p>The APIs that maps multiple pages into highmem are:</p> +<div class="admonition-multi-page-permanent-mappings highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="o">*</span> <span class="nf">vmalloc</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">size</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">vfree</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span> <span class="n">addr</span><span class="p">);</span> + +<span class="kt">void</span> <span class="o">*</span><span class="nf">ioremap</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">offset</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">size</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">iounmap</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span> <span class="n">addr</span><span class="p">);</span> +</pre></div> +</div> +<p><code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code> is used to allocate non-contiguous system memory +pages as a contiguous segment in the kernel virtual address space. It +is usefully when allocating large buffers because due to fragmentation +it is unlikely to find free large chunks of physical contiguous memory.</p> +<p><code class="xref c c-func docutils literal"><span class="pre">ioremap()</span></code> is used to map device memory or device registers +into the kernel address space. It maps a contiguous physical memory +range into highmem with page caching disabled.</p> +</div> +<div class="section" id="fixed-mapped-linear-addresses"> +<h3>Fixed-mapped linear addresses<a class="headerlink" href="#fixed-mapped-linear-addresses" title="Permalink to this headline">¶</a></h3> +<p>Fixed-mapped linear addresses are a special class of singular page +mappings that are used for accessing registers of commonly used +peripherals such as the APIC or IO APIC.</p> +<p>Typical I/O access for peripherals is to use a base (the kernel +virtual address space where the peripheral registers are mapped) + +offsets for various registers.</p> +<p>In order to optimize access, the base is reserved at compile time +(e.g. 0xFFFFF000). Since the base is constant, the various register +accesses of the form <cite>base + register offset</cite> will also be constant +and thus the compiler will avoid generating an extra instruction.</p> +<p>In summary, fixed-mapped linear addresses are:</p> +<ul class="admonition-fixed-mapped-linear-addresses simple"> +<li>Reserved virtual addresses (constants)</li> +<li>Mapped to physical addresses during boot</li> +</ul> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">set_fixmap</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="n">phys_addr</span><span class="p">)</span> +<span class="n">set_fixmap_nocache</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="n">phys_addr</span><span class="p">)</span> +</pre></div> +</div> +<p>These addresses are architecture defined and, as an example, this is +the map for x86:</p> +<div class="admonition-fixed-mapped-linear-addresses highlight-c"><div class="highlight"><pre><span></span><span class="cm">/*</span> +<span class="cm"> * Here we define all the compile-time 'special' virtual</span> +<span class="cm"> * addresses. The point is to have a constant address at</span> +<span class="cm"> * compile time, but to set the physical address only</span> +<span class="cm"> * in the boot process.</span> +<span class="cm"> * for x86_32: We allocate these special addresses</span> +<span class="cm"> * from the end of virtual memory (0xfffff000) backwards.</span> +<span class="cm"> * Also this lets us do fail-safe vmalloc(), we</span> +<span class="cm"> * can guarantee that these special addresses and</span> +<span class="cm"> * vmalloc()-ed addresses never overlap.</span> +<span class="cm"> *</span> +<span class="cm"> * These 'compile-time allocated' memory buffers are</span> +<span class="cm"> * fixed-size 4k pages (or larger if used with an increment</span> +<span class="cm"> * higher than 1). Use set_fixmap(idx,phys) to associate</span> +<span class="cm"> * physical memory with fixmap indices.</span> +<span class="cm"> *</span> +<span class="cm"> * TLB entries of such buffers will not be flushed across</span> +<span class="cm"> * task switches.</span> +<span class="cm"> */</span> + +<span class="k">enum</span> <span class="n">fixed_addresses</span> <span class="p">{</span> +<span class="cp">#ifdef CONFIG_X86_32</span> + <span class="n">FIX_HOLE</span><span class="p">,</span> +<span class="cp">#else</span> +<span class="cp">#ifdef CONFIG_X86_VSYSCALL_EMULATION</span> + <span class="n">VSYSCALL_PAGE</span> <span class="o">=</span> <span class="p">(</span><span class="n">FIXADDR_TOP</span> <span class="o">-</span> <span class="n">VSYSCALL_ADDR</span><span class="p">)</span> <span class="o">>></span> <span class="n">PAGE_SHIFT</span><span class="p">,</span> +<span class="cp">#endif</span> +<span class="cp">#endif</span> + <span class="n">FIX_DBGP_BASE</span><span class="p">,</span> + <span class="n">FIX_EARLYCON_MEM_BASE</span><span class="p">,</span> +<span class="cp">#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT</span> + <span class="n">FIX_OHCI1394_BASE</span><span class="p">,</span> +<span class="cp">#endif</span> +<span class="cp">#ifdef CONFIG_X86_LOCAL_APIC</span> + <span class="n">FIX_APIC_BASE</span><span class="p">,</span> <span class="cm">/* local (CPU) APIC) -- required for SMP or not */</span> +<span class="cp">#endif</span> +<span class="cp">#ifdef CONFIG_X86_IO_APIC</span> + <span class="n">FIX_IO_APIC_BASE_0</span><span class="p">,</span> + <span class="n">FIX_IO_APIC_BASE_END</span> <span class="o">=</span> <span class="n">FIX_IO_APIC_BASE_0</span> <span class="o">+</span> <span class="n">MAX_IO_APICS</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> +<span class="cp">#endif</span> +<span class="cp">#ifdef CONFIG_X86_32</span> + <span class="n">FIX_KMAP_BEGIN</span><span class="p">,</span> <span class="cm">/* reserved pte's for temporary kernel mappings */</span> + <span class="n">FIX_KMAP_END</span> <span class="o">=</span> <span class="n">FIX_KMAP_BEGIN</span><span class="o">+</span><span class="p">(</span><span class="n">KM_TYPE_NR</span><span class="o">*</span><span class="n">NR_CPUS</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> +<span class="cp">#ifdef CONFIG_PCI_MMCONFIG</span> + <span class="n">FIX_PCIE_MCFG</span><span class="p">,</span> +<span class="cp">#endif</span> +</pre></div> +</div> +<p>Notice how easy is to do the conversion between the virtual address +and the fixed address indexes:</p> +<div class="admonition-conversion-between-virtual-address-fixed-address-indexes highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))</span> +<span class="cp">#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)</span> + +<span class="cp">#ifndef __ASSEMBLY__</span> +<span class="cm">/*</span> +<span class="cm"> * 'index to address' translation. If anyone tries to use the idx</span> +<span class="cm"> * directly without translation, we catch the bug with a NULL-deference</span> +<span class="cm"> * kernel oops. Illegal ranges of incoming indices are caught too.</span> +<span class="cm"> */</span> + <span class="k">static</span> <span class="n">__always_inline</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="nf">fix_to_virt</span><span class="p">(</span><span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">idx</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">BUILD_BUG_ON</span><span class="p">(</span><span class="n">idx</span> <span class="o">>=</span> <span class="n">__end_of_fixed_addresses</span><span class="p">);</span> + <span class="k">return</span> <span class="n">__fix_to_virt</span><span class="p">(</span><span class="n">idx</span><span class="p">);</span> + <span class="p">}</span> + + <span class="k">static</span> <span class="kr">inline</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="nf">virt_to_fix</span><span class="p">(</span><span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">vaddr</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">BUG_ON</span><span class="p">(</span><span class="n">vaddr</span> <span class="o">>=</span> <span class="n">FIXADDR_TOP</span> <span class="o">||</span> <span class="n">vaddr</span> <span class="o"><</span> <span class="n">FIXADDR_START</span><span class="p">);</span> + <span class="k">return</span> <span class="n">__virt_to_fix</span><span class="p">(</span><span class="n">vaddr</span><span class="p">);</span> + <span class="p">}</span> + + + <span class="kr">inline</span> <span class="kt">long</span> <span class="nf">fix_to_virt</span><span class="p">(</span><span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">idx</span><span class="p">)</span> + <span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">idx</span> <span class="o">>=</span> <span class="n">__end_of_fixed_addresses</span><span class="p">)</span> + <span class="n">__this_fixmap_does_not_exist</span><span class="p">();</span> + <span class="k">return</span> <span class="p">(</span><span class="mh">0xffffe000UL</span> <span class="o">-</span> <span class="p">(</span><span class="n">idx</span> <span class="o"><<</span> <span class="n">PAGE_SHIFT</span><span class="p">));</span> + <span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="temporary-mappings"> +<h3>Temporary mappings<a class="headerlink" href="#temporary-mappings" title="Permalink to this headline">¶</a></h3> +<p>Temporary mappings can be used to map a single physical page, very +fast, in kernel space. It can be used in interrupt context but the +atomic kmap section, defined in between the <code class="xref c c-func docutils literal"><span class="pre">kmap_atomic()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">kunmap_atomic()</span></code> can not be preempted. That is why these are +called temporary mappings, as they can only be used momentarily.</p> +<span class="admonition-temporary-mappings"></span><p>Temporary mappings are very fast because there is no locking or +searching required and also there is no full TLB invalidation, just +the particular virtual page will be TLB invalidated.</p> +<p>Here are some code snippets that show that temporary mappings are +implemented:</p> +<div class="admonition-temporary-mappings-implementation highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define kmap_atomic(page) kmap_atomic_prot(page, kmap_prot)</span> + +<span class="kt">void</span> <span class="o">*</span><span class="nf">kmap_atomic_high_prot</span><span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">,</span> <span class="n">pgprot_t</span> <span class="n">prot</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">vaddr</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">idx</span><span class="p">,</span> <span class="n">type</span><span class="p">;</span> + + <span class="n">type</span> <span class="o">=</span> <span class="n">kmap_atomic_idx_push</span><span class="p">();</span> + <span class="n">idx</span> <span class="o">=</span> <span class="n">type</span> <span class="o">+</span> <span class="n">KM_TYPE_NR</span><span class="o">*</span><span class="n">smp_processor_id</span><span class="p">();</span> + <span class="n">vaddr</span> <span class="o">=</span> <span class="n">__fix_to_virt</span><span class="p">(</span><span class="n">FIX_KMAP_BEGIN</span> <span class="o">+</span> <span class="n">idx</span><span class="p">);</span> + <span class="n">BUG_ON</span><span class="p">(</span><span class="o">!</span><span class="n">pte_none</span><span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="n">kmap_pte</span><span class="o">-</span><span class="n">idx</span><span class="p">)));</span> + <span class="n">set_pte</span><span class="p">(</span><span class="n">kmap_pte</span><span class="o">-</span><span class="n">idx</span><span class="p">,</span> <span class="n">mk_pte</span><span class="p">(</span><span class="n">page</span><span class="p">,</span> <span class="n">prot</span><span class="p">));</span> + <span class="n">arch_flush_lazy_mmu_mode</span><span class="p">();</span> + + <span class="k">return</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">vaddr</span><span class="p">;</span> +<span class="p">}</span> +<span class="n">EXPORT_SYMBOL</span><span class="p">(</span><span class="n">kmap_atomic_high_prot</span><span class="p">);</span> + +<span class="k">static</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="nf">kmap_atomic_idx_push</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">idx</span> <span class="o">=</span> <span class="n">__this_cpu_inc_return</span><span class="p">(</span><span class="n">__kmap_atomic_idx</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> + +<span class="cp">#ifdef CONFIG_DEBUG_HIGHMEM</span> + <span class="n">WARN_ON_ONCE</span><span class="p">(</span><span class="n">in_irq</span><span class="p">()</span> <span class="o">&&</span> <span class="o">!</span><span class="n">irqs_disabled</span><span class="p">());</span> + <span class="n">BUG_ON</span><span class="p">(</span><span class="n">idx</span> <span class="o">>=</span> <span class="n">KM_TYPE_NR</span><span class="p">);</span> +<span class="cp">#endif</span> + <span class="k">return</span> <span class="n">idx</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Notice that fix-mapped linear addresses and a stack like approach is +used: each CPU has KM_TYPE_NR reserved entries which are used in a +first code first serve option. This allows using multiple temporary +mappings at once, for example one in process context, one in an +interrupt handler, and a few more in tasklets or softirqs.</p> +<span class="admonition-implementation-of-temporary-mappings"></span></div> +<div class="section" id="permanent-mappings"> +<h3>Permanent mappings<a class="headerlink" href="#permanent-mappings" title="Permalink to this headline">¶</a></h3> +<p>Permanent mappings allows users to hold on to a mapping for long +(undefined) periods of time which means that context switch are +allowed after a mapping and before releasing it.</p> +<p>This flexibility comes with a price though. A search operation is +performed to find a free entry and they can not be used in interrupt +context - the operation that tries to find a free virtual address page +may block. There is a limited number of permanent mappings available +(topically one page is reserved for permanent mappings)</p> +<span class="admonition-permanent-mappings"></span></div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="smp.html" class="btn btn-neutral float-left" title="Symmetric Multi-Processing" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="memory-management.html" class="btn btn-neutral float-right" title="Memory Management" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/arch-slides.html b/refs/pull/405/merge/lectures/arch-slides.html new file mode 100644 index 00000000..93cabcde --- /dev/null +++ b/refs/pull/405/merge/lectures/arch-slides.html @@ -0,0 +1,244 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Architecture Layer — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="next" title="Virtualization" href="virt.html" /> + <link rel="prev" title="Network Management" href="networking.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-introduction slide level-2"> + +<h2>Introduction</h2> + +<ul class="simple"> +<li>Overview of the arch layer</li> +<li>Overview of the boot process</li> +</ul> + + + + +</article> +<article class="admonition-overview-of-the-arch-layer slide level-2"> + +<h2>Overview of the arch layer</h2> + +<a class="reference internal image-reference" href="../_images/ditaa-ae895f3a8e26b92bf6c6ecbbd71e2c88912d5607.png"><img alt="../_images/ditaa-ae895f3a8e26b92bf6c6ecbbd71e2c88912d5607.png" src="../_images/ditaa-ae895f3a8e26b92bf6c6ecbbd71e2c88912d5607.png" style="height: 100%;" /></a> + + + + +</article> +<article class="admonition-bootstrap slide level-2"> + +<h2>Bootstrap</h2> + +<ul class="simple"> +<li>The first kernel code that runs</li> +<li>Typically runs with the MMU disabled</li> +<li>Move / Relocate kernel code</li> +</ul> + + + + +</article> +<article class="admonition-bootstrap slide level-2"> + +<h2>Bootstrap</h2> + +<ul class="simple"> +<li>The first kernel code that runs</li> +<li>Typically runs with the MMU disabled</li> +<li>Copy bootloader arguments and determine kernel run location</li> +<li>Move / relocate kernel code to final location</li> +<li>Initial MMU setup - map the kernel</li> +</ul> + + + + +</article> +<article class="admonition-memory-setup slide level-2"> + +<h2>Memory Setup</h2> + +<ul class="simple"> +<li>Determine available memory and setup the boot memory allocator</li> +<li>Manages memory regions before the page allocator is setup</li> +<li>Bootmem - used a bitmap to track free blocks</li> +<li>Memblock - deprecates bootmem and adds support for memory ranges<ul> +<li>Supports both physical and virtual addresses</li> +<li>support NUMA architectures</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-mmu-management slide level-2"> + +<h2>MMU management</h2> + +<ul class="simple"> +<li>Implements the generic page table manipulation APIs: types, +accessors, flags</li> +<li>Implement TLB management APIs: flush, invalidate</li> +</ul> + + + + +</article> +<article class="admonition-thread-management slide level-2"> + +<h2>Thread Management</h2> + +<ul class="simple"> +<li>Defines the thread type (struct thread_info) and implements +functions for allocating threads (if needed)</li> +<li>Implement <code class="xref c c-func docutils literal"><span class="pre">copy_thread()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">switch_context()</span></code></li> +</ul> + + + + +</article> +<article class="admonition-timer-management slide level-2"> + +<h2>Timer Management</h2> + +<ul class="simple"> +<li>Setup the timer tick and provide a time source</li> +<li>Mostly transitioned to platform drivers<ul> +<li>clock_event_device - for scheduling timers</li> +<li>clocksource - for reading the time</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-irqs-and-exception-management slide level-2"> + +<h2>IRQs and exception management</h2> + +<ul class="simple"> +<li>Define interrupt and exception handlers / entry points</li> +<li>Setup priorities</li> +<li>Platform drivers for interrupt controllers</li> +</ul> + + + + +</article> +<article class="admonition-system-calls slide level-2"> + +<h2>System calls</h2> + +<ul class="simple"> +<li>Define system call entry point(s)</li> +<li>Implement user-space access primitives (e.g. copy_to_user)</li> +</ul> + + + + +</article> +<article class="admonition-platform-drivers slide level-2"> + +<h2>Platform Drivers</h2> + +<ul class="simple"> +<li>Platform and architecture specific drivers</li> +<li>Bindings to platform device enumeration methods (e.g. device tree +or ACPI)</li> +</ul> + + + + +</article> +<article class="admonition-machine-specific-code slide level-2"> + +<h2>Machine specific code</h2> + +<ul class="simple"> +<li>Some architectures use a "machine" / "platform" abstraction</li> +<li>Typical for architecture used in embedded systems with a lot of +variety (e.g. ARM, powerPC)</li> +</ul> + + + + +</article> +<article class="admonition-boot-flow-inspection slide level-2"> + +<h2>Boot flow inspection</h2> + +<asciinema-player src="../_images/boot.cast"></asciinema-player> + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/arch.html b/refs/pull/405/merge/lectures/arch.html new file mode 100644 index 00000000..316dfeec --- /dev/null +++ b/refs/pull/405/merge/lectures/arch.html @@ -0,0 +1,282 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Architecture Layer — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Virtualization" href="virt.html" /> + <link rel="prev" title="Network Management" href="networking.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Network Management</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Architecture Layer</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="#overview-of-the-arch-layer">Overview of the arch layer</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#boot-strap">Boot strap</a></li> +<li class="toctree-l3"><a class="reference internal" href="#boot-strap-1">Boot strap</a></li> +<li class="toctree-l3"><a class="reference internal" href="#memory-setup">Memory setup</a></li> +<li class="toctree-l3"><a class="reference internal" href="#mmu-management">MMU management</a></li> +<li class="toctree-l3"><a class="reference internal" href="#thread-management">Thread Management</a></li> +<li class="toctree-l3"><a class="reference internal" href="#time-management">Time Management</a></li> +<li class="toctree-l3"><a class="reference internal" href="#irqs-and-exception-management">IRQs and exception management</a></li> +<li class="toctree-l3"><a class="reference internal" href="#system-calls">System calls</a></li> +<li class="toctree-l3"><a class="reference internal" href="#platform-drivers">Platform Drivers</a></li> +<li class="toctree-l3"><a class="reference internal" href="#machine-specific-code">Machine specific code</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#overview-of-the-boot-process">Overview of the boot process</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Architecture Layer</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/lectures/arch.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="architecture-layer"> +<h1>Architecture Layer<a class="headerlink" href="#architecture-layer" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="arch-slides.html">View slides</a></p> +<div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-introduction simple"> +<li>Overview of the arch layer</li> +<li>Overview of the boot process</li> +</ul> +</div> +<div class="section" id="overview-of-the-arch-layer"> +<h2>Overview of the arch layer<a class="headerlink" href="#overview-of-the-arch-layer" title="Permalink to this headline">¶</a></h2> +<a class="admonition-overview-of-the-arch-layer reference internal image-reference" href="../_images/ditaa-ae895f3a8e26b92bf6c6ecbbd71e2c88912d5607.png"><img alt="../_images/ditaa-ae895f3a8e26b92bf6c6ecbbd71e2c88912d5607.png" class="admonition-overview-of-the-arch-layer" src="../_images/ditaa-ae895f3a8e26b92bf6c6ecbbd71e2c88912d5607.png" style="height: 100%;" /></a> +<div class="section" id="boot-strap"> +<h3>Boot strap<a class="headerlink" href="#boot-strap" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-bootstrap simple"> +<li>The first kernel code that runs</li> +<li>Typically runs with the MMU disabled</li> +<li>Move / Relocate kernel code</li> +</ul> +</div> +<div class="section" id="boot-strap-1"> +<h3>Boot strap<a class="headerlink" href="#boot-strap-1" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-bootstrap simple"> +<li>The first kernel code that runs</li> +<li>Typically runs with the MMU disabled</li> +<li>Copy bootloader arguments and determine kernel run location</li> +<li>Move / relocate kernel code to final location</li> +<li>Initial MMU setup - map the kernel</li> +</ul> +</div> +<div class="section" id="memory-setup"> +<h3>Memory setup<a class="headerlink" href="#memory-setup" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-memory-setup simple"> +<li>Determine available memory and setup the boot memory allocator</li> +<li>Manages memory regions before the page allocator is setup</li> +<li>Bootmem - used a bitmap to track free blocks</li> +<li>Memblock - deprecates bootmem and adds support for memory ranges<ul> +<li>Supports both physical and virtual addresses</li> +<li>support NUMA architectures</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="mmu-management"> +<h3>MMU management<a class="headerlink" href="#mmu-management" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-mmu-management simple"> +<li>Implements the generic page table manipulation APIs: types, +accessors, flags</li> +<li>Implement TLB management APIs: flush, invalidate</li> +</ul> +</div> +<div class="section" id="thread-management"> +<h3>Thread Management<a class="headerlink" href="#thread-management" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-thread-management simple"> +<li>Defines the thread type (struct thread_info) and implements +functions for allocating threads (if needed)</li> +<li>Implement <code class="xref c c-func docutils literal"><span class="pre">copy_thread()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">switch_context()</span></code></li> +</ul> +</div> +<div class="section" id="time-management"> +<h3>Time Management<a class="headerlink" href="#time-management" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-timer-management simple"> +<li>Setup the timer tick and provide a time source</li> +<li>Mostly transitioned to platform drivers<ul> +<li>clock_event_device - for scheduling timers</li> +<li>clocksource - for reading the time</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="irqs-and-exception-management"> +<h3>IRQs and exception management<a class="headerlink" href="#irqs-and-exception-management" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-irqs-and-exception-management simple"> +<li>Define interrupt and exception handlers / entry points</li> +<li>Setup priorities</li> +<li>Platform drivers for interrupt controllers</li> +</ul> +</div> +<div class="section" id="system-calls"> +<h3>System calls<a class="headerlink" href="#system-calls" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-system-calls simple"> +<li>Define system call entry point(s)</li> +<li>Implement user-space access primitives (e.g. copy_to_user)</li> +</ul> +</div> +<div class="section" id="platform-drivers"> +<h3>Platform Drivers<a class="headerlink" href="#platform-drivers" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-platform-drivers simple"> +<li>Platform and architecture specific drivers</li> +<li>Bindings to platform device enumeration methods (e.g. device tree +or ACPI)</li> +</ul> +</div> +<div class="section" id="machine-specific-code"> +<h3>Machine specific code<a class="headerlink" href="#machine-specific-code" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-machine-specific-code simple"> +<li>Some architectures use a "machine" / "platform" abstraction</li> +<li>Typical for architecture used in embedded systems with a lot of +variety (e.g. ARM, powerPC)</li> +</ul> +</div> +</div> +<div class="section" id="overview-of-the-boot-process"> +<h2>Overview of the boot process<a class="headerlink" href="#overview-of-the-boot-process" title="Permalink to this headline">¶</a></h2> +<asciinema-player src="../_images/boot.cast"></asciinema-player></div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="networking.html" class="btn btn-neutral float-left" title="Network Management" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="virt.html" class="btn btn-neutral float-right" title="Virtualization" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/debugging-slides.html b/refs/pull/405/merge/lectures/debugging-slides.html new file mode 100644 index 00000000..692811f1 --- /dev/null +++ b/refs/pull/405/merge/lectures/debugging-slides.html @@ -0,0 +1,830 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Debugging — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="next" title="Network Management" href="networking.html" /> + <link rel="prev" title="Filesystem Management" href="fs.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-debugging slide level-2"> + +<h2>Debugging</h2> + +<ul class="simple"> +<li>decoding an oops/panic</li> +<li>list debugging</li> +<li>memory debugging</li> +<li>locking debugging</li> +<li>profiling</li> +</ul> + + + + +</article> +<article class="admonition-oops-module slide level-2"> + +<h2>Oops module</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">noinline</span> <span class="kt">void</span> <span class="nf">do_oops</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="o">*</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="p">)</span><span class="mh">0x42</span> <span class="o">=</span> <span class="sc">'a'</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">so2_oops_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"oops_init</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="n">do_oops</span><span class="p">();</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">so2_oops_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"oops exit</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> +<span class="p">}</span> + +<span class="n">module_init</span><span class="p">(</span><span class="n">so2_oops_init</span><span class="p">);</span> +<span class="n">module_exit</span><span class="p">(</span><span class="n">so2_oops_exit</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-oops-information slide level-2"> + +<h2>Oops information</h2> + +<div class="highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~/skels/debugging/oops# insmod oops.ko +BUG: unable to handle kernel NULL pointer dereference at <span class="m">00000042</span> +IP: do_oops+0x8/0x10 <span class="o">[</span>oops<span class="o">]</span> +*pde <span class="o">=</span> <span class="m">00000000</span> +Oops: <span class="m">0002</span> <span class="o">[</span><span class="c1">#1] SMP</span> +Modules linked in: oops<span class="o">(</span>O+<span class="o">)</span> +CPU: <span class="m">0</span> PID: <span class="m">234</span> Comm: insmod Tainted: G O <span class="m">4</span>.15.0+ <span class="c1">#3</span> +Hardware name: QEMU Standard PC <span class="o">(</span>i440FX + PIIX, <span class="m">1996</span><span class="o">)</span>, BIOS Ubuntu-1.8.2-1ubuntu1 <span class="m">04</span>/01/2014 +EIP: do_oops+0x8/0x10 <span class="o">[</span>oops<span class="o">]</span> +CR0: <span class="m">80050033</span> CR2: <span class="m">00000042</span> CR3: 0785f000 CR4: <span class="m">00000690</span> +EIP: 0x44902cc2 +EFLAGS: <span class="m">00000206</span> CPU: <span class="m">0</span> +EAX: ffffffda EBX: 08afb050 ECX: 0000eef4 EDX: 08afb008 +ESI: <span class="m">00000000</span> EDI: bf914dbc EBP: <span class="m">00000000</span> ESP: bf914c1c +DS: 007b ES: 007b FS: <span class="m">0000</span> GS: <span class="m">0033</span> SS: 007b +Code: <a3> <span class="m">42</span> <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> 5d c3 <span class="m">90</span> <span class="m">55</span> <span class="m">89</span> e5 <span class="m">83</span> ec <span class="m">04</span> c7 <span class="m">04</span> <span class="m">24</span> <span class="m">24</span> <span class="m">70</span> <span class="m">81</span> c8 e8 +Killed +</pre></div> +</div> + + + + +</article> +<article class="admonition-oops-stacktrace slide level-2"> + +<h2>Oops stacktrace</h2> + +<div class="highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~/skels/debugging/oops# insmod oops.ko +BUG: unable to handle kernel NULL pointer dereference at <span class="m">00000042</span> +Call Trace: +so2_oops_init+0x17/0x20 <span class="o">[</span>oops<span class="o">]</span> +do_one_initcall+0x37/0x170 +? cache_alloc_debugcheck_after.isra.19+0x15f/0x2f0 +? __might_sleep+0x32/0x90 +? trace_hardirqs_on_caller+0x11c/0x1a0 +? do_init_module+0x17/0x1c2 +? kmem_cache_alloc+0xa4/0x1e0 +? do_init_module+0x17/0x1c2 +do_init_module+0x46/0x1c2 +load_module+0x1f45/0x2380 +SyS_init_module+0xe5/0x100 +do_int80_syscall_32+0x61/0x190 +entry_INT80_32+0x2f/0x2f +Killed +</pre></div> +</div> + + + + +</article> +<article class="admonition-debugging slide level-2"> + +<h2>Debugging</h2> + +<ul class="simple"> +<li>CONFIG_DEBUG_INFO</li> +<li>addr2line</li> +<li>gdb</li> +<li>objdump -dSr</li> +</ul> + + + + +</article> +<article class="admonition-addr2line slide level-2"> + +<h2>addr2line</h2> + +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ addr2line -e oops.o 0x08 +$ skels/debugging/oops/oops.c:5 +$ <span class="c1"># 0x08 is the offset of the offending instruction inside the oops.ko module</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-objdump slide level-2"> + +<h2>objdump</h2> + +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ cat /proc/modules +oops <span class="m">20480</span> <span class="m">1</span> - Loading 0xc8816000 <span class="o">(</span>O+<span class="o">)</span> + +$ objdump -dS --adjust-vma<span class="o">=</span>0xc8816000 oops.ko +c8816000: b8 <span class="m">61</span> <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> mov <span class="nv">$0</span>x61,%eax + +static noinline void do_oops<span class="o">(</span>void<span class="o">)</span> +<span class="o">{</span> +c8816005: <span class="m">55</span> push %ebp +c8816006: <span class="m">89</span> e5 mov %esp,%ebp +*<span class="o">(</span>int*<span class="o">)</span><span class="nv">0x42</span> <span class="o">=</span> <span class="s1">'a'</span><span class="p">;</span> +c8816008: a3 <span class="m">42</span> <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> mov %eax,0x42 +</pre></div> +</div> + + + + +</article> +<article class="admonition-gdb slide level-2"> + +<h2>gdb</h2> + +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ gdb ./vmlinux + +<span class="o">(</span>gdb<span class="o">)</span> list *<span class="o">(</span>do_panic+0x8<span class="o">)</span> +0xc1244138 is in do_panic <span class="o">(</span>lib/test_panic.c:8<span class="o">)</span>. +<span class="m">3</span> +<span class="m">4</span> static struct timer_list panic_timer<span class="p">;</span> +<span class="m">5</span> +<span class="m">6</span> static void do_panic<span class="o">(</span>struct timer_list *unused<span class="o">)</span> +<span class="m">7</span> <span class="o">{</span> +<span class="m">8</span> *<span class="o">(</span>int*<span class="o">)</span><span class="nv">0x42</span> <span class="o">=</span> <span class="s1">'a'</span><span class="p">;</span> +<span class="m">9</span> <span class="o">}</span> +<span class="m">10</span> +<span class="m">11</span> static int so2_panic_init<span class="o">(</span>void<span class="o">)</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-kernel-panic slide level-2"> + +<h2>Kernel panic</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="k">struct</span> <span class="n">timer_list</span> <span class="n">panic_timer</span><span class="p">;</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">do_panic</span><span class="p">(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span><span class="n">unused</span><span class="p">)</span> +<span class="p">{</span> + <span class="o">*</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="p">)</span><span class="mh">0x42</span> <span class="o">=</span> <span class="sc">'a'</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">so2_panic_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"panic_init</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + + <span class="n">timer_setup</span><span class="p">(</span><span class="o">&</span><span class="n">panic_timer</span><span class="p">,</span> <span class="n">do_panic</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> + <span class="n">mod_timer</span><span class="p">(</span><span class="o">&</span><span class="n">panic_timer</span><span class="p">,</span> <span class="n">jiffies</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">HZ</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-list-debugging slide level-2"> + +<h2>List debugging</h2> + +<div class="highlight-bash"><div class="highlight"><pre><span></span>static inline void list_del<span class="o">(</span>struct list_head *entry<span class="o">)</span> +<span class="o">{</span> + __list_del<span class="o">(</span>entry->prev, entry->next<span class="o">)</span><span class="p">;</span> + entry->next <span class="o">=</span> <span class="o">(</span>struct list_head*<span class="o">)</span>LIST_POISON1<span class="p">;</span> + entry->prev <span class="o">=</span> <span class="o">(</span>struct list_head*<span class="o">)</span>LIST_POISON2<span class="p">;</span> +<span class="o">}</span> + +BUG: unable to handle kernel NULL pointer dereference at <span class="m">00000100</span> +IP: crush+0x80/0xb0 <span class="o">[</span>list<span class="o">]</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-memory-debugging slide level-2"> + +<h2>Memory debugging</h2> + +<ul class="simple"> +<li>SLAB/SLUB debugging</li> +<li>KASAN</li> +<li>kmemcheck</li> +<li>DEBUG_PAGEALLOC</li> +</ul> + + + + +</article> +<article class="admonition-slab-debugging slide level-2"> + +<h2>Slab debugging</h2> + +<ul class="simple"> +<li>CONFIG_DEBUG_SLAB</li> +<li>poisoned based memory debuggers</li> +</ul> +<img alt="../_images/ditaa-5e6f93e563d6e94c14fe3d483f988e0579b05b38.png" src="../_images/ditaa-5e6f93e563d6e94c14fe3d483f988e0579b05b38.png" /> + + + + +</article> +<article class="admonition-use-before-initialize-bugs slide level-2"> + +<h2>Use before initialize bugs</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>BUG: unable to handle kernel paging request at 5a5a5a5a +IP: [<c1225063>] __list_del_entry+0x37/0x71 +… +Call Trace: +[<c12250a8>] list_del+0xb/0x1b +[<f1de81a2>] use_before_init+0x31/0x38 [crusher] +[<f1de8265>] crush_it+0x38/0xa9 [crusher] +[<f1de82de>] init_module+0x8/0xa [crusher] +[<c1001072>] do_one_initcall+0x72/0x119 +[<f1de82d6>] ? crush_it+0xa9/0xa9 [crusher] +[<c106b8ae>] sys_init_module+0xc8d/0xe77 +[<c14d7d18>] syscall_call+0x7/0xb +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">noinline</span> <span class="kt">void</span> <span class="nf">use_before_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">list_m</span> <span class="o">*</span><span class="n">m</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">m</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + + <span class="n">printk</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">list_del</span><span class="p">(</span><span class="o">&</span><span class="n">m</span><span class="o">-></span><span class="n">lh</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-use-after-free-bug slide level-2"> + +<h2>Use after free bug</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>BUG: unable to handle kernel paging request at 6b6b6b6b +IP: [<c1225063>] __list_del_entry+0x37/0x71 +… +Call Trace: +[<c12250a8>] list_del+0xb/0x1b +[<f4c6816a>] use_after_free+0x38/0x3f [crusher] +[<f4c6827f>] crush_it+0x52/0xa9 [crusher] +[<f4c682de>] init_module+0x8/0xa [crusher] +[<c1001072>] do_one_initcall+0x72/0x119 +[<f4c682d6>] ? crush_it+0xa9/0xa9 [crusher] +[<c106b8ae>] sys_init_module+0xc8d/0xe77 +[<c14d7d18>] syscall_call+0x7/0xb +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">noinline</span> <span class="kt">void</span> <span class="nf">use_after_free</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">list_m</span> <span class="o">*</span><span class="n">m</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">m</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + + <span class="n">printk</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">kfree</span><span class="p">(</span><span class="n">m</span><span class="p">);</span> + <span class="n">list_del</span><span class="p">(</span><span class="o">&</span><span class="n">m</span><span class="o">-></span><span class="n">lh</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-use-after-free-bug slide level-2"> + +<h2>Use after free bug</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span># insmod /system/lib/modules/crusher.ko test=use_before_init +Slab corruption: size-4096 start=ed612000, len=4096 +000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6b 6b +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">noinline</span> <span class="kt">void</span> <span class="nf">use_after_free2</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">char</span> <span class="o">*</span><span class="n">b</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="mi">3000</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + <span class="n">kfree</span><span class="p">(</span><span class="n">b</span><span class="p">);</span> + <span class="n">memset</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">30</span><span class="p">);</span> + <span class="n">b</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="mi">3000</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + <span class="n">kfree</span><span class="p">(</span><span class="n">b</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-buffer-overflow-bugs slide level-2"> + +<h2>Buffer overflow bugs</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>slab error in verify_redzone_free(): cache `dummy': memory outside object was overwritten +Pid: 1282, comm: insmod Not tainted 3.0.16-mid10-00007-ga4a6b62-dirty #70 +Call Trace: +[<c10cc1de>] __slab_error+0x17/0x1c +[<c10cc7ca>] __cache_free+0x12c/0x317 +[<c10ccaba>] kmem_cache_free+0x2b/0xaf +[<f27f1138>] buffer_overflow+0x4c/0x57 [crusher] +[<f27f12aa>] crush_it+0x6c/0xa9 [crusher] +[<f27f12ef>] init_module+0x8/0xd [crusher] +[<c1001072>] do_one_initcall+0x72/0x119 +[<c106b8ae>] sys_init_module+0xc8d/0xe77 +[<c14d7d18>] syscall_call+0x7/0xb +eb002bf8: redzone 1:0xd84156c5635688c0, redzone 2:0x0 +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">noinline</span> <span class="kt">void</span> <span class="nf">buffer_overflow</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">kmem_cache</span> <span class="o">*</span><span class="n">km</span> <span class="o">=</span> <span class="n">kmem_cache_create</span><span class="p">(</span><span class="s">"dummy"</span><span class="p">,</span> <span class="mi">3000</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span> + <span class="kt">char</span> <span class="o">*</span><span class="n">b</span> <span class="o">=</span> <span class="n">kmem_cache_alloc</span><span class="p">(</span><span class="n">km</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + + <span class="n">printk</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">memset</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">3016</span><span class="p">);</span> + <span class="n">kmem_cache_free</span><span class="p">(</span><span class="n">km</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-debug-pagealloc slide level-2"> + +<h2>DEBUG_PAGEALLOC</h2> + +<ul class="simple"> +<li>Memory debugger that works at a page level</li> +<li>Detects invalid accesses either by:<ul> +<li>Filling pages with poison byte patterns and checking the pattern at +reallocation</li> +<li>Unmapping the dellocated pages from kernel space (just a few +architectures)</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-kasan slide level-2"> + +<h2>KASan</h2> + +<ul class="simple"> +<li>dynamic memory error detector</li> +<li>finds user-after-free or out-of-bound bugs</li> +<li>uses shadow memory to track memory operations</li> +<li>lib/test_kasan.c</li> +</ul> + + + + +</article> +<article class="admonition-kasan-vs-debug-pagealloc slide level-2"> + +<h2>KASan vs DEBUG_PAGEALLOC</h2> + +<p>KASan is slower than DEBUG_PAGEALLOC, but KASan works on sub-page granularity +level, so it able to find more bugs.</p> + + + + +</article> +<article class="admonition-kasan-vs-slub-debug slide level-2"> + +<h2>KASan vs SLUB_DEBUG</h2> + +<ul class="simple"> +<li>SLUB_DEBUG has lower overhead than KASan.</li> +<li>SLUB_DEBUG in most cases are not able to detect bad reads, KASan able to +detect both reads and writes.</li> +<li>In some cases (e.g. redzone overwritten) SLUB_DEBUG detect bugs only on +allocation/freeing of object. KASan catch bugs right before it will happen, +so we always know exact place of first bad read/write.</li> +</ul> + + + + +</article> +<article class="admonition-kmemleak slide level-2"> + +<h2>Kmemleak</h2> + +<ul class="simple"> +<li>enable kernel config: <cite>CONFIG_DEBUG_KMEMLEAK</cite></li> +<li>setup: <cite>mount -t debugfs nodev /sys/kernel/debug</cite></li> +<li>trigger a memory scan: <cite>echo scan > /sys/kernel/debug/kmemleak</cite></li> +<li>show memory leaks: <cite>cat /sys/kernel/debug/kmemleak</cite></li> +<li>clear all possible leaks: <cite>echo clear > /sys/kernel/debug/kmemleak</cite></li> +</ul> + + + + +</article> +<article class="admonition-kmemleak-example slide level-2"> + +<h2>Kmemleak example</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">leak_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + + <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">kmalloc</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="n">MODULE_LICENSE</span><span class="p">(</span><span class="s">"GPL v2"</span><span class="p">);</span> +<span class="n">module_init</span><span class="p">(</span><span class="n">leak_init</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-kmemleak-report slide level-2"> + +<h2>Kmemleak report</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>root@qemux86:~# insmod skels/debugging/leak/leak.ko +leak: loading out-of-tree module taints kernel. +leak_init +root@qemux86:~# echo scan > /sys/kernel/debug/kmemleak +root@qemux86:~# echo scan > /sys/kernel/debug/kmemleak +kmemleak: 1 new suspected memory leaks (see /sys/kernel/debug/kmemleak) +root@qemux86:~# cat /sys/kernel/debug/kmemleak +unreferenced object 0xd7871500 (size 32): +comm "insmod", pid 237, jiffies 4294902108 (age 24.628s) +hex dump (first 32 bytes): +5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ +5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a a5 ZZZZZZZZZZZZZZZ. +backtrace: +[<(ptrval)>] kmem_cache_alloc_trace+0x163/0x310 +[<(ptrval)>] leak_init+0x2f/0x1000 [leak] +[<(ptrval)>] do_one_initcall+0x57/0x2e0 +[<(ptrval)>] do_init_module+0x4b/0x1be +[<(ptrval)>] load_module+0x201a/0x2590 +[<(ptrval)>] sys_init_module+0xfd/0x120 +[<(ptrval)>] do_int80_syscall_32+0x6a/0x1a0 +</pre></div> +</div> + + + + +</article> +<article class="admonition-lockdep-checker slide level-2"> + +<h2>Lockdep checker</h2> + +<ul class="simple"> +<li>CONFIG_DEBUG_LOCKDEP</li> +<li>Detects lock inversio, circular dependencies, incorrect usage of locks +(including interrupt context)</li> +<li>Maintains dependency between classes of locks not individual locks</li> +<li>Each scenario is only checked once and hashed</li> +</ul> + + + + +</article> +<article class="admonition-ab-ba-deadlock-example slide level-2"> + +<h2>AB BA Deadlock Example</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">noinline</span> <span class="kt">int</span> <span class="nf">thread_a</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">unused</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">mutex_lock</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired A</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">mutex_lock</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired B</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + + <span class="n">mutex_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">);</span> + <span class="n">mutex_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">noinline</span> <span class="kt">int</span> <span class="nf">thread_b</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">unused</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">mutex_lock</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired B</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">mutex_lock</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired A</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + + <span class="n">mutex_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">);</span> + <span class="n">mutex_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-ab-ba-deadlock-report slide level-2"> + +<h2>AB BA Deadlock Report</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>thread_a acquired A +thread_a acquired B +thread_b acquired B + +====================================================== +WARNING: possible circular locking dependency detected +4.19.0+ #4 Tainted: G O +------------------------------------------------------ +thread_b/238 is trying to acquire lock: +(ptrval) (a){+.+.}, at: thread_b+0x48/0x90 [locking] + +but task is already holding lock: +(ptrval) (b){+.+.}, at: thread_b+0x27/0x90 [locking] + +which lock already depends on the new lock. +</pre></div> +</div> + + + + +</article> +<article class="admonition-ab-ba-deadlock-report-dependency-chain slide level-2"> + +<h2>AB BA Deadlock Report (dependency chain)</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>the existing dependency chain (in reverse order) is: + +-> #1 (b){+.+.}: + __mutex_lock+0x60/0x830 + mutex_lock_nested+0x20/0x30 + thread_a+0x48/0x90 [locking] + kthread+0xeb/0x100 + ret_from_fork+0x2e/0x38 + +-> #0 (a){+.+.}: + lock_acquire+0x93/0x190 + __mutex_lock+0x60/0x830 + mutex_lock_nested+0x20/0x30 + thread_b+0x48/0x90 [locking] + kthread+0xeb/0x100 + ret_from_fork+0x2e/0x38 +</pre></div> +</div> + + + + +</article> +<article class="admonition-ab-ba-deadlock-report-unsafe-locking-scenario slide level-2"> + +<h2>AB BA Deadlock Report (unsafe locking scenario)</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>other info that might help us debug this: + +Possible unsafe locking scenario: + +CPU0 CPU1 +---- ---- +lock(b); + lock(a); + lock(b); +lock(a); + +*** DEADLOCK *** +</pre></div> +</div> + + + + +</article> +<article class="admonition-irq-deadlock-example slide level-2"> + +<h2>IRQ Deadlock Example</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="nf">DEFINE_SPINLOCK</span><span class="p">(</span><span class="n">lock</span><span class="p">);</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">timerfn</span><span class="p">(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span><span class="n">unused</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquiring lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s released lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="nf">DEFINE_TIMER</span><span class="p">(</span><span class="n">timer</span><span class="p">,</span> <span class="n">timerfn</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">init_module</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">mod_timer</span><span class="p">(</span><span class="o">&</span><span class="n">timer</span><span class="p">,</span> <span class="n">jiffies</span><span class="p">);</span> + + <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquiring lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s released lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-irq-deadlock-report slide level-2"> + +<h2>IRQ Deadlock Report</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>init_module acquiring lock +init_module acquired lock +init_module released lock +timerfn acquiring lock + +================================ +WARNING: inconsistent lock state +4.19.0+ #4 Tainted: G O +-------------------------------- +inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage. +ksoftirqd/0/9 [HC0[0]:SC1[1]:HE1:SE0] takes: +(ptrval) (lock#4){+.?.}, at: timerfn+0x25/0x60 [locking2] +{SOFTIRQ-ON-W} state was registered at: +lock_acquire+0x93/0x190 +_raw_spin_lock+0x39/0x50 +init_module+0x35/0x70 [locking2] +do_one_initcall+0x57/0x2e0 +do_init_module+0x4b/0x1be +load_module+0x201a/0x2590 +sys_init_module+0xfd/0x120 +do_int80_syscall_32+0x6a/0x1a0 +restore_all+0x0/0x8d +</pre></div> +</div> + + + + +</article> +<article class="admonition-irq-deadlock-report slide level-2"> + +<h2>IRQ Deadlock Report</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>Possible unsafe locking scenario: + + CPU0 + ---- + lock(lock#4); + <Interrupt> + lock(lock#4); + + *** DEADLOCK *** + +1 lock held by ksoftirqd/0/9: +#0: (ptrval) (/home/tavi/src/linux/tools/labs/skels/./debugging/locking2/locking2.c:13){+.-.}, at: call_timer_f0 +stack backtrace: +CPU: 0 PID: 9 Comm: ksoftirqd/0 Tainted: G O 4.19.0+ #4 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014 +Call Trace: +dump_stack+0x66/0x96 +print_usage_bug.part.26+0x1ee/0x200 +mark_lock+0x5ea/0x640 +__lock_acquire+0x4b4/0x17a0 +lock_acquire+0x93/0x190 +_raw_spin_lock+0x39/0x50 +timerfn+0x25/0x60 [locking2] +</pre></div> +</div> + + + + +</article> +<article class="admonition-perf slide level-2"> + +<h2>perf</h2> + +<ul class="simple"> +<li>performance counters, tracepoints, kprobes, uprobes</li> +<li>hardware events: CPU cycles, TLB misses, cache misses</li> +<li>software events: page faults , context switches</li> +<li>collects backtraces (user + kernel)</li> +</ul> + + + + +</article> +<article class="admonition-other-tools slide level-2"> + +<h2>Other tools</h2> + +<ul class="simple"> +<li>ftrace</li> +<li>kprobes</li> +<li>sparse</li> +<li>coccinelle</li> +<li>checkpatch.pl</li> +<li>printk</li> +<li>dump_stack()</li> +</ul> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/debugging.html b/refs/pull/405/merge/lectures/debugging.html new file mode 100644 index 00000000..ccb92e11 --- /dev/null +++ b/refs/pull/405/merge/lectures/debugging.html @@ -0,0 +1,902 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Debugging — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Network Management" href="networking.html" /> + <link rel="prev" title="Filesystem Management" href="fs.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="fs.html">Filesystem Management</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Debugging</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="#decoding-an-oops-panic">Decoding an oops/panic</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#decoding-an-oops">Decoding an oops</a></li> +<li class="toctree-l3"><a class="reference internal" href="#addr2line">addr2line</a></li> +<li class="toctree-l3"><a class="reference internal" href="#objdump">objdump</a></li> +<li class="toctree-l3"><a class="reference internal" href="#gdb">gdb</a></li> +<li class="toctree-l3"><a class="reference internal" href="#kernel-panic">Kernel panic</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#list-debugging">List debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="#memory-debugging">Memory debugging</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#slab-debugging">Slab debugging</a></li> +<li class="toctree-l3"><a class="reference internal" href="#debug-pagealloc">DEBUG_PAGEALLOC</a></li> +<li class="toctree-l3"><a class="reference internal" href="#kasan">KASan</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#kasan-vs-debug-pagealloc">KASan vs DEBUG_PAGEALLOC</a></li> +<li class="toctree-l4"><a class="reference internal" href="#kasan-vs-slub-debug">KASan vs SLUB_DEBUG</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#kmemleak">Kmemleak</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#lockdep-checker">Lockdep checker</a></li> +<li class="toctree-l2"><a class="reference internal" href="#perf">perf</a></li> +<li class="toctree-l2"><a class="reference internal" href="#other-tools">Other tools</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Debugging</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/lectures/debugging.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="debugging"> +<h1>Debugging<a class="headerlink" href="#debugging" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="debugging-slides.html">View slides</a></p> +<div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<p>One essential part of Linux kernel development is debugging. In user space we had +the support of the kernel so we could easily stop processes and use gdb to inspect +their behavior. In the kernel, in order to use gdb we need to use hypervisor like +QEMU or JTAG based hardware interfaces which are not always available. The Linux +kernel provides a set of tools and debug options useful for investigating abnormal +behavior.</p> +<p>In this lecture we will learn about:</p> +<ul class="admonition-debugging simple"> +<li>decoding an oops/panic</li> +<li>list debugging</li> +<li>memory debugging</li> +<li>locking debugging</li> +<li>profiling</li> +</ul> +</div> +<div class="section" id="decoding-an-oops-panic"> +<h2>Decoding an oops/panic<a class="headerlink" href="#decoding-an-oops-panic" title="Permalink to this headline">¶</a></h2> +<p>An oops is an inconsistent state that the kernel detects inside itself. +Upon detecting an oops the Linux kernel kills the offending process, +prints information that can help debug the problem and continues execution +but with limited reliability.</p> +<p>Lets consider the following Linux kernel module:</p> +<div class="admonition-oops-module highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">noinline</span> <span class="kt">void</span> <span class="nf">do_oops</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="o">*</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="p">)</span><span class="mh">0x42</span> <span class="o">=</span> <span class="sc">'a'</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">so2_oops_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"oops_init</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="n">do_oops</span><span class="p">();</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">so2_oops_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"oops exit</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> +<span class="p">}</span> + +<span class="n">module_init</span><span class="p">(</span><span class="n">so2_oops_init</span><span class="p">);</span> +<span class="n">module_exit</span><span class="p">(</span><span class="n">so2_oops_exit</span><span class="p">);</span> +</pre></div> +</div> +<p>Notice that ''do_oops'' function tries to write at an invalid memory address. Because the kernel +cannot find a suitable physical page were to write, it kills the insmod task in the context of +which ''do_oops'' runs. Then it prints the following oops message:</p> +<blockquote> +<div><div class="highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~/skels/debugging/oops# insmod oops.ko +BUG: unable to handle kernel NULL pointer dereference at <span class="m">00000042</span> +IP: do_oops+0x8/0x10 <span class="o">[</span>oops<span class="o">]</span> +*pde <span class="o">=</span> <span class="m">00000000</span> +Oops: <span class="m">0002</span> <span class="o">[</span><span class="c1">#1] SMP</span> +Modules linked in: oops<span class="o">(</span>O+<span class="o">)</span> +CPU: <span class="m">0</span> PID: <span class="m">234</span> Comm: insmod Tainted: G O <span class="m">4</span>.15.0+ <span class="c1">#3</span> +Hardware name: QEMU Standard PC <span class="o">(</span>i440FX + PIIX, <span class="m">1996</span><span class="o">)</span>, BIOS Ubuntu-1.8.2-1ubuntu1 <span class="m">04</span>/01/2014 +EIP: do_oops+0x8/0x10 <span class="o">[</span>oops<span class="o">]</span> +EFLAGS: <span class="m">00000292</span> CPU: <span class="m">0</span> +EAX: <span class="m">00000061</span> EBX: <span class="m">00000000</span> ECX: c7ed3584 EDX: c7ece8dc +ESI: c716c908 EDI: c8816010 EBP: c7257df0 ESP: c7257df0 +DS: 007b ES: 007b FS: 00d8 GS: <span class="m">0033</span> SS: <span class="m">0068</span> +CR0: <span class="m">80050033</span> CR2: <span class="m">00000042</span> CR3: 0785f000 CR4: <span class="m">00000690</span> +Call Trace: +so2_oops_init+0x17/0x20 <span class="o">[</span>oops<span class="o">]</span> +do_one_initcall+0x37/0x170 +? cache_alloc_debugcheck_after.isra.19+0x15f/0x2f0 +? __might_sleep+0x32/0x90 +? trace_hardirqs_on_caller+0x11c/0x1a0 +? do_init_module+0x17/0x1c2 +? kmem_cache_alloc+0xa4/0x1e0 +? do_init_module+0x17/0x1c2 +do_init_module+0x46/0x1c2 +load_module+0x1f45/0x2380 +SyS_init_module+0xe5/0x100 +do_int80_syscall_32+0x61/0x190 +entry_INT80_32+0x2f/0x2f +EIP: 0x44902cc2 +EFLAGS: <span class="m">00000206</span> CPU: <span class="m">0</span> +EAX: ffffffda EBX: 08afb050 ECX: 0000eef4 EDX: 08afb008 +ESI: <span class="m">00000000</span> EDI: bf914dbc EBP: <span class="m">00000000</span> ESP: bf914c1c +DS: 007b ES: 007b FS: <span class="m">0000</span> GS: <span class="m">0033</span> SS: 007b +Code: <a3> <span class="m">42</span> <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> 5d c3 <span class="m">90</span> <span class="m">55</span> <span class="m">89</span> e5 <span class="m">83</span> ec <span class="m">04</span> c7 <span class="m">04</span> <span class="m">24</span> <span class="m">24</span> <span class="m">70</span> <span class="m">81</span> c8 e8 +EIP: do_oops+0x8/0x10 <span class="o">[</span>oops<span class="o">]</span> SS:ESP: <span class="m">0068</span>:c7257df0 +CR2: <span class="m">0000000000000042</span> +---<span class="o">[</span> end trace 011848be72f8bb42 <span class="o">]</span>--- +Killed +</pre></div> +</div> +</div></blockquote> +<p>An oops contains information about the IP which caused the fault, register status, process, +CPU on which the fault happend like below:</p> +<div class="admonition-oops-information highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~/skels/debugging/oops# insmod oops.ko +BUG: unable to handle kernel NULL pointer dereference at <span class="m">00000042</span> +IP: do_oops+0x8/0x10 <span class="o">[</span>oops<span class="o">]</span> +*pde <span class="o">=</span> <span class="m">00000000</span> +Oops: <span class="m">0002</span> <span class="o">[</span><span class="c1">#1] SMP</span> +Modules linked in: oops<span class="o">(</span>O+<span class="o">)</span> +CPU: <span class="m">0</span> PID: <span class="m">234</span> Comm: insmod Tainted: G O <span class="m">4</span>.15.0+ <span class="c1">#3</span> +Hardware name: QEMU Standard PC <span class="o">(</span>i440FX + PIIX, <span class="m">1996</span><span class="o">)</span>, BIOS Ubuntu-1.8.2-1ubuntu1 <span class="m">04</span>/01/2014 +EIP: do_oops+0x8/0x10 <span class="o">[</span>oops<span class="o">]</span> +CR0: <span class="m">80050033</span> CR2: <span class="m">00000042</span> CR3: 0785f000 CR4: <span class="m">00000690</span> +EIP: 0x44902cc2 +EFLAGS: <span class="m">00000206</span> CPU: <span class="m">0</span> +EAX: ffffffda EBX: 08afb050 ECX: 0000eef4 EDX: 08afb008 +ESI: <span class="m">00000000</span> EDI: bf914dbc EBP: <span class="m">00000000</span> ESP: bf914c1c +DS: 007b ES: 007b FS: <span class="m">0000</span> GS: <span class="m">0033</span> SS: 007b +Code: <a3> <span class="m">42</span> <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> 5d c3 <span class="m">90</span> <span class="m">55</span> <span class="m">89</span> e5 <span class="m">83</span> ec <span class="m">04</span> c7 <span class="m">04</span> <span class="m">24</span> <span class="m">24</span> <span class="m">70</span> <span class="m">81</span> c8 e8 +Killed +</pre></div> +</div> +<p>Another important thing that an oops can provide is the stack trace of functions called before +the fault happend:</p> +<div class="admonition-oops-stacktrace highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~/skels/debugging/oops# insmod oops.ko +BUG: unable to handle kernel NULL pointer dereference at <span class="m">00000042</span> +Call Trace: +so2_oops_init+0x17/0x20 <span class="o">[</span>oops<span class="o">]</span> +do_one_initcall+0x37/0x170 +? cache_alloc_debugcheck_after.isra.19+0x15f/0x2f0 +? __might_sleep+0x32/0x90 +? trace_hardirqs_on_caller+0x11c/0x1a0 +? do_init_module+0x17/0x1c2 +? kmem_cache_alloc+0xa4/0x1e0 +? do_init_module+0x17/0x1c2 +do_init_module+0x46/0x1c2 +load_module+0x1f45/0x2380 +SyS_init_module+0xe5/0x100 +do_int80_syscall_32+0x61/0x190 +entry_INT80_32+0x2f/0x2f +Killed +</pre></div> +</div> +<div class="section" id="decoding-an-oops"> +<h3>Decoding an oops<a class="headerlink" href="#decoding-an-oops" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-debugging simple"> +<li>CONFIG_DEBUG_INFO</li> +<li>addr2line</li> +<li>gdb</li> +<li>objdump -dSr</li> +</ul> +</div> +<div class="section" id="addr2line"> +<h3>addr2line<a class="headerlink" href="#addr2line" title="Permalink to this headline">¶</a></h3> +<p><em>addr2line</em> translates addresses into file names and line numbers. Given +an address in an executable it uses the debugging information to figure out +which file name and line number are associated with it.</p> +<p>Modules are loaded at dynamic addresses but are compiled starting with 0 as +a base address. So, in order to find the line number for a given dynamic address +we need to know module's load address.</p> +<div class="admonition-addr2line highlight-bash"><div class="highlight"><pre><span></span>$ addr2line -e oops.o 0x08 +$ skels/debugging/oops/oops.c:5 +$ <span class="c1"># 0x08 is the offset of the offending instruction inside the oops.ko module</span> +</pre></div> +</div> +</div> +<div class="section" id="objdump"> +<h3>objdump<a class="headerlink" href="#objdump" title="Permalink to this headline">¶</a></h3> +<p>Similar we can determine the offending line using objdump:</p> +<div class="admonition-objdump highlight-bash"><div class="highlight"><pre><span></span>$ cat /proc/modules +oops <span class="m">20480</span> <span class="m">1</span> - Loading 0xc8816000 <span class="o">(</span>O+<span class="o">)</span> + +$ objdump -dS --adjust-vma<span class="o">=</span>0xc8816000 oops.ko +c8816000: b8 <span class="m">61</span> <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> mov <span class="nv">$0</span>x61,%eax + +static noinline void do_oops<span class="o">(</span>void<span class="o">)</span> +<span class="o">{</span> +c8816005: <span class="m">55</span> push %ebp +c8816006: <span class="m">89</span> e5 mov %esp,%ebp +*<span class="o">(</span>int*<span class="o">)</span><span class="nv">0x42</span> <span class="o">=</span> <span class="s1">'a'</span><span class="p">;</span> +c8816008: a3 <span class="m">42</span> <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> mov %eax,0x42 +</pre></div> +</div> +</div> +<div class="section" id="gdb"> +<h3>gdb<a class="headerlink" href="#gdb" title="Permalink to this headline">¶</a></h3> +<div class="admonition-gdb highlight-bash"><div class="highlight"><pre><span></span>$ gdb ./vmlinux + +<span class="o">(</span>gdb<span class="o">)</span> list *<span class="o">(</span>do_panic+0x8<span class="o">)</span> +0xc1244138 is in do_panic <span class="o">(</span>lib/test_panic.c:8<span class="o">)</span>. +<span class="m">3</span> +<span class="m">4</span> static struct timer_list panic_timer<span class="p">;</span> +<span class="m">5</span> +<span class="m">6</span> static void do_panic<span class="o">(</span>struct timer_list *unused<span class="o">)</span> +<span class="m">7</span> <span class="o">{</span> +<span class="m">8</span> *<span class="o">(</span>int*<span class="o">)</span><span class="nv">0x42</span> <span class="o">=</span> <span class="s1">'a'</span><span class="p">;</span> +<span class="m">9</span> <span class="o">}</span> +<span class="m">10</span> +<span class="m">11</span> static int so2_panic_init<span class="o">(</span>void<span class="o">)</span> +</pre></div> +</div> +</div> +<div class="section" id="kernel-panic"> +<h3>Kernel panic<a class="headerlink" href="#kernel-panic" title="Permalink to this headline">¶</a></h3> +<p>A kernel panic is a special type of oops where the kernel cannot continue execution. For example +if the function do_oops from above was called in the interrupt context, the kernel wouldn't know how to kill +and it will decide that it is better to crash the kernel and stop execution.</p> +<p>Here is a sample code that will generate a kernel panic:</p> +<div class="admonition-kernel-panic highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="k">struct</span> <span class="n">timer_list</span> <span class="n">panic_timer</span><span class="p">;</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">do_panic</span><span class="p">(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span><span class="n">unused</span><span class="p">)</span> +<span class="p">{</span> + <span class="o">*</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="p">)</span><span class="mh">0x42</span> <span class="o">=</span> <span class="sc">'a'</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">so2_panic_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"panic_init</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + + <span class="n">timer_setup</span><span class="p">(</span><span class="o">&</span><span class="n">panic_timer</span><span class="p">,</span> <span class="n">do_panic</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> + <span class="n">mod_timer</span><span class="p">(</span><span class="o">&</span><span class="n">panic_timer</span><span class="p">,</span> <span class="n">jiffies</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">HZ</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Loading the module will generate the following kernel panic message:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~/skels/debugging/panic# insmod panic.ko +panic: loading out-of-tree module taints kernel. +panic_init +root@qemux86:~/skels/debugging/panic# BUG: unable to handle kernel NULL pointer dereference at <span class="m">00000042</span> +IP: do_panic+0x8/0x10 <span class="o">[</span>panic<span class="o">]</span> +*pde <span class="o">=</span> <span class="m">00000000</span> +Oops: <span class="m">0002</span> <span class="o">[</span><span class="c1">#1] SMP</span> +Modules linked in: panic<span class="o">(</span>O<span class="o">)</span> +CPU: <span class="m">0</span> PID: <span class="m">0</span> Comm: swapper/0 Tainted: G O <span class="m">4</span>.15.0+ <span class="c1">#19</span> +Hardware name: QEMU Standard PC <span class="o">(</span>i440FX + PIIX, <span class="m">1996</span><span class="o">)</span>, BIOS Ubuntu-1.8.2-1ubuntu1 <span class="m">04</span>/01/2014 +EIP: do_panic+0x8/0x10 <span class="o">[</span>panic<span class="o">]</span> +EFLAGS: <span class="m">00010246</span> CPU: <span class="m">0</span> +EAX: <span class="m">00000061</span> EBX: <span class="m">00000101</span> ECX: 000002d8 EDX: <span class="m">00000000</span> +ESI: c8817000 EDI: c8819200 EBP: c780ff34 ESP: c780ff34 +DS: 007b ES: 007b FS: 00d8 GS: <span class="m">0000</span> SS: <span class="m">0068</span> +CR0: <span class="m">80050033</span> CR2: <span class="m">00000042</span> CR3: 0716b000 CR4: <span class="m">00000690</span> +Call Trace: +<SOFTIRQ> +call_timer_fn+0x63/0xf0 +? process_timeout+0x10/0x10 +run_timer_softirq+0x14f/0x170 +? 0xc8817000 +? trace_hardirqs_on_caller+0x9b/0x1a0 +__do_softirq+0xde/0x1f2 +? __irqentry_text_end+0x6/0x6 +do_softirq_own_stack+0x57/0x70 +</SOFTIRQ> +irq_exit+0x7d/0x90 +smp_apic_timer_interrupt+0x4f/0x90 +? trace_hardirqs_off_thunk+0xc/0x1d +apic_timer_interrupt+0x3a/0x40 +EIP: default_idle+0xa/0x10 +EFLAGS: <span class="m">00000246</span> CPU: <span class="m">0</span> +EAX: c15c97c0 EBX: <span class="m">00000000</span> ECX: <span class="m">00000000</span> EDX: <span class="m">00000001</span> +ESI: <span class="m">00000000</span> EDI: <span class="m">00000000</span> EBP: c15c3f48 ESP: c15c3f48 +DS: 007b ES: 007b FS: 00d8 GS: <span class="m">0000</span> SS: <span class="m">0068</span> +arch_cpu_idle+0x9/0x10 +default_idle_call+0x19/0x30 +do_idle+0x105/0x180 +cpu_startup_entry+0x25/0x30 +rest_init+0x1e3/0x1f0 +start_kernel+0x305/0x30a +i386_start_kernel+0x95/0x99 +startup_32_smp+0x15f/0x164 +Code: <a3> <span class="m">42</span> <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> 5d c3 <span class="m">90</span> <span class="m">55</span> <span class="m">89</span> e5 <span class="m">83</span> ec <span class="m">08</span> c7 <span class="m">04</span> <span class="m">24</span> <span class="m">24</span> <span class="m">80</span> <span class="m">81</span> c8 e8 +EIP: do_panic+0x8/0x10 <span class="o">[</span>panic<span class="o">]</span> SS:ESP: <span class="m">0068</span>:c780ff34 +CR2: <span class="m">0000000000000042</span> +---<span class="o">[</span> end trace 77f49f83f2e42f91 <span class="o">]</span>--- +Kernel panic - not syncing: Fatal exception in interrupt +Kernel Offset: disabled +---<span class="o">[</span> end Kernel panic - not syncing: Fatal exception in interrupt +</pre></div> +</div> +</div> +</div> +<div class="section" id="list-debugging"> +<h2>List debugging<a class="headerlink" href="#list-debugging" title="Permalink to this headline">¶</a></h2> +<p>In order to catch access to uninitialized elements the kernel uses poison +magic values.</p> +<div class="admonition-list-debugging highlight-bash"><div class="highlight"><pre><span></span>static inline void list_del<span class="o">(</span>struct list_head *entry<span class="o">)</span> +<span class="o">{</span> + __list_del<span class="o">(</span>entry->prev, entry->next<span class="o">)</span><span class="p">;</span> + entry->next <span class="o">=</span> <span class="o">(</span>struct list_head*<span class="o">)</span>LIST_POISON1<span class="p">;</span> + entry->prev <span class="o">=</span> <span class="o">(</span>struct list_head*<span class="o">)</span>LIST_POISON2<span class="p">;</span> +<span class="o">}</span> + +BUG: unable to handle kernel NULL pointer dereference at <span class="m">00000100</span> +IP: crush+0x80/0xb0 <span class="o">[</span>list<span class="o">]</span> +</pre></div> +</div> +</div> +<div class="section" id="memory-debugging"> +<h2>Memory debugging<a class="headerlink" href="#memory-debugging" title="Permalink to this headline">¶</a></h2> +<p>There are several tools for memory debugging:</p> +<ul class="admonition-memory-debugging simple"> +<li>SLAB/SLUB debugging</li> +<li>KASAN</li> +<li>kmemcheck</li> +<li>DEBUG_PAGEALLOC</li> +</ul> +<div class="section" id="slab-debugging"> +<h3>Slab debugging<a class="headerlink" href="#slab-debugging" title="Permalink to this headline">¶</a></h3> +<p>Slab debugging uses a memory poison technique to detect several types of memory +bugs in the SLAB/SUB allocators.</p> +<p>The allocated buffers are guarded with memory that has been filled in with +special markers. Any adjacent writes to the buffer will be detected at a later +time when other memory management operations on that buffer are performed +(e.g. when the buffer is freed).</p> +<p>Upon allocation of the buffer, the buffer it is also filled in with a special +value to potentially detect buffer access before initialization (e.g. if the +buffer holds pointers). The value is selected in such a way that it is unlikely +to be a valid address and as such to trigger kernel bugs at the access time.</p> +<p>A similar technique is used when freeing the buffer: the buffer is filled with +another special value that will cause kernel bugs if pointers are accessed after +the memory is freed. In this case, the allocator also checks the next time the +buffer is allocated that the buffer was not modified.</p> +<p>The diagram bellow shows a summary of the way SLAB/SLUB poisoning works:</p> +<ul class="admonition-slab-debugging simple"> +<li>CONFIG_DEBUG_SLAB</li> +<li>poisoned based memory debuggers</li> +</ul> +<img alt="../_images/ditaa-5e6f93e563d6e94c14fe3d483f988e0579b05b38.png" src="../_images/ditaa-5e6f93e563d6e94c14fe3d483f988e0579b05b38.png" /> +<p>Example of an use before initialize bug:</p> +<div class="admonition-use-before-initialize-bugs highlight-none"><div class="highlight"><pre><span></span>BUG: unable to handle kernel paging request at 5a5a5a5a +IP: [<c1225063>] __list_del_entry+0x37/0x71 +… +Call Trace: +[<c12250a8>] list_del+0xb/0x1b +[<f1de81a2>] use_before_init+0x31/0x38 [crusher] +[<f1de8265>] crush_it+0x38/0xa9 [crusher] +[<f1de82de>] init_module+0x8/0xa [crusher] +[<c1001072>] do_one_initcall+0x72/0x119 +[<f1de82d6>] ? crush_it+0xa9/0xa9 [crusher] +[<c106b8ae>] sys_init_module+0xc8d/0xe77 +[<c14d7d18>] syscall_call+0x7/0xb +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">noinline</span> <span class="kt">void</span> <span class="nf">use_before_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">list_m</span> <span class="o">*</span><span class="n">m</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">m</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + + <span class="n">printk</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">list_del</span><span class="p">(</span><span class="o">&</span><span class="n">m</span><span class="o">-></span><span class="n">lh</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Example of an use after free bug:</p> +<div class="admonition-use-after-free-bug highlight-none"><div class="highlight"><pre><span></span>BUG: unable to handle kernel paging request at 6b6b6b6b +IP: [<c1225063>] __list_del_entry+0x37/0x71 +… +Call Trace: +[<c12250a8>] list_del+0xb/0x1b +[<f4c6816a>] use_after_free+0x38/0x3f [crusher] +[<f4c6827f>] crush_it+0x52/0xa9 [crusher] +[<f4c682de>] init_module+0x8/0xa [crusher] +[<c1001072>] do_one_initcall+0x72/0x119 +[<f4c682d6>] ? crush_it+0xa9/0xa9 [crusher] +[<c106b8ae>] sys_init_module+0xc8d/0xe77 +[<c14d7d18>] syscall_call+0x7/0xb +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">noinline</span> <span class="kt">void</span> <span class="nf">use_after_free</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">list_m</span> <span class="o">*</span><span class="n">m</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">m</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + + <span class="n">printk</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">kfree</span><span class="p">(</span><span class="n">m</span><span class="p">);</span> + <span class="n">list_del</span><span class="p">(</span><span class="o">&</span><span class="n">m</span><span class="o">-></span><span class="n">lh</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Another example of an use after free bug is shown below. Note that this time the +bug is detected at the next allocation.</p> +<div class="admonition-use-after-free-bug highlight-none"><div class="highlight"><pre><span></span># insmod /system/lib/modules/crusher.ko test=use_before_init +Slab corruption: size-4096 start=ed612000, len=4096 +000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6b 6b +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">noinline</span> <span class="kt">void</span> <span class="nf">use_after_free2</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">char</span> <span class="o">*</span><span class="n">b</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="mi">3000</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + <span class="n">kfree</span><span class="p">(</span><span class="n">b</span><span class="p">);</span> + <span class="n">memset</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">30</span><span class="p">);</span> + <span class="n">b</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="mi">3000</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + <span class="n">kfree</span><span class="p">(</span><span class="n">b</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Finally this is an example of a buffer overflow bug:</p> +<div class="admonition-buffer-overflow-bugs highlight-none"><div class="highlight"><pre><span></span>slab error in verify_redzone_free(): cache `dummy': memory outside object was overwritten +Pid: 1282, comm: insmod Not tainted 3.0.16-mid10-00007-ga4a6b62-dirty #70 +Call Trace: +[<c10cc1de>] __slab_error+0x17/0x1c +[<c10cc7ca>] __cache_free+0x12c/0x317 +[<c10ccaba>] kmem_cache_free+0x2b/0xaf +[<f27f1138>] buffer_overflow+0x4c/0x57 [crusher] +[<f27f12aa>] crush_it+0x6c/0xa9 [crusher] +[<f27f12ef>] init_module+0x8/0xd [crusher] +[<c1001072>] do_one_initcall+0x72/0x119 +[<c106b8ae>] sys_init_module+0xc8d/0xe77 +[<c14d7d18>] syscall_call+0x7/0xb +eb002bf8: redzone 1:0xd84156c5635688c0, redzone 2:0x0 +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">noinline</span> <span class="kt">void</span> <span class="nf">buffer_overflow</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">kmem_cache</span> <span class="o">*</span><span class="n">km</span> <span class="o">=</span> <span class="n">kmem_cache_create</span><span class="p">(</span><span class="s">"dummy"</span><span class="p">,</span> <span class="mi">3000</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span> + <span class="kt">char</span> <span class="o">*</span><span class="n">b</span> <span class="o">=</span> <span class="n">kmem_cache_alloc</span><span class="p">(</span><span class="n">km</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + + <span class="n">printk</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">memset</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">3016</span><span class="p">);</span> + <span class="n">kmem_cache_free</span><span class="p">(</span><span class="n">km</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="debug-pagealloc"> +<h3>DEBUG_PAGEALLOC<a class="headerlink" href="#debug-pagealloc" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-debug-pagealloc simple"> +<li>Memory debugger that works at a page level</li> +<li>Detects invalid accesses either by:<ul> +<li>Filling pages with poison byte patterns and checking the pattern at +reallocation</li> +<li>Unmapping the dellocated pages from kernel space (just a few +architectures)</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="kasan"> +<h3>KASan<a class="headerlink" href="#kasan" title="Permalink to this headline">¶</a></h3> +<p>KASan is a dynamic memory error detector designed to find use-after-free +and out-of-bounds bugs.</p> +<p>The main idea of KASAN is to use shadow memory to record whether each byte +of memory is safe to access or not, and use compiler's instrumentation to +check the shadow memory on each memory access.</p> +<p>Address sanitizer uses 1 byte of shadow memory to track 8 bytes of kernel +address space. It uses 0-7 to encode the number of consecutive bytes at +the beginning of the eigh-byte region that are valid.</p> +<p>See <cite>The Kernel Address Sanitizer (KASAN)</cite> for more information and have a look +at lib/test_kasan.c for an example of problems that KASan can detect.</p> +<ul class="admonition-kasan simple"> +<li>dynamic memory error detector</li> +<li>finds user-after-free or out-of-bound bugs</li> +<li>uses shadow memory to track memory operations</li> +<li>lib/test_kasan.c</li> +</ul> +<div class="section" id="kasan-vs-debug-pagealloc"> +<h4>KASan vs DEBUG_PAGEALLOC<a class="headerlink" href="#kasan-vs-debug-pagealloc" title="Permalink to this headline">¶</a></h4> +<p class="admonition-kasan-vs-debug-pagealloc">KASan is slower than DEBUG_PAGEALLOC, but KASan works on sub-page granularity +level, so it able to find more bugs.</p> +</div> +<div class="section" id="kasan-vs-slub-debug"> +<h4>KASan vs SLUB_DEBUG<a class="headerlink" href="#kasan-vs-slub-debug" title="Permalink to this headline">¶</a></h4> +<ul class="admonition-kasan-vs-slub-debug simple"> +<li>SLUB_DEBUG has lower overhead than KASan.</li> +<li>SLUB_DEBUG in most cases are not able to detect bad reads, KASan able to +detect both reads and writes.</li> +<li>In some cases (e.g. redzone overwritten) SLUB_DEBUG detect bugs only on +allocation/freeing of object. KASan catch bugs right before it will happen, +so we always know exact place of first bad read/write.</li> +</ul> +</div> +</div> +<div class="section" id="kmemleak"> +<h3>Kmemleak<a class="headerlink" href="#kmemleak" title="Permalink to this headline">¶</a></h3> +<p>Kmemleak provides a way of detecting kernel memory leaks in a way similar to a +tracing garbage collector. Since tracing pointers is not possible in C, kmemleak +scans the kernel stacks as well as dynamically and statically kernel memory for +pointers to allocated buffers. A buffer for which there is no pointer is +considered as leaked. The basic steps to use kmemleak are presented bellow, for +more information see <cite>Kernel Memory Leak Detector</cite></p> +<ul class="admonition-kmemleak simple"> +<li>enable kernel config: <cite>CONFIG_DEBUG_KMEMLEAK</cite></li> +<li>setup: <cite>mount -t debugfs nodev /sys/kernel/debug</cite></li> +<li>trigger a memory scan: <cite>echo scan > /sys/kernel/debug/kmemleak</cite></li> +<li>show memory leaks: <cite>cat /sys/kernel/debug/kmemleak</cite></li> +<li>clear all possible leaks: <cite>echo clear > /sys/kernel/debug/kmemleak</cite></li> +</ul> +<p>As an example, lets look at the following simple module:</p> +<div class="admonition-kmemleak-example highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">leak_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + + <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">kmalloc</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="n">MODULE_LICENSE</span><span class="p">(</span><span class="s">"GPL v2"</span><span class="p">);</span> +<span class="n">module_init</span><span class="p">(</span><span class="n">leak_init</span><span class="p">);</span> +</pre></div> +</div> +<p>Loading the module and triggering a kmemleak scan will issue the +following report:</p> +<div class="admonition-kmemleak-report highlight-none"><div class="highlight"><pre><span></span>root@qemux86:~# insmod skels/debugging/leak/leak.ko +leak: loading out-of-tree module taints kernel. +leak_init +root@qemux86:~# echo scan > /sys/kernel/debug/kmemleak +root@qemux86:~# echo scan > /sys/kernel/debug/kmemleak +kmemleak: 1 new suspected memory leaks (see /sys/kernel/debug/kmemleak) +root@qemux86:~# cat /sys/kernel/debug/kmemleak +unreferenced object 0xd7871500 (size 32): +comm "insmod", pid 237, jiffies 4294902108 (age 24.628s) +hex dump (first 32 bytes): +5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ +5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a a5 ZZZZZZZZZZZZZZZ. +backtrace: +[<(ptrval)>] kmem_cache_alloc_trace+0x163/0x310 +[<(ptrval)>] leak_init+0x2f/0x1000 [leak] +[<(ptrval)>] do_one_initcall+0x57/0x2e0 +[<(ptrval)>] do_init_module+0x4b/0x1be +[<(ptrval)>] load_module+0x201a/0x2590 +[<(ptrval)>] sys_init_module+0xfd/0x120 +[<(ptrval)>] do_int80_syscall_32+0x6a/0x1a0 +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Notice that we did not had to unload the module to detect the memory +leak since kmemleak detects that the allocated buffer is not +reachable anymore.</p> +</div> +</div> +</div> +<div class="section" id="lockdep-checker"> +<h2>Lockdep checker<a class="headerlink" href="#lockdep-checker" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-lockdep-checker simple"> +<li>CONFIG_DEBUG_LOCKDEP</li> +<li>Detects lock inversio, circular dependencies, incorrect usage of locks +(including interrupt context)</li> +<li>Maintains dependency between classes of locks not individual locks</li> +<li>Each scenario is only checked once and hashed</li> +</ul> +<p>Lets take for example the following kernel module that runs two kernel threads:</p> +<div class="admonition-ab-ba-deadlock-example highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">noinline</span> <span class="kt">int</span> <span class="nf">thread_a</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">unused</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">mutex_lock</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired A</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">mutex_lock</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired B</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + + <span class="n">mutex_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">);</span> + <span class="n">mutex_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">noinline</span> <span class="kt">int</span> <span class="nf">thread_b</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">unused</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">mutex_lock</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired B</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">mutex_lock</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired A</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + + <span class="n">mutex_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">);</span> + <span class="n">mutex_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Loading this module with lockdep checker active will produce the following +kernel log:</p> +<div class="admonition-ab-ba-deadlock-report highlight-none"><div class="highlight"><pre><span></span>thread_a acquired A +thread_a acquired B +thread_b acquired B + +====================================================== +WARNING: possible circular locking dependency detected +4.19.0+ #4 Tainted: G O +------------------------------------------------------ +thread_b/238 is trying to acquire lock: +(ptrval) (a){+.+.}, at: thread_b+0x48/0x90 [locking] + +but task is already holding lock: +(ptrval) (b){+.+.}, at: thread_b+0x27/0x90 [locking] + +which lock already depends on the new lock. +</pre></div> +</div> +<p>As you can see, although the deadlock condition did not trigger (because thread +A did not complete execution before thread B started execution) the lockdep +checker identified a potential deadlock scenario.</p> +<p>Lockdep checker will provide even more information to help determine what caused +the deadlock, like the dependency chain:</p> +<div class="admonition-ab-ba-deadlock-report-dependency-chain highlight-none"><div class="highlight"><pre><span></span>the existing dependency chain (in reverse order) is: + +-> #1 (b){+.+.}: + __mutex_lock+0x60/0x830 + mutex_lock_nested+0x20/0x30 + thread_a+0x48/0x90 [locking] + kthread+0xeb/0x100 + ret_from_fork+0x2e/0x38 + +-> #0 (a){+.+.}: + lock_acquire+0x93/0x190 + __mutex_lock+0x60/0x830 + mutex_lock_nested+0x20/0x30 + thread_b+0x48/0x90 [locking] + kthread+0xeb/0x100 + ret_from_fork+0x2e/0x38 +</pre></div> +</div> +<p>and even an unsafe locking scenario:</p> +<div class="admonition-ab-ba-deadlock-report-unsafe-locking-scenario highlight-none"><div class="highlight"><pre><span></span>other info that might help us debug this: + +Possible unsafe locking scenario: + +CPU0 CPU1 +---- ---- +lock(b); + lock(a); + lock(b); +lock(a); + +*** DEADLOCK *** +</pre></div> +</div> +<p>Another example of unsafe locking issues that lockdep checker detects +is unsafe locking from interrupt context. Lets consider the following +kernel module:</p> +<div class="admonition-irq-deadlock-example highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="nf">DEFINE_SPINLOCK</span><span class="p">(</span><span class="n">lock</span><span class="p">);</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">timerfn</span><span class="p">(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span><span class="n">unused</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquiring lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s released lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="nf">DEFINE_TIMER</span><span class="p">(</span><span class="n">timer</span><span class="p">,</span> <span class="n">timerfn</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">init_module</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">mod_timer</span><span class="p">(</span><span class="o">&</span><span class="n">timer</span><span class="p">,</span> <span class="n">jiffies</span><span class="p">);</span> + + <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquiring lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s released lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>As in the previous case, loading the module will trigger a lockdep +warning:</p> +<div class="admonition-irq-deadlock-report highlight-none"><div class="highlight"><pre><span></span>init_module acquiring lock +init_module acquired lock +init_module released lock +timerfn acquiring lock + +================================ +WARNING: inconsistent lock state +4.19.0+ #4 Tainted: G O +-------------------------------- +inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage. +ksoftirqd/0/9 [HC0[0]:SC1[1]:HE1:SE0] takes: +(ptrval) (lock#4){+.?.}, at: timerfn+0x25/0x60 [locking2] +{SOFTIRQ-ON-W} state was registered at: +lock_acquire+0x93/0x190 +_raw_spin_lock+0x39/0x50 +init_module+0x35/0x70 [locking2] +do_one_initcall+0x57/0x2e0 +do_init_module+0x4b/0x1be +load_module+0x201a/0x2590 +sys_init_module+0xfd/0x120 +do_int80_syscall_32+0x6a/0x1a0 +restore_all+0x0/0x8d +</pre></div> +</div> +<p>The warning will also provide additional information and a potential unsafe +locking scenario:</p> +<div class="admonition-irq-deadlock-report highlight-none"><div class="highlight"><pre><span></span>Possible unsafe locking scenario: + + CPU0 + ---- + lock(lock#4); + <Interrupt> + lock(lock#4); + + *** DEADLOCK *** + +1 lock held by ksoftirqd/0/9: +#0: (ptrval) (/home/tavi/src/linux/tools/labs/skels/./debugging/locking2/locking2.c:13){+.-.}, at: call_timer_f0 +stack backtrace: +CPU: 0 PID: 9 Comm: ksoftirqd/0 Tainted: G O 4.19.0+ #4 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014 +Call Trace: +dump_stack+0x66/0x96 +print_usage_bug.part.26+0x1ee/0x200 +mark_lock+0x5ea/0x640 +__lock_acquire+0x4b4/0x17a0 +lock_acquire+0x93/0x190 +_raw_spin_lock+0x39/0x50 +timerfn+0x25/0x60 [locking2] +</pre></div> +</div> +</div> +<div class="section" id="perf"> +<h2>perf<a class="headerlink" href="#perf" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-perf simple"> +<li>performance counters, tracepoints, kprobes, uprobes</li> +<li>hardware events: CPU cycles, TLB misses, cache misses</li> +<li>software events: page faults , context switches</li> +<li>collects backtraces (user + kernel)</li> +</ul> +</div> +<div class="section" id="other-tools"> +<h2>Other tools<a class="headerlink" href="#other-tools" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-other-tools simple"> +<li>ftrace</li> +<li>kprobes</li> +<li>sparse</li> +<li>coccinelle</li> +<li>checkpatch.pl</li> +<li>printk</li> +<li>dump_stack()</li> +</ul> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="fs.html" class="btn btn-neutral float-left" title="Filesystem Management" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="networking.html" class="btn btn-neutral float-right" title="Network Management" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/fs-slides.html b/refs/pull/405/merge/lectures/fs-slides.html new file mode 100644 index 00000000..6a78b011 --- /dev/null +++ b/refs/pull/405/merge/lectures/fs-slides.html @@ -0,0 +1,572 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Filesystem Management — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="next" title="Debugging" href="debugging.html" /> + <link rel="prev" title="Memory Management" href="memory-management.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-filesystem-management slide level-2"> + +<h2>Filesystem Management</h2> + +<ul class="simple"> +<li>Filesystem abstractions</li> +<li>Filesystem operations</li> +<li>Linux VFS</li> +<li>Overview of Linux I/O Management</li> +</ul> + + + + +</article> +<article class="admonition-filesystem-abstractions slide level-2"> + +<h2>Filesystem Abstractions</h2> + +<ul class="simple"> +<li>superblock</li> +<li>file</li> +<li>inode</li> +<li>dentry</li> +</ul> + + + + +</article> +<article class="admonition-filesystem-abstractions-in-memory slide level-2"> + +<h2>Filesystem Abstractions - in memory</h2> + +<img alt="../_images/ditaa-29f54aaa1a85b819ff29cb7d101a4d646b3b0b06.png" src="../_images/ditaa-29f54aaa1a85b819ff29cb7d101a4d646b3b0b06.png" /> + + + + +</article> +<article class="admonition-filesystem-abstractions-on-storage slide level-2"> + +<h2>Filesystem Abstractions - on storage</h2> + +<img alt="../_images/ditaa-bc662dab7bb3d9ba3a37efbf69b82c513dcaadd4.png" src="../_images/ditaa-bc662dab7bb3d9ba3a37efbf69b82c513dcaadd4.png" /> + + + + +</article> +<article class="admonition-simple-filesystem-example slide level-2"> + +<h2>Simple filesystem example</h2> + +<p> </p> +<img alt="../_images/ditaa-8b59fc3f5245ffb5d7089dc80cf2e306c39a62d8.png" src="../_images/ditaa-8b59fc3f5245ffb5d7089dc80cf2e306c39a62d8.png" /> + + + + +</article> +<article class="admonition-overview slide level-2"> + +<h2>Overview</h2> + +<img alt="../_images/ditaa-6d39f541805ae8197b413ec9c79116382abc4dbc.png" src="../_images/ditaa-6d39f541805ae8197b413ec9c79116382abc4dbc.png" /> + + + + +</article> +<article class="admonition-filesystem-operations slide level-2"> + +<h2>Filesystem Operations</h2> + +<ul class="simple"> +<li>Mount</li> +<li>Open a file</li> +<li>Querying file attributes</li> +<li>Reading data from a file</li> +<li>Writing file to a file</li> +<li>Creating a file</li> +<li>Deleting a file</li> +</ul> + + + + +</article> +<article class="admonition-mounting-a-filesystem slide level-2"> + +<h2>Mounting a filesystem</h2> + +<ul class="simple"> +<li>Input: a storage device (partition)</li> +<li>Output: dentry pointing to the root directory</li> +<li>Steps: check device, determine filesystem parameters, locate the root inode</li> +<li>Example: check magic, determine block size, read the root inode and create dentry</li> +</ul> + + + + +</article> +<article class="admonition-opening-a-file slide level-2"> + +<h2>Opening a file</h2> + +<ul class="simple"> +<li>Input: path</li> +<li>Output: file descriptor</li> +<li>Steps:<ul> +<li>Determine the filesystem type</li> +<li>For each name in the path: lookup parent dentry, load inode, +load data, find dentry</li> +<li>Create a new <em>file</em> that points to the last <em>dentry</em></li> +<li>Find a free entry in the file descriptor table and set it to <em>file</em></li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-querying-file-attributes slide level-2"> + +<h2>Querying file attributes</h2> + +<ul class="simple"> +<li>Input: path</li> +<li>Output: file attributes</li> +<li>Steps:<ul> +<li>Access <cite>file->dentry->inode</cite></li> +<li>Read file attributes from the <em>inode</em></li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-reading-data-from-a-file slide level-2"> + +<h2>Reading data from a file</h2> + +<ul class="simple"> +<li>Input: file descriptor, offset, length</li> +<li>Output: data</li> +<li>Steps:<ul> +<li>Access <cite>file->dentry->inode</cite></li> +<li>Determine data blocks</li> +<li>Copy data blocks to memory</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-writing-data-to-a-file slide level-2"> + +<h2>Writing data to a file</h2> + +<ul class="simple"> +<li>Input: file descriptor, offset, length, data</li> +<li>Output:</li> +<li>Steps:<ul> +<li>Allocate one or more data blocks</li> +<li>Add the allocated blocks to the inode and update file size</li> +<li>Copy data from userspace to internal buffers and write them to +storage</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-closing-a-file slide level-2"> + +<h2>Closing a file</h2> + +<ul class="simple"> +<li>Input: file descriptor</li> +<li>Output:</li> +<li>Steps:<ul> +<li>set the file descriptor entry to NULL</li> +<li>Decrement file reference counter</li> +<li>When the counter reaches 0 free <em>file</em></li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-directories slide level-2"> + +<h2>Directories</h2> + +<p>Directories are special files which contain one or more dentries.</p> + + + + +</article> +<article class="admonition-creating-a-file slide level-2"> + +<h2>Creating a file</h2> + +<ul class="simple"> +<li>Input: path</li> +<li>Output:</li> +<li>Steps:<ul> +<li>Determine the inode directory</li> +<li>Read data blocks and find space for a new dentry</li> +<li>Write back the modified inode directory data blocks</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-deleting-a-file slide level-2"> + +<h2>Deleting a file</h2> + +<ul class="simple"> +<li>Input: path</li> +<li>Output:</li> +<li>Steps:<ul> +<li>determine the parent inode</li> +<li>read parent inode data blocks</li> +<li>find and erase the dentry (check for links)</li> +<li>when last file is closed: deallocate data and inode blocks</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-virtual-file-system slide level-2"> + +<h2>Virtual File System</h2> + +<a class="reference internal image-reference" href="../_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.png"><img alt="../_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.png" src="../_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.png" style="height: 100%;" /></a> + + + + +</article> +<article class="admonition-superblock-operations slide level-2"> + +<h2>Superblock Operations</h2> + +<table class="hlist"><tr><td><ul class="simple"> +<li>fill_super</li> +<li>put_super</li> +<li>write_super</li> +<li>read_inode</li> +</ul> +</td><td><ul class="simple"> +<li>write_inode</li> +<li>evict_inode</li> +<li>statfs</li> +<li>remount_fs</li> +</ul> +</td></tr></table> + + + + +</article> +<article class="admonition-inode-operations slide level-2"> + +<h2>Inode Operations</h2> + +<table class="hlist"><tr><td><ul class="simple"> +<li>create</li> +<li>lookup</li> +<li>link</li> +<li>unlink</li> +<li>symlink</li> +<li>mkdir</li> +</ul> +</td><td><ul class="simple"> +<li>rmdir</li> +<li>rename</li> +<li>readlink</li> +<li>follow_link</li> +<li>put_link</li> +<li>...</li> +</ul> +</td></tr></table> + + + + +</article> +<article class="admonition-the-inode-cache slide level-2"> + +<h2>The Inode Cache</h2> + +<ul class="simple"> +<li>Caches inodes into memory to avoid costly storage operations</li> +<li>An inode is cached until low memory conditions are triggered</li> +<li>inodes are indexed with a hash table</li> +<li>The inode hash function takes the superblock and inode number as +inputs</li> +</ul> + + + + +</article> +<article class="admonition-the-dentry-cache slide level-2"> + +<h2>The Dentry Cache</h2> + +<ul class="simple"> +<li>State:<ul> +<li>Used – <em>d_inode</em> is valid and the <em>dentry</em> object is in use</li> +<li>Unused – <em>d_inode</em> is valid but the dentry object is not in use</li> +<li>Negative – <em>d_inode</em> is not valid; the inode was not yet loaded +or the file was erased</li> +</ul> +</li> +<li>Dentry cache<ul> +<li>List of used dentries (dentry->d_state == used)</li> +<li>List of the most recent used dentries (sorted by access time)</li> +<li>Hash table to avoid searching the tree</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-the-page-cache slide level-2"> + +<h2>The Page Cache</h2> + +<ul class="simple"> +<li>Caches file data and not block device data</li> +<li>Uses the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">address_space</span></code> to translate file offsets +to block offsets</li> +<li>Used for both <cite>read</cite> / <cite>write</cite> and <cite>mmap</cite></li> +<li>Uses a radix tree</li> +</ul> + + + + +</article> +<article class="admonition-struct-address-space slide level-2"> + +<h2>struct address_space</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/**</span> +<span class="cm"> * struct address_space - Contents of a cacheable, mappable object.</span> +<span class="cm"> * @host: Owner, either the inode or the block_device.</span> +<span class="cm"> * @i_pages: Cached pages.</span> +<span class="cm"> * @gfp_mask: Memory allocation flags to use for allocating pages.</span> +<span class="cm"> * @i_mmap_writable: Number of VM_SHARED mappings.</span> +<span class="cm"> * @nr_thps: Number of THPs in the pagecache (non-shmem only).</span> +<span class="cm"> * @i_mmap: Tree of private and shared mappings.</span> +<span class="cm"> * @i_mmap_rwsem: Protects @i_mmap and @i_mmap_writable.</span> +<span class="cm"> * @nrpages: Number of page entries, protected by the i_pages lock.</span> +<span class="cm"> * @nrexceptional: Shadow or DAX entries, protected by the i_pages lock.</span> +<span class="cm"> * @writeback_index: Writeback starts here.</span> +<span class="cm"> * @a_ops: Methods.</span> +<span class="cm"> * @flags: Error bits and flags (AS_*).</span> +<span class="cm"> * @wb_err: The most recent error which has occurred.</span> +<span class="cm"> * @private_lock: For use by the owner of the address_space.</span> +<span class="cm"> * @private_list: For use by the owner of the address_space.</span> +<span class="cm"> * @private_data: For use by the owner of the address_space.</span> +<span class="cm"> */</span> +<span class="k">struct</span> <span class="n">address_space</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">host</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">xarray</span> <span class="n">i_pages</span><span class="p">;</span> + <span class="n">gfp_t</span> <span class="n">gfp_mask</span><span class="p">;</span> + <span class="n">atomic_t</span> <span class="n">i_mmap_writable</span><span class="p">;</span> +<span class="cp">#ifdef CONFIG_READ_ONLY_THP_FOR_FS</span> + <span class="cm">/* number of thp, only for non-shmem files */</span> + <span class="n">atomic_t</span> <span class="n">nr_thps</span><span class="p">;</span> +<span class="cp">#endif</span> + <span class="k">struct</span> <span class="n">rb_root_cached</span> <span class="n">i_mmap</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">rw_semaphore</span> <span class="n">i_mmap_rwsem</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">nrpages</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">nrexceptional</span><span class="p">;</span> + <span class="n">pgoff_t</span> <span class="n">writeback_index</span><span class="p">;</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">address_space_operations</span> <span class="o">*</span><span class="n">a_ops</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + <span class="n">errseq_t</span> <span class="n">wb_err</span><span class="p">;</span> + <span class="n">spinlock_t</span> <span class="n">private_lock</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="n">private_list</span><span class="p">;</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">private_data</span><span class="p">;</span> +<span class="p">}</span> <span class="n">__attribute__</span><span class="p">((</span><span class="n">aligned</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">long</span><span class="p">))))</span> <span class="n">__randomize_layout</span><span class="p">;</span> + +<span class="k">struct</span> <span class="n">address_space_operations</span> <span class="p">{</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">writepage</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">,</span> <span class="k">struct</span> <span class="n">writeback_control</span> <span class="o">*</span><span class="n">wbc</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">readpage</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + + <span class="cm">/* Write back some dirty pages from this mapping. */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">writepages</span><span class="p">)(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">writeback_control</span> <span class="o">*</span><span class="p">);</span> + + <span class="cm">/* Set a page dirty. Return true if this dirtied it */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">set_page_dirty</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">);</span> + + <span class="cm">/*</span> +<span class="cm"> * Reads in the requested pages. Unlike ->readpage(), this is</span> +<span class="cm"> * PURELY used for read-ahead!.</span> +<span class="cm"> */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">readpages</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">filp</span><span class="p">,</span> <span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="n">mapping</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="o">*</span><span class="n">pages</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">nr_pages</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">readahead</span><span class="p">)(</span><span class="k">struct</span> <span class="n">readahead_control</span> <span class="o">*</span><span class="p">);</span> + + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">write_begin</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="n">mapping</span><span class="p">,</span> + <span class="n">loff_t</span> <span class="n">pos</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">len</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">flags</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">page</span> <span class="o">**</span><span class="n">pagep</span><span class="p">,</span> <span class="kt">void</span> <span class="o">**</span><span class="n">fsdata</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">write_end</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="n">mapping</span><span class="p">,</span> + <span class="n">loff_t</span> <span class="n">pos</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">len</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">copied</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">fsdata</span><span class="p">);</span> + + <span class="cm">/* Unfortunately this kludge is needed for FIBMAP. Don't use it */</span> + <span class="n">sector_t</span> <span class="p">(</span><span class="o">*</span><span class="n">bmap</span><span class="p">)(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="p">,</span> <span class="n">sector_t</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">invalidatepage</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">releasepage</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="n">gfp_t</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">freepage</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">ssize_t</span> <span class="p">(</span><span class="o">*</span><span class="n">direct_IO</span><span class="p">)(</span><span class="k">struct</span> <span class="n">kiocb</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">iov_iter</span> <span class="o">*</span><span class="n">iter</span><span class="p">);</span> + <span class="cm">/*</span> +<span class="cm"> * migrate the contents of a page to the specified target. If</span> +<span class="cm"> * migrate_mode is MIGRATE_ASYNC, it must not block.</span> +<span class="cm"> */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">migratepage</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="k">enum</span> <span class="n">migrate_mode</span><span class="p">);</span> + <span class="kt">bool</span> <span class="p">(</span><span class="o">*</span><span class="n">isolate_page</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="n">isolate_mode_t</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">putback_page</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">launder_page</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">is_partially_uptodate</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">is_dirty_writeback</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="kt">bool</span> <span class="o">*</span><span class="p">,</span> <span class="kt">bool</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">error_remove_page</span><span class="p">)(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + + <span class="cm">/* swapfile support */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">swap_activate</span><span class="p">)(</span><span class="k">struct</span> <span class="n">swap_info_struct</span> <span class="o">*</span><span class="n">sis</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> + <span class="n">sector_t</span> <span class="o">*</span><span class="n">span</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">swap_deactivate</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">);</span> +<span class="p">};</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-reading-data slide level-2"> + +<h2>Reading data</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/**</span> +<span class="cm"> * generic_file_read_iter - generic filesystem read routine</span> +<span class="cm"> * @iocb: kernel I/O control block</span> +<span class="cm"> * @iter: destination for the data read</span> +<span class="cm"> *</span> +<span class="cm"> * This is the "read_iter()" routine for all filesystems</span> +<span class="cm"> * that can use the page cache directly.</span> +<span class="cm"> *</span> +<span class="cm"> * The IOCB_NOWAIT flag in iocb->ki_flags indicates that -EAGAIN shall</span> +<span class="cm"> * be returned when no data can be read without waiting for I/O requests</span> +<span class="cm"> * to complete; it doesn't prevent readahead.</span> +<span class="cm"> *</span> +<span class="cm"> * The IOCB_NOIO flag in iocb->ki_flags indicates that no new I/O</span> +<span class="cm"> * requests shall be made for the read or for readahead. When no data</span> +<span class="cm"> * can be read, -EAGAIN shall be returned. When readahead would be</span> +<span class="cm"> * triggered, a partial, possibly empty read shall be returned.</span> +<span class="cm"> *</span> +<span class="cm"> * Return:</span> +<span class="cm"> * * number of bytes copied, even for partial reads</span> +<span class="cm"> * * negative error code (or 0 if IOCB_NOIO) if nothing was read</span> +<span class="cm"> */</span> +<span class="kt">ssize_t</span> +<span class="n">generic_file_read_iter</span><span class="p">(</span><span class="k">struct</span> <span class="n">kiocb</span> <span class="o">*</span><span class="n">iocb</span><span class="p">,</span> <span class="k">struct</span> <span class="n">iov_iter</span> <span class="o">*</span><span class="n">iter</span><span class="p">)</span> + +<span class="cm">/*</span> +<span class="cm"> * Generic "read page" function for block devices that have the normal</span> +<span class="cm"> * get_block functionality. This is most of the block device filesystems.</span> +<span class="cm"> * Reads the page asynchronously --- the unlock_buffer() and</span> +<span class="cm"> * set/clear_buffer_uptodate() functions propagate buffer state into the</span> +<span class="cm"> * page struct once IO has completed.</span> +<span class="cm"> */</span> +<span class="kt">int</span> <span class="n">block_read_full_page</span><span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">,</span> <span class="n">get_block_t</span> <span class="o">*</span><span class="n">get_block</span><span class="p">)</span> +</pre></div> +</div> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/fs.html b/refs/pull/405/merge/lectures/fs.html new file mode 100644 index 00000000..e9cc54fd --- /dev/null +++ b/refs/pull/405/merge/lectures/fs.html @@ -0,0 +1,654 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Filesystem Management — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Debugging" href="debugging.html" /> + <link rel="prev" title="Memory Management" href="memory-management.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory-management.html">Memory Management</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Filesystem Management</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="#filesystem-abstractions">Filesystem Abstractions</a></li> +<li class="toctree-l2"><a class="reference internal" href="#filesystem-operations">Filesystem Operations</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#mounting-a-filesystem">Mounting a filesystem</a></li> +<li class="toctree-l3"><a class="reference internal" href="#opening-a-file">Opening a file</a></li> +<li class="toctree-l3"><a class="reference internal" href="#querying-file-attributes">Querying file attributes</a></li> +<li class="toctree-l3"><a class="reference internal" href="#reading-data-from-a-file">Reading data from a file</a></li> +<li class="toctree-l3"><a class="reference internal" href="#writing-data-to-a-file">Writing data to a file</a></li> +<li class="toctree-l3"><a class="reference internal" href="#closing-a-file">Closing a file</a></li> +<li class="toctree-l3"><a class="reference internal" href="#directories">Directories</a></li> +<li class="toctree-l3"><a class="reference internal" href="#creating-a-file">Creating a file</a></li> +<li class="toctree-l3"><a class="reference internal" href="#deleting-a-file">Deleting a file</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#linux-virtual-file-system">Linux Virtual File System</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#superblock-operations">Superblock Operations</a></li> +<li class="toctree-l3"><a class="reference internal" href="#inode-operations">Inode Operations</a></li> +<li class="toctree-l3"><a class="reference internal" href="#the-inode-cache">The Inode Cache</a></li> +<li class="toctree-l3"><a class="reference internal" href="#the-dentry-cache">The Dentry Cache</a></li> +<li class="toctree-l3"><a class="reference internal" href="#the-page-cache">The Page Cache</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Filesystem Management</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/lectures/fs.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="filesystem-management"> +<h1>Filesystem Management<a class="headerlink" href="#filesystem-management" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="fs-slides.html">View slides</a></p> +<div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-filesystem-management simple"> +<li>Filesystem abstractions</li> +<li>Filesystem operations</li> +<li>Linux VFS</li> +<li>Overview of Linux I/O Management</li> +</ul> +</div> +<div class="section" id="filesystem-abstractions"> +<h2>Filesystem Abstractions<a class="headerlink" href="#filesystem-abstractions" title="Permalink to this headline">¶</a></h2> +<p>A fileystem is a way to organize files and directories on storage +devices such as hard disks, SSDs or flash memory. There are many types +of filesystems (e.g. FAT, ext4, btrfs, ntfs) and on one running system +we can have multiple instances of the same filesystem type in use.</p> +<p>While filesystems use different data structures to organizing the +files, directories, user data and meta (internal) data on storage +devices there are a few common abstractions that are used in almost +all filesystems:</p> +<ul class="admonition-filesystem-abstractions simple"> +<li>superblock</li> +<li>file</li> +<li>inode</li> +<li>dentry</li> +</ul> +<p>Some of these abstractions are present both on disk and in memory +while some are only present in memory.</p> +<p>The <em>superblock</em> abstraction contains information about the filesystem +instance such as the block size, the root inode, filesystem size. It +is present both on storage and in memory (for caching purposes).</p> +<p>The <em>file</em> abstraction contains information about an opened file such +as the current file pointer. It only exists in memory.</p> +<p>The <em>inode</em> is identifying a file on disk. It exists both on storage +and in memory (for caching purposes). An inode identifies a file in a +unique way and has various properties such as the file size, access +rights, file type, etc.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The file name is not a property of the file.</p> +</div> +<p>The <em>dentry</em> associates a name with an inode. It exists both on +storage and in memory (for caching purposes).</p> +<p>The following diagram shows the relationship between the various filesystem +abstractions as they used in memory:</p> +<img alt="../_images/ditaa-29f54aaa1a85b819ff29cb7d101a4d646b3b0b06.png" class="admonition-filesystem-abstractions-in-memory" src="../_images/ditaa-29f54aaa1a85b819ff29cb7d101a4d646b3b0b06.png" /> +<p>Note that not all of the one to many relationships between the various +abstractions are depicted.</p> +<p>Multiple file descriptors can point to the same <em>file</em> because we can +use the <code class="xref c c-func docutils literal"><span class="pre">dup()</span></code> system call to duplicate a file descriptor.</p> +<p>Multiple <em>file</em> abstractions can point to the same <em>dentry</em> if we open +the same path multiple times.</p> +<p>Multiple <em>dentries</em> can point to the same <em>inode</em> when hard links are +used.</p> +<p>The following diagram shows the relationship of the filesystem +abstraction on storage:</p> +<img alt="../_images/ditaa-bc662dab7bb3d9ba3a37efbf69b82c513dcaadd4.png" class="admonition-filesystem-abstractions-on-storage" src="../_images/ditaa-bc662dab7bb3d9ba3a37efbf69b82c513dcaadd4.png" /> +<p>The diagram shows that the <em>superblock</em> is typically stored at the +beginning of the fileystem and that various blocks are used with +different purposes: some to store dentries, some to store inodes and +some to store user data blocks. There are also blocks used to manage +the available free blocks (e.g. bitmaps for the simple filesystems).</p> +<p>The next diagram show a very simple filesystem where blocks are +grouped together by function:</p> +<ul class="simple"> +<li>the superblock contains information about the block size as well as +the IMAP, DMAP, IZONE and DZONE areas.</li> +<li>the IMAP area is comprised of multiple blocks which contains a +bitmap for inode allocation; it maintains the allocated/free state +for all inodes in the IZONE area</li> +<li>the DMAP area is comprised of multiple blocks which contains a +bitmap for data blocks; it maintains the allocated/free state for +all blocks the DZONE area</li> +</ul> +<p class="admonition-simple-filesystem-example"> </p> +<img alt="../_images/ditaa-8b59fc3f5245ffb5d7089dc80cf2e306c39a62d8.png" src="../_images/ditaa-8b59fc3f5245ffb5d7089dc80cf2e306c39a62d8.png" /> +</div> +<div class="section" id="filesystem-operations"> +<h2>Filesystem Operations<a class="headerlink" href="#filesystem-operations" title="Permalink to this headline">¶</a></h2> +<p>The following diagram shows a high level overview of how the file +system drivers interact with the rest of the file system "stack". In +order to support multiple filesystem types and instances Linux +implements a large and complex subsystem that deals with filesystem +management. This is called Virtual File System (or sometimes Virtual +File Switch) and it is abbreviated with VFS.</p> +<img alt="../_images/ditaa-6d39f541805ae8197b413ec9c79116382abc4dbc.png" class="admonition-overview" src="../_images/ditaa-6d39f541805ae8197b413ec9c79116382abc4dbc.png" /> +<p>VFS translates the complex file management related system calls to +simpler operations that are implemented by the device drivers. These +are some of the operations that a file system must implement:</p> +<ul class="admonition-filesystem-operations simple"> +<li>Mount</li> +<li>Open a file</li> +<li>Querying file attributes</li> +<li>Reading data from a file</li> +<li>Writing file to a file</li> +<li>Creating a file</li> +<li>Deleting a file</li> +</ul> +<p>The next sections will look in-depth at some of these operations.</p> +<div class="section" id="mounting-a-filesystem"> +<h3>Mounting a filesystem<a class="headerlink" href="#mounting-a-filesystem" title="Permalink to this headline">¶</a></h3> +<p>A summary of a typical implementation is presented below:</p> +<ul class="admonition-mounting-a-filesystem simple"> +<li>Input: a storage device (partition)</li> +<li>Output: dentry pointing to the root directory</li> +<li>Steps: check device, determine filesystem parameters, locate the root inode</li> +<li>Example: check magic, determine block size, read the root inode and create dentry</li> +</ul> +</div> +<div class="section" id="opening-a-file"> +<h3>Opening a file<a class="headerlink" href="#opening-a-file" title="Permalink to this headline">¶</a></h3> +<p>A summary of a typical implementation is presented below:</p> +<ul class="admonition-opening-a-file simple"> +<li>Input: path</li> +<li>Output: file descriptor</li> +<li>Steps:<ul> +<li>Determine the filesystem type</li> +<li>For each name in the path: lookup parent dentry, load inode, +load data, find dentry</li> +<li>Create a new <em>file</em> that points to the last <em>dentry</em></li> +<li>Find a free entry in the file descriptor table and set it to <em>file</em></li> +</ul> +</li> +</ul> +</div> +<div class="section" id="querying-file-attributes"> +<h3>Querying file attributes<a class="headerlink" href="#querying-file-attributes" title="Permalink to this headline">¶</a></h3> +<p>A summary of a typical implementation is presented below:</p> +<ul class="admonition-querying-file-attributes simple"> +<li>Input: path</li> +<li>Output: file attributes</li> +<li>Steps:<ul> +<li>Access <cite>file->dentry->inode</cite></li> +<li>Read file attributes from the <em>inode</em></li> +</ul> +</li> +</ul> +</div> +<div class="section" id="reading-data-from-a-file"> +<h3>Reading data from a file<a class="headerlink" href="#reading-data-from-a-file" title="Permalink to this headline">¶</a></h3> +<p>A summary of a typical implementation is presented below:</p> +<ul class="admonition-reading-data-from-a-file simple"> +<li>Input: file descriptor, offset, length</li> +<li>Output: data</li> +<li>Steps:<ul> +<li>Access <cite>file->dentry->inode</cite></li> +<li>Determine data blocks</li> +<li>Copy data blocks to memory</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="writing-data-to-a-file"> +<h3>Writing data to a file<a class="headerlink" href="#writing-data-to-a-file" title="Permalink to this headline">¶</a></h3> +<p>A summary of a typical implementation is presented below:</p> +<ul class="admonition-writing-data-to-a-file simple"> +<li>Input: file descriptor, offset, length, data</li> +<li>Output:</li> +<li>Steps:<ul> +<li>Allocate one or more data blocks</li> +<li>Add the allocated blocks to the inode and update file size</li> +<li>Copy data from userspace to internal buffers and write them to +storage</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="closing-a-file"> +<h3>Closing a file<a class="headerlink" href="#closing-a-file" title="Permalink to this headline">¶</a></h3> +<p>A summary of a typical implementation is presented below:</p> +<ul class="admonition-closing-a-file simple"> +<li>Input: file descriptor</li> +<li>Output:</li> +<li>Steps:<ul> +<li>set the file descriptor entry to NULL</li> +<li>Decrement file reference counter</li> +<li>When the counter reaches 0 free <em>file</em></li> +</ul> +</li> +</ul> +</div> +<div class="section" id="directories"> +<h3>Directories<a class="headerlink" href="#directories" title="Permalink to this headline">¶</a></h3> +<p class="admonition-directories">Directories are special files which contain one or more dentries.</p> +</div> +<div class="section" id="creating-a-file"> +<h3>Creating a file<a class="headerlink" href="#creating-a-file" title="Permalink to this headline">¶</a></h3> +<p>A summary of a typical implementation is presented below:</p> +<ul class="admonition-creating-a-file simple"> +<li>Input: path</li> +<li>Output:</li> +<li>Steps:<ul> +<li>Determine the inode directory</li> +<li>Read data blocks and find space for a new dentry</li> +<li>Write back the modified inode directory data blocks</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="deleting-a-file"> +<h3>Deleting a file<a class="headerlink" href="#deleting-a-file" title="Permalink to this headline">¶</a></h3> +<p>A summary of a typical implementation is presented below:</p> +<ul class="admonition-deleting-a-file simple"> +<li>Input: path</li> +<li>Output:</li> +<li>Steps:<ul> +<li>determine the parent inode</li> +<li>read parent inode data blocks</li> +<li>find and erase the dentry (check for links)</li> +<li>when last file is closed: deallocate data and inode blocks</li> +</ul> +</li> +</ul> +</div> +</div> +<div class="section" id="linux-virtual-file-system"> +<h2>Linux Virtual File System<a class="headerlink" href="#linux-virtual-file-system" title="Permalink to this headline">¶</a></h2> +<p>Although the main purpose for the original introduction of VFS in UNIX +kernels was to support multiple filesystem types and instances, a side +effect was that it simplified fileystem device driver development +since command parts are now implement in the VFS. Almost all of the +caching and buffer management is dealt with VFS, leaving just +efficient data storage management to the filesystem device driver.</p> +<p>In order to deal with multiple filesystem types, VFS introduced the +common filesystem abstractions previously presented. Note that the +filesystem driver can also use its own particular fileystem +abstractions in memory (e.g. ext4 inode or dentry) and that there +might be a different abstraction on storage as well. Thus we may end +up with three slightly different filesystem abstractions: one for +VFS - always in memory, and two for a particular filesystem - one in +memory used by the filesystem driver, and one on storage.</p> +<a class="admonition-virtual-file-system reference internal image-reference" href="../_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.png"><img alt="../_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.png" class="admonition-virtual-file-system" src="../_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.png" style="height: 100%;" /></a> +<div class="section" id="superblock-operations"> +<h3>Superblock Operations<a class="headerlink" href="#superblock-operations" title="Permalink to this headline">¶</a></h3> +<p>VFS requires that all filesystem implement a set of "superblock +operations".</p> +<p>They deal with initializing, updating and freeing the VFS superblock:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">fill_super()</span></code> - reads the filesystem statistics (e.g. total +number of inode, free number of inodes, total number of blocks, free +number of blocks)</li> +<li><code class="xref c c-func docutils literal"><span class="pre">write_super()</span></code> - updates the superblock information on storage +(e.g. updating the number of free inode or data blocks)</li> +<li><code class="xref c c-func docutils literal"><span class="pre">put_super()</span></code> - free any data associated with the filsystem +instance, called when unmounting a filesystem</li> +</ul> +</div></blockquote> +<p>The next class of operations are dealing with manipulating fileystem +inodes. These operations will receive VFS inodes as parameters but the +filesystem driver may use its own inode structures internally and, if +so, they will convert in between them as necessary.</p> +<p>A summary of the superblock operations are presented below:</p> +<table class="hlist"><tr><td><ul class="simple"> +<li>fill_super</li> +<li>put_super</li> +<li>write_super</li> +<li>read_inode</li> +</ul> +</td><td><ul class="simple"> +<li>write_inode</li> +<li>evict_inode</li> +<li>statfs</li> +<li>remount_fs</li> +</ul> +</td></tr></table> +</div> +<div class="section" id="inode-operations"> +<h3>Inode Operations<a class="headerlink" href="#inode-operations" title="Permalink to this headline">¶</a></h3> +<p>The next set of operations that VFS calls when interacting with +filesystem device drivers are the "inode operations". Non-intuitively +these mostly deal with manipulating dentries - looking up a file name, +creating, linking and removing files, dealing with symbolic links, +creating and removing directories.</p> +<p>This is the list of the most important inode operations:</p> +<table class="hlist"><tr><td><ul class="simple"> +<li>create</li> +<li>lookup</li> +<li>link</li> +<li>unlink</li> +<li>symlink</li> +<li>mkdir</li> +</ul> +</td><td><ul class="simple"> +<li>rmdir</li> +<li>rename</li> +<li>readlink</li> +<li>follow_link</li> +<li>put_link</li> +<li>...</li> +</ul> +</td></tr></table> +</div> +<div class="section" id="the-inode-cache"> +<h3>The Inode Cache<a class="headerlink" href="#the-inode-cache" title="Permalink to this headline">¶</a></h3> +<p>The inode cache is used to avoid reading and writing inodes to and +from storage every time we need to read or update them. The cache uses +a hash table and inodes are indexed with a hash function which takes +as parameters the superblock (of a particular filesystem instance) and +the inode number associated with an inode.</p> +<p>inodes are cached until either the filesystem is unmounted, the inode +deleted or the system enters a memory pressure state. When this +happens the Linux memory management system will (among other things) +free inodes from the inode cache based on how often they were +accessed.</p> +<ul class="admonition-the-inode-cache simple"> +<li>Caches inodes into memory to avoid costly storage operations</li> +<li>An inode is cached until low memory conditions are triggered</li> +<li>inodes are indexed with a hash table</li> +<li>The inode hash function takes the superblock and inode number as +inputs</li> +</ul> +</div> +<div class="section" id="the-dentry-cache"> +<h3>The Dentry Cache<a class="headerlink" href="#the-dentry-cache" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-the-dentry-cache simple"> +<li>State:<ul> +<li>Used – <em>d_inode</em> is valid and the <em>dentry</em> object is in use</li> +<li>Unused – <em>d_inode</em> is valid but the dentry object is not in use</li> +<li>Negative – <em>d_inode</em> is not valid; the inode was not yet loaded +or the file was erased</li> +</ul> +</li> +<li>Dentry cache<ul> +<li>List of used dentries (dentry->d_state == used)</li> +<li>List of the most recent used dentries (sorted by access time)</li> +<li>Hash table to avoid searching the tree</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="the-page-cache"> +<h3>The Page Cache<a class="headerlink" href="#the-page-cache" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-the-page-cache simple"> +<li>Caches file data and not block device data</li> +<li>Uses the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">address_space</span></code> to translate file offsets +to block offsets</li> +<li>Used for both <cite>read</cite> / <cite>write</cite> and <cite>mmap</cite></li> +<li>Uses a radix tree</li> +</ul> +<div class="admonition-struct-address-space highlight-c"><div class="highlight"><pre><span></span><span class="cm">/**</span> +<span class="cm"> * struct address_space - Contents of a cacheable, mappable object.</span> +<span class="cm"> * @host: Owner, either the inode or the block_device.</span> +<span class="cm"> * @i_pages: Cached pages.</span> +<span class="cm"> * @gfp_mask: Memory allocation flags to use for allocating pages.</span> +<span class="cm"> * @i_mmap_writable: Number of VM_SHARED mappings.</span> +<span class="cm"> * @nr_thps: Number of THPs in the pagecache (non-shmem only).</span> +<span class="cm"> * @i_mmap: Tree of private and shared mappings.</span> +<span class="cm"> * @i_mmap_rwsem: Protects @i_mmap and @i_mmap_writable.</span> +<span class="cm"> * @nrpages: Number of page entries, protected by the i_pages lock.</span> +<span class="cm"> * @nrexceptional: Shadow or DAX entries, protected by the i_pages lock.</span> +<span class="cm"> * @writeback_index: Writeback starts here.</span> +<span class="cm"> * @a_ops: Methods.</span> +<span class="cm"> * @flags: Error bits and flags (AS_*).</span> +<span class="cm"> * @wb_err: The most recent error which has occurred.</span> +<span class="cm"> * @private_lock: For use by the owner of the address_space.</span> +<span class="cm"> * @private_list: For use by the owner of the address_space.</span> +<span class="cm"> * @private_data: For use by the owner of the address_space.</span> +<span class="cm"> */</span> +<span class="k">struct</span> <span class="n">address_space</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">host</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">xarray</span> <span class="n">i_pages</span><span class="p">;</span> + <span class="n">gfp_t</span> <span class="n">gfp_mask</span><span class="p">;</span> + <span class="n">atomic_t</span> <span class="n">i_mmap_writable</span><span class="p">;</span> +<span class="cp">#ifdef CONFIG_READ_ONLY_THP_FOR_FS</span> + <span class="cm">/* number of thp, only for non-shmem files */</span> + <span class="n">atomic_t</span> <span class="n">nr_thps</span><span class="p">;</span> +<span class="cp">#endif</span> + <span class="k">struct</span> <span class="n">rb_root_cached</span> <span class="n">i_mmap</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">rw_semaphore</span> <span class="n">i_mmap_rwsem</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">nrpages</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">nrexceptional</span><span class="p">;</span> + <span class="n">pgoff_t</span> <span class="n">writeback_index</span><span class="p">;</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">address_space_operations</span> <span class="o">*</span><span class="n">a_ops</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + <span class="n">errseq_t</span> <span class="n">wb_err</span><span class="p">;</span> + <span class="n">spinlock_t</span> <span class="n">private_lock</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="n">private_list</span><span class="p">;</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">private_data</span><span class="p">;</span> +<span class="p">}</span> <span class="n">__attribute__</span><span class="p">((</span><span class="n">aligned</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">long</span><span class="p">))))</span> <span class="n">__randomize_layout</span><span class="p">;</span> + +<span class="k">struct</span> <span class="n">address_space_operations</span> <span class="p">{</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">writepage</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">,</span> <span class="k">struct</span> <span class="n">writeback_control</span> <span class="o">*</span><span class="n">wbc</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">readpage</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + + <span class="cm">/* Write back some dirty pages from this mapping. */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">writepages</span><span class="p">)(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">writeback_control</span> <span class="o">*</span><span class="p">);</span> + + <span class="cm">/* Set a page dirty. Return true if this dirtied it */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">set_page_dirty</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">);</span> + + <span class="cm">/*</span> +<span class="cm"> * Reads in the requested pages. Unlike ->readpage(), this is</span> +<span class="cm"> * PURELY used for read-ahead!.</span> +<span class="cm"> */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">readpages</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">filp</span><span class="p">,</span> <span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="n">mapping</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="o">*</span><span class="n">pages</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">nr_pages</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">readahead</span><span class="p">)(</span><span class="k">struct</span> <span class="n">readahead_control</span> <span class="o">*</span><span class="p">);</span> + + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">write_begin</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="n">mapping</span><span class="p">,</span> + <span class="n">loff_t</span> <span class="n">pos</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">len</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">flags</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">page</span> <span class="o">**</span><span class="n">pagep</span><span class="p">,</span> <span class="kt">void</span> <span class="o">**</span><span class="n">fsdata</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">write_end</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="n">mapping</span><span class="p">,</span> + <span class="n">loff_t</span> <span class="n">pos</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">len</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">copied</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">fsdata</span><span class="p">);</span> + + <span class="cm">/* Unfortunately this kludge is needed for FIBMAP. Don't use it */</span> + <span class="n">sector_t</span> <span class="p">(</span><span class="o">*</span><span class="n">bmap</span><span class="p">)(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="p">,</span> <span class="n">sector_t</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">invalidatepage</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">releasepage</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="n">gfp_t</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">freepage</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">ssize_t</span> <span class="p">(</span><span class="o">*</span><span class="n">direct_IO</span><span class="p">)(</span><span class="k">struct</span> <span class="n">kiocb</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">iov_iter</span> <span class="o">*</span><span class="n">iter</span><span class="p">);</span> + <span class="cm">/*</span> +<span class="cm"> * migrate the contents of a page to the specified target. If</span> +<span class="cm"> * migrate_mode is MIGRATE_ASYNC, it must not block.</span> +<span class="cm"> */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">migratepage</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="k">enum</span> <span class="n">migrate_mode</span><span class="p">);</span> + <span class="kt">bool</span> <span class="p">(</span><span class="o">*</span><span class="n">isolate_page</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="n">isolate_mode_t</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">putback_page</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">launder_page</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">is_partially_uptodate</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">is_dirty_writeback</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="kt">bool</span> <span class="o">*</span><span class="p">,</span> <span class="kt">bool</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">error_remove_page</span><span class="p">)(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + + <span class="cm">/* swapfile support */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">swap_activate</span><span class="p">)(</span><span class="k">struct</span> <span class="n">swap_info_struct</span> <span class="o">*</span><span class="n">sis</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> + <span class="n">sector_t</span> <span class="o">*</span><span class="n">span</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">swap_deactivate</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">);</span> +<span class="p">};</span> +</pre></div> +</div> +<div class="admonition-reading-data highlight-c"><div class="highlight"><pre><span></span><span class="cm">/**</span> +<span class="cm"> * generic_file_read_iter - generic filesystem read routine</span> +<span class="cm"> * @iocb: kernel I/O control block</span> +<span class="cm"> * @iter: destination for the data read</span> +<span class="cm"> *</span> +<span class="cm"> * This is the "read_iter()" routine for all filesystems</span> +<span class="cm"> * that can use the page cache directly.</span> +<span class="cm"> *</span> +<span class="cm"> * The IOCB_NOWAIT flag in iocb->ki_flags indicates that -EAGAIN shall</span> +<span class="cm"> * be returned when no data can be read without waiting for I/O requests</span> +<span class="cm"> * to complete; it doesn't prevent readahead.</span> +<span class="cm"> *</span> +<span class="cm"> * The IOCB_NOIO flag in iocb->ki_flags indicates that no new I/O</span> +<span class="cm"> * requests shall be made for the read or for readahead. When no data</span> +<span class="cm"> * can be read, -EAGAIN shall be returned. When readahead would be</span> +<span class="cm"> * triggered, a partial, possibly empty read shall be returned.</span> +<span class="cm"> *</span> +<span class="cm"> * Return:</span> +<span class="cm"> * * number of bytes copied, even for partial reads</span> +<span class="cm"> * * negative error code (or 0 if IOCB_NOIO) if nothing was read</span> +<span class="cm"> */</span> +<span class="kt">ssize_t</span> +<span class="n">generic_file_read_iter</span><span class="p">(</span><span class="k">struct</span> <span class="n">kiocb</span> <span class="o">*</span><span class="n">iocb</span><span class="p">,</span> <span class="k">struct</span> <span class="n">iov_iter</span> <span class="o">*</span><span class="n">iter</span><span class="p">)</span> + +<span class="cm">/*</span> +<span class="cm"> * Generic "read page" function for block devices that have the normal</span> +<span class="cm"> * get_block functionality. This is most of the block device filesystems.</span> +<span class="cm"> * Reads the page asynchronously --- the unlock_buffer() and</span> +<span class="cm"> * set/clear_buffer_uptodate() functions propagate buffer state into the</span> +<span class="cm"> * page struct once IO has completed.</span> +<span class="cm"> */</span> +<span class="kt">int</span> <span class="n">block_read_full_page</span><span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">,</span> <span class="n">get_block_t</span> <span class="o">*</span><span class="n">get_block</span><span class="p">)</span> +</pre></div> +</div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="memory-management.html" class="btn btn-neutral float-left" title="Memory Management" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="debugging.html" class="btn btn-neutral float-right" title="Debugging" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/interrupts-slides.html b/refs/pull/405/merge/lectures/interrupts-slides.html new file mode 100644 index 00000000..aff9d470 --- /dev/null +++ b/refs/pull/405/merge/lectures/interrupts-slides.html @@ -0,0 +1,628 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Interrupts — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="next" title="Symmetric Multi-Processing" href="smp.html" /> + <link rel="prev" title="Processes" href="processes.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-interrupts slide level-2"> + +<h2>Interrupts</h2> + +<ul class="simple"> +<li>Interrupts and exceptions (x86)</li> +<li>Interrupts and exceptions (Linux)</li> +<li>Deferrable work</li> +<li>Timers</li> +</ul> + + + + +</article> +<article class="admonition-interrupts slide level-2"> + +<h2>Interrupts</h2> + +<ul class="simple"> +<li><strong>synchronous</strong>, generated by executing an instruction</li> +<li><strong>asynchronous</strong>, generated by an external event</li> +<li><strong>maskable</strong><ul> +<li>can be ignored</li> +<li>signaled via INT pin</li> +</ul> +</li> +<li><strong>non-maskable</strong><ul> +<li>cannot be ignored</li> +<li>signaled via NMI pin</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-exceptions slide level-2"> + +<h2>Exceptions</h2> + +<ul class="simple"> +<li>processor detected<ul> +<li><strong>faults</strong></li> +<li><strong>traps</strong></li> +<li><strong>aborts</strong></li> +</ul> +</li> +<li>programmed<ul> +<li><strong>int n</strong></li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-quiz-interrupt-terminology slide level-2"> + +<h2>Quiz: interrupt terminology</h2> + +<p>For each of the following terms on the left select all the terms +from right that best describe them.</p> +<table class="hlist"><tr><td><ul class="simple"> +<li>Watchdog</li> +<li>Demand paging</li> +<li>Division by zero</li> +<li>Timer</li> +<li>System call</li> +<li>Breakpoint</li> +</ul> +</td><td><ul class="simple"> +<li>Exception</li> +<li>Interrupt</li> +<li>Maskable</li> +<li>Nonmaskable</li> +<li>Trap</li> +<li>Fault</li> +</ul> +</td></tr></table> + + + + +</article> +<article class="admonition-programmable-interrupt-controller slide level-2"> + +<h2>Programmable Interrupt Controller</h2> + +<p> </p> +<img alt="../_images/ditaa-5db1739b80a83b12505e4ff749b5e69fccd01f1b.png" src="../_images/ditaa-5db1739b80a83b12505e4ff749b5e69fccd01f1b.png" /> + + + + +</article> +<article class="admonition-interrupt-controllers-in-smp-systems slide level-2"> + +<h2>Interrupt controllers in SMP systems</h2> + +<p> </p> +<img alt="../_images/ditaa-9d23d02ebdff6eeb6bec8044480f055de9852ecc.png" src="../_images/ditaa-9d23d02ebdff6eeb6bec8044480f055de9852ecc.png" /> + + + + +</article> +<article class="admonition-enabling-disabling-the-interrupts slide level-2"> + +<h2>Enabling/disabling the interrupts</h2> + +<ul class="simple"> +<li>at the device level<ul> +<li>by programming the device control registers</li> +</ul> +</li> +<li>at the PIC level<ul> +<li>PIC can be programmed to disable a given IRQ line</li> +</ul> +</li> +<li>at the CPU level; for example, on x86 one can use the following +instructions:</li> +</ul> +<blockquote> +<div><ul class="simple"> +<li>cli (CLear Interrupt flag)</li> +<li>sti (SeT Interrupt flag)</li> +</ul> +</div></blockquote> + + + + +</article> +<article class="admonition-interrupt-priorities slide level-2"> + +<h2>Interrupt priorities</h2> + +<p> </p> +<img alt="../_images/ditaa-8b00a68b494f72d54b5fad38c88f7265aadaaa0e.png" src="../_images/ditaa-8b00a68b494f72d54b5fad38c88f7265aadaaa0e.png" /> + + + + +</article> +<article class="admonition-quiz-hardware-concepts slide level-2"> + +<h2>Quiz: hardware concepts</h2> + +<p>Which of the following statements are true?</p> +<ul class="simple"> +<li>The CPU can start processing a new interrupt before the current +one is finished</li> +<li>Interrupts can be disabled at the device level</li> +<li>Lower priority interrupts can not preempt handlers for higher +priority interrupts</li> +<li>Interrupts can be disabled at the interrupt controller level</li> +<li>On SMP systems the same interrupt can be routed to different CPUs</li> +<li>Interrupts can be disabled at the CPU level</li> +</ul> + + + + +</article> +<article class="admonition-interrupt-descriptor-table slide level-2"> + +<h2>Interrupt Descriptor Table</h2> + +<ul class="simple"> +<li>it is used as a jump table by the CPU when a given vector is triggered</li> +<li>it is an array of 256 x 8 bytes entries</li> +<li>may reside anywhere in physical memory</li> +<li>processor locates IDT by the means of IDTR</li> +</ul> + + + + +</article> +<article class="admonition-linux-irq-vector-layout slide level-2"> + +<h2>Linux IRQ vector layout</h2> + +<p> </p> +<img alt="../_images/ditaa-5b3c93f6e612d0cc0e4d4837d92a443627405262.png" src="../_images/ditaa-5b3c93f6e612d0cc0e4d4837d92a443627405262.png" /> + + + + +</article> +<article class="admonition-interrupt-descriptor-table-entry-gate slide level-2"> + +<h2>Interrupt descriptor table entry (gate)</h2> + +<p> </p> +<img alt="../_images/ditaa-eff5e0e3b58ce239d5310b22b89c0927be5853bd.png" src="../_images/ditaa-eff5e0e3b58ce239d5310b22b89c0927be5853bd.png" /> + + + + +</article> +<article class="admonition-interrupt-handler-address slide level-2"> + +<h2>Interrupt handler address</h2> + +<p> </p> +<img alt="../_images/ditaa-b2023fce22479e20bbe08fd76eed87e9a0527688.png" src="../_images/ditaa-b2023fce22479e20bbe08fd76eed87e9a0527688.png" /> + + + + +</article> +<article class="admonition-interrupt-handler-stack slide level-2"> + +<h2>Interrupt handler stack</h2> + +<p> </p> +<img alt="../_images/ditaa-85b69602726fa6143fc3ba0ffdb492454864aacf.png" src="../_images/ditaa-85b69602726fa6143fc3ba0ffdb492454864aacf.png" /> + + + + +</article> +<article class="admonition-handling-an-interrupt-request slide level-2"> + +<h2>Handling an interrupt request</h2> + +<ul> +<li><p class="first">CPU checks the current privilege level</p> +</li> +<li><p class="first">if need to change privilege level</p> +<blockquote> +<div><ul class="simple"> +<li>change stack with the one associated with new privilege</li> +<li>save old stack information on the new stack</li> +</ul> +</div></blockquote> +</li> +<li><p class="first">save EFLAGS, CS, EIP on stack</p> +</li> +<li><p class="first">save error code on stack in case of an abort</p> +</li> +<li><p class="first">execute the kernel interrupt handler</p> +</li> +</ul> + + + + +</article> +<article class="admonition-returning-from-an-interrupt slide level-2"> + +<h2>Returning from an interrupt</h2> + +<ul class="simple"> +<li>pop the error code (in case of an abort)</li> +<li>call IRET<ul> +<li>pops values from the stack and restore the following register: CS, EIP, EFLAGS</li> +<li>if privilege level changed returns to the old stack and old privilege level</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-inspecting-the-x86-interrupt-handling slide level-2"> + +<h2>Inspecting the x86 interrupt handling</h2> + +<p> </p> +<asciinema-player src="../_images/intr_x86.cast"></asciinema-player> + + + +</article> +<article class="admonition-quiz-x86-interrupt-handling slide level-2"> + +<h2>Quiz: x86 interrupt handling</h2> + +<p>The following gdb commands are used to determine the handler for +the int80 based system call exception. Select and arrange the +commands or output of the commands in the correct order.</p> +<div class="highlight-gdb"><div class="highlight"><pre><span></span>(void *) 0xc15de780 <entry_SYSENTER_32> + +set $idtr_addr=($idtr_entry>>48<<16)|($idtr_entry&0xffff) + +print (void*)$idtr_addr + +set $idtr = 0xff800000 + +(void *) 0xc15de874 <entry_INT80_32> + +set $idtr = 0xff801000 + +set $idtr_entry = *(uint64_t*)($idtr + 8 * 128) + +monitor info registers +</pre></div> +</div> + + + + +</article> +<article class="admonition-interrupt-handling-in-linux slide level-2"> + +<h2>Interrupt handling in Linux</h2> + +<p> </p> +<img alt="../_images/ditaa-da31e3d17a4d55e5c3dbc0bd5903306418a896ca.png" src="../_images/ditaa-da31e3d17a4d55e5c3dbc0bd5903306418a896ca.png" /> + + + + +</article> +<article class="admonition-irq-and-exception-nesting-in-linux slide level-2"> + +<h2>IRQ and exception nesting in Linux</h2> + +<ul class="simple"> +<li>an exception (e.g. page fault, system call) can not preempt an interrupt; +if that occurs it is considered a bug</li> +<li>an interrupt can preempt an exception</li> +<li>an interrupt can not preempt another interrupt (it used to be possible)</li> +</ul> + + + + +</article> +<article class="admonition-interrupt-exception-nesting slide level-2"> + +<h2>Interrupt/Exception nesting</h2> + +<p> </p> +<img alt="../_images/ditaa-2e49ca6ac606dab4b2b53231cfbe85ff06312d36.png" src="../_images/ditaa-2e49ca6ac606dab4b2b53231cfbe85ff06312d36.png" /> + + + + +</article> +<article class="admonition-interrupt-context slide level-2"> + +<h2>Interrupt context</h2> + +<blockquote> +<div><ul class="simple"> +<li>it runs as a result of an IRQ (not of an exception)</li> +<li>there is no well defined process context associated</li> +<li>not allowed to trigger a context switch (no sleep, schedule, or user memory access)</li> +</ul> +</div></blockquote> + + + + +</article> +<article class="admonition-deferrable-actions slide level-2"> + +<h2>Deferrable actions</h2> + +<blockquote> +<div><ul class="simple"> +<li>Schedule callback functions to run at a later time</li> +<li>Interrupt context deferrable actions</li> +<li>Process context deferrable actions</li> +<li>APIs for initialization, scheduling, and masking</li> +</ul> +</div></blockquote> + + + + +</article> +<article class="admonition-soft-irqs slide level-2"> + +<h2>Soft IRQs</h2> + +<blockquote> +<div><p>Soft IRQ APIs:</p> +<blockquote> +<div><ul class="simple"> +<li>initialize: <code class="xref c c-func docutils literal"><span class="pre">open_softirq()</span></code></li> +<li>activation: <code class="xref c c-func docutils literal"><span class="pre">raise_softirq()</span></code></li> +<li>masking: <code class="xref c c-func docutils literal"><span class="pre">local_bh_disable()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">local_bh_enable()</span></code></li> +</ul> +</div></blockquote> +<p>Once activated, the callback function <code class="xref c c-func docutils literal"><span class="pre">do_softirq()</span></code> runs either:</p> +<blockquote> +<div><ul class="simple"> +<li>after an interrupt handler or</li> +<li>from the ksoftirqd kernel thread</li> +</ul> +</div></blockquote> +</div></blockquote> + + + + +</article> +<article class="admonition-ksoftirqd slide level-2"> + +<h2>ksoftirqd</h2> + +<blockquote> +<div><ul class="simple"> +<li>minimum priority kernel thread</li> +<li>runs softirqs after certain limits are reached</li> +<li>tries to achieve good latency and avoid process starvation</li> +</ul> +</div></blockquote> + + + + +</article> +<article class="admonition-types-of-soft-irqs slide level-2"> + +<h2>Types of soft IRQs</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* PLEASE, avoid to allocate new softirqs, if you need not _really_ high</span> +<span class="cm"> frequency threaded job scheduling. For almost all the purposes</span> +<span class="cm"> tasklets are more than enough. F.e. all serial device BHs et</span> +<span class="cm"> al. should be converted to tasklets, not to softirqs.</span> +<span class="cm">*/</span> + +<span class="k">enum</span> +<span class="p">{</span> + <span class="n">HI_SOFTIRQ</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> + <span class="n">TIMER_SOFTIRQ</span><span class="p">,</span> + <span class="n">NET_TX_SOFTIRQ</span><span class="p">,</span> + <span class="n">NET_RX_SOFTIRQ</span><span class="p">,</span> + <span class="n">BLOCK_SOFTIRQ</span><span class="p">,</span> + <span class="n">IRQ_POLL_SOFTIRQ</span><span class="p">,</span> + <span class="n">TASKLET_SOFTIRQ</span><span class="p">,</span> + <span class="n">SCHED_SOFTIRQ</span><span class="p">,</span> + <span class="n">HRTIMER_SOFTIRQ</span><span class="p">,</span> + <span class="n">RCU_SOFTIRQ</span><span class="p">,</span> <span class="cm">/* Preferable RCU should always be the last softirq */</span> + + <span class="n">NR_SOFTIRQS</span> +<span class="p">};</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-packet-flood-example slide level-2"> + +<h2>Packet flood example</h2> + +<p> </p> +<asciinema-player src="../_images/ksoftirqd-packet-flood.cast"></asciinema-player> + + + +</article> +<article class="admonition-tasklets slide level-2"> + +<h2>Tasklets</h2> + +<p>Tasklets are a dynamic type (not limited to a fixed number) of +deferred work running in interrupt context.</p> +<p>Tasklets API:</p> +<blockquote> +<div><ul class="simple"> +<li>initialization: <code class="xref c c-func docutils literal"><span class="pre">tasklet_init()</span></code></li> +<li>activation: <code class="xref c c-func docutils literal"><span class="pre">tasklet_schedule()</span></code></li> +<li>masking: <code class="xref c c-func docutils literal"><span class="pre">tasklet_disable()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">tasklet_enable()</span></code></li> +</ul> +</div></blockquote> +<p>Tasklets are implemented on top of two dedicated softirqs: +<code class="xref c c-macro docutils literal"><span class="pre">TASKLET_SOFITIRQ</span></code> and <code class="xref c c-macro docutils literal"><span class="pre">HI_SOFTIRQ</span></code></p> +<p>Tasklets are also serialized, i.e. the same tasklet can only execute on one processor.</p> + + + + +</article> +<article class="admonition-workqueues slide level-2"> + +<h2>Workqueues</h2> + +<p>Workqueues are a type of deferred work that runs in process context.</p> +<p>They are implemented on top of kernel threads.</p> +<p>Workqueues API:</p> +<blockquote> +<div><ul class="simple"> +<li>init: <code class="xref c c-macro docutils literal"><span class="pre">INIT_WORK</span></code></li> +<li>activation: <code class="xref c c-func docutils literal"><span class="pre">schedule_work()</span></code></li> +</ul> +</div></blockquote> + + + + +</article> +<article class="admonition-timers slide level-2"> + +<h2>Timers</h2> + +<blockquote> +<div><p>Timers are implemented on top of the <code class="xref c c-macro docutils literal"><span class="pre">TIMER_SOFTIRQ</span></code></p> +<p>Timer API:</p> +<ul class="simple"> +<li>initialization: <code class="xref c c-func docutils literal"><span class="pre">setup_timer()</span></code></li> +<li>activation: <code class="xref c c-func docutils literal"><span class="pre">mod_timer()</span></code></li> +</ul> +</div></blockquote> + + + + +</article> +<article class="admonition-deferrable-actions-summary slide level-2"> + +<h2>Deferrable actions summary</h2> + +<blockquote> +<div><ul class="simple"> +<li>softIRQ<ul> +<li>runs in interrupt context</li> +<li>statically allocated</li> +<li>same handler may run in parallel on multiple cores</li> +</ul> +</li> +<li>tasklet<ul> +<li>runs in interrupt context</li> +<li>can be dynamically allocated</li> +<li>same handler runs are serialized</li> +</ul> +</li> +<li>workqueues<ul> +<li>run in process context</li> +</ul> +</li> +</ul> +</div></blockquote> + + + + +</article> +<article class="admonition-quiz-linux-interrupt-handling slide level-2"> + +<h2>Quiz: Linux interrupt handling</h2> + +<p>Which of the following phases of interrupt handling runs with +interrupts disabled at the CPU level?</p> +<ul class="simple"> +<li>Critical</li> +<li>Immediate</li> +<li>Deferred</li> +</ul> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/interrupts.html b/refs/pull/405/merge/lectures/interrupts.html new file mode 100644 index 00000000..5ce40a8f --- /dev/null +++ b/refs/pull/405/merge/lectures/interrupts.html @@ -0,0 +1,755 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Interrupts — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Symmetric Multi-Processing" href="smp.html" /> + <link rel="prev" title="Processes" href="processes.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="processes.html">Processes</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Interrupts</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lecture-objectives">Lecture objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="#what-is-an-interrupt">What is an interrupt?</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#exceptions">Exceptions</a></li> +<li class="toctree-l3"><a class="reference internal" href="#quiz-interrupt-terminology">Quiz: interrupt terminology</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#hardware-concepts">Hardware Concepts</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#programmable-interrupt-controller">Programmable Interrupt Controller</a></li> +<li class="toctree-l3"><a class="reference internal" href="#interrupt-controllers-in-smp-systems">Interrupt controllers in SMP systems</a></li> +<li class="toctree-l3"><a class="reference internal" href="#interrupt-control">Interrupt Control</a></li> +<li class="toctree-l3"><a class="reference internal" href="#interrupt-priorities">Interrupt priorities</a></li> +<li class="toctree-l3"><a class="reference internal" href="#quiz-hardware-concepts">Quiz: hardware concepts</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#interrupt-handling-on-the-x86-architecture">Interrupt handling on the x86 architecture</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#interrupt-descriptor-table">Interrupt Descriptor Table</a></li> +<li class="toctree-l3"><a class="reference internal" href="#interrupt-handler-address">Interrupt handler address</a></li> +<li class="toctree-l3"><a class="reference internal" href="#stack-of-interrupt-handler">Stack of interrupt handler</a></li> +<li class="toctree-l3"><a class="reference internal" href="#handling-an-interrupt-request">Handling an interrupt request</a></li> +<li class="toctree-l3"><a class="reference internal" href="#returning-from-an-interrupt-handler">Returning from an interrupt handler</a></li> +<li class="toctree-l3"><a class="reference internal" href="#inspecting-the-x86-interrupt-handling">Inspecting the x86 interrupt handling</a></li> +<li class="toctree-l3"><a class="reference internal" href="#quiz-x86-interrupt-handling">Quiz: x86 interrupt handling</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#interrupt-handling-in-linux">Interrupt handling in Linux</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#nested-interrupts-and-exceptions">Nested interrupts and exceptions</a></li> +<li class="toctree-l3"><a class="reference internal" href="#interrupt-context">Interrupt context</a></li> +<li class="toctree-l3"><a class="reference internal" href="#deferrable-actions">Deferrable actions</a></li> +<li class="toctree-l3"><a class="reference internal" href="#soft-irqs">Soft IRQs</a></li> +<li class="toctree-l3"><a class="reference internal" href="#packet-flood-example">Packet flood example</a></li> +<li class="toctree-l3"><a class="reference internal" href="#tasklets">Tasklets</a></li> +<li class="toctree-l3"><a class="reference internal" href="#workqueues">Workqueues</a></li> +<li class="toctree-l3"><a class="reference internal" href="#timers">Timers</a></li> +<li class="toctree-l3"><a class="reference internal" href="#deferrable-actions-summary">Deferrable actions summary</a></li> +<li class="toctree-l3"><a class="reference internal" href="#quiz-linux-interrupt-handling">Quiz: Linux interrupt handling</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Interrupts</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/lectures/interrupts.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="interrupts"> +<h1>Interrupts<a class="headerlink" href="#interrupts" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="interrupts-slides.html">View slides</a></p> +<div class="section" id="lecture-objectives"> +<h2>Lecture objectives<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-interrupts simple"> +<li>Interrupts and exceptions (x86)</li> +<li>Interrupts and exceptions (Linux)</li> +<li>Deferrable work</li> +<li>Timers</li> +</ul> +</div> +<div class="section" id="what-is-an-interrupt"> +<h2>What is an interrupt?<a class="headerlink" href="#what-is-an-interrupt" title="Permalink to this headline">¶</a></h2> +<p>An interrupt is an event that alters the normal execution flow of a +program and can be generated by hardware devices or even by the CPU +itself. When an interrupt occurs the current flow of execution is +suspended and interrupt handler runs. After the interrupt handler runs +the previous execution flow is resumed.</p> +<p>Interrupts can be grouped into two categories based on the source of +the interrupt. They can also be grouped into two other categories based +on the ability to postpone or temporarily disable the interrupt:</p> +<ul class="admonition-interrupts simple"> +<li><strong>synchronous</strong>, generated by executing an instruction</li> +<li><strong>asynchronous</strong>, generated by an external event</li> +<li><strong>maskable</strong><ul> +<li>can be ignored</li> +<li>signaled via INT pin</li> +</ul> +</li> +<li><strong>non-maskable</strong><ul> +<li>cannot be ignored</li> +<li>signaled via NMI pin</li> +</ul> +</li> +</ul> +<p>Synchronous interrupts, usually named exceptions, handle conditions detected by the +processor itself in the course of executing an instruction. Divide by zero or +a system call are examples of exceptions.</p> +<p>Asynchronous interrupts, usually named interrupts, are external events generated +by I/O devices. For example a network card generates an interrupts to signal +that a packet has arrived.</p> +<p>Most interrupts are maskable, which means we can temporarily postpone +running the interrupt handler when we disable the interrupt until the +time the interrupt is re-enabled. However, there are a few critical +interrupts that can not be disabled/postponed.</p> +<div class="section" id="exceptions"> +<h3>Exceptions<a class="headerlink" href="#exceptions" title="Permalink to this headline">¶</a></h3> +<p>There are two sources for exceptions:</p> +<ul class="admonition-exceptions simple"> +<li>processor detected<ul> +<li><strong>faults</strong></li> +<li><strong>traps</strong></li> +<li><strong>aborts</strong></li> +</ul> +</li> +<li>programmed<ul> +<li><strong>int n</strong></li> +</ul> +</li> +</ul> +<p>Processor detected exceptions are raised when an abnormal condition is +detected while executing an instruction.</p> +<p>A fault is a type of exception that is reported before the execution of the +instruction and can be usually corrected. The saved EIP is the address of +the instruction that caused the fault, so after the fault is corrected +the program can re-execute the faulty instruction. (e.g page fault).</p> +<p>A trap is a type of exception that is reported after the execution of the +instruction in which the exception was detected. The saved EIP is the address +of the instruction after the instruction that caused the trap. (e.g debug trap).</p> +</div> +<div class="section" id="quiz-interrupt-terminology"> +<h3>Quiz: interrupt terminology<a class="headerlink" href="#quiz-interrupt-terminology" title="Permalink to this headline">¶</a></h3> +<p class="admonition-quiz-interrupt-terminology">For each of the following terms on the left select all the terms +from right that best describe them.</p> +<table class="hlist"><tr><td><ul class="simple"> +<li>Watchdog</li> +<li>Demand paging</li> +<li>Division by zero</li> +<li>Timer</li> +<li>System call</li> +<li>Breakpoint</li> +</ul> +</td><td><ul class="simple"> +<li>Exception</li> +<li>Interrupt</li> +<li>Maskable</li> +<li>Nonmaskable</li> +<li>Trap</li> +<li>Fault</li> +</ul> +</td></tr></table> +</div> +</div> +<div class="section" id="hardware-concepts"> +<h2>Hardware Concepts<a class="headerlink" href="#hardware-concepts" title="Permalink to this headline">¶</a></h2> +<div class="section" id="programmable-interrupt-controller"> +<h3>Programmable Interrupt Controller<a class="headerlink" href="#programmable-interrupt-controller" title="Permalink to this headline">¶</a></h3> +<p class="admonition-programmable-interrupt-controller"> </p> +<img alt="../_images/ditaa-5db1739b80a83b12505e4ff749b5e69fccd01f1b.png" src="../_images/ditaa-5db1739b80a83b12505e4ff749b5e69fccd01f1b.png" /> +<p>A device supporting interrupts has an output pin used for signaling an Interrupt ReQuest. IRQ +pins are connected to a device named Programmable Interrupt Controller (PIC) which is connected +to CPU's INTR pin.</p> +<p>A PIC usually has a set of ports used to exchange information with the CPU. When a device +connected to one of the PIC's IRQ lines needs CPU attention the following flow happens:</p> +<blockquote> +<div><ul class="simple"> +<li>device raises an interrupt on the corresponding IRQn pin</li> +<li>PIC converts the IRQ into a vector number and writes it to a port for CPU to read</li> +<li>PIC raises an interrupt on CPU INTR pin</li> +<li>PIC waits for CPU to acknowledge an interrupt before raising another interrupt</li> +<li>CPU acknowledges the interrupt then it starts handling the interrupt</li> +</ul> +</div></blockquote> +<p>Will see later how the CPU handles the interrupt. Notice that by +design PIC won't raise another interrupt until the CPU acknowledged +the current interrupt.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Once the interrupt is acknowledged by the CPU the interrupt +controller can request another interrupt, regardless if the CPU +finished handled the previous interrupt or not. Thus, depending on +how the OS controls the CPU it is possible to have nested +interrupts.</p> +</div> +<p>The interrupt controller allows each IRQ line to be individually +disabled. This allows simplifying design by making sure that interrupt +handlers are always executed serially.</p> +</div> +<div class="section" id="interrupt-controllers-in-smp-systems"> +<h3>Interrupt controllers in SMP systems<a class="headerlink" href="#interrupt-controllers-in-smp-systems" title="Permalink to this headline">¶</a></h3> +<p>In SMP systems we may have multiple interrupt controllers in the +systems.</p> +<p>For example, on the x86 architecture each core has a local APIC used +to process interrupts from locally connected devices like timers or +thermals sensors. Then there is an I/O APIC is used to distribute IRQ +from external devices to CPU cores.</p> +<p class="admonition-interrupt-controllers-in-smp-systems"> </p> +<img alt="../_images/ditaa-9d23d02ebdff6eeb6bec8044480f055de9852ecc.png" src="../_images/ditaa-9d23d02ebdff6eeb6bec8044480f055de9852ecc.png" /> +</div> +<div class="section" id="interrupt-control"> +<h3>Interrupt Control<a class="headerlink" href="#interrupt-control" title="Permalink to this headline">¶</a></h3> +<p>In order to synchronize access to shared data between the interrupt handler +and other potential concurrent activities such as driver initialization or +driver data processing, it is often required to enable and disable interrupts in +a controlled fashion.</p> +<p>This can be accomplished at several levels:</p> +<ul class="admonition-enabling-disabling-the-interrupts simple"> +<li>at the device level<ul> +<li>by programming the device control registers</li> +</ul> +</li> +<li>at the PIC level<ul> +<li>PIC can be programmed to disable a given IRQ line</li> +</ul> +</li> +<li>at the CPU level; for example, on x86 one can use the following +instructions:</li> +</ul> +<blockquote> +<div><ul class="simple"> +<li>cli (CLear Interrupt flag)</li> +<li>sti (SeT Interrupt flag)</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="interrupt-priorities"> +<h3>Interrupt priorities<a class="headerlink" href="#interrupt-priorities" title="Permalink to this headline">¶</a></h3> +<p>Most architectures also support interrupt priorities. When this is +enabled, it permits interrupt nesting only for those interrupts that +have a higher priority than the current priority level.</p> +<p class="admonition-interrupt-priorities"> </p> +<img alt="../_images/ditaa-8b00a68b494f72d54b5fad38c88f7265aadaaa0e.png" src="../_images/ditaa-8b00a68b494f72d54b5fad38c88f7265aadaaa0e.png" /> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Not all architectures support interrupt priorities. It is also +difficult to support defining a generic scheme for interrupt +priorities for general use OSes and some kernels (Linux included) +do not use interrupt priorities. On the other hand most RTOS use +interrupt priorities since they are typically used in more +constraint use-cases where it is easier to define interrupt +priorities.</p> +</div> +</div> +<div class="section" id="quiz-hardware-concepts"> +<h3>Quiz: hardware concepts<a class="headerlink" href="#quiz-hardware-concepts" title="Permalink to this headline">¶</a></h3> +<p class="admonition-quiz-hardware-concepts">Which of the following statements are true?</p> +<ul class="simple"> +<li>The CPU can start processing a new interrupt before the current +one is finished</li> +<li>Interrupts can be disabled at the device level</li> +<li>Lower priority interrupts can not preempt handlers for higher +priority interrupts</li> +<li>Interrupts can be disabled at the interrupt controller level</li> +<li>On SMP systems the same interrupt can be routed to different CPUs</li> +<li>Interrupts can be disabled at the CPU level</li> +</ul> +</div> +</div> +<div class="section" id="interrupt-handling-on-the-x86-architecture"> +<h2>Interrupt handling on the x86 architecture<a class="headerlink" href="#interrupt-handling-on-the-x86-architecture" title="Permalink to this headline">¶</a></h2> +<p>This section will examine how interrupts are handled by the CPU on the +x86 architecture.</p> +<div class="section" id="interrupt-descriptor-table"> +<h3>Interrupt Descriptor Table<a class="headerlink" href="#interrupt-descriptor-table" title="Permalink to this headline">¶</a></h3> +<p>The interrupt descriptor table (IDT) associates each interrupt or exception +identifier with a descriptor for the instructions that service the associated +event. We will name the identifier as vector number and the associated +instructions as interrupt/exception handler.</p> +<p>An IDT has the following characteristics:</p> +<ul class="admonition-interrupt-descriptor-table simple"> +<li>it is used as a jump table by the CPU when a given vector is triggered</li> +<li>it is an array of 256 x 8 bytes entries</li> +<li>may reside anywhere in physical memory</li> +<li>processor locates IDT by the means of IDTR</li> +</ul> +<p>Below we can find Linux IRQ vector layout. The first 32 entries are reserved +for exceptions, vector 128 is used for syscall interface and the rest are +used mostly for hardware interrupts handlers.</p> +<p class="admonition-linux-irq-vector-layout"> </p> +<img alt="../_images/ditaa-5b3c93f6e612d0cc0e4d4837d92a443627405262.png" src="../_images/ditaa-5b3c93f6e612d0cc0e4d4837d92a443627405262.png" /> +<p>On x86 an IDT entry has 8 bytes and it is named gate. There can be 3 types of gates:</p> +<blockquote> +<div><ul class="simple"> +<li>interrupt gate, holds the address of an interrupt or exception handler. +Jumping to the handler disables maskable interrupts (IF flag is cleared).</li> +<li>trap gates, similar to an interrupt gate but it does not disable maskable +interrupts while jumping to interrupt/exception handler.</li> +<li>task gates (not used in Linux)</li> +</ul> +</div></blockquote> +<p>Let's have a look at several fields of an IDT entry:</p> +<blockquote> +<div><ul class="simple"> +<li>segment selector, index into GDT/LDT to find the start of the code segment where +the interrupt handlers reside</li> +<li>offset, offset inside the code segment</li> +<li>T, represents the type of gate</li> +<li>DPL, minimum privilege required for using the segments content.</li> +</ul> +</div></blockquote> +<p class="admonition-interrupt-descriptor-table-entry-gate"> </p> +<img alt="../_images/ditaa-eff5e0e3b58ce239d5310b22b89c0927be5853bd.png" src="../_images/ditaa-eff5e0e3b58ce239d5310b22b89c0927be5853bd.png" /> +</div> +<div class="section" id="interrupt-handler-address"> +<h3>Interrupt handler address<a class="headerlink" href="#interrupt-handler-address" title="Permalink to this headline">¶</a></h3> +<p>In order to find the interrupt handler address we first need to find the start +address of the code segment where interrupt handler resides. For this we +use the segment selector to index into GDT/LDT where we can find the corresponding +segment descriptor. This will provide the start address kept in the 'base' field. +Using base address and the offset we can now go to the start of the interrupt handler.</p> +<p class="admonition-interrupt-handler-address"> </p> +<img alt="../_images/ditaa-b2023fce22479e20bbe08fd76eed87e9a0527688.png" src="../_images/ditaa-b2023fce22479e20bbe08fd76eed87e9a0527688.png" /> +</div> +<div class="section" id="stack-of-interrupt-handler"> +<h3>Stack of interrupt handler<a class="headerlink" href="#stack-of-interrupt-handler" title="Permalink to this headline">¶</a></h3> +<p>Similar to control transfer to a normal function, a control transfer +to an interrupt or exception handler uses the stack to store the +information needed for returning to the interrupted code.</p> +<p>As can be seen in the figure below, an interrupt pushes the EFLAGS register +before saving the address of the interrupted instruction. Certain types +of exceptions also cause an error code to be pushed on the stack to help +debug the exception.</p> +<p class="admonition-interrupt-handler-stack"> </p> +<img alt="../_images/ditaa-85b69602726fa6143fc3ba0ffdb492454864aacf.png" src="../_images/ditaa-85b69602726fa6143fc3ba0ffdb492454864aacf.png" /> +</div> +<div class="section" id="handling-an-interrupt-request"> +<h3>Handling an interrupt request<a class="headerlink" href="#handling-an-interrupt-request" title="Permalink to this headline">¶</a></h3> +<p>After an interrupt request has been generated the processor runs a sequence of +events that eventually end up with running the kernel interrupt handler:</p> +<ul class="admonition-handling-an-interrupt-request"> +<li><p class="first">CPU checks the current privilege level</p> +</li> +<li><p class="first">if need to change privilege level</p> +<blockquote> +<div><ul class="simple"> +<li>change stack with the one associated with new privilege</li> +<li>save old stack information on the new stack</li> +</ul> +</div></blockquote> +</li> +<li><p class="first">save EFLAGS, CS, EIP on stack</p> +</li> +<li><p class="first">save error code on stack in case of an abort</p> +</li> +<li><p class="first">execute the kernel interrupt handler</p> +</li> +</ul> +</div> +<div class="section" id="returning-from-an-interrupt-handler"> +<h3>Returning from an interrupt handler<a class="headerlink" href="#returning-from-an-interrupt-handler" title="Permalink to this headline">¶</a></h3> +<p>Most architectures offer special instructions to clean up the stack and resume +the execution after the interrupt handler has been executed. On x86 IRET is used +to return from an interrupt handler. IRET is similar to RET except that IRET +increments ESP by extra four bytes (because of the flags on stack) and moves the +saved flags into EFLAGS register.</p> +<p>To resume the execution after an interrupt the following sequence is used (x86):</p> +<ul class="admonition-returning-from-an-interrupt simple"> +<li>pop the error code (in case of an abort)</li> +<li>call IRET<ul> +<li>pops values from the stack and restore the following register: CS, EIP, EFLAGS</li> +<li>if privilege level changed returns to the old stack and old privilege level</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="inspecting-the-x86-interrupt-handling"> +<h3>Inspecting the x86 interrupt handling<a class="headerlink" href="#inspecting-the-x86-interrupt-handling" title="Permalink to this headline">¶</a></h3> +<p class="admonition-inspecting-the-x86-interrupt-handling"> </p> +<asciinema-player src="../_images/intr_x86.cast"></asciinema-player></div> +<div class="section" id="quiz-x86-interrupt-handling"> +<h3>Quiz: x86 interrupt handling<a class="headerlink" href="#quiz-x86-interrupt-handling" title="Permalink to this headline">¶</a></h3> +<p class="admonition-quiz-x86-interrupt-handling">The following gdb commands are used to determine the handler for +the int80 based system call exception. Select and arrange the +commands or output of the commands in the correct order.</p> +<div class="highlight-gdb"><div class="highlight"><pre><span></span>(void *) 0xc15de780 <entry_SYSENTER_32> + +set $idtr_addr=($idtr_entry>>48<<16)|($idtr_entry&0xffff) + +print (void*)$idtr_addr + +set $idtr = 0xff800000 + +(void *) 0xc15de874 <entry_INT80_32> + +set $idtr = 0xff801000 + +set $idtr_entry = *(uint64_t*)($idtr + 8 * 128) + +monitor info registers +</pre></div> +</div> +</div> +</div> +<div class="section" id="interrupt-handling-in-linux"> +<h2>Interrupt handling in Linux<a class="headerlink" href="#interrupt-handling-in-linux" title="Permalink to this headline">¶</a></h2> +<p>In Linux the interrupt handling is done in three phases: critical, immediate and +deferred.</p> +<p>In the first phase the kernel will run the generic interrupt handler that +determines the interrupt number, the interrupt handler for this particular +interrupt and the interrupt controller. At this point any timing critical +actions will also be performed (e.g. acknowledge the interrupt at the interrupt +controller level). Local processor interrupts are disabled for the duration of +this phase and continue to be disabled in the next phase.</p> +<p>In the second phase, all of the device driver's handlers associated with this +interrupt will be executed. At the end of this phase, the interrupt controller's +"end of interrupt" method is called to allow the interrupt controller to +reassert this interrupt. The local processor interrupts are enabled at this +point.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">It is possible that one interrupt is associated with multiple +devices and in this case it is said that the interrupt is +shared. Usually, when using shared interrupts it is the +responsibility of the device driver to determine if the interrupt +is target to its device or not.</p> +</div> +<p>Finally, in the last phase of interrupt handling interrupt context deferrable +actions will be run. These are also sometimes known as "bottom half" of the +interrupt (the upper half being the part of the interrupt handling that runs +with interrupts disabled). At this point, interrupts are enabled on the local +processor.</p> +<p class="admonition-interrupt-handling-in-linux"> </p> +<img alt="../_images/ditaa-da31e3d17a4d55e5c3dbc0bd5903306418a896ca.png" src="../_images/ditaa-da31e3d17a4d55e5c3dbc0bd5903306418a896ca.png" /> +<div class="section" id="nested-interrupts-and-exceptions"> +<h3>Nested interrupts and exceptions<a class="headerlink" href="#nested-interrupts-and-exceptions" title="Permalink to this headline">¶</a></h3> +<p>Linux used to support nested interrupts but this was removed some time +ago in order to avoid increasingly complex solutions to stack +overflows issues - allow just one level of nesting, allow multiple +levels of nesting up to a certain kernel stack depth, etc.</p> +<p>However, it is still possible to have nesting between exceptions and +interrupts but the rules are fairly restrictive:</p> +<ul class="admonition-irq-and-exception-nesting-in-linux simple"> +<li>an exception (e.g. page fault, system call) can not preempt an interrupt; +if that occurs it is considered a bug</li> +<li>an interrupt can preempt an exception</li> +<li>an interrupt can not preempt another interrupt (it used to be possible)</li> +</ul> +<p>The diagram below shows the possible nesting scenarios:</p> +<p class="admonition-interrupt-exception-nesting"> </p> +<img alt="../_images/ditaa-2e49ca6ac606dab4b2b53231cfbe85ff06312d36.png" src="../_images/ditaa-2e49ca6ac606dab4b2b53231cfbe85ff06312d36.png" /> +</div> +<div class="section" id="interrupt-context"> +<h3>Interrupt context<a class="headerlink" href="#interrupt-context" title="Permalink to this headline">¶</a></h3> +<p>While an interrupt is handled (from the time the CPU jumps to the interrupt +handler until the interrupt handler returns - e.g. IRET is issued) it is said +that code runs in "interrupt context".</p> +<p>Code that runs in interrupt context has the following properties:</p> +<blockquote class="admonition-interrupt-context"> +<div><ul class="simple"> +<li>it runs as a result of an IRQ (not of an exception)</li> +<li>there is no well defined process context associated</li> +<li>not allowed to trigger a context switch (no sleep, schedule, or user memory access)</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="deferrable-actions"> +<h3>Deferrable actions<a class="headerlink" href="#deferrable-actions" title="Permalink to this headline">¶</a></h3> +<p>Deferrable actions are used to run callback functions at a later time. If +deferrable actions scheduled from an interrupt handler, the associated callback +function will run after the interrupt handler has completed.</p> +<p>There are two large categories of deferrable actions: those that run in +interrupt context and those that run in process context.</p> +<p>The purpose of interrupt context deferrable actions is to avoid doing too much +work in the interrupt handler function. Running for too long with interrupts +disabled can have undesired effects such as increased latency or poor system +performance due to missing other interrupts (e.g. dropping network packets +because the CPU did not react in time to dequeue packets from the network +interface and the network card buffer is full).</p> +<p>Deferrable actions have APIs to: <strong>initialize</strong> an instance, <strong>activate</strong> or +<strong>schedule</strong> the action and <strong>mask/disable</strong> and <strong>unmask/enable</strong> the execution +of the callback function. The latter is used for synchronization purposes between +the callback function and other contexts.</p> +<p>Typically the device driver will initialize the deferrable action +structure during the device instance initialization and will activate +/ schedule the deferrable action from the interrupt handler.</p> +<span class="admonition-deferrable-actions"></span></div> +<div class="section" id="soft-irqs"> +<h3>Soft IRQs<a class="headerlink" href="#soft-irqs" title="Permalink to this headline">¶</a></h3> +<p>Soft IRQs is the term used for the low-level mechanism that implements deferring +work from interrupt handlers but that still runs in interrupt context.</p> +<blockquote class="admonition-soft-irqs"> +<div><p>Soft IRQ APIs:</p> +<blockquote> +<div><ul class="simple"> +<li>initialize: <code class="xref c c-func docutils literal"><span class="pre">open_softirq()</span></code></li> +<li>activation: <code class="xref c c-func docutils literal"><span class="pre">raise_softirq()</span></code></li> +<li>masking: <code class="xref c c-func docutils literal"><span class="pre">local_bh_disable()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">local_bh_enable()</span></code></li> +</ul> +</div></blockquote> +<p>Once activated, the callback function <code class="xref c c-func docutils literal"><span class="pre">do_softirq()</span></code> runs either:</p> +<blockquote> +<div><ul class="simple"> +<li>after an interrupt handler or</li> +<li>from the ksoftirqd kernel thread</li> +</ul> +</div></blockquote> +</div></blockquote> +<p>Since softirqs can reschedule themselves or other interrupts can occur that +reschedules them, they can potentially lead to (temporary) process starvation if +checks are not put into place. Currently, the Linux kernel does not allow +running soft irqs for more than <code class="xref c c-macro docutils literal"><span class="pre">MAX_SOFTIRQ_TIME</span></code> or rescheduling for +more than <code class="xref c c-macro docutils literal"><span class="pre">MAX_SOFTIRQ_RESTART</span></code> consecutive times.</p> +<p>Once these limits are reached a special kernel thread, <strong>ksoftirqd</strong> is woken up +and all of the rest of pending soft irqs will be run from the context of this +kernel thread.</p> +<span class="admonition-ksoftirqd"></span><p>Soft irqs usage is restricted, they are use by a handful of subsystems that have +low latency requirements and high frequency:</p> +<div class="admonition-types-of-soft-irqs highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* PLEASE, avoid to allocate new softirqs, if you need not _really_ high</span> +<span class="cm"> frequency threaded job scheduling. For almost all the purposes</span> +<span class="cm"> tasklets are more than enough. F.e. all serial device BHs et</span> +<span class="cm"> al. should be converted to tasklets, not to softirqs.</span> +<span class="cm">*/</span> + +<span class="k">enum</span> +<span class="p">{</span> + <span class="n">HI_SOFTIRQ</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> + <span class="n">TIMER_SOFTIRQ</span><span class="p">,</span> + <span class="n">NET_TX_SOFTIRQ</span><span class="p">,</span> + <span class="n">NET_RX_SOFTIRQ</span><span class="p">,</span> + <span class="n">BLOCK_SOFTIRQ</span><span class="p">,</span> + <span class="n">IRQ_POLL_SOFTIRQ</span><span class="p">,</span> + <span class="n">TASKLET_SOFTIRQ</span><span class="p">,</span> + <span class="n">SCHED_SOFTIRQ</span><span class="p">,</span> + <span class="n">HRTIMER_SOFTIRQ</span><span class="p">,</span> + <span class="n">RCU_SOFTIRQ</span><span class="p">,</span> <span class="cm">/* Preferable RCU should always be the last softirq */</span> + + <span class="n">NR_SOFTIRQS</span> +<span class="p">};</span> +</pre></div> +</div> +</div> +<div class="section" id="packet-flood-example"> +<h3>Packet flood example<a class="headerlink" href="#packet-flood-example" title="Permalink to this headline">¶</a></h3> +<p>The following screencast will look at what happens when we flood the +system with a large number of packets. Since at least a part of the +packet processing is happening in softirq we should expect the CPU to +spend most of the time running softirqs but the majority of that +should be in the context of the <cite>ksoftirqd</cite> thread.</p> +<p class="admonition-packet-flood-example"> </p> +<asciinema-player src="../_images/ksoftirqd-packet-flood.cast"></asciinema-player></div> +<div class="section" id="tasklets"> +<h3>Tasklets<a class="headerlink" href="#tasklets" title="Permalink to this headline">¶</a></h3> +<p class="admonition-tasklets">Tasklets are a dynamic type (not limited to a fixed number) of +deferred work running in interrupt context.</p> +<p>Tasklets API:</p> +<blockquote> +<div><ul class="simple"> +<li>initialization: <code class="xref c c-func docutils literal"><span class="pre">tasklet_init()</span></code></li> +<li>activation: <code class="xref c c-func docutils literal"><span class="pre">tasklet_schedule()</span></code></li> +<li>masking: <code class="xref c c-func docutils literal"><span class="pre">tasklet_disable()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">tasklet_enable()</span></code></li> +</ul> +</div></blockquote> +<p>Tasklets are implemented on top of two dedicated softirqs: +<code class="xref c c-macro docutils literal"><span class="pre">TASKLET_SOFITIRQ</span></code> and <code class="xref c c-macro docutils literal"><span class="pre">HI_SOFTIRQ</span></code></p> +<p>Tasklets are also serialized, i.e. the same tasklet can only execute on one processor.</p> +</div> +<div class="section" id="workqueues"> +<h3>Workqueues<a class="headerlink" href="#workqueues" title="Permalink to this headline">¶</a></h3> +<blockquote> +<div><p class="admonition-workqueues">Workqueues are a type of deferred work that runs in process context.</p> +<p>They are implemented on top of kernel threads.</p> +<p>Workqueues API:</p> +<blockquote> +<div><ul class="simple"> +<li>init: <code class="xref c c-macro docutils literal"><span class="pre">INIT_WORK</span></code></li> +<li>activation: <code class="xref c c-func docutils literal"><span class="pre">schedule_work()</span></code></li> +</ul> +</div></blockquote> +</div></blockquote> +</div> +<div class="section" id="timers"> +<h3>Timers<a class="headerlink" href="#timers" title="Permalink to this headline">¶</a></h3> +<blockquote class="admonition-timers"> +<div><p>Timers are implemented on top of the <code class="xref c c-macro docutils literal"><span class="pre">TIMER_SOFTIRQ</span></code></p> +<p>Timer API:</p> +<ul class="simple"> +<li>initialization: <code class="xref c c-func docutils literal"><span class="pre">setup_timer()</span></code></li> +<li>activation: <code class="xref c c-func docutils literal"><span class="pre">mod_timer()</span></code></li> +</ul> +</div></blockquote> +</div> +<div class="section" id="deferrable-actions-summary"> +<h3>Deferrable actions summary<a class="headerlink" href="#deferrable-actions-summary" title="Permalink to this headline">¶</a></h3> +<p>Here is a cheat sheet which summarizes Linux deferrable actions:</p> +<blockquote class="admonition-deferrable-actions-summary"> +<div><ul class="simple"> +<li>softIRQ<ul> +<li>runs in interrupt context</li> +<li>statically allocated</li> +<li>same handler may run in parallel on multiple cores</li> +</ul> +</li> +<li>tasklet<ul> +<li>runs in interrupt context</li> +<li>can be dynamically allocated</li> +<li>same handler runs are serialized</li> +</ul> +</li> +<li>workqueues<ul> +<li>run in process context</li> +</ul> +</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="quiz-linux-interrupt-handling"> +<h3>Quiz: Linux interrupt handling<a class="headerlink" href="#quiz-linux-interrupt-handling" title="Permalink to this headline">¶</a></h3> +<p class="admonition-quiz-linux-interrupt-handling">Which of the following phases of interrupt handling runs with +interrupts disabled at the CPU level?</p> +<ul class="simple"> +<li>Critical</li> +<li>Immediate</li> +<li>Deferred</li> +</ul> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="processes.html" class="btn btn-neutral float-left" title="Processes" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="smp.html" class="btn btn-neutral float-right" title="Symmetric Multi-Processing" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/intro-slides.html b/refs/pull/405/merge/lectures/intro-slides.html new file mode 100644 index 00000000..5589ceb6 --- /dev/null +++ b/refs/pull/405/merge/lectures/intro-slides.html @@ -0,0 +1,503 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Introduction — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="next" title="System Calls" href="syscalls.html" /> + <link rel="prev" title="Assignment 7 - SO2 Virtual Machine Manager with KVM" href="../so2/assign7-kvm-vmm.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-introduction slide level-2"> + +<h2>Introduction</h2> + +<ul class="simple"> +<li>Basic operating systems terms and concepts</li> +<li>Overview of the Linux kernel</li> +</ul> + + + + +</article> +<article class="admonition-user-vs-kernel slide level-2"> + +<h2>User vs Kernel</h2> + +<ul class="simple"> +<li>Execution modes<ul> +<li>Kernel mode</li> +<li>User mode</li> +</ul> +</li> +<li>Memory protection<ul> +<li>Kernel-space</li> +<li>User-space</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-typical-operating-system-architecture slide level-2"> + +<h2>Typical operating system architecture</h2> + +<img alt="../_images/ditaa-48374873962ca32ada36c14ab9a83b60f112a1e0.png" src="../_images/ditaa-48374873962ca32ada36c14ab9a83b60f112a1e0.png" /> + + + + +</article> +<article class="admonition-monolithic-kernel slide level-2"> + +<h2>Monolithic kernel</h2> + +<img alt="../_images/ditaa-3dc899167df5e16a230c434cf5d6964cb5868482.png" src="../_images/ditaa-3dc899167df5e16a230c434cf5d6964cb5868482.png" /> + + + + +</article> +<article class="admonition-micro-kernel slide level-2"> + +<h2>Micro-kernel</h2> + +<img alt="../_images/ditaa-c8a3d93d0109b7be6f608871d16adff4aaa933da.png" src="../_images/ditaa-c8a3d93d0109b7be6f608871d16adff4aaa933da.png" /> + + + + +</article> +<article class="admonition-monolithic-kernels-can-be-modular slide level-2"> + +<h2>Monolithic kernels <em>can</em> be modular</h2> + +<ul class="simple"> +<li>Components can enabled or disabled at compile time</li> +<li>Support of loadable kernel modules (at runtime)</li> +<li>Organize the kernel in logical, independent subsystems</li> +<li>Strict interfaces but with low performance overhead: macros, +inline functions, function pointers</li> +</ul> + + + + +</article> +<article class="admonition-hybrid-kernels slide level-2"> + +<h2>"Hybrid" kernels</h2> + +<p>Many operating systems and kernel experts have dismissed the label +as meaningless, and just marketing. Linus Torvalds said of this +issue:</p> +<p>"As to the whole 'hybrid kernel' thing - it's just marketing. It's +'oh, those microkernels had good PR, how can we try to get good PR +for our working kernel? Oh, I know, let's use a cool name and try +to imply that it has all the PR advantages that that other system +has'."</p> + + + + +</article> +<article class="admonition-address-space slide level-2"> + +<h2>Address space</h2> + +<ul class="simple"> +<li>Physical address space<ul> +<li>RAM and peripheral memory</li> +</ul> +</li> +<li>Virtual address space<ul> +<li>How the CPU sees the memory (when in protected / paging mode)</li> +<li>Process address space</li> +<li>Kernel address space</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-user-and-kernel-sharing-the-virtual-address-space slide level-2"> + +<h2>User and kernel sharing the virtual address space</h2> + +<img alt="../_images/ditaa-a5f93e0d17ccdc2ba24828b620d7227f7fc75e33.png" src="../_images/ditaa-a5f93e0d17ccdc2ba24828b620d7227f7fc75e33.png" /> + + + + +</article> +<article class="admonition-execution-contexts slide level-2"> + +<h2>Execution contexts</h2> + +<ul class="simple"> +<li>Process context<ul> +<li>Code that runs in user mode, part of a process</li> +<li>Code that runs in kernel mode, as a result of a system call +issued by a process</li> +</ul> +</li> +<li>Interrupt context<ul> +<li>Code that runs as a result of an interrupt</li> +<li>Always runs in kernel mode</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-multi-tasking slide level-2"> + +<h2>Multi-tasking</h2> + +<ul class="simple"> +<li>An OS that supports the "simultaneous" execution of multiple processes</li> +<li>Implemented by fast switching between running processes to allow +the user to interact with each program</li> +<li>Implementation:<ul> +<li>Cooperative</li> +<li>Preemptive</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-preemptive-kernel slide level-2"> + +<h2>Preemptive kernel</h2> + +<p>Preemptive multitasking and preemptive kernels are different terms.</p> +<p>A kernel is preemptive if a process can be preempted while running +in kernel mode.</p> +<p>However, note that non-preemptive kernels may support preemptive +multitasking.</p> + + + + +</article> +<article class="admonition-pageable-kernel-memory slide level-2"> + +<h2>Pageable kernel memory</h2> + +<p>A kernel supports pageable kernel memory if parts of kernel memory +(code, data, stack or dynamically allocated memory) can be swapped +to disk.</p> + + + + +</article> +<article class="admonition-kernel-stack slide level-2"> + +<h2>Kernel stack</h2> + +<p>Each process has a kernel stack that is used to maintain the +function call chain and local variables state while it is executing +in kernel mode, as a result of a system call.</p> +<p>The kernel stack is small (4KB - 12 KB) so the kernel developer has +to avoid allocating large structures on stack or recursive calls +that are not properly bounded.</p> + + + + +</article> +<article class="admonition-portability slide level-2"> + +<h2>Portability</h2> + +<ul class="simple"> +<li>Architecture and machine specific code (C & ASM)</li> +<li>Independent architecture code (C):<ul> +<li>kernel core (further split in multiple subsystems)</li> +<li>device drivers</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-asymmetric-multiprocessing-asmp slide level-2"> + +<h2>Asymmetric MultiProcessing (ASMP)</h2> + +<img alt="../_images/ditaa-cb16db58a2489307b74d4f70256a48c81c65f6c6.png" src="../_images/ditaa-cb16db58a2489307b74d4f70256a48c81c65f6c6.png" /> + + + + +</article> +<article class="admonition-symmetric-multiprocessing-smp slide level-2"> + +<h2>Symmetric MultiProcessing (SMP)</h2> + +<img alt="../_images/ditaa-08aff771b3ff7a5525df7b0c090e28c836502788.png" src="../_images/ditaa-08aff771b3ff7a5525df7b0c090e28c836502788.png" /> + + + + +</article> +<article class="admonition-cpu-scalability slide level-2"> + +<h2>CPU Scalability</h2> + +<ul class="simple"> +<li>Use lock free algorithms when possible</li> +<li>Use fine grained locking for high contention areas</li> +<li>Pay attention to algorithm complexity</li> +</ul> + + + + +</article> +<article class="admonition-linux-development-model slide level-2"> + +<h2>Linux development model</h2> + +<ul class="simple"> +<li>Open source, GPLv2 License</li> +<li>Contributors: companies, academia and independent developers</li> +<li>Development cycle: 3 – 4 months which consists of a 1 - 2 week +merge window followed by bug fixing</li> +<li>Features are only allowed in the merge window</li> +<li>After the merge window a release candidate is done on a weekly +basis (rc1, rc2, etc.)</li> +</ul> + + + + +</article> +<article class="admonition-maintainer-hierarchy slide level-2"> + +<h2>Maintainer hierarchy</h2> + +<ul class="simple"> +<li>Linus Torvalds is the maintainer of the Linux kernel and merges pull +requests from subsystem maintainers</li> +<li>Each subsystem has one or more maintainers that accept patches or +pull requests from developers or device driver maintainers</li> +<li>Each maintainer has its own git tree, e.g.:<ul> +<li>Linux Torvalds: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git</li> +<li>David Miller (networking): git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git/</li> +</ul> +</li> +<li>Each subsystem may maintain a -next tree where developers can submit +patches for the next merge window</li> +</ul> + + + + +</article> +<article class="admonition-linux-source-code-layout slide level-2"> + +<h2>Linux source code layout</h2> + +<img alt="../_images/ditaa-f45246aade5ecc7cfb71f7f103a57f95fc7c2b9e.png" src="../_images/ditaa-f45246aade5ecc7cfb71f7f103a57f95fc7c2b9e.png" /> + + + + +</article> +<article class="admonition-linux-kernel-architecture slide level-2"> + +<h2>Linux kernel architecture</h2> + +<a class="reference internal image-reference" href="../_images/ditaa-b9ffae65be16d30be11b5eca188a7a143b1b8227.png"><img alt="../_images/ditaa-b9ffae65be16d30be11b5eca188a7a143b1b8227.png" src="../_images/ditaa-b9ffae65be16d30be11b5eca188a7a143b1b8227.png" style="height: 100%;" /></a> + + + + +</article> +<article class="admonition-arch slide level-2"> + +<h2>arch</h2> + +<ul class="simple"> +<li>Architecture specific code</li> +<li>May be further sub-divided in machine specific code</li> +<li>Interfacing with the boot loader and architecture specific +initialization</li> +<li>Access to various hardware bits that are architecture or machine +specific such as interrupt controller, SMP controllers, BUS +controllers, exceptions and interrupt setup, virtual memory handling</li> +<li>Architecture optimized functions (e.g. memcpy, string operations, +etc.)</li> +</ul> + + + + +</article> +<article class="admonition-device-drivers slide level-2"> + +<h2>Device drivers</h2> + +<ul class="simple"> +<li>Unified device model</li> +<li>Each subsystem has its own specific driver interfaces</li> +<li>Many device driver types (TTY, serial, SCSI, fileystem, ethernet, +USB, framebuffer, input, sound, etc.)</li> +</ul> + + + + +</article> +<article class="admonition-process-management slide level-2"> + +<h2>Process management</h2> + +<ul class="simple"> +<li>Unix basic process management and POSIX threads support</li> +<li>Processes and threads are abstracted as tasks</li> +<li>Operating system level virtualization<ul> +<li>Namespaces</li> +<li>Control groups</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-memory-management slide level-2"> + +<h2>Memory management</h2> + +<ul class="simple"> +<li>Management of the physical memory: allocating and freeing memory</li> +<li>Management of the virtual memory: paging, swapping, demand +paging, copy on write</li> +<li>User services: user address space management (e.g. mmap(), brk(), +shared memory)</li> +<li>Kernel services: SL*B allocators, vmalloc</li> +</ul> + + + + +</article> +<article class="admonition-block-i-o-management slide level-2"> + +<h2>Block I/O management</h2> + +<a class="reference internal image-reference" href="../_images/ditaa-0a96997f269a7a9cd0cdc9c9125f6e62e549be94.png"><img alt="../_images/ditaa-0a96997f269a7a9cd0cdc9c9125f6e62e549be94.png" src="../_images/ditaa-0a96997f269a7a9cd0cdc9c9125f6e62e549be94.png" style="height: 100%;" /></a> + + + + +</article> +<article class="admonition-virtual-filesystem-switch slide level-2"> + +<h2>Virtual Filesystem Switch</h2> + +<a class="reference internal image-reference" href="../_images/ditaa-afa57a07e21b1b842554278abe30fea575278452.png"><img alt="../_images/ditaa-afa57a07e21b1b842554278abe30fea575278452.png" src="../_images/ditaa-afa57a07e21b1b842554278abe30fea575278452.png" style="height: 100%;" /></a> + + + + +</article> +<article class="admonition-networking-stack slide level-2"> + +<h2>Networking stack</h2> + +<a class="reference internal image-reference" href="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png"><img alt="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png" src="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png" style="height: 100%;" /></a> + + + + +</article> +<article class="admonition-linux-security-modules slide level-2"> + +<h2>Linux Security Modules</h2> + +<ul class="simple"> +<li>Hooks to extend the default Linux security model</li> +<li>Used by several Linux security extensions:<ul> +<li>Security Enhancened Linux</li> +<li>AppArmor</li> +<li>Tomoyo</li> +<li>Smack</li> +</ul> +</li> +</ul> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/intro.html b/refs/pull/405/merge/lectures/intro.html new file mode 100644 index 00000000..3661f8c2 --- /dev/null +++ b/refs/pull/405/merge/lectures/intro.html @@ -0,0 +1,710 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Introduction — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="System Calls" href="syscalls.html" /> + <link rel="prev" title="Assignment 7 - SO2 Virtual Machine Manager with KVM" href="../so2/assign7-kvm-vmm.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul class="current"> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Introduction</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="#basic-operating-systems-terms-and-concepts">Basic operating systems terms and concepts</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#user-vs-kernel">User vs Kernel</a></li> +<li class="toctree-l3"><a class="reference internal" href="#typical-operating-system-architecture">Typical operating system architecture</a></li> +<li class="toctree-l3"><a class="reference internal" href="#monolithic-kernel">Monolithic kernel</a></li> +<li class="toctree-l3"><a class="reference internal" href="#micro-kernel">Micro kernel</a></li> +<li class="toctree-l3"><a class="reference internal" href="#micro-kernels-vs-monolithic-kernels">Micro-kernels vs monolithic kernels</a></li> +<li class="toctree-l3"><a class="reference internal" href="#address-space">Address space</a></li> +<li class="toctree-l3"><a class="reference internal" href="#user-and-kernel-sharing-the-virtual-address-space">User and kernel sharing the virtual address space</a></li> +<li class="toctree-l3"><a class="reference internal" href="#execution-contexts">Execution contexts</a></li> +<li class="toctree-l3"><a class="reference internal" href="#multi-tasking">Multi-tasking</a></li> +<li class="toctree-l3"><a class="reference internal" href="#preemptive-kernel">Preemptive kernel</a></li> +<li class="toctree-l3"><a class="reference internal" href="#pageable-kernel-memory">Pageable kernel memory</a></li> +<li class="toctree-l3"><a class="reference internal" href="#kernel-stack">Kernel stack</a></li> +<li class="toctree-l3"><a class="reference internal" href="#portability">Portability</a></li> +<li class="toctree-l3"><a class="reference internal" href="#asymmetric-multiprocessing-asmp">Asymmetric MultiProcessing (ASMP)</a></li> +<li class="toctree-l3"><a class="reference internal" href="#symmetric-multiprocessing-smp">Symmetric MultiProcessing (SMP)</a></li> +<li class="toctree-l3"><a class="reference internal" href="#cpu-scalability">CPU Scalability</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#overview-of-the-linux-kernel">Overview of the Linux kernel</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#linux-development-model">Linux development model</a></li> +<li class="toctree-l3"><a class="reference internal" href="#maintainer-hierarchy">Maintainer hierarchy</a></li> +<li class="toctree-l3"><a class="reference internal" href="#linux-source-code-layout">Linux source code layout</a></li> +<li class="toctree-l3"><a class="reference internal" href="#linux-kernel-architecture">Linux kernel architecture</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#arch">arch</a></li> +<li class="toctree-l4"><a class="reference internal" href="#device-drivers">Device drivers</a></li> +<li class="toctree-l4"><a class="reference internal" href="#process-management">Process management</a></li> +<li class="toctree-l4"><a class="reference internal" href="#memory-management">Memory management</a></li> +<li class="toctree-l4"><a class="reference internal" href="#block-i-o-management">Block I/O management</a></li> +<li class="toctree-l4"><a class="reference internal" href="#virtual-filesystem-switch">Virtual Filesystem Switch</a></li> +<li class="toctree-l4"><a class="reference internal" href="#networking-stack">Networking stack</a></li> +<li class="toctree-l4"><a class="reference internal" href="#linux-security-modules">Linux Security Modules</a></li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Introduction</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/lectures/intro.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="introduction"> +<h1>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="intro-slides.html">View slides</a></p> +<div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-introduction simple"> +<li>Basic operating systems terms and concepts</li> +<li>Overview of the Linux kernel</li> +</ul> +</div> +<div class="section" id="basic-operating-systems-terms-and-concepts"> +<h2>Basic operating systems terms and concepts<a class="headerlink" href="#basic-operating-systems-terms-and-concepts" title="Permalink to this headline">¶</a></h2> +<div class="section" id="user-vs-kernel"> +<h3>User vs Kernel<a class="headerlink" href="#user-vs-kernel" title="Permalink to this headline">¶</a></h3> +<span class="admonition-user-vs-kernel"></span><p>Kernel and user are two terms that are often used in operating +systems. Their definition is pretty straight forward: The kernel is +the part of the operating system that runs with higher privileges +while user (space) usually means by applications running with low +privileges.</p> +<p>However these terms are heavily overloaded and might have very +specific meanings in some contexts.</p> +<p>User mode and kernel mode are terms that may refer specifically to the +processor execution mode. Code that runs in kernel mode can fully +<a class="footnote-reference" href="#hypervisor" id="footnote-reference-1">[1]</a> control the CPU while code that runs in user mode has +certain limitations. For example, local CPU interrupts can only be +disabled or enable while running in kernel mode. If such an operation +is attempted while running in user mode an exception will be generated +and the kernel will take over to handle it.</p> +<table class="docutils footnote" frame="void" id="hypervisor" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#footnote-reference-1">[1]</a></td><td>some processors may have even higher privileges than +kernel mode, e.g. a hypervisor mode, that is only +accessible to code running in a hypervisor (virtual +machine monitor)</td></tr> +</tbody> +</table> +<p>User space and kernel space may refer specifically to memory +protection or to virtual address spaces associated with either the +kernel or user applications.</p> +<p>Grossly simplifying, the kernel space is the memory area that is +reserved to the kernel while user space is the memory area reserved to +a particular user process. The kernel space is accessed protected so +that user applications can not access it directly, while user space +can be directly accessed from code running in kernel mode.</p> +</div> +<div class="section" id="typical-operating-system-architecture"> +<h3>Typical operating system architecture<a class="headerlink" href="#typical-operating-system-architecture" title="Permalink to this headline">¶</a></h3> +<p>In the typical operating system architecture (see the figure below) +the operating system kernel is responsible for access and sharing the +hardware in a secure and fair manner with multiple applications.</p> +<img alt="../_images/ditaa-48374873962ca32ada36c14ab9a83b60f112a1e0.png" class="admonition-typical-operating-system-architecture" src="../_images/ditaa-48374873962ca32ada36c14ab9a83b60f112a1e0.png" /> +<p>The kernel offers a set of APIs that applications issue which are +generally referred to as "System Calls". These APIs are different from +regular library APIs because they are the boundary at which the +execution mode switch from user mode to kernel mode.</p> +<p>In order to provide application compatibility, system calls are rarely +changed. Linux particularly enforces this (as opposed to in kernel +APIs that can change as needed).</p> +<p>The kernel code itself can be logically separated in core kernel +code and device drivers code. Device drivers code is responsible of +accessing particular devices while the core kernel code is +generic. The core kernel can be further divided into multiple logical +subsystems (e.g. file access, networking, process management, etc.)</p> +</div> +<div class="section" id="monolithic-kernel"> +<h3>Monolithic kernel<a class="headerlink" href="#monolithic-kernel" title="Permalink to this headline">¶</a></h3> +<p>A monolithic kernel is one where there is no access protection between +the various kernel subsystems and where public functions can be +directly called between various subsystems.</p> +<img alt="../_images/ditaa-3dc899167df5e16a230c434cf5d6964cb5868482.png" class="admonition-monolithic-kernel" src="../_images/ditaa-3dc899167df5e16a230c434cf5d6964cb5868482.png" /> +<p>However, most monolithic kernels do enforce a logical separation +between subsystems especially between the core kernel and device +drivers with relatively strict APIs (but not necessarily fixed in +stone) that must be used to access services offered by one subsystem +or device drivers. This, of course, depends on the particular kernel +implementation and the kernel's architecture.</p> +</div> +<div class="section" id="micro-kernel"> +<h3>Micro kernel<a class="headerlink" href="#micro-kernel" title="Permalink to this headline">¶</a></h3> +<p>A micro-kernel is one where large parts of the kernel are protected +from each-other, usually running as services in user space. Because +significant parts of the kernel are now running in user mode, the +remaining code that runs in kernel mode is significantly smaller, hence +micro-kernel term.</p> +<img alt="../_images/ditaa-c8a3d93d0109b7be6f608871d16adff4aaa933da.png" class="admonition-micro-kernel" src="../_images/ditaa-c8a3d93d0109b7be6f608871d16adff4aaa933da.png" /> +<p>In a micro-kernel architecture the kernel contains just enough code +that allows for message passing between different running +processes. Practically that means implement the scheduler and an IPC +mechanism in the kernel, as well as basic memory management to setup +the protection between applications and services.</p> +<p>One of the advantages of this architecture is that the services are +isolated and hence bugs in one service won't impact other services.</p> +<p>As such, if a service crashes we can just restart it without affecting +the whole system. However, in practice this is difficult to achieve +since restarting a service may affect all applications that depend on +that service (e.g. if the file server crashes all applications with +opened file descriptors would encounter errors when accessing them).</p> +<p>This architecture imposes a modular approach to the kernel and offers +memory protection between services but at a cost of performance. What +is a simple function call between two services on monolithic kernels +now requires going through IPC and scheduling which will incur a +performance penalty <a class="footnote-reference" href="#minix-vs-linux" id="footnote-reference-2">[2]</a>.</p> +<table class="docutils footnote" frame="void" id="minix-vs-linux" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#footnote-reference-2">[2]</a></td><td><a class="reference external" href="https://lwn.net/Articles/220255/">https://lwn.net/Articles/220255/</a></td></tr> +</tbody> +</table> +</div> +<div class="section" id="micro-kernels-vs-monolithic-kernels"> +<h3>Micro-kernels vs monolithic kernels<a class="headerlink" href="#micro-kernels-vs-monolithic-kernels" title="Permalink to this headline">¶</a></h3> +<p>Advocates of micro-kernels often suggest that micro-kernel are +superior because of the modular design a micro-kernel +enforces. However, monolithic kernels can also be modular and there +are several approaches that modern monolithic kernels use toward this +goal:</p> +<ul class="admonition-monolithic-kernels-can-be-modular simple"> +<li>Components can enabled or disabled at compile time</li> +<li>Support of loadable kernel modules (at runtime)</li> +<li>Organize the kernel in logical, independent subsystems</li> +<li>Strict interfaces but with low performance overhead: macros, +inline functions, function pointers</li> +</ul> +<p>There is a class of operating systems that (used to) claim to be +hybrid kernels, in between monolithic and micro-kernels (e.g. Windows, +Mac OS X). However, since all of the typical monolithic services run +in kernel-mode in these operating systems, there is little merit to +qualify them other then monolithic kernels.</p> +<p class="admonition-hybrid-kernels">Many operating systems and kernel experts have dismissed the label +as meaningless, and just marketing. Linus Torvalds said of this +issue:</p> +<p>"As to the whole 'hybrid kernel' thing - it's just marketing. It's +'oh, those microkernels had good PR, how can we try to get good PR +for our working kernel? Oh, I know, let's use a cool name and try +to imply that it has all the PR advantages that that other system +has'."</p> +</div> +<div class="section" id="address-space"> +<h3>Address space<a class="headerlink" href="#address-space" title="Permalink to this headline">¶</a></h3> +<span class="admonition-address-space"></span><p>The address space term is an overload term that can have different +meanings in different contexts.</p> +<p>The physical address space refers to the way the RAM and device +memories are visible on the memory bus. For example, on 32bit Intel +architecture, it is common to have the RAM mapped into the lower +physical address space while the graphics card memory is mapped high +in the physical address space.</p> +<p>The virtual address space (or sometimes just address space) refers to +the way the CPU sees the memory when the virtual memory module is +activated (sometime called protected mode or paging enabled). The +kernel is responsible of setting up a mapping that creates a virtual +address space in which areas of this space are mapped to certain +physical memory areas.</p> +<p>Related to the virtual address space there are two other terms that +are often used: process (address) space and kernel (address) space.</p> +<p>The process space is (part of) the virtual address space associated +with a process. It is the "memory view" of processes. It is a +continuous area that starts at zero. Where the process's address space +ends depends on the implementation and architecture.</p> +<p>The kernel space is the "memory view" of the code that runs in kernel +mode.</p> +</div> +<div class="section" id="user-and-kernel-sharing-the-virtual-address-space"> +<h3>User and kernel sharing the virtual address space<a class="headerlink" href="#user-and-kernel-sharing-the-virtual-address-space" title="Permalink to this headline">¶</a></h3> +<p>A typical implementation for user and kernel spaces is one where the +virtual address space is shared between user processes and the kernel.</p> +<p>In this case kernel space is located at the top of the address space, +while user space at the bottom. In order to prevent the user processes +from accessing kernel space, the kernel creates mappings that prevent +access to the kernel space from user mode.</p> +<img alt="../_images/ditaa-a5f93e0d17ccdc2ba24828b620d7227f7fc75e33.png" class="admonition-user-and-kernel-sharing-the-virtual-address-space" src="../_images/ditaa-a5f93e0d17ccdc2ba24828b620d7227f7fc75e33.png" /> +</div> +<div class="section" id="execution-contexts"> +<h3>Execution contexts<a class="headerlink" href="#execution-contexts" title="Permalink to this headline">¶</a></h3> +<span class="admonition-execution-contexts"></span><p>One of the most important jobs of the kernel is to service interrupts +and to service them efficiently. This is so important that a special +execution context is associated with it.</p> +<p>The kernel executes in interrupt context when it runs as a result of +an interrupt. This includes the interrupt handler, but it is not +limited to it, there are other special (software) constructs that run +in interrupt mode.</p> +<p>Code running in interrupt context always runs in kernel mode and there +are certain limitations that the kernel programmer has to be aware of +(e.g. not calling blocking functions or accessing user space).</p> +<p>Opposed to interrupt context there is process context. Code that runs +in process context can do so in user mode (executing application code) +or in kernel mode (executing a system call).</p> +</div> +<div class="section" id="multi-tasking"> +<h3>Multi-tasking<a class="headerlink" href="#multi-tasking" title="Permalink to this headline">¶</a></h3> +<span class="admonition-multi-tasking"></span><p>Multitasking is the ability of the operating system to +"simultaneously" execute multiple programs. It does so by quickly +switching between running processes.</p> +<p>Cooperative multitasking requires the programs to cooperate to achieve +multitasking. A program will run and relinquish CPU control back +to the OS, which will then schedule another program.</p> +<p>With preemptive multitasking the kernel will enforce strict limits for +each process, so that all processes have a fair chance of +running. Each process is allowed to run a time slice (e.g. 100ms) +after which, if it is still running, it is forcefully preempted and +another task is scheduled.</p> +</div> +<div class="section" id="preemptive-kernel"> +<h3>Preemptive kernel<a class="headerlink" href="#preemptive-kernel" title="Permalink to this headline">¶</a></h3> +<p class="admonition-preemptive-kernel">Preemptive multitasking and preemptive kernels are different terms.</p> +<p>A kernel is preemptive if a process can be preempted while running +in kernel mode.</p> +<p>However, note that non-preemptive kernels may support preemptive +multitasking.</p> +</div> +<div class="section" id="pageable-kernel-memory"> +<h3>Pageable kernel memory<a class="headerlink" href="#pageable-kernel-memory" title="Permalink to this headline">¶</a></h3> +<p class="admonition-pageable-kernel-memory">A kernel supports pageable kernel memory if parts of kernel memory +(code, data, stack or dynamically allocated memory) can be swapped +to disk.</p> +</div> +<div class="section" id="kernel-stack"> +<h3>Kernel stack<a class="headerlink" href="#kernel-stack" title="Permalink to this headline">¶</a></h3> +<p class="admonition-kernel-stack">Each process has a kernel stack that is used to maintain the +function call chain and local variables state while it is executing +in kernel mode, as a result of a system call.</p> +<p>The kernel stack is small (4KB - 12 KB) so the kernel developer has +to avoid allocating large structures on stack or recursive calls +that are not properly bounded.</p> +</div> +<div class="section" id="portability"> +<h3>Portability<a class="headerlink" href="#portability" title="Permalink to this headline">¶</a></h3> +<p>In order to increase portability across various architectures and +hardware configurations, modern kernels are organized as follows at the +top level:</p> +<ul class="admonition-portability simple"> +<li>Architecture and machine specific code (C & ASM)</li> +<li>Independent architecture code (C):<ul> +<li>kernel core (further split in multiple subsystems)</li> +<li>device drivers</li> +</ul> +</li> +</ul> +<p>This makes it easier to reuse code as much as possible between +different architectures and machine configurations.</p> +</div> +<div class="section" id="asymmetric-multiprocessing-asmp"> +<h3>Asymmetric MultiProcessing (ASMP)<a class="headerlink" href="#asymmetric-multiprocessing-asmp" title="Permalink to this headline">¶</a></h3> +<p>Asymmetric MultiProcessing (ASMP) is a way of supporting multiple +processors (cores) by a kernel, where a processor is dedicated to the +kernel and all other processors run user space programs.</p> +<p>The disadvantage of this approach is that the kernel throughput +(e.g. system calls, interrupt handling, etc.) does not scale with the +number of processors and hence typical processes frequently use system +calls. The scalability of the approach is limited to very specific +systems (e.g. scientific applications).</p> +<img alt="../_images/ditaa-cb16db58a2489307b74d4f70256a48c81c65f6c6.png" class="admonition-asymmetric-multiprocessing-asmp" src="../_images/ditaa-cb16db58a2489307b74d4f70256a48c81c65f6c6.png" /> +</div> +<div class="section" id="symmetric-multiprocessing-smp"> +<h3>Symmetric MultiProcessing (SMP)<a class="headerlink" href="#symmetric-multiprocessing-smp" title="Permalink to this headline">¶</a></h3> +<p>As opposed to ASMP, in SMP mode the kernel can run on any of the +existing processors, just as user processes. This approach is more +difficult to implement, because it creates race conditions in the +kernel if two processes run kernel functions that access the same +memory locations.</p> +<p>In order to support SMP the kernel must implement synchronization +primitives (e.g. spin locks) to guarantee that only one processor is +executing a critical section.</p> +<img alt="../_images/ditaa-08aff771b3ff7a5525df7b0c090e28c836502788.png" class="admonition-symmetric-multiprocessing-smp" src="../_images/ditaa-08aff771b3ff7a5525df7b0c090e28c836502788.png" /> +</div> +<div class="section" id="cpu-scalability"> +<h3>CPU Scalability<a class="headerlink" href="#cpu-scalability" title="Permalink to this headline">¶</a></h3> +<p>CPU scalability refers to how well the performance scales with +the number of cores. There are a few things that the kernel developer +should keep in mind with regard to CPU scalability:</p> +<ul class="admonition-cpu-scalability simple"> +<li>Use lock free algorithms when possible</li> +<li>Use fine grained locking for high contention areas</li> +<li>Pay attention to algorithm complexity</li> +</ul> +</div> +</div> +<div class="section" id="overview-of-the-linux-kernel"> +<h2>Overview of the Linux kernel<a class="headerlink" href="#overview-of-the-linux-kernel" title="Permalink to this headline">¶</a></h2> +<div class="section" id="linux-development-model"> +<h3>Linux development model<a class="headerlink" href="#linux-development-model" title="Permalink to this headline">¶</a></h3> +<span class="admonition-linux-development-model"></span><p>The Linux kernel is one the largest open source projects in the world +with thousands of developers contributing code and millions of lines of +code changed for each release.</p> +<p>It is distributed under the GPLv2 license, which simply put, +requires that any modification of the kernel done on software that is +shipped to customer should be made available to them (the customers), +although in practice most companies make the source code publicly +available.</p> +<p>There are many companies (often competing) that contribute code to the +Linux kernel as well as people from academia and independent +developers.</p> +<p>The current development model is based on doing releases at fixed +intervals of time (usually 3 - 4 months). New features are merged into +the kernel during a one or two week merge window. After the merge +window, a release candidate is done on a weekly basis (rc1, rc2, etc.)</p> +</div> +<div class="section" id="maintainer-hierarchy"> +<h3>Maintainer hierarchy<a class="headerlink" href="#maintainer-hierarchy" title="Permalink to this headline">¶</a></h3> +<p>In order to scale the development process, Linux uses a hierarchical +maintainership model:</p> +<ul class="admonition-maintainer-hierarchy simple"> +<li>Linus Torvalds is the maintainer of the Linux kernel and merges pull +requests from subsystem maintainers</li> +<li>Each subsystem has one or more maintainers that accept patches or +pull requests from developers or device driver maintainers</li> +<li>Each maintainer has its own git tree, e.g.:<ul> +<li>Linux Torvalds: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git</li> +<li>David Miller (networking): git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git/</li> +</ul> +</li> +<li>Each subsystem may maintain a -next tree where developers can submit +patches for the next merge window</li> +</ul> +<p>Since the merge window is only a maximum of two weeks, most of the +maintainers have a -next tree where they accept new features from +developers or maintainers downstream while even when the merge window +is closed.</p> +<p>Note that bug fixes are accepted even outside merge window in the +maintainer's tree from where they are periodically pulled by the +upstream maintainer regularly, for every release candidate.</p> +</div> +<div class="section" id="linux-source-code-layout"> +<h3>Linux source code layout<a class="headerlink" href="#linux-source-code-layout" title="Permalink to this headline">¶</a></h3> +<img alt="../_images/ditaa-f45246aade5ecc7cfb71f7f103a57f95fc7c2b9e.png" class="admonition-linux-source-code-layout" src="../_images/ditaa-f45246aade5ecc7cfb71f7f103a57f95fc7c2b9e.png" /> +<p>These are the top level of the Linux source code folders:</p> +<ul class="simple"> +<li>arch - contains architecture specific code; each architecture is +implemented in a specific sub-folder (e.g. arm, arm64, x86)</li> +<li>block - contains the block subsystem code that deals with reading +and writing data from block devices: creating block I/O requests, +scheduling them (there are several I/O schedulers available), +merging requests, and passing them down through the I/O stack to the +block device drivers</li> +<li>certs - implements support for signature checking using certificates</li> +<li>crypto - software implementation of various cryptography algorithms +as well as a framework that allows offloading such algorithms in +hardware</li> +<li>Documentation - documentation for various subsystems, Linux kernel +command line options, description for sysfs files and format, device +tree bindings (supported device tree nodes and format)</li> +<li>drivers - driver for various devices as well as the Linux driver +model implementation (an abstraction that describes drivers, devices +buses and the way they are connected)</li> +<li>firmware - binary or hex firmware files that are used by various +device drivers</li> +<li>fs - home of the Virtual Filesystem Switch (generic filesystem code) +and of various filesystem drivers</li> +<li>include - header files</li> +<li>init - the generic (as opposed to architecture specific) +initialization code that runs during boot</li> +<li>ipc - implementation for various Inter Process Communication system +calls such as message queue, semaphores, shared memory</li> +<li>kernel - process management code (including support for kernel +thread, workqueues), scheduler, tracing, time management, generic +irq code, locking</li> +<li>lib - various generic functions such as sorting, checksums, +compression and decompression, bitmap manipulation, etc.</li> +<li>mm - memory management code, for both physical and virtual memory, +including the page, SL*B and CMA allocators, swapping, virtual memory +mapping, process address space manipulation, etc.</li> +<li>net - implementation for various network stacks including IPv4 and +IPv6; BSD socket implementation, routing, filtering, packet +scheduling, bridging, etc.</li> +<li>samples - various driver samples</li> +<li>scripts - parts the build system, scripts used for building modules, +kconfig the Linux kernel configurator, as well as various other +scripts (e.g. checkpatch.pl that checks if a patch is conform with +the Linux kernel coding style)</li> +<li>security - home of the Linux Security Module framework that allows +extending the default (Unix) security model as well as +implementation for multiple such extensions such as SELinux, smack, +apparmor, tomoyo, etc.</li> +<li>sound - home of ALSA (Advanced Linux Sound System) as well as the +old Linux sound framework (OSS)</li> +<li>tools - various user space tools for testing or interacting with +Linux kernel subsystems</li> +<li>usr - support for embedding an initrd file in the kernel image</li> +<li>virt - home of the KVM (Kernel Virtual Machine) hypervisor</li> +</ul> +</div> +<div class="section" id="linux-kernel-architecture"> +<h3>Linux kernel architecture<a class="headerlink" href="#linux-kernel-architecture" title="Permalink to this headline">¶</a></h3> +<a class="admonition-linux-kernel-architecture reference internal image-reference" href="../_images/ditaa-b9ffae65be16d30be11b5eca188a7a143b1b8227.png"><img alt="../_images/ditaa-b9ffae65be16d30be11b5eca188a7a143b1b8227.png" class="admonition-linux-kernel-architecture" src="../_images/ditaa-b9ffae65be16d30be11b5eca188a7a143b1b8227.png" style="height: 100%;" /></a> +<div class="section" id="arch"> +<h4>arch<a class="headerlink" href="#arch" title="Permalink to this headline">¶</a></h4> +<ul class="admonition-arch simple"> +<li>Architecture specific code</li> +<li>May be further sub-divided in machine specific code</li> +<li>Interfacing with the boot loader and architecture specific +initialization</li> +<li>Access to various hardware bits that are architecture or machine +specific such as interrupt controller, SMP controllers, BUS +controllers, exceptions and interrupt setup, virtual memory handling</li> +<li>Architecture optimized functions (e.g. memcpy, string operations, +etc.)</li> +</ul> +<p>This part of the Linux kernel contains architecture specific code and +may be further sub-divided in machine specific code for certain +architectures (e.g. arm).</p> +<p>"Linux was first developed for 32-bit x86-based PCs (386 or +higher). These days it also runs on (at least) the Compaq Alpha AXP, +Sun SPARC and UltraSPARC, Motorola 68000, PowerPC, PowerPC64, ARM, +Hitachi SuperH, IBM S/390, MIPS, HP PA-RISC, Intel IA-64, DEC VAX, AMD +x86-64 and CRIS architectures.”</p> +<p>It implements access to various hardware bits that are architecture or +machine specific such as interrupt controller, SMP controllers, BUS +controllers, exceptions and interrupt setup, virtual memory handling.</p> +<p>It also implements architecture optimized functions (e.g. memcpy, +string operations, etc.)</p> +</div> +<div class="section" id="device-drivers"> +<h4>Device drivers<a class="headerlink" href="#device-drivers" title="Permalink to this headline">¶</a></h4> +<span class="admonition-device-drivers"></span><p>The Linux kernel uses a unified device model whose purpose is to +maintain internal data structures that reflect the state and structure +of the system. Such information includes what devices are present, +what is their status, what bus they are attached to, to what driver +they are attached, etc. This information is essential for implementing +system wide power management, as well as device discovery and dynamic +device removal.</p> +<p>Each subsystem has its own specific driver interface that is tailored +to the devices it represents in order to make it easier to write +correct drivers and to reduce code duplication.</p> +<p>Linux supports one of the most diverse set of device drivers type, +some examples are: TTY, serial, SCSI, fileystem, ethernet, USB, +framebuffer, input, sound, etc.</p> +</div> +<div class="section" id="process-management"> +<h4>Process management<a class="headerlink" href="#process-management" title="Permalink to this headline">¶</a></h4> +<span class="admonition-process-management"></span><p>Linux implements the standard Unix process management APIs such as +fork(), exec(), wait(), as well as standard POSIX threads.</p> +<p>However, Linux processes and threads are implemented particularly +different than other kernels. There are no internal structures +implementing processes or threads, instead there is a <code class="xref c c-type docutils literal"><span class="pre">struct</span> +<span class="pre">task_struct</span></code> that describe an abstract scheduling unit called task.</p> +<p>A task has pointers to resources, such as address space, file +descriptors, IPC ids, etc. The resource pointers for tasks that are +part of the same process point to the same resources, while resources +of tasks of different processes will point to different resources.</p> +<p>This peculiarity, together with the <cite>clone()</cite> and <cite>unshare()</cite> system +call allows for implementing new features such as namespaces.</p> +<p>Namespaces are used together with control groups (cgroup) to implement +operating system virtualization in Linux.</p> +<p>cgroup is a mechanism to organize processes hierarchically and +distribute system resources along the hierarchy in a controlled and +configurable manner.</p> +</div> +<div class="section" id="memory-management"> +<h4>Memory management<a class="headerlink" href="#memory-management" title="Permalink to this headline">¶</a></h4> +<p>Linux memory management is a complex subsystem that deals with:</p> +<ul class="admonition-memory-management simple"> +<li>Management of the physical memory: allocating and freeing memory</li> +<li>Management of the virtual memory: paging, swapping, demand +paging, copy on write</li> +<li>User services: user address space management (e.g. mmap(), brk(), +shared memory)</li> +<li>Kernel services: SL*B allocators, vmalloc</li> +</ul> +</div> +<div class="section" id="block-i-o-management"> +<h4>Block I/O management<a class="headerlink" href="#block-i-o-management" title="Permalink to this headline">¶</a></h4> +<p>The Linux Block I/O subsystem deals with reading and writing data from +or to block devices: creating block I/O requests, transforming block I/O +requests (e.g. for software RAID or LVM), merging and sorting the +requests and scheduling them via various I/O schedulers to the block +device drivers.</p> +<a class="admonition-block-i-o-management reference internal image-reference" href="../_images/ditaa-0a96997f269a7a9cd0cdc9c9125f6e62e549be94.png"><img alt="../_images/ditaa-0a96997f269a7a9cd0cdc9c9125f6e62e549be94.png" class="admonition-block-i-o-management" src="../_images/ditaa-0a96997f269a7a9cd0cdc9c9125f6e62e549be94.png" style="height: 100%;" /></a> +</div> +<div class="section" id="virtual-filesystem-switch"> +<h4>Virtual Filesystem Switch<a class="headerlink" href="#virtual-filesystem-switch" title="Permalink to this headline">¶</a></h4> +<p>The Linux Virtual Filesystem Switch implements common / generic +filesystem code to reduce duplication in filesystem drivers. It +introduces certain filesystem abstractions such as:</p> +<ul class="simple"> +<li>inode - describes the file on disk (attributes, location of data +blocks on disk)</li> +<li>dentry - links an inode to a name</li> +<li>file - describes the properties of an opened file (e.g. file +pointer)</li> +<li>superblock - describes the properties of a formatted filesystem +(e.g. number of blocks, block size, location of root directory on +disk, encryption, etc.)</li> +</ul> +<a class="admonition-virtual-filesystem-switch reference internal image-reference" href="../_images/ditaa-afa57a07e21b1b842554278abe30fea575278452.png"><img alt="../_images/ditaa-afa57a07e21b1b842554278abe30fea575278452.png" class="admonition-virtual-filesystem-switch" src="../_images/ditaa-afa57a07e21b1b842554278abe30fea575278452.png" style="height: 100%;" /></a> +<p>The Linux VFS also implements a complex caching mechanism which +includes the following:</p> +<ul class="simple"> +<li>the inode cache - caches the file attributes and internal file +metadata</li> +<li>the dentry cache - caches the directory hierarchy of a filesystem</li> +<li>the page cache - caches file data blocks in memory</li> +</ul> +</div> +<div class="section" id="networking-stack"> +<h4>Networking stack<a class="headerlink" href="#networking-stack" title="Permalink to this headline">¶</a></h4> +<a class="admonition-networking-stack reference internal image-reference" href="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png"><img alt="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png" class="admonition-networking-stack" src="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png" style="height: 100%;" /></a> +</div> +<div class="section" id="linux-security-modules"> +<h4>Linux Security Modules<a class="headerlink" href="#linux-security-modules" title="Permalink to this headline">¶</a></h4> +<ul class="admonition-linux-security-modules simple"> +<li>Hooks to extend the default Linux security model</li> +<li>Used by several Linux security extensions:<ul> +<li>Security Enhancened Linux</li> +<li>AppArmor</li> +<li>Tomoyo</li> +<li>Smack</li> +</ul> +</li> +</ul> +</div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../so2/assign7-kvm-vmm.html" class="btn btn-neutral float-left" title="Assignment 7 - SO2 Virtual Machine Manager with KVM" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="syscalls.html" class="btn btn-neutral float-right" title="System Calls" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/memory-management-slides.html b/refs/pull/405/merge/lectures/memory-management-slides.html new file mode 100644 index 00000000..7c9d9db1 --- /dev/null +++ b/refs/pull/405/merge/lectures/memory-management-slides.html @@ -0,0 +1,550 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Memory Management — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="next" title="Filesystem Management" href="fs.html" /> + <link rel="prev" title="Address Space" href="address-space.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-memory-management slide level-2"> + +<h2>Memory Management</h2> + +<ul class="simple"> +<li>Physical Memory Management<ul> +<li>Page allocations</li> +<li>Small allocations</li> +</ul> +</li> +<li>Virtual Memory Management</li> +<li>Page Fault Handling Overview</li> +</ul> + + + + +</article> +<article class="admonition-physical-memory-management slide level-2"> + +<h2>Physical Memory Management</h2> + +<ul class="simple"> +<li>Algorithms and data structure that keep track of physical memory +pages</li> +<li>Independent of virtual memory management</li> +<li>Both virtual and physical memory management is required for complete +memory management</li> +<li>Physical pages are being tracked using a special data structure: +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code></li> +<li>All physical pages have an entry reserved in the <code class="xref c c-data docutils literal"><span class="pre">mem_map</span></code> +vector</li> +<li>The physical page status may include: a counter for how many +times is a page used, position in swap or file, buffers for this +page, position int the page cache, etc.</li> +</ul> + + + + +</article> +<article class="admonition-memory-zones slide level-2"> + +<h2>Memory zones</h2> + +<ul class="simple"> +<li>DMA zone</li> +<li>DMA32 zone</li> +<li>Normal zone (LowMem)</li> +<li>HighMem Zone</li> +<li>Movable Zone</li> +</ul> + + + + +</article> +<article class="admonition-non-uniform-memory-access slide level-2"> + +<h2>Non-Uniform Memory Access</h2> + +<ul class="simple"> +<li>Physical memory is split in between multiple nodes, one for each CPU</li> +<li>There is single physical address space accessible from every node</li> +<li>Access to the local memory is faster</li> +<li>Each node maintains is own memory zones (.e. DMA, NORMAL, HIGHMEM, etc.)</li> +</ul> + + + + +</article> +<article class="admonition-page-allocation slide level-2"> + +<h2>Page allocation</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* Allocates 2^order contiguous pages and returns a pointer to the</span> +<span class="cm"> * descriptor for the first page</span> +<span class="cm"> */</span> +<span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="nf">alloc_pages</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">,</span> <span class="n">order</span><span class="p">);</span> + +<span class="cm">/* allocates a single page */</span> +<span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="nf">alloc_page</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">);</span> + + +<span class="cm">/* helper functions that return the kernel virtual address */</span> +<span class="kt">void</span> <span class="o">*</span><span class="nf">__get_free_pages</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">,</span> <span class="n">order</span><span class="p">);</span> +<span class="kt">void</span> <span class="o">*</span><span class="nf">__get_free_page</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">);</span> +<span class="kt">void</span> <span class="o">*</span><span class="nf">__get_zero_page</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">);</span> +<span class="kt">void</span> <span class="o">*</span><span class="nf">__get_dma_pages</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">,</span> <span class="n">order</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-why-only-allocate-pages-in-chunks-of-power-of-2 slide level-2"> + +<h2>Why only allocate pages in chunks of power of 2?</h2> + +<ul class="simple"> +<li>Typical memory allocation algorithms have linear complexity</li> +<li>Why not use paging?<ul> +<li>Sometime we do need contiguous memory allocations (for DMA)</li> +<li>Allocation would require page table changes and TLB flushes</li> +<li>Not able to use extended pages</li> +<li>Some architecture directly (in hardware) linearly maps a part +of the address space (e.g. MIPS)</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-the-buddy-algorithm slide level-2"> + +<h2>The buddy algorithm</h2> + +<ul class="simple"> +<li>Free blocks are distributed in multiple lists</li> +<li>Each list contains blocks of the same size</li> +<li>The block size is a power of two</li> +</ul> + + + + +</article> +<article class="admonition-allocating-a-block-of-size-n slide level-2"> + +<h2>Allocating a block of size N</h2> + +<ul class="simple"> +<li>If there is a free block in the N-size list, pick the first</li> +<li>If not, look for a free block in the 2N-size list</li> +<li>Split the 2N-size block in two N-size blocks and add them to the +N-size list</li> +<li>Now that we have the N-size list populated, pick the first free +block from that list</li> +</ul> + + + + +</article> +<article class="admonition-freeing-a-block-of-size-n slide level-2"> + +<h2>Freeing a block of size N</h2> + +<ul class="simple"> +<li>If the "buddy" is free coalesce into a 2N-size block</li> +<li>Try until no more free buddy block is found and place the +resulting block in the respective list</li> +</ul> + + + + +</article> +<article class="admonition-the-linux-implementation slide level-2"> + +<h2>The Linux implementation</h2> + +<ul class="simple"> +<li>11 lists for blocks of 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, +1024 pages</li> +<li>Each memory zone has its own buddy allocator</li> +<li>Each zone has a vector of descriptors for free blocks, one entry +for each size</li> +<li>The descriptor contains the number of free blocks and the head of +the list</li> +<li>Blocks are linked in the list using the <cite>lru</cite> field of +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code></li> +<li>Free pages have the PG_buddy flag set</li> +<li>The page descriptor keeps a copy of the block size in the private +field to easily check if the "buddy" is free</li> +</ul> + + + + +</article> +<article class="admonition-small-allocations slide level-2"> + +<h2>Small allocations</h2> + +<ul class="simple"> +<li>Buddy is used to allocate pages</li> +<li>Many of the kernel subsystems need to allocate buffers smaller +than a page</li> +<li>Typical solution: variable size buffer allocation<ul> +<li>Leads to external fragmentation</li> +</ul> +</li> +<li>Alternative solution: fixed size buffer allocation<ul> +<li>Leads to internal fragmentation</li> +</ul> +</li> +<li>Compromise: fixed size block allocation with multiple sizes, geometrically distributed<ul> +<li>e.g.: 32, 64, ..., 131056</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-the-slab-allocator slide level-2"> + +<h2>The SLAB allocator</h2> + +<ul class="simple"> +<li>Buffers = objects</li> +<li>Uses buddy to allocate a pool of pages for object allocations</li> +<li>Each object (optionally) has a constructor and destructor</li> +<li>Deallocated objects are cached - avoids subsequent calls for +constructors and buddy allocation / deallocation</li> +</ul> + + + + +</article> +<article class="admonition-why-slab slide level-2"> + +<h2>Why SLAB?</h2> + +<ul class="simple"> +<li>The kernel will typically allocate and deallocate multiple types +the same data structures over time (e.g. <code class="xref c c-type docutils literal"><span class="pre">struct</span> +<span class="pre">task_struct</span></code>) effectively using fixed size allocations. Using the +SLAB reduces the frequency of the more heavy +allocation/deallocation operations.</li> +<li>For variable size buffers (which occurs less frequently) a +geometric distribution of caches with fixed-size can be used</li> +<li>Reduces the memory allocation foot-print since we are searching a +much smaller memory area, compared to buddy which can span over a +larger area</li> +<li>Employs cache optimization techniques (slab coloring)</li> +</ul> + + + + +</article> +<article class="admonition-slab-architecture slide level-2"> + +<h2>Slab architecture</h2> + +<img alt="../_images/slab-overview.png" src="../_images/slab-overview.png" /> + + + + +</article> +<article class="admonition-cache-descriptors slide level-2"> + +<h2>Cache descriptors</h2> + +<ul class="simple"> +<li>A name to identify the cache for stats</li> +<li>object constructor and destructor functions</li> +<li>size of the objects</li> +<li>Flags</li> +<li>Size of the slab in power of 2 pages</li> +<li>GFP masks</li> +<li>One or mores slabs, grouped by state: full, partially full, empty</li> +</ul> + + + + +</article> +<article class="admonition-slab-descriptors slide level-2"> + +<h2>SLAB descriptors</h2> + +<ul class="simple"> +<li>Number of objects</li> +<li>Memory region where the objects are stored</li> +<li>Pointer to the first free object</li> +<li>Descriptor are stored either in<ul> +<li>the SLAB itself (if the object size is lower the 512 or if +internal fragmentation leaves enough space for the SLAB +descriptor)</li> +<li>in generic caches internally used by the SLAB allocator</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-slab-detailed-architecture slide level-2"> + +<h2>Slab detailed architecture</h2> + +<img alt="../_images/slab-detailed-arch.png" src="../_images/slab-detailed-arch.png" /> + + + + +</article> +<article class="admonition-generic-vs-specific-caches slide level-2"> + +<h2>Generic vs specific caches</h2> + +<ul class="simple"> +<li>Generic caches are used internally by the slab allocator<ul> +<li>allocating memory for cache and slab descriptors</li> +</ul> +</li> +<li>They are also used to implement <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> by implementing +20 caches with object sizes geometrically distributed between +32bytes and 4MB</li> +<li>Specific cache are created on demand by kernel subsystems</li> +</ul> + + + + +</article> +<article class="admonition-object-descriptors slide level-2"> + +<h2>Object descriptors</h2> + +<img alt="../_images/slab-object-descriptors.png" src="../_images/slab-object-descriptors.png" /> + + + + +</article> +<article class="admonition-object-descriptors slide level-2"> + +<h2>Object descriptors</h2> + +<ul class="simple"> +<li>Only used for free objects</li> +<li>An integer that points to the next free object</li> +<li>The last free object uses a terminator value</li> +<li>Internal descriptors - stored in the slab</li> +<li>External descriptors - stored in generic caches</li> +</ul> + + + + +</article> +<article class="admonition-slab-coloring slide level-2"> + +<h2>SLAB coloring</h2> + +<img alt="../_images/slab-coloring.png" src="../_images/slab-coloring.png" /> + + + + +</article> +<article class="admonition-virtual-memory-management slide level-2"> + +<h2>Virtual memory management</h2> + +<ul class="simple"> +<li>Used in both kernel and user space</li> +<li>Using virtual memory requires:<ul> +<li>reserving (allocating) a segment in the <em>virtual</em> address space +(be it kernel or user)</li> +<li>allocating one or more physical pages for the buffer</li> +<li>allocating one or more physical pages for page tables and +internal structures</li> +<li>mapping the virtual memory segment to the physical allocated +pages</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-address-space-descriptors slide level-2"> + +<h2>Address space descriptors</h2> + +<p> </p> +<img alt="../_images/ditaa-0eda95a3f39dfac448fd07589656b123d3548328.png" src="../_images/ditaa-0eda95a3f39dfac448fd07589656b123d3548328.png" /> + + + + +</article> +<article class="admonition-address-space-descriptors slide level-2"> + +<h2>Address space descriptors</h2> + +<ul class="simple"> +<li>Page table is used either by:<ul> +<li>The CPU's MMU</li> +<li>The kernel to handle TLB exception (some RISC processors)</li> +</ul> +</li> +<li>The address space descriptor is used by the kernel to maintain +high level information such as file and file offset (for mmap +with files), read-only segment, copy-on-write segment, etc.</li> +</ul> + + + + +</article> +<article class="admonition-allocating-virtual-memory slide level-2"> + +<h2>Allocating virtual memory</h2> + +<ul class="simple"> +<li>Search a free area in the address space descriptor</li> +<li>Allocate memory for a new area descriptor</li> +<li>Insert the new area descriptor in the address space descriptor</li> +<li>Allocate physical memory for one or more page tables</li> +<li>Setup the page tables for the newly allocated area in the virtual +address space</li> +<li>Allocating (on demand) physical pages and map them in the virtual +address space by updating the page tables</li> +</ul> + + + + +</article> +<article class="admonition-freeing-virtual-memory slide level-2"> + +<h2>Freeing virtual memory</h2> + +<ul class="simple"> +<li>Removing the area descriptor</li> +<li>Freeing the area descriptor memory</li> +<li>Updating the page tables to remove the area from the virtual +address space</li> +<li>Flushing the TLB for the freed virtual memory area</li> +<li>Freeing physical memory of the page tables associated with the +freed area</li> +<li>Freeing physical memory of the freed virtual memory area</li> +</ul> + + + + +</article> +<article class="admonition-linux-virtual-memory-management slide level-2"> + +<h2>Linux virtual memory management</h2> + +<ul class="simple"> +<li>Kernel<ul> +<li>vmalloc<ul> +<li>area descriptor: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_struct</span></code></li> +<li>address space descriptor: simple linked list of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_struct</span></code></li> +</ul> +</li> +</ul> +</li> +<li>Userspace<ul> +<li>area descriptor: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code></li> +<li>address space descriptor: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code>, red-black tree</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-linux-virtual-memory-management slide level-2"> + +<h2>Linux virtual memory management</h2> + +<img alt="../_images/page-fault-handling.png" src="../_images/page-fault-handling.png" /> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/memory-management.html b/refs/pull/405/merge/lectures/memory-management.html new file mode 100644 index 00000000..ab137479 --- /dev/null +++ b/refs/pull/405/merge/lectures/memory-management.html @@ -0,0 +1,433 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Memory Management — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Filesystem Management" href="fs.html" /> + <link rel="prev" title="Address Space" href="address-space.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="address-space.html">Address Space</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Memory Management</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="#physical-memory-management">Physical Memory Management</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#memory-zones">Memory zones</a></li> +<li class="toctree-l3"><a class="reference internal" href="#non-uniform-memory-access">Non-Uniform Memory Access</a></li> +<li class="toctree-l3"><a class="reference internal" href="#page-allocation">Page allocation</a></li> +<li class="toctree-l3"><a class="reference internal" href="#small-allocations">Small allocations</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#virtual-memory-management">Virtual memory management</a></li> +<li class="toctree-l2"><a class="reference internal" href="#fault-page-handling">Fault page handling</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Memory Management</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/lectures/memory-management.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="memory-management"> +<h1>Memory Management<a class="headerlink" href="#memory-management" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="memory-management-slides.html">View slides</a></p> +<div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-memory-management simple"> +<li>Physical Memory Management<ul> +<li>Page allocations</li> +<li>Small allocations</li> +</ul> +</li> +<li>Virtual Memory Management</li> +<li>Page Fault Handling Overview</li> +</ul> +</div> +<div class="section" id="physical-memory-management"> +<h2>Physical Memory Management<a class="headerlink" href="#physical-memory-management" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-physical-memory-management simple"> +<li>Algorithms and data structure that keep track of physical memory +pages</li> +<li>Independent of virtual memory management</li> +<li>Both virtual and physical memory management is required for complete +memory management</li> +<li>Physical pages are being tracked using a special data structure: +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code></li> +<li>All physical pages have an entry reserved in the <code class="xref c c-data docutils literal"><span class="pre">mem_map</span></code> +vector</li> +<li>The physical page status may include: a counter for how many +times is a page used, position in swap or file, buffers for this +page, position int the page cache, etc.</li> +</ul> +<div class="section" id="memory-zones"> +<h3>Memory zones<a class="headerlink" href="#memory-zones" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-memory-zones simple"> +<li>DMA zone</li> +<li>DMA32 zone</li> +<li>Normal zone (LowMem)</li> +<li>HighMem Zone</li> +<li>Movable Zone</li> +</ul> +</div> +<div class="section" id="non-uniform-memory-access"> +<h3>Non-Uniform Memory Access<a class="headerlink" href="#non-uniform-memory-access" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-non-uniform-memory-access simple"> +<li>Physical memory is split in between multiple nodes, one for each CPU</li> +<li>There is single physical address space accessible from every node</li> +<li>Access to the local memory is faster</li> +<li>Each node maintains is own memory zones (.e. DMA, NORMAL, HIGHMEM, etc.)</li> +</ul> +</div> +<div class="section" id="page-allocation"> +<h3>Page allocation<a class="headerlink" href="#page-allocation" title="Permalink to this headline">¶</a></h3> +<div class="admonition-page-allocation highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* Allocates 2^order contiguous pages and returns a pointer to the</span> +<span class="cm"> * descriptor for the first page</span> +<span class="cm"> */</span> +<span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="nf">alloc_pages</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">,</span> <span class="n">order</span><span class="p">);</span> + +<span class="cm">/* allocates a single page */</span> +<span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="nf">alloc_page</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">);</span> + + +<span class="cm">/* helper functions that return the kernel virtual address */</span> +<span class="kt">void</span> <span class="o">*</span><span class="nf">__get_free_pages</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">,</span> <span class="n">order</span><span class="p">);</span> +<span class="kt">void</span> <span class="o">*</span><span class="nf">__get_free_page</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">);</span> +<span class="kt">void</span> <span class="o">*</span><span class="nf">__get_zero_page</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">);</span> +<span class="kt">void</span> <span class="o">*</span><span class="nf">__get_dma_pages</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">,</span> <span class="n">order</span><span class="p">);</span> +</pre></div> +</div> +<ul class="admonition-why-only-allocate-pages-in-chunks-of-power-of-2 simple"> +<li>Typical memory allocation algorithms have linear complexity</li> +<li>Why not use paging?<ul> +<li>Sometime we do need contiguous memory allocations (for DMA)</li> +<li>Allocation would require page table changes and TLB flushes</li> +<li>Not able to use extended pages</li> +<li>Some architecture directly (in hardware) linearly maps a part +of the address space (e.g. MIPS)</li> +</ul> +</li> +</ul> +<ul class="admonition-the-buddy-algorithm simple"> +<li>Free blocks are distributed in multiple lists</li> +<li>Each list contains blocks of the same size</li> +<li>The block size is a power of two</li> +</ul> +<ul class="admonition-allocating-a-block-of-size-n simple"> +<li>If there is a free block in the N-size list, pick the first</li> +<li>If not, look for a free block in the 2N-size list</li> +<li>Split the 2N-size block in two N-size blocks and add them to the +N-size list</li> +<li>Now that we have the N-size list populated, pick the first free +block from that list</li> +</ul> +<ul class="admonition-freeing-a-block-of-size-n simple"> +<li>If the "buddy" is free coalesce into a 2N-size block</li> +<li>Try until no more free buddy block is found and place the +resulting block in the respective list</li> +</ul> +<ul class="admonition-the-linux-implementation simple"> +<li>11 lists for blocks of 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, +1024 pages</li> +<li>Each memory zone has its own buddy allocator</li> +<li>Each zone has a vector of descriptors for free blocks, one entry +for each size</li> +<li>The descriptor contains the number of free blocks and the head of +the list</li> +<li>Blocks are linked in the list using the <cite>lru</cite> field of +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code></li> +<li>Free pages have the PG_buddy flag set</li> +<li>The page descriptor keeps a copy of the block size in the private +field to easily check if the "buddy" is free</li> +</ul> +</div> +<div class="section" id="small-allocations"> +<h3>Small allocations<a class="headerlink" href="#small-allocations" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-small-allocations simple"> +<li>Buddy is used to allocate pages</li> +<li>Many of the kernel subsystems need to allocate buffers smaller +than a page</li> +<li>Typical solution: variable size buffer allocation<ul> +<li>Leads to external fragmentation</li> +</ul> +</li> +<li>Alternative solution: fixed size buffer allocation<ul> +<li>Leads to internal fragmentation</li> +</ul> +</li> +<li>Compromise: fixed size block allocation with multiple sizes, geometrically distributed<ul> +<li>e.g.: 32, 64, ..., 131056</li> +</ul> +</li> +</ul> +<ul class="admonition-the-slab-allocator simple"> +<li>Buffers = objects</li> +<li>Uses buddy to allocate a pool of pages for object allocations</li> +<li>Each object (optionally) has a constructor and destructor</li> +<li>Deallocated objects are cached - avoids subsequent calls for +constructors and buddy allocation / deallocation</li> +</ul> +<ul class="admonition-why-slab simple"> +<li>The kernel will typically allocate and deallocate multiple types +the same data structures over time (e.g. <code class="xref c c-type docutils literal"><span class="pre">struct</span> +<span class="pre">task_struct</span></code>) effectively using fixed size allocations. Using the +SLAB reduces the frequency of the more heavy +allocation/deallocation operations.</li> +<li>For variable size buffers (which occurs less frequently) a +geometric distribution of caches with fixed-size can be used</li> +<li>Reduces the memory allocation foot-print since we are searching a +much smaller memory area, compared to buddy which can span over a +larger area</li> +<li>Employs cache optimization techniques (slab coloring)</li> +</ul> +<img alt="../_images/slab-overview.png" class="admonition-slab-architecture" src="../_images/slab-overview.png" /> +<ul class="admonition-cache-descriptors simple"> +<li>A name to identify the cache for stats</li> +<li>object constructor and destructor functions</li> +<li>size of the objects</li> +<li>Flags</li> +<li>Size of the slab in power of 2 pages</li> +<li>GFP masks</li> +<li>One or mores slabs, grouped by state: full, partially full, empty</li> +</ul> +<ul class="admonition-slab-descriptors simple"> +<li>Number of objects</li> +<li>Memory region where the objects are stored</li> +<li>Pointer to the first free object</li> +<li>Descriptor are stored either in<ul> +<li>the SLAB itself (if the object size is lower the 512 or if +internal fragmentation leaves enough space for the SLAB +descriptor)</li> +<li>in generic caches internally used by the SLAB allocator</li> +</ul> +</li> +</ul> +<img alt="../_images/slab-detailed-arch.png" class="admonition-slab-detailed-architecture" src="../_images/slab-detailed-arch.png" /> +<ul class="admonition-generic-vs-specific-caches simple"> +<li>Generic caches are used internally by the slab allocator<ul> +<li>allocating memory for cache and slab descriptors</li> +</ul> +</li> +<li>They are also used to implement <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> by implementing +20 caches with object sizes geometrically distributed between +32bytes and 4MB</li> +<li>Specific cache are created on demand by kernel subsystems</li> +</ul> +<img alt="../_images/slab-object-descriptors.png" class="admonition-object-descriptors" src="../_images/slab-object-descriptors.png" /> +<ul class="admonition-object-descriptors simple"> +<li>Only used for free objects</li> +<li>An integer that points to the next free object</li> +<li>The last free object uses a terminator value</li> +<li>Internal descriptors - stored in the slab</li> +<li>External descriptors - stored in generic caches</li> +</ul> +<img alt="../_images/slab-coloring.png" class="admonition-slab-coloring" src="../_images/slab-coloring.png" /> +</div> +</div> +<div class="section" id="virtual-memory-management"> +<h2>Virtual memory management<a class="headerlink" href="#virtual-memory-management" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-virtual-memory-management simple"> +<li>Used in both kernel and user space</li> +<li>Using virtual memory requires:<ul> +<li>reserving (allocating) a segment in the <em>virtual</em> address space +(be it kernel or user)</li> +<li>allocating one or more physical pages for the buffer</li> +<li>allocating one or more physical pages for page tables and +internal structures</li> +<li>mapping the virtual memory segment to the physical allocated +pages</li> +</ul> +</li> +</ul> +<p class="admonition-address-space-descriptors"> </p> +<img alt="../_images/ditaa-0eda95a3f39dfac448fd07589656b123d3548328.png" src="../_images/ditaa-0eda95a3f39dfac448fd07589656b123d3548328.png" /> +<ul class="admonition-address-space-descriptors simple"> +<li>Page table is used either by:<ul> +<li>The CPU's MMU</li> +<li>The kernel to handle TLB exception (some RISC processors)</li> +</ul> +</li> +<li>The address space descriptor is used by the kernel to maintain +high level information such as file and file offset (for mmap +with files), read-only segment, copy-on-write segment, etc.</li> +</ul> +<ul class="admonition-allocating-virtual-memory simple"> +<li>Search a free area in the address space descriptor</li> +<li>Allocate memory for a new area descriptor</li> +<li>Insert the new area descriptor in the address space descriptor</li> +<li>Allocate physical memory for one or more page tables</li> +<li>Setup the page tables for the newly allocated area in the virtual +address space</li> +<li>Allocating (on demand) physical pages and map them in the virtual +address space by updating the page tables</li> +</ul> +<ul class="admonition-freeing-virtual-memory simple"> +<li>Removing the area descriptor</li> +<li>Freeing the area descriptor memory</li> +<li>Updating the page tables to remove the area from the virtual +address space</li> +<li>Flushing the TLB for the freed virtual memory area</li> +<li>Freeing physical memory of the page tables associated with the +freed area</li> +<li>Freeing physical memory of the freed virtual memory area</li> +</ul> +<ul class="admonition-linux-virtual-memory-management simple"> +<li>Kernel<ul> +<li>vmalloc<ul> +<li>area descriptor: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_struct</span></code></li> +<li>address space descriptor: simple linked list of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_struct</span></code></li> +</ul> +</li> +</ul> +</li> +<li>Userspace<ul> +<li>area descriptor: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code></li> +<li>address space descriptor: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code>, red-black tree</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="fault-page-handling"> +<h2>Fault page handling<a class="headerlink" href="#fault-page-handling" title="Permalink to this headline">¶</a></h2> +<img alt="../_images/page-fault-handling.png" class="admonition-linux-virtual-memory-management" src="../_images/page-fault-handling.png" /> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="address-space.html" class="btn btn-neutral float-left" title="Address Space" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="fs.html" class="btn btn-neutral float-right" title="Filesystem Management" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/networking-slides.html b/refs/pull/405/merge/lectures/networking-slides.html new file mode 100644 index 00000000..d7a51db6 --- /dev/null +++ b/refs/pull/405/merge/lectures/networking-slides.html @@ -0,0 +1,514 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Network Management — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="next" title="Architecture Layer" href="arch.html" /> + <link rel="prev" title="Debugging" href="debugging.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-network-management slide level-2"> + +<h2>Network Management</h2> + +<ul class="simple"> +<li>Socket implementation</li> +<li>Routing implementation</li> +<li>Network Device Interface</li> +<li>Hardware and Software Acceleration Techniques</li> +</ul> + + + + +</article> +<article class="admonition-network-management-overview slide level-2"> + +<h2>Network Management Overview</h2> + +<a class="reference internal image-reference" href="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png"><img alt="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png" src="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png" style="height: 100%;" /></a> + + + + +</article> +<article class="admonition-sockets-implementation-overview slide level-2"> + +<h2>Sockets Implementation Overview</h2> + +<a class="reference internal image-reference" href="../_images/ditaa-79e3734c36891f6c04d684aa5caa39f76915dbaf.png"><img alt="../_images/ditaa-79e3734c36891f6c04d684aa5caa39f76915dbaf.png" src="../_images/ditaa-79e3734c36891f6c04d684aa5caa39f76915dbaf.png" style="height: 100%;" /></a> + + + + +</article> +<article class="admonition-sockets-families-and-protocols slide level-2"> + +<h2>Sockets Families and Protocols</h2> + +<a class="reference internal image-reference" href="../_images/ditaa-bf1244d1a5c3d99bd8d40148d81cb3e5748c0b94.png"><img alt="../_images/ditaa-bf1244d1a5c3d99bd8d40148d81cb3e5748c0b94.png" src="../_images/ditaa-bf1244d1a5c3d99bd8d40148d81cb3e5748c0b94.png" style="height: 100%;" /></a> + + + + +</article> +<article class="admonition-example-udp-send slide level-2"> + +<h2>Example: UDP send</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">char</span> <span class="n">c</span><span class="p">;</span> +<span class="k">struct</span> <span class="n">sockaddr_in</span> <span class="n">addr</span><span class="p">;</span> +<span class="kt">int</span> <span class="n">s</span><span class="p">;</span> + +<span class="n">s</span> <span class="o">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_DGRAM</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> +<span class="n">connect</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span><span class="o">*</span><span class="p">)</span><span class="o">&</span><span class="n">addr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">addr</span><span class="p">));</span> +<span class="n">write</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="o">&</span><span class="n">c</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> +<span class="n">close</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-example-udp-send slide level-2"> + +<h2>Example: UDP send</h2> + +<img alt="../_images/ditaa-ee04e3e544de75375b914f7645c79d5ae46fe6f3.png" src="../_images/ditaa-ee04e3e544de75375b914f7645c79d5ae46fe6f3.png" /> + + + + +</article> +<article class="admonition-network-processing-phases slide level-2"> + +<h2>Network processing phases</h2> + +<ul class="simple"> +<li>Interrupt handler - device driver fetches data from the RX ring, +creates a network packet and queues it to the network stack for +processing</li> +<li>NET_SOFTIRQ - packet goes through the stack layer and it is +processed: decapsulate Ethernet frame, check IP packet and route +it, if local packet decapsulate protocol packet (e.g. TCP) and +queues it to a socket</li> +<li>Process context - application fetches data from the socket queue +or pushes data to the socket queue</li> +</ul> + + + + +</article> +<article class="admonition-packet-routing slide level-2"> + +<h2>Packet Routing</h2> + +<img alt="../_images/ditaa-528948c80a3fd78b89fb6f7bd69503a58b93a4ae.png" src="../_images/ditaa-528948c80a3fd78b89fb6f7bd69503a58b93a4ae.png" /> + + + + +</article> +<article class="admonition-routing-table slide level-2"> + +<h2>Routing Table</h2> + +<div class="highlight-shell"><div class="highlight"><pre><span></span>tavi@desktop-tavi:~/src/linux$ ip route list table main +default via <span class="m">172</span>.30.240.1 dev eth0 +<span class="m">172</span>.30.240.0/20 dev eth0 proto kernel scope link src <span class="m">172</span>.30.249.241 + +tavi@desktop-tavi:~/src/linux$ ip route list table <span class="nb">local</span> +broadcast <span class="m">127</span>.0.0.0 dev lo proto kernel scope link src <span class="m">127</span>.0.0.1 +<span class="nb">local</span> <span class="m">127</span>.0.0.0/8 dev lo proto kernel scope host src <span class="m">127</span>.0.0.1 +<span class="nb">local</span> <span class="m">127</span>.0.0.1 dev lo proto kernel scope host src <span class="m">127</span>.0.0.1 +broadcast <span class="m">127</span>.255.255.255 dev lo proto kernel scope link src <span class="m">127</span>.0.0.1 +broadcast <span class="m">172</span>.30.240.0 dev eth0 proto kernel scope link src <span class="m">172</span>.30.249.241 +<span class="nb">local</span> <span class="m">172</span>.30.249.241 dev eth0 proto kernel scope host src <span class="m">172</span>.30.249.241 +broadcast <span class="m">172</span>.30.255.255 dev eth0 proto kernel scope link src <span class="m">172</span>.30.249.241 + +tavi@desktop-tavi:~/src/linux$ ip rule list +<span class="m">0</span>: from all lookup <span class="nb">local</span> +<span class="m">32766</span>: from all lookup main +<span class="m">32767</span>: from all lookup default +</pre></div> +</div> + + + + +</article> +<article class="admonition-routing-policy-database slide level-2"> + +<h2>Routing Policy Database</h2> + +<ul class="simple"> +<li>"Regular" routing only uses the destination address</li> +<li>To increase flexibility a "Routing Policy Database" is used that +allows different routing based on other fields such as the source +address, protocol type, transport ports, etc.</li> +<li>This is encoded as a list of rules that are evaluated based on +their priority (priority 0 is the highest)</li> +<li>Each rule has a selector (how to match the packet) and an +action (what action to take if the packet matches)</li> +<li>Selectors: source address, destination address, type of service (TOS), +input interface, output interface, etc.</li> +<li>Action: lookup / unicast - use given routing table, blackhole - +drop packet, unreachable - send ICMP unreachable message and drop +packet, etc.</li> +</ul> + + + + +</article> +<article class="admonition-routing-table-processing slide level-2"> + +<h2>Routing table processing</h2> + +<ul class="simple"> +<li>Special table for local addreses -> route packets to sockets +based on family, type, ports</li> +<li>Check every routing entry for starting with the most specific +routes (e.g. 192.168.0.0/24 is checked before 192.168.0.0/16)</li> +<li>A route matches if the packet destination addreess logical ORed +with the subnet mask equals the subnet address</li> +<li>Once a route matches the following information is retrieved: +interface, link layer next-hop address, network next host address</li> +</ul> + + + + +</article> +<article class="admonition-forward-information-database-removed-in-3-6 slide level-2"> + +<h2>Forward Information Database (removed in 3.6)</h2> + +<p> </p> +<img alt="../_images/fidb-overview.png" src="../_images/fidb-overview.png" /> + + + + +</article> +<article class="admonition-forward-information-database-removed-in-3-6 slide level-2"> + +<h2>Forward Information Database (removed in 3.6)</h2> + +<img alt="../_images/fidb-details.png" src="../_images/fidb-details.png" /> + + + + +</article> +<article class="admonition-routing-cache-removed-in-3-6 slide level-2"> + +<h2>Routing Cache (removed in 3.6)</h2> + +<p> </p> +<img alt="../_images/routing-cache.png" src="../_images/routing-cache.png" /> + + + + +</article> +<article class="admonition-fib-trie slide level-2"> + +<h2>FIB TRIE</h2> + +<p> </p> +<img alt="../_images/fib-trie.png" src="../_images/fib-trie.png" /> + + + + +</article> +<article class="admonition-compressed-trie slide level-2"> + +<h2>Compressed Trie</h2> + +<p> </p> +<img alt="../_images/fib-trie-compressed.png" src="../_images/fib-trie-compressed.png" /> + + + + +</article> +<article class="admonition-netfilter slide level-2"> + +<h2>Netfilter</h2> + +<ul class="simple"> +<li>Framework that implements packet filtering and NAT</li> +<li>It uses hooks inserted in key places in the packet flow:<ul> +<li>NF_IP_PRE_ROUTING</li> +<li>NF_IP_LOCAL_IN</li> +<li>NF_IP_FORWARD</li> +<li>NF_IP_LOCAL_OUT</li> +<li>NF_IP_POST_ROUTING</li> +<li>NF_IP_NUMHOOKS</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-network-packets-skbs slide level-2"> + +<h2>Network packets (skbs)</h2> + +<img alt="../_images/skb.png" src="../_images/skb.png" /> + + + + +</article> +<article class="admonition-struct-sk-buff slide level-2"> + +<h2>struct sk_buff</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">prev</span><span class="p">;</span> + + <span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">;</span> + <span class="n">ktime_t</span> <span class="n">tstamp</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">net_device</span> <span class="o">*</span><span class="n">dev</span><span class="p">;</span> + <span class="kt">char</span> <span class="n">cb</span><span class="p">[</span><span class="mi">48</span><span class="p">];</span> + + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">,</span> + <span class="n">data_len</span><span class="p">;</span> + <span class="n">__u16</span> <span class="n">mac_len</span><span class="p">,</span> + <span class="n">hdr_len</span><span class="p">;</span> + + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">destructor</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + + <span class="n">sk_buff_data_t</span> <span class="n">transport_header</span><span class="p">;</span> + <span class="n">sk_buff_data_t</span> <span class="n">network_header</span><span class="p">;</span> + <span class="n">sk_buff_data_t</span> <span class="n">mac_header</span><span class="p">;</span> + <span class="n">sk_buff_data_t</span> <span class="n">tail</span><span class="p">;</span> + <span class="n">sk_buff_data_t</span> <span class="n">end</span><span class="p">;</span> + + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">head</span><span class="p">,</span> + <span class="o">*</span><span class="n">data</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">truesize</span><span class="p">;</span> + <span class="n">atomic_t</span> <span class="n">users</span><span class="p">;</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-skb-apis slide level-2"> + +<h2>skb APIs</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* reserve head room */</span> +<span class="kt">void</span> <span class="nf">skb_reserve</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="cm">/* add data to the end */</span> +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_put</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="cm">/* add data to the top */</span> +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_push</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="cm">/* discard data at the top */</span> +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_pull</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="cm">/* discard data at the end */</span> +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_trim</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_transport_header</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_reset_transport_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_set_transport_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">offset</span><span class="p">);</span> + +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_network_header</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_reset_network_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_set_network_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">offset</span><span class="p">);</span> + +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_mac_header</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">skb_mac_header_was_set</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_reset_mac_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_set_mac_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">offset</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-skb-data-management slide level-2"> + +<h2>skb data management</h2> + +<p> </p> +<a class="reference internal image-reference" href="../_images/ditaa-91073cb05a3f537eb54ab10745c307531e6795a0.png"><img alt="../_images/ditaa-91073cb05a3f537eb54ab10745c307531e6795a0.png" src="../_images/ditaa-91073cb05a3f537eb54ab10745c307531e6795a0.png" style="height: 50%;" /></a> + + + + +</article> +<article class="admonition-network-device-interface slide level-2"> + +<h2>Network Device Interface</h2> + +<img alt="../_images/net-dev-hw.png" src="../_images/net-dev-hw.png" /> + + + + +</article> +<article class="admonition-advanced-features slide level-2"> + +<h2>Advanced features</h2> + +<ul class="simple"> +<li>Scatter-Gather</li> +<li>Checksum offloading: Ethernet, IP, UDP, TCP</li> +<li>Adaptive interrupt handling (coalescence, adaptive)</li> +</ul> + + + + +</article> +<article class="admonition-tcp-offload slide level-2"> + +<h2>TCP offload</h2> + +<ul class="simple"> +<li>Full offload - Implement TCP/IP stack in hardware</li> +<li>Issues:<ul> +<li>Scaling number of connections</li> +<li>Security</li> +<li>Conformance</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-performance-observation slide level-2"> + +<h2>Performance observation</h2> + +<ul class="simple"> +<li>Performance is proportional with the number of packets to be +processed</li> +<li>Example: if an end-point can process 60K pps<ul> +<li>1538 MSS -> 738Mbps</li> +<li>2038 MSS -> 978Mbps</li> +<li>9038 MSS -> 4.3Gbps</li> +<li>20738 MSS -> 9.9Gbps</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-stateless-offload slide level-2"> + +<h2>Stateless offload</h2> + +<ul class="simple"> +<li>The networking stack processes large packets</li> +<li>TX path: the hardware splits large packets in smaller packets +(TCP Segmentation Offload)</li> +<li>RX path: the hardware aggregates small packets into larger +packets (Large Receive Offload - LRO)</li> +</ul> + + + + +</article> +<article class="admonition-tcp-segmentation-offload slide level-2"> + +<h2>TCP Segmentation Offload</h2> + +<img alt="../_images/tso.png" src="../_images/tso.png" /> + + + + +</article> +<article class="admonition-large-receive-offload slide level-2"> + +<h2>Large Receive Offload</h2> + +<img alt="../_images/lro.png" src="../_images/lro.png" /> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/networking.html b/refs/pull/405/merge/lectures/networking.html new file mode 100644 index 00000000..d83f8608 --- /dev/null +++ b/refs/pull/405/merge/lectures/networking.html @@ -0,0 +1,427 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Network Management — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Architecture Layer" href="arch.html" /> + <link rel="prev" title="Debugging" href="debugging.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="debugging.html">Debugging</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Network Management</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="#network-management-overview">Network Management Overview</a></li> +<li class="toctree-l2"><a class="reference internal" href="#sockets-implementation-overview">Sockets Implementation Overview</a></li> +<li class="toctree-l2"><a class="reference internal" href="#sockets-families-and-protocols">Sockets Families and Protocols</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#example-udp-send">Example: UDP send</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#network-processing-phases">Network processing phases</a></li> +<li class="toctree-l2"><a class="reference internal" href="#packet-routing">Packet Routing</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#routing-table-s">Routing Table(s)</a></li> +<li class="toctree-l3"><a class="reference internal" href="#routing-policy-database">Routing Policy Database</a></li> +<li class="toctree-l3"><a class="reference internal" href="#routing-table-processing">Routing table processing</a></li> +<li class="toctree-l3"><a class="reference internal" href="#forwarding-information-database">Forwarding Information Database</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#netfilter">Netfilter</a></li> +<li class="toctree-l2"><a class="reference internal" href="#network-packets-skbs-struct-sk-buff">Network packets / skbs (struct sk_buff)</a></li> +<li class="toctree-l2"><a class="reference internal" href="#network-device">Network Device</a></li> +<li class="toctree-l2"><a class="reference internal" href="#hardware-and-software-acceleration-techniques">Hardware and Software Acceleration Techniques</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Network Management</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/lectures/networking.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="network-management"> +<h1>Network Management<a class="headerlink" href="#network-management" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="networking-slides.html">View slides</a></p> +<div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-network-management simple"> +<li>Socket implementation</li> +<li>Routing implementation</li> +<li>Network Device Interface</li> +<li>Hardware and Software Acceleration Techniques</li> +</ul> +</div> +<div class="section" id="network-management-overview"> +<h2>Network Management Overview<a class="headerlink" href="#network-management-overview" title="Permalink to this headline">¶</a></h2> +<a class="admonition-network-management-overview reference internal image-reference" href="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png"><img alt="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png" class="admonition-network-management-overview" src="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png" style="height: 100%;" /></a> +</div> +<div class="section" id="sockets-implementation-overview"> +<h2>Sockets Implementation Overview<a class="headerlink" href="#sockets-implementation-overview" title="Permalink to this headline">¶</a></h2> +<a class="admonition-sockets-implementation-overview reference internal image-reference" href="../_images/ditaa-79e3734c36891f6c04d684aa5caa39f76915dbaf.png"><img alt="../_images/ditaa-79e3734c36891f6c04d684aa5caa39f76915dbaf.png" class="admonition-sockets-implementation-overview" src="../_images/ditaa-79e3734c36891f6c04d684aa5caa39f76915dbaf.png" style="height: 100%;" /></a> +</div> +<div class="section" id="sockets-families-and-protocols"> +<h2>Sockets Families and Protocols<a class="headerlink" href="#sockets-families-and-protocols" title="Permalink to this headline">¶</a></h2> +<a class="admonition-sockets-families-and-protocols reference internal image-reference" href="../_images/ditaa-bf1244d1a5c3d99bd8d40148d81cb3e5748c0b94.png"><img alt="../_images/ditaa-bf1244d1a5c3d99bd8d40148d81cb3e5748c0b94.png" class="admonition-sockets-families-and-protocols" src="../_images/ditaa-bf1244d1a5c3d99bd8d40148d81cb3e5748c0b94.png" style="height: 100%;" /></a> +<div class="section" id="example-udp-send"> +<h3>Example: UDP send<a class="headerlink" href="#example-udp-send" title="Permalink to this headline">¶</a></h3> +<div class="admonition-example-udp-send highlight-c"><div class="highlight"><pre><span></span><span class="kt">char</span> <span class="n">c</span><span class="p">;</span> +<span class="k">struct</span> <span class="n">sockaddr_in</span> <span class="n">addr</span><span class="p">;</span> +<span class="kt">int</span> <span class="n">s</span><span class="p">;</span> + +<span class="n">s</span> <span class="o">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_DGRAM</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> +<span class="n">connect</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span><span class="o">*</span><span class="p">)</span><span class="o">&</span><span class="n">addr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">addr</span><span class="p">));</span> +<span class="n">write</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="o">&</span><span class="n">c</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> +<span class="n">close</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> +</pre></div> +</div> +<img alt="../_images/ditaa-ee04e3e544de75375b914f7645c79d5ae46fe6f3.png" class="admonition-example-udp-send" src="../_images/ditaa-ee04e3e544de75375b914f7645c79d5ae46fe6f3.png" /> +</div> +</div> +<div class="section" id="network-processing-phases"> +<h2>Network processing phases<a class="headerlink" href="#network-processing-phases" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-network-processing-phases simple"> +<li>Interrupt handler - device driver fetches data from the RX ring, +creates a network packet and queues it to the network stack for +processing</li> +<li>NET_SOFTIRQ - packet goes through the stack layer and it is +processed: decapsulate Ethernet frame, check IP packet and route +it, if local packet decapsulate protocol packet (e.g. TCP) and +queues it to a socket</li> +<li>Process context - application fetches data from the socket queue +or pushes data to the socket queue</li> +</ul> +</div> +<div class="section" id="packet-routing"> +<h2>Packet Routing<a class="headerlink" href="#packet-routing" title="Permalink to this headline">¶</a></h2> +<img alt="../_images/ditaa-528948c80a3fd78b89fb6f7bd69503a58b93a4ae.png" class="admonition-packet-routing" src="../_images/ditaa-528948c80a3fd78b89fb6f7bd69503a58b93a4ae.png" /> +<div class="section" id="routing-table-s"> +<h3>Routing Table(s)<a class="headerlink" href="#routing-table-s" title="Permalink to this headline">¶</a></h3> +<div class="admonition-routing-table highlight-shell"><div class="highlight"><pre><span></span>tavi@desktop-tavi:~/src/linux$ ip route list table main +default via <span class="m">172</span>.30.240.1 dev eth0 +<span class="m">172</span>.30.240.0/20 dev eth0 proto kernel scope link src <span class="m">172</span>.30.249.241 + +tavi@desktop-tavi:~/src/linux$ ip route list table <span class="nb">local</span> +broadcast <span class="m">127</span>.0.0.0 dev lo proto kernel scope link src <span class="m">127</span>.0.0.1 +<span class="nb">local</span> <span class="m">127</span>.0.0.0/8 dev lo proto kernel scope host src <span class="m">127</span>.0.0.1 +<span class="nb">local</span> <span class="m">127</span>.0.0.1 dev lo proto kernel scope host src <span class="m">127</span>.0.0.1 +broadcast <span class="m">127</span>.255.255.255 dev lo proto kernel scope link src <span class="m">127</span>.0.0.1 +broadcast <span class="m">172</span>.30.240.0 dev eth0 proto kernel scope link src <span class="m">172</span>.30.249.241 +<span class="nb">local</span> <span class="m">172</span>.30.249.241 dev eth0 proto kernel scope host src <span class="m">172</span>.30.249.241 +broadcast <span class="m">172</span>.30.255.255 dev eth0 proto kernel scope link src <span class="m">172</span>.30.249.241 + +tavi@desktop-tavi:~/src/linux$ ip rule list +<span class="m">0</span>: from all lookup <span class="nb">local</span> +<span class="m">32766</span>: from all lookup main +<span class="m">32767</span>: from all lookup default +</pre></div> +</div> +</div> +<div class="section" id="routing-policy-database"> +<h3>Routing Policy Database<a class="headerlink" href="#routing-policy-database" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-routing-policy-database simple"> +<li>"Regular" routing only uses the destination address</li> +<li>To increase flexibility a "Routing Policy Database" is used that +allows different routing based on other fields such as the source +address, protocol type, transport ports, etc.</li> +<li>This is encoded as a list of rules that are evaluated based on +their priority (priority 0 is the highest)</li> +<li>Each rule has a selector (how to match the packet) and an +action (what action to take if the packet matches)</li> +<li>Selectors: source address, destination address, type of service (TOS), +input interface, output interface, etc.</li> +<li>Action: lookup / unicast - use given routing table, blackhole - +drop packet, unreachable - send ICMP unreachable message and drop +packet, etc.</li> +</ul> +</div> +<div class="section" id="routing-table-processing"> +<h3>Routing table processing<a class="headerlink" href="#routing-table-processing" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-routing-table-processing simple"> +<li>Special table for local addreses -> route packets to sockets +based on family, type, ports</li> +<li>Check every routing entry for starting with the most specific +routes (e.g. 192.168.0.0/24 is checked before 192.168.0.0/16)</li> +<li>A route matches if the packet destination addreess logical ORed +with the subnet mask equals the subnet address</li> +<li>Once a route matches the following information is retrieved: +interface, link layer next-hop address, network next host address</li> +</ul> +</div> +<div class="section" id="forwarding-information-database"> +<h3>Forwarding Information Database<a class="headerlink" href="#forwarding-information-database" title="Permalink to this headline">¶</a></h3> +<p class="admonition-forward-information-database-removed-in-3-6"> </p> +<img alt="../_images/fidb-overview.png" src="../_images/fidb-overview.png" /> +<img alt="../_images/fidb-details.png" class="admonition-forward-information-database-removed-in-3-6" src="../_images/fidb-details.png" /> +<p class="admonition-routing-cache-removed-in-3-6"> </p> +<img alt="../_images/routing-cache.png" src="../_images/routing-cache.png" /> +<p class="admonition-fib-trie"> </p> +<img alt="../_images/fib-trie.png" src="../_images/fib-trie.png" /> +<p class="admonition-compressed-trie"> </p> +<img alt="../_images/fib-trie-compressed.png" src="../_images/fib-trie-compressed.png" /> +</div> +</div> +<div class="section" id="netfilter"> +<h2>Netfilter<a class="headerlink" href="#netfilter" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-netfilter simple"> +<li>Framework that implements packet filtering and NAT</li> +<li>It uses hooks inserted in key places in the packet flow:<ul> +<li>NF_IP_PRE_ROUTING</li> +<li>NF_IP_LOCAL_IN</li> +<li>NF_IP_FORWARD</li> +<li>NF_IP_LOCAL_OUT</li> +<li>NF_IP_POST_ROUTING</li> +<li>NF_IP_NUMHOOKS</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="network-packets-skbs-struct-sk-buff"> +<h2>Network packets / skbs (struct sk_buff)<a class="headerlink" href="#network-packets-skbs-struct-sk-buff" title="Permalink to this headline">¶</a></h2> +<img alt="../_images/skb.png" class="admonition-network-packets-skbs" src="../_images/skb.png" /> +<div class="admonition-struct-sk-buff highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">prev</span><span class="p">;</span> + + <span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">;</span> + <span class="n">ktime_t</span> <span class="n">tstamp</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">net_device</span> <span class="o">*</span><span class="n">dev</span><span class="p">;</span> + <span class="kt">char</span> <span class="n">cb</span><span class="p">[</span><span class="mi">48</span><span class="p">];</span> + + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">,</span> + <span class="n">data_len</span><span class="p">;</span> + <span class="n">__u16</span> <span class="n">mac_len</span><span class="p">,</span> + <span class="n">hdr_len</span><span class="p">;</span> + + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">destructor</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + + <span class="n">sk_buff_data_t</span> <span class="n">transport_header</span><span class="p">;</span> + <span class="n">sk_buff_data_t</span> <span class="n">network_header</span><span class="p">;</span> + <span class="n">sk_buff_data_t</span> <span class="n">mac_header</span><span class="p">;</span> + <span class="n">sk_buff_data_t</span> <span class="n">tail</span><span class="p">;</span> + <span class="n">sk_buff_data_t</span> <span class="n">end</span><span class="p">;</span> + + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">head</span><span class="p">,</span> + <span class="o">*</span><span class="n">data</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">truesize</span><span class="p">;</span> + <span class="n">atomic_t</span> <span class="n">users</span><span class="p">;</span> +</pre></div> +</div> +<div class="admonition-skb-apis highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* reserve head room */</span> +<span class="kt">void</span> <span class="nf">skb_reserve</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="cm">/* add data to the end */</span> +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_put</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="cm">/* add data to the top */</span> +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_push</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="cm">/* discard data at the top */</span> +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_pull</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="cm">/* discard data at the end */</span> +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_trim</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_transport_header</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_reset_transport_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_set_transport_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">offset</span><span class="p">);</span> + +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_network_header</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_reset_network_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_set_network_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">offset</span><span class="p">);</span> + +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_mac_header</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">skb_mac_header_was_set</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_reset_mac_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_set_mac_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">offset</span><span class="p">);</span> +</pre></div> +</div> +<p class="admonition-skb-data-management"> </p> +<a class="reference internal image-reference" href="../_images/ditaa-91073cb05a3f537eb54ab10745c307531e6795a0.png"><img alt="../_images/ditaa-91073cb05a3f537eb54ab10745c307531e6795a0.png" src="../_images/ditaa-91073cb05a3f537eb54ab10745c307531e6795a0.png" style="height: 50%;" /></a> +</div> +<div class="section" id="network-device"> +<h2>Network Device<a class="headerlink" href="#network-device" title="Permalink to this headline">¶</a></h2> +<img alt="../_images/net-dev-hw.png" class="admonition-network-device-interface" src="../_images/net-dev-hw.png" /> +<ul class="admonition-advanced-features simple"> +<li>Scatter-Gather</li> +<li>Checksum offloading: Ethernet, IP, UDP, TCP</li> +<li>Adaptive interrupt handling (coalescence, adaptive)</li> +</ul> +</div> +<div class="section" id="hardware-and-software-acceleration-techniques"> +<h2>Hardware and Software Acceleration Techniques<a class="headerlink" href="#hardware-and-software-acceleration-techniques" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-tcp-offload simple"> +<li>Full offload - Implement TCP/IP stack in hardware</li> +<li>Issues:<ul> +<li>Scaling number of connections</li> +<li>Security</li> +<li>Conformance</li> +</ul> +</li> +</ul> +<ul class="admonition-performance-observation simple"> +<li>Performance is proportional with the number of packets to be +processed</li> +<li>Example: if an end-point can process 60K pps<ul> +<li>1538 MSS -> 738Mbps</li> +<li>2038 MSS -> 978Mbps</li> +<li>9038 MSS -> 4.3Gbps</li> +<li>20738 MSS -> 9.9Gbps</li> +</ul> +</li> +</ul> +<ul class="admonition-stateless-offload simple"> +<li>The networking stack processes large packets</li> +<li>TX path: the hardware splits large packets in smaller packets +(TCP Segmentation Offload)</li> +<li>RX path: the hardware aggregates small packets into larger +packets (Large Receive Offload - LRO)</li> +</ul> +<img alt="../_images/tso.png" class="admonition-tcp-segmentation-offload" src="../_images/tso.png" /> +<img alt="../_images/lro.png" class="admonition-large-receive-offload" src="../_images/lro.png" /> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="debugging.html" class="btn btn-neutral float-left" title="Debugging" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="arch.html" class="btn btn-neutral float-right" title="Architecture Layer" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/processes-slides.html b/refs/pull/405/merge/lectures/processes-slides.html new file mode 100644 index 00000000..60a65ddf --- /dev/null +++ b/refs/pull/405/merge/lectures/processes-slides.html @@ -0,0 +1,986 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Processes — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="next" title="Interrupts" href="interrupts.html" /> + <link rel="prev" title="System Calls" href="syscalls.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-processes-and-threads slide level-2"> + +<h2>Processes and threads</h2> + +<ul class="simple"> +<li>Process and threads</li> +<li>Context switching</li> +<li>Blocking and waking up</li> +<li>Process context</li> +</ul> + + + + +</article> +<article class="admonition-what-is-a-process slide level-2"> + +<h2>What is a process?</h2> + +<table class="hlist"><tr><td><ul class="simple"> +<li>An address space</li> +<li>One or more threads</li> +<li>Opened files</li> +<li>Sockets</li> +<li>Semaphores</li> +</ul> +</td><td><ul class="simple"> +<li>Shared memory regions</li> +<li>Timers</li> +<li>Signal handlers</li> +<li>Many other resources and status information</li> +</ul> +</td></tr></table> +<p>All this information is grouped in the Process Control Group +(PCB). In Linux this is <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>.</p> + + + + +</article> +<article class="admonition-overview-of-process-resources slide level-2"> + +<h2>Overview of process resources</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span> +-------------------------------------------------------------------+ + | dr-x------ 2 tavi tavi 0 2021 03 14 12:34 . | + | dr-xr-xr-x 6 tavi tavi 0 2021 03 14 12:34 .. | + | lrwx------ 1 tavi tavi 64 2021 03 14 12:34 0 -> /dev/pts/4 | + +--->| lrwx------ 1 tavi tavi 64 2021 03 14 12:34 1 -> /dev/pts/4 | + | | lrwx------ 1 tavi tavi 64 2021 03 14 12:34 2 -> /dev/pts/4 | + | | lr-x------ 1 tavi tavi 64 2021 03 14 12:34 3 -> /proc/18312/fd | + | +-------------------------------------------------------------------+ + | +----------------------------------------------------------------+ + | | 08048000-0804c000 r-xp 00000000 08:02 16875609 /bin/cat | +$ ls -1 /proc/self/ | 0804c000-0804d000 rw-p 00003000 08:02 16875609 /bin/cat | +cmdline | | 0804d000-0806e000 rw-p 0804d000 00:00 0 [heap] | +cwd | | ... | +environ | +----------->| b7f46000-b7f49000 rw-p b7f46000 00:00 0 | +exe | | | b7f59000-b7f5b000 rw-p b7f59000 00:00 0 | +fd --------+ | | b7f5b000-b7f77000 r-xp 00000000 08:02 11601524 /lib/ld-2.7.so | +fdinfo | | b7f77000-b7f79000 rw-p 0001b000 08:02 11601524 /lib/ld-2.7.so | +maps -----------+ | bfa05000-bfa1a000 rw-p bffeb000 00:00 0 [stack] | +mem | ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso] | +root +----------------------------------------------------------------+ +stat +----------------------------+ +statm | Name: cat | +status ------+ | State: R (running) | +task | | Tgid: 18205 | +wchan +------>| Pid: 18205 | + | PPid: 18133 | + | Uid: 1000 1000 1000 1000 | + | Gid: 1000 1000 1000 1000 | + +----------------------------+ +</pre></div> +</div> + + + + +</article> +<article class="admonition-struct-task-struct slide level-2"> + +<h2>struct task_struct</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span>$ pahole -C task_struct vmlinux + +struct task_struct { + struct thread_info thread_info; /* 0 8 */ + volatile long int state; /* 8 4 */ + void * stack; /* 12 4 */ + + ... + + /* --- cacheline 45 boundary (2880 bytes) --- */ + struct thread_struct thread __attribute__((__aligned__(64))); /* 2880 4288 */ + + /* size: 7168, cachelines: 112, members: 155 */ + /* sum members: 7148, holes: 2, sum holes: 12 */ + /* sum bitfield members: 7 bits, bit holes: 2, sum bit holes: 57 bits */ + /* paddings: 1, sum paddings: 2 */ + /* forced alignments: 6, forced holes: 2, sum forced holes: 12 */ +} __attribute__((__aligned__(64))); +</pre></div> +</div> + + + + +</article> +<article class="admonition-inspecting-task-struct slide level-2"> + +<h2>Inspecting task_struct</h2> + +<p> </p> +<asciinema-player src="../_images/inspect_task_struct.cast"></asciinema-player> + + + +</article> +<article class="admonition-quiz-inspect-opened-files slide level-2"> + +<h2>Quiz: Inspect opened files</h2> + +<p>Use the debugger to inspect the process named syslogd.</p> +<ul class="simple"> +<li>What command should we use to list the opened file descriptors?</li> +<li>How many file descriptors are opened?</li> +<li>What command should we use the determine the file name for opened file descriptor 3?</li> +<li>What is the filename for file descriptor 3?</li> +</ul> + + + + +</article> +<article class="admonition-threads slide level-2"> + +<h2>Threads</h2> + +<ul class="simple"> +<li>Each thread has its own stack and together with the register +values it determines the thread execution state</li> +<li>A thread runs in the context of a process and all threads in the +same process share the resources</li> +<li>The kernel schedules threads not processes and user-level threads +(e.g. fibers, coroutines, etc.) are not visible at the kernel level</li> +</ul> + + + + +</article> +<article class="admonition-classic-implementation-windows slide level-2"> + +<h2>Classic implementation (Windows)</h2> + +<p> </p> +<img alt="../_images/ditaa-4b5c1874d3924d9716f26d4893a3e4f313bf1c43.png" src="../_images/ditaa-4b5c1874d3924d9716f26d4893a3e4f313bf1c43.png" /> + + + + +</article> +<article class="admonition-linux-implementation slide level-2"> + +<h2>Linux implementation</h2> + +<p> </p> +<img alt="../_images/ditaa-fd771038e88b95def30ae9bd4df0b7bd6b7b3503.png" src="../_images/ditaa-fd771038e88b95def30ae9bd4df0b7bd6b7b3503.png" /> + + + + +</article> +<article class="admonition-the-clone-system-call slide level-2"> + +<h2>The clone system call</h2> + +<ul class="simple"> +<li>CLONE_FILES - shares the file descriptor table with the parent</li> +<li>CLONE_VM - shares the address space with the parent</li> +<li>CLONE_FS - shares the filesystem information (root directory, +current directory) with the parent</li> +<li>CLONE_NEWNS - does not share the mount namespace with the parent</li> +<li>CLONE_NEWIPC - does not share the IPC namespace (System V IPC +objects, POSIX message queues) with the parent</li> +<li>CLONE_NEWNET - does not share the networking namespaces (network +interfaces, routing table) with the parent</li> +</ul> + + + + +</article> +<article class="admonition-namespaces-and-containers slide level-2"> + +<h2>Namespaces and "containers"</h2> + +<ul class="simple"> +<li>Containers = a form of lightweight virtual machines</li> +<li>Container based technologies: LXC, docker</li> +<li>Containers are built of top of kernel namespaces</li> +<li>Kernel namespaces allows isolation of otherwise globally visible +resources</li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">nsproxy</span></code> has multiple namespaces each of which +can be selectively shared between groups of processes</li> +<li>At boot initial namespaces are created (e.g. <code class="xref c c-data docutils literal"><span class="pre">init_net</span></code>) +that are by default shared between new processes (e.g. list of +available network interfaces)</li> +<li>New namespace can be created a runtime and new processes can +point to these new namespaces</li> +</ul> + + + + +</article> +<article class="admonition-accessing-the-current-process slide level-2"> + +<h2>Accessing the current process</h2> + +<p>Accessing the current process is a frequent operation:</p> +<ul class="simple"> +<li>opening a file needs access to <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>'s +file field</li> +<li>mapping a new file needs access to <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>'s +mm field</li> +<li>Over 90% of the system calls needs to access the current process +structure so it needs to be fast</li> +<li>The <code class="xref c c-macro docutils literal"><span class="pre">current</span></code> macro is available to access to current +process's <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code></li> +</ul> + + + + +</article> +<article class="admonition-accessing-the-current-process-on-x86 slide level-2"> + +<h2>Accessing the current process on x86</h2> + +<p> </p> +<img alt="../_images/ditaa-019489e686a2f60f1594e37458cfcb10320eae0f.png" src="../_images/ditaa-019489e686a2f60f1594e37458cfcb10320eae0f.png" /> + + + + +</article> +<article class="admonition-previous-implementation-for-current-x86 slide level-2"> + +<h2>Previous implementation for current (x86)</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span>/* how to get the current stack pointer from C */ +register unsigned long current_stack_pointer asm("esp") __attribute_used__; + +/* how to get the thread information struct from C */ +static inline struct thread_info *current_thread_info(void) +{ + return (struct thread_info *)(current_stack_pointer & ~(THREAD_SIZE – 1)); +} + +#define current current_thread_info()->task +</pre></div> +</div> + + + + +</article> +<article class="admonition-quiz-previous-implementation-for-current-x86 slide level-2"> + +<h2>Quiz: previous implementation for current (x86)</h2> + +<p>What is the size of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">thread_info</span></code>?</p> +<p>Which of the following are potential valid sizes for +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">thread_info</span></code>: 4095, 4096, 4097?</p> + + + + +</article> +<article class="admonition-overview-the-context-switching-processes slide level-2"> + +<h2>Overview the context switching processes</h2> + +<img alt="../_images/ditaa-f6b228332baf165f498d8a1bb0bc0bdb91ae50c5.png" src="../_images/ditaa-f6b228332baf165f498d8a1bb0bc0bdb91ae50c5.png" /> + + + + +</article> +<article class="admonition-context-switch slide level-2"> + +<h2>context_switch</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">__always_inline</span> <span class="k">struct</span> <span class="n">rq</span> <span class="o">*</span> +<span class="nf">context_switch</span><span class="p">(</span><span class="k">struct</span> <span class="n">rq</span> <span class="o">*</span><span class="n">rq</span><span class="p">,</span> <span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">prev</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">next</span><span class="p">,</span> <span class="k">struct</span> <span class="n">rq_flags</span> <span class="o">*</span><span class="n">rf</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">prepare_task_switch</span><span class="p">(</span><span class="n">rq</span><span class="p">,</span> <span class="n">prev</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span> + + <span class="cm">/*</span> +<span class="cm"> * For paravirt, this is coupled with an exit in switch_to to</span> +<span class="cm"> * combine the page table reload and the switch backend into</span> +<span class="cm"> * one hypercall.</span> +<span class="cm"> */</span> + <span class="n">arch_start_context_switch</span><span class="p">(</span><span class="n">prev</span><span class="p">);</span> + + <span class="cm">/*</span> +<span class="cm"> * kernel -> kernel lazy + transfer active</span> +<span class="cm"> * user -> kernel lazy + mmgrab() active</span> +<span class="cm"> *</span> +<span class="cm"> * kernel -> user switch + mmdrop() active</span> +<span class="cm"> * user -> user switch</span> +<span class="cm"> */</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">next</span><span class="o">-></span><span class="n">mm</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// to kernel</span> + <span class="n">enter_lazy_tlb</span><span class="p">(</span><span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span> + + <span class="n">next</span><span class="o">-></span><span class="n">active_mm</span> <span class="o">=</span> <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">;</span> + <span class="k">if</span> <span class="p">(</span><span class="n">prev</span><span class="o">-></span><span class="n">mm</span><span class="p">)</span> <span class="c1">// from user</span> + <span class="n">mmgrab</span><span class="p">(</span><span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">);</span> + <span class="k">else</span> + <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="c1">// to user</span> + <span class="n">membarrier_switch_mm</span><span class="p">(</span><span class="n">rq</span><span class="p">,</span> <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">,</span> <span class="n">next</span><span class="o">-></span><span class="n">mm</span><span class="p">);</span> + <span class="cm">/*</span> +<span class="cm"> * sys_membarrier() requires an smp_mb() between setting</span> +<span class="cm"> * rq->curr / membarrier_switch_mm() and returning to userspace.</span> +<span class="cm"> *</span> +<span class="cm"> * The below provides this either through switch_mm(), or in</span> +<span class="cm"> * case 'prev->active_mm == next->mm' through</span> +<span class="cm"> * finish_task_switch()'s mmdrop().</span> +<span class="cm"> */</span> + <span class="n">switch_mm_irqs_off</span><span class="p">(</span><span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">,</span> <span class="n">next</span><span class="o">-></span><span class="n">mm</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">prev</span><span class="o">-></span><span class="n">mm</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// from kernel</span> + <span class="cm">/* will mmdrop() in finish_task_switch(). */</span> + <span class="n">rq</span><span class="o">-></span><span class="n">prev_mm</span> <span class="o">=</span> <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">;</span> + <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="p">}</span> + <span class="p">}</span> + + <span class="n">rq</span><span class="o">-></span><span class="n">clock_update_flags</span> <span class="o">&=</span> <span class="o">~</span><span class="p">(</span><span class="n">RQCF_ACT_SKIP</span><span class="o">|</span><span class="n">RQCF_REQ_SKIP</span><span class="p">);</span> + + <span class="n">prepare_lock_switch</span><span class="p">(</span><span class="n">rq</span><span class="p">,</span> <span class="n">next</span><span class="p">,</span> <span class="n">rf</span><span class="p">);</span> + + <span class="cm">/* Here we just switch the register state and the stack. */</span> + <span class="n">switch_to</span><span class="p">(</span><span class="n">prev</span><span class="p">,</span> <span class="n">next</span><span class="p">,</span> <span class="n">prev</span><span class="p">);</span> + <span class="n">barrier</span><span class="p">();</span> + + <span class="k">return</span> <span class="n">finish_task_switch</span><span class="p">(</span><span class="n">prev</span><span class="p">);</span> + <span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-switch-to slide level-2"> + +<h2>switch_to</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define switch_to(prev, next, last) \</span> +<span class="cp">do { \</span> +<span class="cp"> ((last) = __switch_to_asm((prev), (next))); \</span> +<span class="cp">} while (0)</span> + + +<span class="cm">/*</span> +<span class="cm"> * %eax: prev task</span> +<span class="cm"> * %edx: next task</span> +<span class="cm"> */</span> +<span class="p">.</span><span class="n">pushsection</span> <span class="p">.</span><span class="n">text</span><span class="p">,</span> <span class="s">"ax"</span> +<span class="n">SYM_CODE_START</span><span class="p">(</span><span class="n">__switch_to_asm</span><span class="p">)</span> + <span class="cm">/*</span> +<span class="cm"> * Save callee-saved registers</span> +<span class="cm"> * This must match the order in struct inactive_task_frame</span> +<span class="cm"> */</span> + <span class="n">pushl</span> <span class="o">%</span><span class="n">ebp</span> + <span class="n">pushl</span> <span class="o">%</span><span class="n">ebx</span> + <span class="n">pushl</span> <span class="o">%</span><span class="n">edi</span> + <span class="n">pushl</span> <span class="o">%</span><span class="n">esi</span> + <span class="cm">/*</span> +<span class="cm"> * Flags are saved to prevent AC leakage. This could go</span> +<span class="cm"> * away if objtool would have 32bit support to verify</span> +<span class="cm"> * the STAC/CLAC correctness.</span> +<span class="cm"> */</span> + <span class="n">pushfl</span> + +<span class="hll"> <span class="cm">/* switch stack */</span> +</span><span class="hll"> <span class="n">movl</span> <span class="o">%</span><span class="n">esp</span><span class="p">,</span> <span class="n">TASK_threadsp</span><span class="p">(</span><span class="o">%</span><span class="n">eax</span><span class="p">)</span> +</span><span class="hll"> <span class="n">movl</span> <span class="n">TASK_threadsp</span><span class="p">(</span><span class="o">%</span><span class="n">edx</span><span class="p">),</span> <span class="o">%</span><span class="n">esp</span> +</span> + <span class="cp">#ifdef CONFIG_STACKPROTECTOR</span> + <span class="n">movl</span> <span class="n">TASK_stack_canary</span><span class="p">(</span><span class="o">%</span><span class="n">edx</span><span class="p">),</span> <span class="o">%</span><span class="n">ebx</span> + <span class="n">movl</span> <span class="o">%</span><span class="n">ebx</span><span class="p">,</span> <span class="n">PER_CPU_VAR</span><span class="p">(</span><span class="n">stack_canary</span><span class="p">)</span><span class="o">+</span><span class="n">stack_canary_offset</span> + <span class="cp">#endif</span> + + <span class="cp">#ifdef CONFIG_RETPOLINE</span> + <span class="cm">/*</span> +<span class="cm"> * When switching from a shallower to a deeper call stack</span> +<span class="cm"> * the RSB may either underflow or use entries populated</span> +<span class="cm"> * with userspace addresses. On CPUs where those concerns</span> +<span class="cm"> * exist, overwrite the RSB with entries which capture</span> +<span class="cm"> * speculative execution to prevent attack.</span> +<span class="cm"> */</span> + <span class="n">FILL_RETURN_BUFFER</span> <span class="o">%</span><span class="n">ebx</span><span class="p">,</span> <span class="n">RSB_CLEAR_LOOPS</span><span class="p">,</span> <span class="n">X86_FEATURE_RSB_CTXSW</span> + <span class="cp">#endif</span> + + <span class="cm">/* Restore flags or the incoming task to restore AC state. */</span> + <span class="n">popfl</span> + <span class="cm">/* restore callee-saved registers */</span> + <span class="n">popl</span> <span class="o">%</span><span class="n">esi</span> + <span class="n">popl</span> <span class="o">%</span><span class="n">edi</span> + <span class="n">popl</span> <span class="o">%</span><span class="n">ebx</span> + <span class="n">popl</span> <span class="o">%</span><span class="n">ebp</span> + +<span class="hll"> <span class="n">jmp</span> <span class="n">__switch_to</span> +</span> <span class="n">SYM_CODE_END</span><span class="p">(</span><span class="n">__switch_to_asm</span><span class="p">)</span> + <span class="p">.</span><span class="n">popsection</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-inspecting-task-struct slide level-2"> + +<h2>Inspecting task_struct</h2> + +<p> </p> +<asciinema-player src="../_images/context_switch.cast"></asciinema-player> + + + +</article> +<article class="admonition-quiz-context-switch slide level-2"> + +<h2>Quiz: context switch</h2> + +<p>We are executing a context switch. Select all of the statements that are true.</p> +<ul class="simple"> +<li>the ESP register is saved in the task structure</li> +<li>the EIP register is saved in the task structure</li> +<li>general registers are saved in the task structure</li> +<li>the ESP register is saved on the stack</li> +<li>the EIP register is saved on the stack</li> +<li>general registers are saved on the stack</li> +</ul> + + + + +</article> +<article class="admonition-task-states slide level-2"> + +<h2>Task states</h2> + +<img alt="../_images/ditaa-0b8cde2be9bbd195ac9dcaeac978a8bbe0d3b805.png" src="../_images/ditaa-0b8cde2be9bbd195ac9dcaeac978a8bbe0d3b805.png" /> + + + + +</article> +<article class="admonition-blocking-the-current-thread slide level-2"> + +<h2>Blocking the current thread</h2> + +<ul class="simple"> +<li>Set the current thread state to TASK_UINTERRUPTIBLE or +TASK_INTERRUPTIBLE</li> +<li>Add the task to a waiting queue</li> +<li>Call the scheduler which will pick up a new task from the READY +queue</li> +<li>Do the context switch to the new task</li> +</ul> + + + + +</article> +<article class="admonition-wait-event slide level-2"> + +<h2>wait_event</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/**</span> +<span class="cm"> * wait_event - sleep until a condition gets true</span> +<span class="cm"> * @wq_head: the waitqueue to wait on</span> +<span class="cm"> * @condition: a C expression for the event to wait for</span> +<span class="cm"> *</span> +<span class="cm"> * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the</span> +<span class="cm"> * @condition evaluates to true. The @condition is checked each time</span> +<span class="cm"> * the waitqueue @wq_head is woken up.</span> +<span class="cm"> *</span> +<span class="cm"> * wake_up() has to be called after changing any variable that could</span> +<span class="cm"> * change the result of the wait condition.</span> +<span class="cm"> */</span> +<span class="cp">#define wait_event(wq_head, condition) \</span> +<span class="cp">do { \</span> +<span class="cp"> might_sleep(); \</span> +<span class="cp"> if (condition) \</span> +<span class="cp"> break; \</span> +<span class="cp"> __wait_event(wq_head, condition); \</span> +<span class="cp">} while (0)</span> + +<span class="cp">#define __wait_event(wq_head, condition) \</span> +<span class="cp"> (void)___wait_event(wq_head, condition, TASK_UNINTERRUPTIBLE, 0, 0, \</span> +<span class="cp"> schedule())</span> + +<span class="cm">/*</span> +<span class="cm"> * The below macro ___wait_event() has an explicit shadow of the __ret</span> +<span class="cm"> * variable when used from the wait_event_*() macros.</span> +<span class="cm"> *</span> +<span class="cm"> * This is so that both can use the ___wait_cond_timeout() construct</span> +<span class="cm"> * to wrap the condition.</span> +<span class="cm"> *</span> +<span class="cm"> * The type inconsistency of the wait_event_*() __ret variable is also</span> +<span class="cm"> * on purpose; we use long where we can return timeout values and int</span> +<span class="cm"> * otherwise.</span> +<span class="cm"> */</span> +<span class="cp">#define ___wait_event(wq_head, condition, state, exclusive, ret, cmd) \</span> +<span class="cp">({ \</span> +<span class="cp"> __label__ __out; \</span> +<span class="cp"> struct wait_queue_entry __wq_entry; \</span> +<span class="cp"> long __ret = ret; </span><span class="cm">/* explicit shadow */</span><span class="cp"> \</span> +<span class="cp"> \</span> +<span class="cp"> init_wait_entry(&__wq_entry, exclusive ? WQ_FLAG_EXCLUSIVE : 0); \</span> +<span class="cp"> for (;;) { \</span> +<span class="cp"> long __int = prepare_to_wait_event(&wq_head, &__wq_entry, state);\</span> +<span class="cp"> \</span> +<span class="cp"> if (condition) \</span> +<span class="cp"> break; \</span> +<span class="cp"> \</span> +<span class="cp"> if (___wait_is_interruptible(state) && __int) { \</span> +<span class="cp"> __ret = __int; \</span> +<span class="cp"> goto __out; \</span> +<span class="cp"> } \</span> +<span class="cp"> \</span> +<span class="cp"> cmd; \</span> +<span class="cp"> } \</span> +<span class="cp"> finish_wait(&wq_head, &__wq_entry); \</span> +<span class="cp"> __out: __ret; \</span> +<span class="cp"> })</span> + + <span class="kt">void</span> <span class="nf">init_wait_entry</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">,</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">wq_entry</span><span class="o">-></span><span class="n">flags</span> <span class="o">=</span> <span class="n">flags</span><span class="p">;</span> + <span class="n">wq_entry</span><span class="o">-></span><span class="n">private</span> <span class="o">=</span> <span class="n">current</span><span class="p">;</span> + <span class="n">wq_entry</span><span class="o">-></span><span class="n">func</span> <span class="o">=</span> <span class="n">autoremove_wake_function</span><span class="p">;</span> + <span class="n">INIT_LIST_HEAD</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="p">}</span> + + <span class="kt">long</span> <span class="nf">prepare_to_wait_event</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">,</span> <span class="kt">int</span> <span class="n">state</span><span class="p">)</span> + <span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + <span class="kt">long</span> <span class="n">ret</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + + <span class="n">spin_lock_irqsave</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">signal_pending_state</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">current</span><span class="p">))</span> <span class="p">{</span> + <span class="cm">/*</span> +<span class="cm"> * Exclusive waiter must not fail if it was selected by wakeup,</span> +<span class="cm"> * it should "consume" the condition we were waiting for.</span> +<span class="cm"> *</span> +<span class="cm"> * The caller will recheck the condition and return success if</span> +<span class="cm"> * we were already woken up, we can not miss the event because</span> +<span class="cm"> * wakeup locks/unlocks the same wq_head->lock.</span> +<span class="cm"> *</span> +<span class="cm"> * But we need to ensure that set-condition + wakeup after that</span> +<span class="cm"> * can't see us, it should wake up another exclusive waiter if</span> +<span class="cm"> * we fail.</span> +<span class="cm"> */</span> + <span class="n">list_del_init</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="n">ret</span> <span class="o">=</span> <span class="o">-</span><span class="n">ERESTARTSYS</span><span class="p">;</span> + <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">list_empty</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">))</span> <span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_EXCLUSIVE</span><span class="p">)</span> + <span class="n">__add_wait_queue_entry_tail</span><span class="p">(</span><span class="n">wq_head</span><span class="p">,</span> <span class="n">wq_entry</span><span class="p">);</span> + <span class="k">else</span> + <span class="n">__add_wait_queue</span><span class="p">(</span><span class="n">wq_head</span><span class="p">,</span> <span class="n">wq_entry</span><span class="p">);</span> + <span class="p">}</span> + <span class="n">set_current_state</span><span class="p">(</span><span class="n">state</span><span class="p">);</span> + <span class="p">}</span> + <span class="n">spin_unlock_irqrestore</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + + <span class="k">return</span> <span class="n">ret</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">static</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="nf">__add_wait_queue</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">list_add</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">,</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">);</span> + <span class="p">}</span> + + <span class="k">static</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="nf">__add_wait_queue_entry_tail</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">list_add_tail</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">,</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">);</span> + <span class="p">}</span> + + <span class="cm">/**</span> +<span class="cm"> * finish_wait - clean up after waiting in a queue</span> +<span class="cm"> * @wq_head: waitqueue waited on</span> +<span class="cm"> * @wq_entry: wait descriptor</span> +<span class="cm"> *</span> +<span class="cm"> * Sets current thread back to running state and removes</span> +<span class="cm"> * the wait descriptor from the given waitqueue if still</span> +<span class="cm"> * queued.</span> +<span class="cm"> */</span> + <span class="kt">void</span> <span class="nf">finish_wait</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">)</span> + <span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + + <span class="n">__set_current_state</span><span class="p">(</span><span class="n">TASK_RUNNING</span><span class="p">);</span> + <span class="cm">/*</span> +<span class="cm"> * We can check for list emptiness outside the lock</span> +<span class="cm"> * IFF:</span> +<span class="cm"> * - we use the "careful" check that verifies both</span> +<span class="cm"> * the next and prev pointers, so that there cannot</span> +<span class="cm"> * be any half-pending updates in progress on other</span> +<span class="cm"> * CPU's that we haven't seen yet (and that might</span> +<span class="cm"> * still change the stack area.</span> +<span class="cm"> * and</span> +<span class="cm"> * - all other users take the lock (ie we can only</span> +<span class="cm"> * have _one_ other CPU that looks at or modifies</span> +<span class="cm"> * the list).</span> +<span class="cm"> */</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">list_empty_careful</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">))</span> <span class="p">{</span> + <span class="n">spin_lock_irqsave</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="n">list_del_init</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="n">spin_unlock_irqrestore</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="p">}</span> + <span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-waking-up-a-task slide level-2"> + +<h2>Waking up a task</h2> + +<ul class="simple"> +<li>Select a task from the waiting queue</li> +<li>Set the task state to TASK_READY</li> +<li>Insert the task into the scheduler's READY queue</li> +<li>On SMP system this is a complex operation: each processor has its +own queue, queues need to be balanced, CPUs needs to be signaled</li> +</ul> + + + + +</article> +<article class="admonition-wake-up slide level-2"> + +<h2>wake_up</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)</span> + +<span class="cm">/**</span> +<span class="cm"> * __wake_up - wake up threads blocked on a waitqueue.</span> +<span class="cm"> * @wq_head: the waitqueue</span> +<span class="cm"> * @mode: which threads</span> +<span class="cm"> * @nr_exclusive: how many wake-one or wake-many threads to wake up</span> +<span class="cm"> * @key: is directly passed to the wakeup function</span> +<span class="cm"> *</span> +<span class="cm"> * If this function wakes up a task, it executes a full memory barrier before</span> +<span class="cm"> * accessing the task state.</span> +<span class="cm"> */</span> +<span class="kt">void</span> <span class="nf">__wake_up</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">mode</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">nr_exclusive</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">__wake_up_common_lock</span><span class="p">(</span><span class="n">wq_head</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">nr_exclusive</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">key</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">__wake_up_common_lock</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">mode</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">nr_exclusive</span><span class="p">,</span> <span class="kt">int</span> <span class="n">wake_flags</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + <span class="n">wait_queue_entry_t</span> <span class="n">bookmark</span><span class="p">;</span> + + <span class="n">bookmark</span><span class="p">.</span><span class="n">flags</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="n">bookmark</span><span class="p">.</span><span class="n">private</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="n">bookmark</span><span class="p">.</span><span class="n">func</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="n">INIT_LIST_HEAD</span><span class="p">(</span><span class="o">&</span><span class="n">bookmark</span><span class="p">.</span><span class="n">entry</span><span class="p">);</span> + + <span class="k">do</span> <span class="p">{</span> + <span class="n">spin_lock_irqsave</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="n">nr_exclusive</span> <span class="o">=</span> <span class="n">__wake_up_common</span><span class="p">(</span><span class="n">wq_head</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">nr_exclusive</span><span class="p">,</span> + <span class="n">wake_flags</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="o">&</span><span class="n">bookmark</span><span class="p">);</span> + <span class="n">spin_unlock_irqrestore</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="n">bookmark</span><span class="p">.</span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_BOOKMARK</span><span class="p">);</span> +<span class="p">}</span> + +<span class="cm">/*</span> +<span class="cm"> * The core wakeup function. Non-exclusive wakeups (nr_exclusive == 0) just</span> +<span class="cm"> * wake everything up. If it's an exclusive wakeup (nr_exclusive == small +ve</span> +<span class="cm"> * number) then we wake all the non-exclusive tasks and one exclusive task.</span> +<span class="cm"> *</span> +<span class="cm"> * There are circumstances in which we can try to wake a task which has already</span> +<span class="cm"> * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns</span> +<span class="cm"> * zero in this (rare) case, and we handle it by continuing to scan the queue.</span> +<span class="cm"> */</span> +<span class="k">static</span> <span class="kt">int</span> <span class="nf">__wake_up_common</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">mode</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">nr_exclusive</span><span class="p">,</span> <span class="kt">int</span> <span class="n">wake_flags</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">,</span> + <span class="n">wait_queue_entry_t</span> <span class="o">*</span><span class="n">bookmark</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">wait_queue_entry_t</span> <span class="o">*</span><span class="n">curr</span><span class="p">,</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">cnt</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + + <span class="n">lockdep_assert_held</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">bookmark</span> <span class="o">&&</span> <span class="p">(</span><span class="n">bookmark</span><span class="o">-></span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_BOOKMARK</span><span class="p">))</span> <span class="p">{</span> + <span class="n">curr</span> <span class="o">=</span> <span class="n">list_next_entry</span><span class="p">(</span><span class="n">bookmark</span><span class="p">,</span> <span class="n">entry</span><span class="p">);</span> + + <span class="n">list_del</span><span class="p">(</span><span class="o">&</span><span class="n">bookmark</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="n">bookmark</span><span class="o">-></span><span class="n">flags</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="p">}</span> <span class="k">else</span> + <span class="n">curr</span> <span class="o">=</span> <span class="n">list_first_entry</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">,</span> <span class="n">wait_queue_entry_t</span><span class="p">,</span> <span class="n">entry</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">&</span><span class="n">curr</span><span class="o">-></span><span class="n">entry</span> <span class="o">==</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">)</span> + <span class="k">return</span> <span class="n">nr_exclusive</span><span class="p">;</span> + + <span class="n">list_for_each_entry_safe_from</span><span class="p">(</span><span class="n">curr</span><span class="p">,</span> <span class="n">next</span><span class="p">,</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">,</span> <span class="n">entry</span><span class="p">)</span> <span class="p">{</span> + <span class="kt">unsigned</span> <span class="n">flags</span> <span class="o">=</span> <span class="n">curr</span><span class="o">-></span><span class="n">flags</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">ret</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_BOOKMARK</span><span class="p">)</span> + <span class="k">continue</span><span class="p">;</span> + + <span class="n">ret</span> <span class="o">=</span> <span class="n">curr</span><span class="o">-></span><span class="n">func</span><span class="p">(</span><span class="n">curr</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">wake_flags</span><span class="p">,</span> <span class="n">key</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">ret</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">break</span><span class="p">;</span> + <span class="k">if</span> <span class="p">(</span><span class="n">ret</span> <span class="o">&&</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_EXCLUSIVE</span><span class="p">)</span> <span class="o">&&</span> <span class="o">!--</span><span class="n">nr_exclusive</span><span class="p">)</span> + <span class="k">break</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">bookmark</span> <span class="o">&&</span> <span class="p">(</span><span class="o">++</span><span class="n">cnt</span> <span class="o">></span> <span class="n">WAITQUEUE_WALK_BREAK_CNT</span><span class="p">)</span> <span class="o">&&</span> + <span class="p">(</span><span class="o">&</span><span class="n">next</span><span class="o">-></span><span class="n">entry</span> <span class="o">!=</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">))</span> <span class="p">{</span> + <span class="n">bookmark</span><span class="o">-></span><span class="n">flags</span> <span class="o">=</span> <span class="n">WQ_FLAG_BOOKMARK</span><span class="p">;</span> + <span class="n">list_add_tail</span><span class="p">(</span><span class="o">&</span><span class="n">bookmark</span><span class="o">-></span><span class="n">entry</span><span class="p">,</span> <span class="o">&</span><span class="n">next</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="k">break</span><span class="p">;</span> + <span class="p">}</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="n">nr_exclusive</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">int</span> <span class="nf">autoremove_wake_function</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">mode</span><span class="p">,</span> <span class="kt">int</span> <span class="n">sync</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">default_wake_function</span><span class="p">(</span><span class="n">wq_entry</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">sync</span><span class="p">,</span> <span class="n">key</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">ret</span><span class="p">)</span> + <span class="n">list_del_init_careful</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + + <span class="k">return</span> <span class="n">ret</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">int</span> <span class="nf">default_wake_function</span><span class="p">(</span><span class="n">wait_queue_entry_t</span> <span class="o">*</span><span class="n">curr</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">mode</span><span class="p">,</span> <span class="kt">int</span> <span class="n">wake_flags</span><span class="p">,</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">WARN_ON_ONCE</span><span class="p">(</span><span class="n">IS_ENABLED</span><span class="p">(</span><span class="n">CONFIG_SCHED_DEBUG</span><span class="p">)</span> <span class="o">&&</span> <span class="n">wake_flags</span> <span class="o">&</span> <span class="o">~</span><span class="n">WF_SYNC</span><span class="p">);</span> + <span class="k">return</span> <span class="n">try_to_wake_up</span><span class="p">(</span><span class="n">curr</span><span class="o">-></span><span class="n">private</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">wake_flags</span><span class="p">);</span> +<span class="p">}</span> + +<span class="cm">/**</span> +<span class="cm"> * try_to_wake_up - wake up a thread</span> +<span class="cm"> * @p: the thread to be awakened</span> +<span class="cm"> * @state: the mask of task states that can be woken</span> +<span class="cm"> * @wake_flags: wake modifier flags (WF_*)</span> +<span class="cm"> *</span> +<span class="cm"> * Conceptually does:</span> +<span class="cm"> *</span> +<span class="cm"> * If (@state & @p->state) @p->state = TASK_RUNNING.</span> +<span class="cm"> *</span> +<span class="cm"> * If the task was not queued/runnable, also place it back on a runqueue.</span> +<span class="cm"> *</span> +<span class="cm"> * This function is atomic against schedule() which would dequeue the task.</span> +<span class="cm"> *</span> +<span class="cm"> * It issues a full memory barrier before accessing @p->state, see the comment</span> +<span class="cm"> * with set_current_state().</span> +<span class="cm"> *</span> +<span class="cm"> * Uses p->pi_lock to serialize against concurrent wake-ups.</span> +<span class="cm"> *</span> +<span class="cm"> * Relies on p->pi_lock stabilizing:</span> +<span class="cm"> * - p->sched_class</span> +<span class="cm"> * - p->cpus_ptr</span> +<span class="cm"> * - p->sched_task_group</span> +<span class="cm"> * in order to do migration, see its use of select_task_rq()/set_task_cpu().</span> +<span class="cm"> *</span> +<span class="cm"> * Tries really hard to only take one task_rq(p)->lock for performance.</span> +<span class="cm"> * Takes rq->lock in:</span> +<span class="cm"> * - ttwu_runnable() -- old rq, unavoidable, see comment there;</span> +<span class="cm"> * - ttwu_queue() -- new rq, for enqueue of the task;</span> +<span class="cm"> * - psi_ttwu_dequeue() -- much sadness :-( accounting will kill us.</span> +<span class="cm"> *</span> +<span class="cm"> * As a consequence we race really badly with just about everything. See the</span> +<span class="cm"> * many memory barriers and their comments for details.</span> +<span class="cm"> *</span> +<span class="cm"> * Return: %true if @p->state changes (an actual wakeup was done),</span> +<span class="cm"> * %false otherwise.</span> +<span class="cm"> */</span> + <span class="k">static</span> <span class="kt">int</span> + <span class="nf">try_to_wake_up</span><span class="p">(</span><span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">p</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">state</span><span class="p">,</span> <span class="kt">int</span> <span class="n">wake_flags</span><span class="p">)</span> + <span class="p">{</span> + <span class="p">...</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-non-preemptive-kernel slide level-2"> + +<h2>Non preemptive kernel</h2> + +<ul class="simple"> +<li>At every tick the kernel checks to see if the current process has +its time slice consumed</li> +<li>If that happens a flag is set in interrupt context</li> +<li>Before returning to userspace the kernel checks this flag and +calls <code class="xref c c-func docutils literal"><span class="pre">schedule()</span></code> if needed</li> +<li>In this case tasks are not preempted while running in kernel mode +(e.g. system call) so there are no synchronization issues</li> +</ul> + + + + +</article> +<article class="admonition-preemptive-kernel slide level-2"> + +<h2>Preemptive kernel</h2> + +<ul class="simple"> +<li>Tasks can be preempted even when running in kernel mode</li> +<li>It requires new synchronization primitives to be used in critical +sections: <code class="xref c c-macro docutils literal"><span class="pre">preempt_disable</span></code> and +<code class="xref c c-macro docutils literal"><span class="pre">preempt_enable</span></code></li> +<li>Spinlocks also disable preemption</li> +<li>When a thread needs to be preempted a flag is set and action is +taken (e.g. scheduler is called) when preemption is reactivated</li> +</ul> + + + + +</article> +<article class="admonition-process-context slide level-2"> + +<h2>Process context</h2> + +<p>The kernel is executing in process context when it is running a +system call.</p> +<p>In process context there is a well defined context and we can +access the current process data with <code class="xref c c-macro docutils literal"><span class="pre">current</span></code></p> +<p>In process context we can sleep (wait on a condition).</p> +<p>In process context we can access the user-space (unless we are +running in a kernel thread context).</p> + + + + +</article> +<article class="admonition-kernel-threads slide level-2"> + +<h2>Kernel threads</h2> + +<p>Sometimes the kernel core or device drivers need to perform blocking +operations and thus they need to run in process context.</p> +<p>Kernel threads are used exactly for this and are a special class of +tasks that don't "userspace" resources (e.g. no address space or +opened files).</p> + + + + +</article> +<article class="admonition-inspecting-kernel-threads slide level-2"> + +<h2>Inspecting kernel threads</h2> + +<p> </p> +<asciinema-player src="../_images/kernel_threads.cast"></asciinema-player> + + + +</article> +<article class="admonition-quiz-kernel-gdb-scripts slide level-2"> + +<h2>Quiz: Kernel gdb scripts</h2> + +<p>What is the following change of the lx-ps script trying to +accomplish?</p> +<div class="highlight-diff"><div class="highlight"><pre><span></span><span class="gh">diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py</span> +<span class="gh">index 17ec19e9b5bf..7e43c163832f 100644</span> +<span class="gd">--- a/scripts/gdb/linux/tasks.py</span> +<span class="gi">+++ b/scripts/gdb/linux/tasks.py</span> +<span class="gu">@@ -75,10 +75,13 @@ class LxPs(gdb.Command):</span> + def invoke(self, arg, from_tty): + gdb.write("{:>10} {:>12} {:>7}\n".format("TASK", "PID", "COMM")) + for task in task_lists(): +<span class="gd">- gdb.write("{} {:^5} {}\n".format(</span> +<span class="gi">+ check = task["mm"].format_string() == "0x0"</span> +<span class="gi">+ gdb.write("{} {:^5} {}{}{}\n".format(</span> + task.format_string().split()[0], + task["pid"].format_string(), +<span class="gd">- task["comm"].string()))</span> +<span class="gi">+ "[" if check else "",</span> +<span class="gi">+ task["comm"].string(),</span> +<span class="gi">+ "]" if check else ""))</span> + + + LxPs() +</pre></div> +</div> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/processes.html b/refs/pull/405/merge/lectures/processes.html new file mode 100644 index 00000000..80aedeca --- /dev/null +++ b/refs/pull/405/merge/lectures/processes.html @@ -0,0 +1,1084 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Processes — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Interrupts" href="interrupts.html" /> + <link rel="prev" title="System Calls" href="syscalls.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="syscalls.html">System Calls</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Processes</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lecture-objectives">Lecture objectives</a></li> +<li class="toctree-l2"><a class="reference internal" href="#processes-and-threads">Processes and threads</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#overview-of-process-resources">Overview of process resources</a></li> +<li class="toctree-l3"><a class="reference internal" href="#struct-task-struct"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code></a></li> +<li class="toctree-l3"><a class="reference internal" href="#inspecting-task-struct">Inspecting task_struct</a></li> +<li class="toctree-l3"><a class="reference internal" href="#quiz-inspect-a-task-to-determine-opened-files">Quiz: Inspect a task to determine opened files</a></li> +<li class="toctree-l3"><a class="reference internal" href="#threads">Threads</a></li> +<li class="toctree-l3"><a class="reference internal" href="#the-clone-system-call">The clone system call</a></li> +<li class="toctree-l3"><a class="reference internal" href="#namespaces-and-containers">Namespaces and "containers"</a></li> +<li class="toctree-l3"><a class="reference internal" href="#accessing-the-current-process">Accessing the current process</a></li> +<li class="toctree-l3"><a class="reference internal" href="#quiz-previous-implementation-for-current-x86">Quiz: previous implementation for current (x86)</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#context-switching">Context switching</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#quiz-context-switch">Quiz: context switch</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#blocking-and-waking-up-tasks">Blocking and waking up tasks</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#task-states">Task states</a></li> +<li class="toctree-l3"><a class="reference internal" href="#blocking-the-current-thread">Blocking the current thread</a></li> +<li class="toctree-l3"><a class="reference internal" href="#waking-up-a-task">Waking up a task</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#preempting-tasks">Preempting tasks</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#non-preemptive-kernel">Non preemptive kernel</a></li> +<li class="toctree-l3"><a class="reference internal" href="#preemptive-kernel">Preemptive kernel</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#process-context">Process context</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#kernel-threads">Kernel threads</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#using-gdb-scripts-for-kernel-inspection">Using gdb scripts for kernel inspection</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#quiz-kernel-gdb-scripts">Quiz: Kernel gdb scripts</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Processes</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/lectures/processes.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="processes"> +<h1>Processes<a class="headerlink" href="#processes" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="processes-slides.html">View slides</a></p> +<div class="section" id="lecture-objectives"> +<h2>Lecture objectives<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-processes-and-threads simple"> +<li>Process and threads</li> +<li>Context switching</li> +<li>Blocking and waking up</li> +<li>Process context</li> +</ul> +</div> +<div class="section" id="processes-and-threads"> +<h2>Processes and threads<a class="headerlink" href="#processes-and-threads" title="Permalink to this headline">¶</a></h2> +<p>A process is an operating system abstraction that groups together +multiple resources:</p> +<table class="hlist"><tr><td><ul class="simple"> +<li>An address space</li> +<li>One or more threads</li> +<li>Opened files</li> +<li>Sockets</li> +<li>Semaphores</li> +</ul> +</td><td><ul class="simple"> +<li>Shared memory regions</li> +<li>Timers</li> +<li>Signal handlers</li> +<li>Many other resources and status information</li> +</ul> +</td></tr></table> +<p>All this information is grouped in the Process Control Group +(PCB). In Linux this is <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>.</p> +<div class="section" id="overview-of-process-resources"> +<h3>Overview of process resources<a class="headerlink" href="#overview-of-process-resources" title="Permalink to this headline">¶</a></h3> +<p>A summary of the resources a process has can be obtain from the +<cite>/proc/<pid></cite> directory, where <cite><pid></cite> is the process id for the +process we want to look at.</p> +<div class="highlight-none"><div class="highlight"><pre><span></span> +-------------------------------------------------------------------+ + | dr-x------ 2 tavi tavi 0 2021 03 14 12:34 . | + | dr-xr-xr-x 6 tavi tavi 0 2021 03 14 12:34 .. | + | lrwx------ 1 tavi tavi 64 2021 03 14 12:34 0 -> /dev/pts/4 | + +--->| lrwx------ 1 tavi tavi 64 2021 03 14 12:34 1 -> /dev/pts/4 | + | | lrwx------ 1 tavi tavi 64 2021 03 14 12:34 2 -> /dev/pts/4 | + | | lr-x------ 1 tavi tavi 64 2021 03 14 12:34 3 -> /proc/18312/fd | + | +-------------------------------------------------------------------+ + | +----------------------------------------------------------------+ + | | 08048000-0804c000 r-xp 00000000 08:02 16875609 /bin/cat | +$ ls -1 /proc/self/ | 0804c000-0804d000 rw-p 00003000 08:02 16875609 /bin/cat | +cmdline | | 0804d000-0806e000 rw-p 0804d000 00:00 0 [heap] | +cwd | | ... | +environ | +----------->| b7f46000-b7f49000 rw-p b7f46000 00:00 0 | +exe | | | b7f59000-b7f5b000 rw-p b7f59000 00:00 0 | +fd --------+ | | b7f5b000-b7f77000 r-xp 00000000 08:02 11601524 /lib/ld-2.7.so | +fdinfo | | b7f77000-b7f79000 rw-p 0001b000 08:02 11601524 /lib/ld-2.7.so | +maps -----------+ | bfa05000-bfa1a000 rw-p bffeb000 00:00 0 [stack] | +mem | ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso] | +root +----------------------------------------------------------------+ +stat +----------------------------+ +statm | Name: cat | +status ------+ | State: R (running) | +task | | Tgid: 18205 | +wchan +------>| Pid: 18205 | + | PPid: 18133 | + | Uid: 1000 1000 1000 1000 | + | Gid: 1000 1000 1000 1000 | + +----------------------------+ +</pre></div> +</div> +</div> +<div class="section" id="struct-task-struct"> +<h3><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code><a class="headerlink" href="#struct-task-struct" title="Permalink to this headline">¶</a></h3> +<p>Lets take a close look at <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>. For that we +could just look at the source code, but here we will use a tool called +<cite>pahole</cite> (part of the dwarves install package) in order to get +some insights about this structure:</p> +<div class="admonition-struct-task-struct highlight-c"><div class="highlight"><pre><span></span>$ pahole -C task_struct vmlinux + +struct task_struct { + struct thread_info thread_info; /* 0 8 */ + volatile long int state; /* 8 4 */ + void * stack; /* 12 4 */ + + ... + + /* --- cacheline 45 boundary (2880 bytes) --- */ + struct thread_struct thread __attribute__((__aligned__(64))); /* 2880 4288 */ + + /* size: 7168, cachelines: 112, members: 155 */ + /* sum members: 7148, holes: 2, sum holes: 12 */ + /* sum bitfield members: 7 bits, bit holes: 2, sum bit holes: 57 bits */ + /* paddings: 1, sum paddings: 2 */ + /* forced alignments: 6, forced holes: 2, sum forced holes: 12 */ +} __attribute__((__aligned__(64))); +</pre></div> +</div> +<p>As you can see it is a pretty large data structure: almost 8KB in size +and 155 fields.</p> +</div> +<div class="section" id="inspecting-task-struct"> +<h3>Inspecting task_struct<a class="headerlink" href="#inspecting-task-struct" title="Permalink to this headline">¶</a></h3> +<p>The following screencast is going to demonstrate how we can inspect +the process control block (<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>) by connecting +the debugger to the running virtual machine. We are going to use a +helper gdb command <cite>lx-ps</cite> to list the processes and the address of +the task_struct for each process.</p> +<p class="admonition-inspecting-task-struct"> </p> +<asciinema-player src="../_images/inspect_task_struct.cast"></asciinema-player></div> +<div class="section" id="quiz-inspect-a-task-to-determine-opened-files"> +<h3>Quiz: Inspect a task to determine opened files<a class="headerlink" href="#quiz-inspect-a-task-to-determine-opened-files" title="Permalink to this headline">¶</a></h3> +<p class="admonition-quiz-inspect-opened-files">Use the debugger to inspect the process named syslogd.</p> +<ul class="simple"> +<li>What command should we use to list the opened file descriptors?</li> +<li>How many file descriptors are opened?</li> +<li>What command should we use the determine the file name for opened file descriptor 3?</li> +<li>What is the filename for file descriptor 3?</li> +</ul> +</div> +<div class="section" id="threads"> +<h3>Threads<a class="headerlink" href="#threads" title="Permalink to this headline">¶</a></h3> +<p>A thread is the basic unit that the kernel process scheduler uses to +allow applications to run the CPU. A thread has the following +characteristics:</p> +<ul class="admonition-threads simple"> +<li>Each thread has its own stack and together with the register +values it determines the thread execution state</li> +<li>A thread runs in the context of a process and all threads in the +same process share the resources</li> +<li>The kernel schedules threads not processes and user-level threads +(e.g. fibers, coroutines, etc.) are not visible at the kernel level</li> +</ul> +<p>The typical thread implementation is one where the threads is +implemented as a separate data structure which is then linked to the +process data structure. For example, the Windows kernel uses such an +implementation:</p> +<p class="admonition-classic-implementation-windows"> </p> +<img alt="../_images/ditaa-4b5c1874d3924d9716f26d4893a3e4f313bf1c43.png" src="../_images/ditaa-4b5c1874d3924d9716f26d4893a3e4f313bf1c43.png" /> +<p>Linux uses a different implementation for threads. The basic unit is +called a task (hence the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>) and it is used +for both threads and processes. Instead of embedding resources in the +task structure it has pointers to these resources.</p> +<p>Thus, if two threads are the same process will point to the same +resource structure instance. If two threads are in different processes +they will point to different resource structure instances.</p> +<p class="admonition-linux-implementation"> </p> +<img alt="../_images/ditaa-fd771038e88b95def30ae9bd4df0b7bd6b7b3503.png" src="../_images/ditaa-fd771038e88b95def30ae9bd4df0b7bd6b7b3503.png" /> +</div> +<div class="section" id="the-clone-system-call"> +<h3>The clone system call<a class="headerlink" href="#the-clone-system-call" title="Permalink to this headline">¶</a></h3> +<p>In Linux a new thread or process is create with the <code class="xref c c-func docutils literal"><span class="pre">clone()</span></code> +system call. Both the <code class="xref c c-func docutils literal"><span class="pre">fork()</span></code> system call and the +<code class="xref c c-func docutils literal"><span class="pre">pthread_create()</span></code> function uses the <code class="xref c c-func docutils literal"><span class="pre">clone()</span></code> +implementation.</p> +<p>It allows the caller to decide what resources should be shared with +the parent and which should be copied or isolated:</p> +<ul class="admonition-the-clone-system-call simple"> +<li>CLONE_FILES - shares the file descriptor table with the parent</li> +<li>CLONE_VM - shares the address space with the parent</li> +<li>CLONE_FS - shares the filesystem information (root directory, +current directory) with the parent</li> +<li>CLONE_NEWNS - does not share the mount namespace with the parent</li> +<li>CLONE_NEWIPC - does not share the IPC namespace (System V IPC +objects, POSIX message queues) with the parent</li> +<li>CLONE_NEWNET - does not share the networking namespaces (network +interfaces, routing table) with the parent</li> +</ul> +<p>For example, if <cite>CLONE_FILES | CLONE_VM | CLONE_FS</cite> is used by the +caller then effectively a new thread is created. If these flags are +not used then a new process is created.</p> +</div> +<div class="section" id="namespaces-and-containers"> +<h3>Namespaces and "containers"<a class="headerlink" href="#namespaces-and-containers" title="Permalink to this headline">¶</a></h3> +<p>"Containers" are a form of lightweight virtual machines that share the +same kernel instance, as opposed to normal virtualization where a +hypervisor runs multiple VMs, each with its one kernel +instance.</p> +<p>Examples of container technologies are LXC - that allows running +lightweight "VM" and docker - a specialized container for running a +single application.</p> +<p>Containers are built on top of a few kernel features, one of which is +namespaces. They allow isolation of different resources that would +otherwise be globally visible. For example, without containers, all +processes would be visible in /proc. With containers, processes in one +container will not be visible (in /proc or be killable) to other +containers.</p> +<p>To achieve this partitioning, the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">nsproxy</span></code> structure +is used to group types of resources that we want to partition. It +currently supports IPC, networking, cgroup, mount, networking, PID, +time namespaces. For example, instead of having a global list for +networking interfaces, the list is part of a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">net</span></code>. The +system initializes with a default namespace (<code class="xref c c-data docutils literal"><span class="pre">init_net</span></code>) and by +default all processes will share this namespace. When a new namespace +is created a new net namespace is created and then new processes can +point to that new namespace instead of the default one.</p> +<span class="admonition-namespaces-and-containers"></span></div> +<div class="section" id="accessing-the-current-process"> +<h3>Accessing the current process<a class="headerlink" href="#accessing-the-current-process" title="Permalink to this headline">¶</a></h3> +<p class="admonition-accessing-the-current-process">Accessing the current process is a frequent operation:</p> +<ul class="simple"> +<li>opening a file needs access to <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>'s +file field</li> +<li>mapping a new file needs access to <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>'s +mm field</li> +<li>Over 90% of the system calls needs to access the current process +structure so it needs to be fast</li> +<li>The <code class="xref c c-macro docutils literal"><span class="pre">current</span></code> macro is available to access to current +process's <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code></li> +</ul> +<p>In order to support fast access in multi processor configurations a +per CPU variable is used to store and retrieve the pointer to the +current <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>:</p> +<p class="admonition-accessing-the-current-process-on-x86"> </p> +<img alt="../_images/ditaa-019489e686a2f60f1594e37458cfcb10320eae0f.png" src="../_images/ditaa-019489e686a2f60f1594e37458cfcb10320eae0f.png" /> +<p>Previously the following sequence was used as the implementation for +the <code class="xref c c-macro docutils literal"><span class="pre">current</span></code> macro:</p> +<div class="admonition-previous-implementation-for-current-x86 highlight-c"><div class="highlight"><pre><span></span>/* how to get the current stack pointer from C */ +register unsigned long current_stack_pointer asm("esp") __attribute_used__; + +/* how to get the thread information struct from C */ +static inline struct thread_info *current_thread_info(void) +{ + return (struct thread_info *)(current_stack_pointer & ~(THREAD_SIZE – 1)); +} + +#define current current_thread_info()->task +</pre></div> +</div> +</div> +<div class="section" id="quiz-previous-implementation-for-current-x86"> +<h3>Quiz: previous implementation for current (x86)<a class="headerlink" href="#quiz-previous-implementation-for-current-x86" title="Permalink to this headline">¶</a></h3> +<p class="admonition-quiz-previous-implementation-for-current-x86">What is the size of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">thread_info</span></code>?</p> +<p>Which of the following are potential valid sizes for +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">thread_info</span></code>: 4095, 4096, 4097?</p> +</div> +</div> +<div class="section" id="context-switching"> +<h2>Context switching<a class="headerlink" href="#context-switching" title="Permalink to this headline">¶</a></h2> +<p>The following diagram shows an overview of the Linux kernel context +switch process:</p> +<img alt="../_images/ditaa-f6b228332baf165f498d8a1bb0bc0bdb91ae50c5.png" class="admonition-overview-the-context-switching-processes" src="../_images/ditaa-f6b228332baf165f498d8a1bb0bc0bdb91ae50c5.png" /> +<p>Note that before a context switch can occur we must do a kernel +transition, either with a system call or with an interrupt. At that +point the user space registers are saved on the kernel stack. At some +point the <code class="xref c c-func docutils literal"><span class="pre">schedule()</span></code> function will be called which can decide +that a context switch must occur from T0 to T1 (e.g. because the +current thread is blocking waiting for an I/O operation to complete or +because it's allocated time slice has expired).</p> +<p>At that point <code class="xref c c-func docutils literal"><span class="pre">context_switch()</span></code> will perform architecture +specific operations and will switch the address space if needed:</p> +<div class="admonition-context-switch highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">__always_inline</span> <span class="k">struct</span> <span class="n">rq</span> <span class="o">*</span> +<span class="nf">context_switch</span><span class="p">(</span><span class="k">struct</span> <span class="n">rq</span> <span class="o">*</span><span class="n">rq</span><span class="p">,</span> <span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">prev</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">next</span><span class="p">,</span> <span class="k">struct</span> <span class="n">rq_flags</span> <span class="o">*</span><span class="n">rf</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">prepare_task_switch</span><span class="p">(</span><span class="n">rq</span><span class="p">,</span> <span class="n">prev</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span> + + <span class="cm">/*</span> +<span class="cm"> * For paravirt, this is coupled with an exit in switch_to to</span> +<span class="cm"> * combine the page table reload and the switch backend into</span> +<span class="cm"> * one hypercall.</span> +<span class="cm"> */</span> + <span class="n">arch_start_context_switch</span><span class="p">(</span><span class="n">prev</span><span class="p">);</span> + + <span class="cm">/*</span> +<span class="cm"> * kernel -> kernel lazy + transfer active</span> +<span class="cm"> * user -> kernel lazy + mmgrab() active</span> +<span class="cm"> *</span> +<span class="cm"> * kernel -> user switch + mmdrop() active</span> +<span class="cm"> * user -> user switch</span> +<span class="cm"> */</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">next</span><span class="o">-></span><span class="n">mm</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// to kernel</span> + <span class="n">enter_lazy_tlb</span><span class="p">(</span><span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span> + + <span class="n">next</span><span class="o">-></span><span class="n">active_mm</span> <span class="o">=</span> <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">;</span> + <span class="k">if</span> <span class="p">(</span><span class="n">prev</span><span class="o">-></span><span class="n">mm</span><span class="p">)</span> <span class="c1">// from user</span> + <span class="n">mmgrab</span><span class="p">(</span><span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">);</span> + <span class="k">else</span> + <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="c1">// to user</span> + <span class="n">membarrier_switch_mm</span><span class="p">(</span><span class="n">rq</span><span class="p">,</span> <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">,</span> <span class="n">next</span><span class="o">-></span><span class="n">mm</span><span class="p">);</span> + <span class="cm">/*</span> +<span class="cm"> * sys_membarrier() requires an smp_mb() between setting</span> +<span class="cm"> * rq->curr / membarrier_switch_mm() and returning to userspace.</span> +<span class="cm"> *</span> +<span class="cm"> * The below provides this either through switch_mm(), or in</span> +<span class="cm"> * case 'prev->active_mm == next->mm' through</span> +<span class="cm"> * finish_task_switch()'s mmdrop().</span> +<span class="cm"> */</span> + <span class="n">switch_mm_irqs_off</span><span class="p">(</span><span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">,</span> <span class="n">next</span><span class="o">-></span><span class="n">mm</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">prev</span><span class="o">-></span><span class="n">mm</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// from kernel</span> + <span class="cm">/* will mmdrop() in finish_task_switch(). */</span> + <span class="n">rq</span><span class="o">-></span><span class="n">prev_mm</span> <span class="o">=</span> <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">;</span> + <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="p">}</span> + <span class="p">}</span> + + <span class="n">rq</span><span class="o">-></span><span class="n">clock_update_flags</span> <span class="o">&=</span> <span class="o">~</span><span class="p">(</span><span class="n">RQCF_ACT_SKIP</span><span class="o">|</span><span class="n">RQCF_REQ_SKIP</span><span class="p">);</span> + + <span class="n">prepare_lock_switch</span><span class="p">(</span><span class="n">rq</span><span class="p">,</span> <span class="n">next</span><span class="p">,</span> <span class="n">rf</span><span class="p">);</span> + + <span class="cm">/* Here we just switch the register state and the stack. */</span> + <span class="n">switch_to</span><span class="p">(</span><span class="n">prev</span><span class="p">,</span> <span class="n">next</span><span class="p">,</span> <span class="n">prev</span><span class="p">);</span> + <span class="n">barrier</span><span class="p">();</span> + + <span class="k">return</span> <span class="n">finish_task_switch</span><span class="p">(</span><span class="n">prev</span><span class="p">);</span> + <span class="p">}</span> +</pre></div> +</div> +<p>Then it will call the architecture specific <code class="xref c c-macro docutils literal"><span class="pre">switch_to</span></code> +implementation to switch the registers state and kernel stack. Note +that registers are saved on stack and that the stack pointer is saved +in the task structure:</p> +<div class="admonition-switch-to highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define switch_to(prev, next, last) \</span> +<span class="cp">do { \</span> +<span class="cp"> ((last) = __switch_to_asm((prev), (next))); \</span> +<span class="cp">} while (0)</span> + + +<span class="cm">/*</span> +<span class="cm"> * %eax: prev task</span> +<span class="cm"> * %edx: next task</span> +<span class="cm"> */</span> +<span class="p">.</span><span class="n">pushsection</span> <span class="p">.</span><span class="n">text</span><span class="p">,</span> <span class="s">"ax"</span> +<span class="n">SYM_CODE_START</span><span class="p">(</span><span class="n">__switch_to_asm</span><span class="p">)</span> + <span class="cm">/*</span> +<span class="cm"> * Save callee-saved registers</span> +<span class="cm"> * This must match the order in struct inactive_task_frame</span> +<span class="cm"> */</span> + <span class="n">pushl</span> <span class="o">%</span><span class="n">ebp</span> + <span class="n">pushl</span> <span class="o">%</span><span class="n">ebx</span> + <span class="n">pushl</span> <span class="o">%</span><span class="n">edi</span> + <span class="n">pushl</span> <span class="o">%</span><span class="n">esi</span> + <span class="cm">/*</span> +<span class="cm"> * Flags are saved to prevent AC leakage. This could go</span> +<span class="cm"> * away if objtool would have 32bit support to verify</span> +<span class="cm"> * the STAC/CLAC correctness.</span> +<span class="cm"> */</span> + <span class="n">pushfl</span> + +<span class="hll"> <span class="cm">/* switch stack */</span> +</span><span class="hll"> <span class="n">movl</span> <span class="o">%</span><span class="n">esp</span><span class="p">,</span> <span class="n">TASK_threadsp</span><span class="p">(</span><span class="o">%</span><span class="n">eax</span><span class="p">)</span> +</span><span class="hll"> <span class="n">movl</span> <span class="n">TASK_threadsp</span><span class="p">(</span><span class="o">%</span><span class="n">edx</span><span class="p">),</span> <span class="o">%</span><span class="n">esp</span> +</span> + <span class="cp">#ifdef CONFIG_STACKPROTECTOR</span> + <span class="n">movl</span> <span class="n">TASK_stack_canary</span><span class="p">(</span><span class="o">%</span><span class="n">edx</span><span class="p">),</span> <span class="o">%</span><span class="n">ebx</span> + <span class="n">movl</span> <span class="o">%</span><span class="n">ebx</span><span class="p">,</span> <span class="n">PER_CPU_VAR</span><span class="p">(</span><span class="n">stack_canary</span><span class="p">)</span><span class="o">+</span><span class="n">stack_canary_offset</span> + <span class="cp">#endif</span> + + <span class="cp">#ifdef CONFIG_RETPOLINE</span> + <span class="cm">/*</span> +<span class="cm"> * When switching from a shallower to a deeper call stack</span> +<span class="cm"> * the RSB may either underflow or use entries populated</span> +<span class="cm"> * with userspace addresses. On CPUs where those concerns</span> +<span class="cm"> * exist, overwrite the RSB with entries which capture</span> +<span class="cm"> * speculative execution to prevent attack.</span> +<span class="cm"> */</span> + <span class="n">FILL_RETURN_BUFFER</span> <span class="o">%</span><span class="n">ebx</span><span class="p">,</span> <span class="n">RSB_CLEAR_LOOPS</span><span class="p">,</span> <span class="n">X86_FEATURE_RSB_CTXSW</span> + <span class="cp">#endif</span> + + <span class="cm">/* Restore flags or the incoming task to restore AC state. */</span> + <span class="n">popfl</span> + <span class="cm">/* restore callee-saved registers */</span> + <span class="n">popl</span> <span class="o">%</span><span class="n">esi</span> + <span class="n">popl</span> <span class="o">%</span><span class="n">edi</span> + <span class="n">popl</span> <span class="o">%</span><span class="n">ebx</span> + <span class="n">popl</span> <span class="o">%</span><span class="n">ebp</span> + +<span class="hll"> <span class="n">jmp</span> <span class="n">__switch_to</span> +</span> <span class="n">SYM_CODE_END</span><span class="p">(</span><span class="n">__switch_to_asm</span><span class="p">)</span> + <span class="p">.</span><span class="n">popsection</span> +</pre></div> +</div> +<p>You can notice that the instruction pointer is not explicitly +saved. It is not needed because:</p> +<blockquote> +<div><ul class="simple"> +<li>a task will always resume in this function</li> +<li>the <code class="xref c c-func docutils literal"><span class="pre">schedule()</span></code> (<code class="xref c c-func docutils literal"><span class="pre">context_switch()</span></code> is always +inlined) caller's return address is saved on the kernel stack</li> +<li>a jmp is used to execute <code class="xref c c-func docutils literal"><span class="pre">__switch_to()</span></code> which is a function +and when it returns it will pop the original (next task) return +address from the stack</li> +</ul> +</div></blockquote> +<p>The following screencast uses the debugger to setup a breaking in +__switch_to_asm and examine the stack during the context switch:</p> +<p class="admonition-inspecting-task-struct"> </p> +<asciinema-player src="../_images/context_switch.cast"></asciinema-player><div class="section" id="quiz-context-switch"> +<h3>Quiz: context switch<a class="headerlink" href="#quiz-context-switch" title="Permalink to this headline">¶</a></h3> +<p class="admonition-quiz-context-switch">We are executing a context switch. Select all of the statements that are true.</p> +<ul class="simple"> +<li>the ESP register is saved in the task structure</li> +<li>the EIP register is saved in the task structure</li> +<li>general registers are saved in the task structure</li> +<li>the ESP register is saved on the stack</li> +<li>the EIP register is saved on the stack</li> +<li>general registers are saved on the stack</li> +</ul> +</div> +</div> +<div class="section" id="blocking-and-waking-up-tasks"> +<h2>Blocking and waking up tasks<a class="headerlink" href="#blocking-and-waking-up-tasks" title="Permalink to this headline">¶</a></h2> +<div class="section" id="task-states"> +<h3>Task states<a class="headerlink" href="#task-states" title="Permalink to this headline">¶</a></h3> +<p>The following diagram shows to the task (threads) states and the +possible transitions between them:</p> +<img alt="../_images/ditaa-0b8cde2be9bbd195ac9dcaeac978a8bbe0d3b805.png" class="admonition-task-states" src="../_images/ditaa-0b8cde2be9bbd195ac9dcaeac978a8bbe0d3b805.png" /> +</div> +<div class="section" id="blocking-the-current-thread"> +<h3>Blocking the current thread<a class="headerlink" href="#blocking-the-current-thread" title="Permalink to this headline">¶</a></h3> +<p>Blocking the current thread is an important operation we need to +perform to implement efficient task scheduling - we want to run other +threads while I/O operations complete.</p> +<p>In order to accomplish this the following operations take place:</p> +<ul class="admonition-blocking-the-current-thread simple"> +<li>Set the current thread state to TASK_UINTERRUPTIBLE or +TASK_INTERRUPTIBLE</li> +<li>Add the task to a waiting queue</li> +<li>Call the scheduler which will pick up a new task from the READY +queue</li> +<li>Do the context switch to the new task</li> +</ul> +<p>Below are some snippets for the <code class="xref c c-macro docutils literal"><span class="pre">wait_event</span></code> +implementation. Note that the waiting queue is a list with some extra +information like a pointer to the task struct.</p> +<p>Also note that a lot of effort is put into making sure no deadlock can +occur between <code class="xref c c-macro docutils literal"><span class="pre">wait_event</span></code> and <code class="xref c c-macro docutils literal"><span class="pre">wake_up</span></code>: the task +is added to the list before checking <code class="xref c c-data docutils literal"><span class="pre">condition</span></code>, signals are +checked before calling <code class="xref c c-func docutils literal"><span class="pre">schedule()</span></code>.</p> +<div class="admonition-wait-event highlight-c"><div class="highlight"><pre><span></span><span class="cm">/**</span> +<span class="cm"> * wait_event - sleep until a condition gets true</span> +<span class="cm"> * @wq_head: the waitqueue to wait on</span> +<span class="cm"> * @condition: a C expression for the event to wait for</span> +<span class="cm"> *</span> +<span class="cm"> * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the</span> +<span class="cm"> * @condition evaluates to true. The @condition is checked each time</span> +<span class="cm"> * the waitqueue @wq_head is woken up.</span> +<span class="cm"> *</span> +<span class="cm"> * wake_up() has to be called after changing any variable that could</span> +<span class="cm"> * change the result of the wait condition.</span> +<span class="cm"> */</span> +<span class="cp">#define wait_event(wq_head, condition) \</span> +<span class="cp">do { \</span> +<span class="cp"> might_sleep(); \</span> +<span class="cp"> if (condition) \</span> +<span class="cp"> break; \</span> +<span class="cp"> __wait_event(wq_head, condition); \</span> +<span class="cp">} while (0)</span> + +<span class="cp">#define __wait_event(wq_head, condition) \</span> +<span class="cp"> (void)___wait_event(wq_head, condition, TASK_UNINTERRUPTIBLE, 0, 0, \</span> +<span class="cp"> schedule())</span> + +<span class="cm">/*</span> +<span class="cm"> * The below macro ___wait_event() has an explicit shadow of the __ret</span> +<span class="cm"> * variable when used from the wait_event_*() macros.</span> +<span class="cm"> *</span> +<span class="cm"> * This is so that both can use the ___wait_cond_timeout() construct</span> +<span class="cm"> * to wrap the condition.</span> +<span class="cm"> *</span> +<span class="cm"> * The type inconsistency of the wait_event_*() __ret variable is also</span> +<span class="cm"> * on purpose; we use long where we can return timeout values and int</span> +<span class="cm"> * otherwise.</span> +<span class="cm"> */</span> +<span class="cp">#define ___wait_event(wq_head, condition, state, exclusive, ret, cmd) \</span> +<span class="cp">({ \</span> +<span class="cp"> __label__ __out; \</span> +<span class="cp"> struct wait_queue_entry __wq_entry; \</span> +<span class="cp"> long __ret = ret; </span><span class="cm">/* explicit shadow */</span><span class="cp"> \</span> +<span class="cp"> \</span> +<span class="cp"> init_wait_entry(&__wq_entry, exclusive ? WQ_FLAG_EXCLUSIVE : 0); \</span> +<span class="cp"> for (;;) { \</span> +<span class="cp"> long __int = prepare_to_wait_event(&wq_head, &__wq_entry, state);\</span> +<span class="cp"> \</span> +<span class="cp"> if (condition) \</span> +<span class="cp"> break; \</span> +<span class="cp"> \</span> +<span class="cp"> if (___wait_is_interruptible(state) && __int) { \</span> +<span class="cp"> __ret = __int; \</span> +<span class="cp"> goto __out; \</span> +<span class="cp"> } \</span> +<span class="cp"> \</span> +<span class="cp"> cmd; \</span> +<span class="cp"> } \</span> +<span class="cp"> finish_wait(&wq_head, &__wq_entry); \</span> +<span class="cp"> __out: __ret; \</span> +<span class="cp"> })</span> + + <span class="kt">void</span> <span class="nf">init_wait_entry</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">,</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">wq_entry</span><span class="o">-></span><span class="n">flags</span> <span class="o">=</span> <span class="n">flags</span><span class="p">;</span> + <span class="n">wq_entry</span><span class="o">-></span><span class="n">private</span> <span class="o">=</span> <span class="n">current</span><span class="p">;</span> + <span class="n">wq_entry</span><span class="o">-></span><span class="n">func</span> <span class="o">=</span> <span class="n">autoremove_wake_function</span><span class="p">;</span> + <span class="n">INIT_LIST_HEAD</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="p">}</span> + + <span class="kt">long</span> <span class="nf">prepare_to_wait_event</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">,</span> <span class="kt">int</span> <span class="n">state</span><span class="p">)</span> + <span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + <span class="kt">long</span> <span class="n">ret</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + + <span class="n">spin_lock_irqsave</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">signal_pending_state</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">current</span><span class="p">))</span> <span class="p">{</span> + <span class="cm">/*</span> +<span class="cm"> * Exclusive waiter must not fail if it was selected by wakeup,</span> +<span class="cm"> * it should "consume" the condition we were waiting for.</span> +<span class="cm"> *</span> +<span class="cm"> * The caller will recheck the condition and return success if</span> +<span class="cm"> * we were already woken up, we can not miss the event because</span> +<span class="cm"> * wakeup locks/unlocks the same wq_head->lock.</span> +<span class="cm"> *</span> +<span class="cm"> * But we need to ensure that set-condition + wakeup after that</span> +<span class="cm"> * can't see us, it should wake up another exclusive waiter if</span> +<span class="cm"> * we fail.</span> +<span class="cm"> */</span> + <span class="n">list_del_init</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="n">ret</span> <span class="o">=</span> <span class="o">-</span><span class="n">ERESTARTSYS</span><span class="p">;</span> + <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">list_empty</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">))</span> <span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_EXCLUSIVE</span><span class="p">)</span> + <span class="n">__add_wait_queue_entry_tail</span><span class="p">(</span><span class="n">wq_head</span><span class="p">,</span> <span class="n">wq_entry</span><span class="p">);</span> + <span class="k">else</span> + <span class="n">__add_wait_queue</span><span class="p">(</span><span class="n">wq_head</span><span class="p">,</span> <span class="n">wq_entry</span><span class="p">);</span> + <span class="p">}</span> + <span class="n">set_current_state</span><span class="p">(</span><span class="n">state</span><span class="p">);</span> + <span class="p">}</span> + <span class="n">spin_unlock_irqrestore</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + + <span class="k">return</span> <span class="n">ret</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">static</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="nf">__add_wait_queue</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">list_add</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">,</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">);</span> + <span class="p">}</span> + + <span class="k">static</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="nf">__add_wait_queue_entry_tail</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">list_add_tail</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">,</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">);</span> + <span class="p">}</span> + + <span class="cm">/**</span> +<span class="cm"> * finish_wait - clean up after waiting in a queue</span> +<span class="cm"> * @wq_head: waitqueue waited on</span> +<span class="cm"> * @wq_entry: wait descriptor</span> +<span class="cm"> *</span> +<span class="cm"> * Sets current thread back to running state and removes</span> +<span class="cm"> * the wait descriptor from the given waitqueue if still</span> +<span class="cm"> * queued.</span> +<span class="cm"> */</span> + <span class="kt">void</span> <span class="nf">finish_wait</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">)</span> + <span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + + <span class="n">__set_current_state</span><span class="p">(</span><span class="n">TASK_RUNNING</span><span class="p">);</span> + <span class="cm">/*</span> +<span class="cm"> * We can check for list emptiness outside the lock</span> +<span class="cm"> * IFF:</span> +<span class="cm"> * - we use the "careful" check that verifies both</span> +<span class="cm"> * the next and prev pointers, so that there cannot</span> +<span class="cm"> * be any half-pending updates in progress on other</span> +<span class="cm"> * CPU's that we haven't seen yet (and that might</span> +<span class="cm"> * still change the stack area.</span> +<span class="cm"> * and</span> +<span class="cm"> * - all other users take the lock (ie we can only</span> +<span class="cm"> * have _one_ other CPU that looks at or modifies</span> +<span class="cm"> * the list).</span> +<span class="cm"> */</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">list_empty_careful</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">))</span> <span class="p">{</span> + <span class="n">spin_lock_irqsave</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="n">list_del_init</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="n">spin_unlock_irqrestore</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="p">}</span> + <span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="waking-up-a-task"> +<h3>Waking up a task<a class="headerlink" href="#waking-up-a-task" title="Permalink to this headline">¶</a></h3> +<p>We can wake-up tasks by using the <code class="xref c c-macro docutils literal"><span class="pre">wake_up</span></code> primitive. The +following high level operations are performed to wake up a task:</p> +<ul class="admonition-waking-up-a-task simple"> +<li>Select a task from the waiting queue</li> +<li>Set the task state to TASK_READY</li> +<li>Insert the task into the scheduler's READY queue</li> +<li>On SMP system this is a complex operation: each processor has its +own queue, queues need to be balanced, CPUs needs to be signaled</li> +</ul> +<div class="admonition-wake-up highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)</span> + +<span class="cm">/**</span> +<span class="cm"> * __wake_up - wake up threads blocked on a waitqueue.</span> +<span class="cm"> * @wq_head: the waitqueue</span> +<span class="cm"> * @mode: which threads</span> +<span class="cm"> * @nr_exclusive: how many wake-one or wake-many threads to wake up</span> +<span class="cm"> * @key: is directly passed to the wakeup function</span> +<span class="cm"> *</span> +<span class="cm"> * If this function wakes up a task, it executes a full memory barrier before</span> +<span class="cm"> * accessing the task state.</span> +<span class="cm"> */</span> +<span class="kt">void</span> <span class="nf">__wake_up</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">mode</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">nr_exclusive</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">__wake_up_common_lock</span><span class="p">(</span><span class="n">wq_head</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">nr_exclusive</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">key</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">__wake_up_common_lock</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">mode</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">nr_exclusive</span><span class="p">,</span> <span class="kt">int</span> <span class="n">wake_flags</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + <span class="n">wait_queue_entry_t</span> <span class="n">bookmark</span><span class="p">;</span> + + <span class="n">bookmark</span><span class="p">.</span><span class="n">flags</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="n">bookmark</span><span class="p">.</span><span class="n">private</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="n">bookmark</span><span class="p">.</span><span class="n">func</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="n">INIT_LIST_HEAD</span><span class="p">(</span><span class="o">&</span><span class="n">bookmark</span><span class="p">.</span><span class="n">entry</span><span class="p">);</span> + + <span class="k">do</span> <span class="p">{</span> + <span class="n">spin_lock_irqsave</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="n">nr_exclusive</span> <span class="o">=</span> <span class="n">__wake_up_common</span><span class="p">(</span><span class="n">wq_head</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">nr_exclusive</span><span class="p">,</span> + <span class="n">wake_flags</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="o">&</span><span class="n">bookmark</span><span class="p">);</span> + <span class="n">spin_unlock_irqrestore</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="n">bookmark</span><span class="p">.</span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_BOOKMARK</span><span class="p">);</span> +<span class="p">}</span> + +<span class="cm">/*</span> +<span class="cm"> * The core wakeup function. Non-exclusive wakeups (nr_exclusive == 0) just</span> +<span class="cm"> * wake everything up. If it's an exclusive wakeup (nr_exclusive == small +ve</span> +<span class="cm"> * number) then we wake all the non-exclusive tasks and one exclusive task.</span> +<span class="cm"> *</span> +<span class="cm"> * There are circumstances in which we can try to wake a task which has already</span> +<span class="cm"> * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns</span> +<span class="cm"> * zero in this (rare) case, and we handle it by continuing to scan the queue.</span> +<span class="cm"> */</span> +<span class="k">static</span> <span class="kt">int</span> <span class="nf">__wake_up_common</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">mode</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">nr_exclusive</span><span class="p">,</span> <span class="kt">int</span> <span class="n">wake_flags</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">,</span> + <span class="n">wait_queue_entry_t</span> <span class="o">*</span><span class="n">bookmark</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">wait_queue_entry_t</span> <span class="o">*</span><span class="n">curr</span><span class="p">,</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">cnt</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + + <span class="n">lockdep_assert_held</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">bookmark</span> <span class="o">&&</span> <span class="p">(</span><span class="n">bookmark</span><span class="o">-></span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_BOOKMARK</span><span class="p">))</span> <span class="p">{</span> + <span class="n">curr</span> <span class="o">=</span> <span class="n">list_next_entry</span><span class="p">(</span><span class="n">bookmark</span><span class="p">,</span> <span class="n">entry</span><span class="p">);</span> + + <span class="n">list_del</span><span class="p">(</span><span class="o">&</span><span class="n">bookmark</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="n">bookmark</span><span class="o">-></span><span class="n">flags</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="p">}</span> <span class="k">else</span> + <span class="n">curr</span> <span class="o">=</span> <span class="n">list_first_entry</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">,</span> <span class="n">wait_queue_entry_t</span><span class="p">,</span> <span class="n">entry</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">&</span><span class="n">curr</span><span class="o">-></span><span class="n">entry</span> <span class="o">==</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">)</span> + <span class="k">return</span> <span class="n">nr_exclusive</span><span class="p">;</span> + + <span class="n">list_for_each_entry_safe_from</span><span class="p">(</span><span class="n">curr</span><span class="p">,</span> <span class="n">next</span><span class="p">,</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">,</span> <span class="n">entry</span><span class="p">)</span> <span class="p">{</span> + <span class="kt">unsigned</span> <span class="n">flags</span> <span class="o">=</span> <span class="n">curr</span><span class="o">-></span><span class="n">flags</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">ret</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_BOOKMARK</span><span class="p">)</span> + <span class="k">continue</span><span class="p">;</span> + + <span class="n">ret</span> <span class="o">=</span> <span class="n">curr</span><span class="o">-></span><span class="n">func</span><span class="p">(</span><span class="n">curr</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">wake_flags</span><span class="p">,</span> <span class="n">key</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">ret</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">break</span><span class="p">;</span> + <span class="k">if</span> <span class="p">(</span><span class="n">ret</span> <span class="o">&&</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_EXCLUSIVE</span><span class="p">)</span> <span class="o">&&</span> <span class="o">!--</span><span class="n">nr_exclusive</span><span class="p">)</span> + <span class="k">break</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">bookmark</span> <span class="o">&&</span> <span class="p">(</span><span class="o">++</span><span class="n">cnt</span> <span class="o">></span> <span class="n">WAITQUEUE_WALK_BREAK_CNT</span><span class="p">)</span> <span class="o">&&</span> + <span class="p">(</span><span class="o">&</span><span class="n">next</span><span class="o">-></span><span class="n">entry</span> <span class="o">!=</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">))</span> <span class="p">{</span> + <span class="n">bookmark</span><span class="o">-></span><span class="n">flags</span> <span class="o">=</span> <span class="n">WQ_FLAG_BOOKMARK</span><span class="p">;</span> + <span class="n">list_add_tail</span><span class="p">(</span><span class="o">&</span><span class="n">bookmark</span><span class="o">-></span><span class="n">entry</span><span class="p">,</span> <span class="o">&</span><span class="n">next</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="k">break</span><span class="p">;</span> + <span class="p">}</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="n">nr_exclusive</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">int</span> <span class="nf">autoremove_wake_function</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">mode</span><span class="p">,</span> <span class="kt">int</span> <span class="n">sync</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">default_wake_function</span><span class="p">(</span><span class="n">wq_entry</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">sync</span><span class="p">,</span> <span class="n">key</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">ret</span><span class="p">)</span> + <span class="n">list_del_init_careful</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + + <span class="k">return</span> <span class="n">ret</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">int</span> <span class="nf">default_wake_function</span><span class="p">(</span><span class="n">wait_queue_entry_t</span> <span class="o">*</span><span class="n">curr</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">mode</span><span class="p">,</span> <span class="kt">int</span> <span class="n">wake_flags</span><span class="p">,</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">WARN_ON_ONCE</span><span class="p">(</span><span class="n">IS_ENABLED</span><span class="p">(</span><span class="n">CONFIG_SCHED_DEBUG</span><span class="p">)</span> <span class="o">&&</span> <span class="n">wake_flags</span> <span class="o">&</span> <span class="o">~</span><span class="n">WF_SYNC</span><span class="p">);</span> + <span class="k">return</span> <span class="n">try_to_wake_up</span><span class="p">(</span><span class="n">curr</span><span class="o">-></span><span class="n">private</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">wake_flags</span><span class="p">);</span> +<span class="p">}</span> + +<span class="cm">/**</span> +<span class="cm"> * try_to_wake_up - wake up a thread</span> +<span class="cm"> * @p: the thread to be awakened</span> +<span class="cm"> * @state: the mask of task states that can be woken</span> +<span class="cm"> * @wake_flags: wake modifier flags (WF_*)</span> +<span class="cm"> *</span> +<span class="cm"> * Conceptually does:</span> +<span class="cm"> *</span> +<span class="cm"> * If (@state & @p->state) @p->state = TASK_RUNNING.</span> +<span class="cm"> *</span> +<span class="cm"> * If the task was not queued/runnable, also place it back on a runqueue.</span> +<span class="cm"> *</span> +<span class="cm"> * This function is atomic against schedule() which would dequeue the task.</span> +<span class="cm"> *</span> +<span class="cm"> * It issues a full memory barrier before accessing @p->state, see the comment</span> +<span class="cm"> * with set_current_state().</span> +<span class="cm"> *</span> +<span class="cm"> * Uses p->pi_lock to serialize against concurrent wake-ups.</span> +<span class="cm"> *</span> +<span class="cm"> * Relies on p->pi_lock stabilizing:</span> +<span class="cm"> * - p->sched_class</span> +<span class="cm"> * - p->cpus_ptr</span> +<span class="cm"> * - p->sched_task_group</span> +<span class="cm"> * in order to do migration, see its use of select_task_rq()/set_task_cpu().</span> +<span class="cm"> *</span> +<span class="cm"> * Tries really hard to only take one task_rq(p)->lock for performance.</span> +<span class="cm"> * Takes rq->lock in:</span> +<span class="cm"> * - ttwu_runnable() -- old rq, unavoidable, see comment there;</span> +<span class="cm"> * - ttwu_queue() -- new rq, for enqueue of the task;</span> +<span class="cm"> * - psi_ttwu_dequeue() -- much sadness :-( accounting will kill us.</span> +<span class="cm"> *</span> +<span class="cm"> * As a consequence we race really badly with just about everything. See the</span> +<span class="cm"> * many memory barriers and their comments for details.</span> +<span class="cm"> *</span> +<span class="cm"> * Return: %true if @p->state changes (an actual wakeup was done),</span> +<span class="cm"> * %false otherwise.</span> +<span class="cm"> */</span> + <span class="k">static</span> <span class="kt">int</span> + <span class="nf">try_to_wake_up</span><span class="p">(</span><span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">p</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">state</span><span class="p">,</span> <span class="kt">int</span> <span class="n">wake_flags</span><span class="p">)</span> + <span class="p">{</span> + <span class="p">...</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="preempting-tasks"> +<h2>Preempting tasks<a class="headerlink" href="#preempting-tasks" title="Permalink to this headline">¶</a></h2> +<p>Up until this point we look at how context switches occurs voluntary +between threads. Next we will look at how preemption is handled. We +will start wight the simpler case where the kernel is configured as +non preemptive and then we will move to the preemptive kernel case.</p> +<div class="section" id="non-preemptive-kernel"> +<h3>Non preemptive kernel<a class="headerlink" href="#non-preemptive-kernel" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-non-preemptive-kernel simple"> +<li>At every tick the kernel checks to see if the current process has +its time slice consumed</li> +<li>If that happens a flag is set in interrupt context</li> +<li>Before returning to userspace the kernel checks this flag and +calls <code class="xref c c-func docutils literal"><span class="pre">schedule()</span></code> if needed</li> +<li>In this case tasks are not preempted while running in kernel mode +(e.g. system call) so there are no synchronization issues</li> +</ul> +</div> +<div class="section" id="preemptive-kernel"> +<h3>Preemptive kernel<a class="headerlink" href="#preemptive-kernel" title="Permalink to this headline">¶</a></h3> +<p>In this case the current task can be preempted even if we are running +in kernel mode and executing a system call. This requires using a +special synchronization primitives: <code class="xref c c-macro docutils literal"><span class="pre">preempt_disable</span></code> and +<code class="xref c c-macro docutils literal"><span class="pre">preempt_enable</span></code>.</p> +<p>In order to simplify handling for preemptive kernels and since +synchronization primitives are needed for the SMP case anyway, +preemption is disabled automatically when a spinlock is used.</p> +<p>As before, if we run into a condition that requires the preemption of +the current task (its time slices has expired) a flag is set. This +flag is checked whenever the preemption is reactivated, e.g. when +exiting a critical section through a <code class="xref c c-func docutils literal"><span class="pre">spin_unlock()</span></code> and if +needed the scheduler is called to select a new task.</p> +<span class="admonition-preemptive-kernel"></span></div> +</div> +<div class="section" id="process-context"> +<h2>Process context<a class="headerlink" href="#process-context" title="Permalink to this headline">¶</a></h2> +<p>Now that we have examined the implementation of processes and threads +(tasks), how context switching occurs, how we can block, wake-up and +preempt tasks, we can finally define what the process context is what +are its properties:</p> +<p class="admonition-process-context">The kernel is executing in process context when it is running a +system call.</p> +<p>In process context there is a well defined context and we can +access the current process data with <code class="xref c c-macro docutils literal"><span class="pre">current</span></code></p> +<p>In process context we can sleep (wait on a condition).</p> +<p>In process context we can access the user-space (unless we are +running in a kernel thread context).</p> +<div class="section" id="kernel-threads"> +<h3>Kernel threads<a class="headerlink" href="#kernel-threads" title="Permalink to this headline">¶</a></h3> +<p class="admonition-kernel-threads">Sometimes the kernel core or device drivers need to perform blocking +operations and thus they need to run in process context.</p> +<p>Kernel threads are used exactly for this and are a special class of +tasks that don't "userspace" resources (e.g. no address space or +opened files).</p> +<p>The following screencast takes a closer look at kernel threads:</p> +<p class="admonition-inspecting-kernel-threads"> </p> +<asciinema-player src="../_images/kernel_threads.cast"></asciinema-player></div> +</div> +<div class="section" id="using-gdb-scripts-for-kernel-inspection"> +<h2>Using gdb scripts for kernel inspection<a class="headerlink" href="#using-gdb-scripts-for-kernel-inspection" title="Permalink to this headline">¶</a></h2> +<p>The Linux kernel comes with a predefined set of gdb extra commands we +can use to inspect the kernel during debugging. They will +automatically be loaded as long gdbinit is properly setup</p> +<div class="highlight-sh"><div class="highlight"><pre><span></span>ubuntu@so2:/linux/tools/labs$ cat ~/.gdbinit +add-auto-load-safe-path /linux/scripts/gdb/vmlinux-gdb.py +</pre></div> +</div> +<p>All of the kernel specific commands are prefixed with lx-. You can use +TAB in gdb to list all of them:</p> +<div class="highlight-sh"><div class="highlight"><pre><span></span><span class="o">(</span>gdb<span class="o">)</span> lx- +lx-clk-summary lx-dmesg lx-mounts +lx-cmdline lx-fdtdump lx-ps +lx-configdump lx-genpd-summary lx-symbols +lx-cpus lx-iomem lx-timerlist +lx-device-list-bus lx-ioports lx-version +lx-device-list-class lx-list-check +lx-device-list-tree lx-lsmod +</pre></div> +</div> +<p>The implementation of the commands can be found at +<cite>script/gdb/linux</cite>. Lets take a closer look at the lx-ps +implementation:</p> +<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">task_type</span> <span class="o">=</span> <span class="n">utils</span><span class="o">.</span><span class="n">CachedType</span><span class="p">(</span><span class="s2">"struct task_struct"</span><span class="p">)</span> + + +<span class="k">def</span> <span class="nf">task_lists</span><span class="p">():</span> + <span class="n">task_ptr_type</span> <span class="o">=</span> <span class="n">task_type</span><span class="o">.</span><span class="n">get_type</span><span class="p">()</span><span class="o">.</span><span class="n">pointer</span><span class="p">()</span> + <span class="n">init_task</span> <span class="o">=</span> <span class="n">gdb</span><span class="o">.</span><span class="n">parse_and_eval</span><span class="p">(</span><span class="s2">"init_task"</span><span class="p">)</span><span class="o">.</span><span class="n">address</span> + <span class="n">t</span> <span class="o">=</span> <span class="n">g</span> <span class="o">=</span> <span class="n">init_task</span> + + <span class="k">while</span> <span class="bp">True</span><span class="p">:</span> + <span class="k">while</span> <span class="bp">True</span><span class="p">:</span> + <span class="k">yield</span> <span class="n">t</span> + + <span class="n">t</span> <span class="o">=</span> <span class="n">utils</span><span class="o">.</span><span class="n">container_of</span><span class="p">(</span><span class="n">t</span><span class="p">[</span><span class="s1">'thread_group'</span><span class="p">][</span><span class="s1">'next'</span><span class="p">],</span> + <span class="n">task_ptr_type</span><span class="p">,</span> <span class="s2">"thread_group"</span><span class="p">)</span> + <span class="k">if</span> <span class="n">t</span> <span class="o">==</span> <span class="n">g</span><span class="p">:</span> + <span class="k">break</span> + + <span class="n">t</span> <span class="o">=</span> <span class="n">g</span> <span class="o">=</span> <span class="n">utils</span><span class="o">.</span><span class="n">container_of</span><span class="p">(</span><span class="n">g</span><span class="p">[</span><span class="s1">'tasks'</span><span class="p">][</span><span class="s1">'next'</span><span class="p">],</span> + <span class="n">task_ptr_type</span><span class="p">,</span> <span class="s2">"tasks"</span><span class="p">)</span> + <span class="k">if</span> <span class="n">t</span> <span class="o">==</span> <span class="n">init_task</span><span class="p">:</span> + <span class="k">return</span> + + + <span class="k">class</span> <span class="nc">LxPs</span><span class="p">(</span><span class="n">gdb</span><span class="o">.</span><span class="n">Command</span><span class="p">):</span> + <span class="sd">"""Dump Linux tasks."""</span> + + <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="nb">super</span><span class="p">(</span><span class="n">LxPs</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="s2">"lx-ps"</span><span class="p">,</span> <span class="n">gdb</span><span class="o">.</span><span class="n">COMMAND_DATA</span><span class="p">)</span> + + <span class="k">def</span> <span class="nf">invoke</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">arg</span><span class="p">,</span> <span class="n">from_tty</span><span class="p">):</span> + <span class="n">gdb</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">"{:>10} {:>12} {:>7}</span><span class="se">\n</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">"TASK"</span><span class="p">,</span> <span class="s2">"PID"</span><span class="p">,</span> <span class="s2">"COMM"</span><span class="p">))</span> + <span class="k">for</span> <span class="n">task</span> <span class="ow">in</span> <span class="n">task_lists</span><span class="p">():</span> + <span class="n">gdb</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">"{} {:^5} {}</span><span class="se">\n</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span> + <span class="n">task</span><span class="o">.</span><span class="n">format_string</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">()[</span><span class="mi">0</span><span class="p">],</span> + <span class="n">task</span><span class="p">[</span><span class="s2">"pid"</span><span class="p">]</span><span class="o">.</span><span class="n">format_string</span><span class="p">(),</span> + <span class="n">task</span><span class="p">[</span><span class="s2">"comm"</span><span class="p">]</span><span class="o">.</span><span class="n">string</span><span class="p">()))</span> +</pre></div> +</div> +<div class="section" id="quiz-kernel-gdb-scripts"> +<h3>Quiz: Kernel gdb scripts<a class="headerlink" href="#quiz-kernel-gdb-scripts" title="Permalink to this headline">¶</a></h3> +<p class="admonition-quiz-kernel-gdb-scripts">What is the following change of the lx-ps script trying to +accomplish?</p> +<div class="highlight-diff"><div class="highlight"><pre><span></span><span class="gh">diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py</span> +<span class="gh">index 17ec19e9b5bf..7e43c163832f 100644</span> +<span class="gd">--- a/scripts/gdb/linux/tasks.py</span> +<span class="gi">+++ b/scripts/gdb/linux/tasks.py</span> +<span class="gu">@@ -75,10 +75,13 @@ class LxPs(gdb.Command):</span> + def invoke(self, arg, from_tty): + gdb.write("{:>10} {:>12} {:>7}\n".format("TASK", "PID", "COMM")) + for task in task_lists(): +<span class="gd">- gdb.write("{} {:^5} {}\n".format(</span> +<span class="gi">+ check = task["mm"].format_string() == "0x0"</span> +<span class="gi">+ gdb.write("{} {:^5} {}{}{}\n".format(</span> + task.format_string().split()[0], + task["pid"].format_string(), +<span class="gd">- task["comm"].string()))</span> +<span class="gi">+ "[" if check else "",</span> +<span class="gi">+ task["comm"].string(),</span> +<span class="gi">+ "]" if check else ""))</span> + + + LxPs() +</pre></div> +</div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="syscalls.html" class="btn btn-neutral float-left" title="System Calls" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="interrupts.html" class="btn btn-neutral float-right" title="Interrupts" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/smp-slides.html b/refs/pull/405/merge/lectures/smp-slides.html new file mode 100644 index 00000000..7c6e375c --- /dev/null +++ b/refs/pull/405/merge/lectures/smp-slides.html @@ -0,0 +1,811 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Symmetric Multi-Processing — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="next" title="Address Space" href="address-space.html" /> + <link rel="prev" title="Interrupts" href="interrupts.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-symmetric-multi-processing slide level-2"> + +<h2>Symmetric Multi-Processing</h2> + +<ul class="simple"> +<li>Kernel Concurrency</li> +<li>Atomic operations</li> +<li>Spin locks</li> +<li>Cache thrashing</li> +<li>Optimized spin locks</li> +<li>Process and Interrupt Context Synchronization</li> +<li>Mutexes</li> +<li>Per CPU data</li> +<li>Memory Ordering and Barriers</li> +<li>Read-Copy Update</li> +</ul> + + + + +</article> +<article class="admonition-race-conditions slide level-2"> + +<h2>Race conditions</h2> + +<ul class="simple"> +<li>there are at least two execution contexts that run in "parallel":<ul> +<li>truly run in parallel (e.g. two system calls running on +different processors)</li> +<li>one of the contexts can arbitrary preempt the other (e.g. an +interrupt preempts a system call)</li> +</ul> +</li> +<li>the execution contexts perform read-write accesses to shared +memory</li> +</ul> + + + + +</article> +<article class="admonition-race-condition-resource-counter-release slide level-2"> + +<h2>Race condition: resource counter release</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">release_resource</span><span class="p">()</span> +<span class="p">{</span> + <span class="n">counter</span><span class="o">--</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">counter</span><span class="p">)</span> + <span class="n">free_resource</span><span class="p">();</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-race-condition-scenario slide level-2"> + +<h2>Race condition scenario</h2> + +<p> </p> +<img alt="../_images/ditaa-35f7597b35b83bb0025ac2a5f158c9eae23050c8.png" src="../_images/ditaa-35f7597b35b83bb0025ac2a5f158c9eae23050c8.png" /> + + + + +</article> +<article class="admonition-avoiding-race-conditions slide level-2"> + +<h2>Avoiding race conditions</h2> + +<ul class="simple"> +<li>make the critical section <strong>atomic</strong> (e.g. use atomic +instructions)</li> +<li><strong>disable preemption</strong> during the critical section (e.g. disable +interrupts, bottom-half handlers, or thread preemption)</li> +<li><strong>serialize the access</strong> to the critical section (e.g. use spin +locks or mutexes to allow only one context or thread in the +critical section)</li> +</ul> + + + + +</article> +<article class="admonition-linux-kernel-concurrency-sources slide level-2"> + +<h2>Linux kernel concurrency sources</h2> + +<ul class="simple"> +<li><strong>single core systems</strong>, <strong>non-preemptive kernel</strong>: the current +process can be preempted by interrupts</li> +<li><strong>single core systems</strong>, <strong>preemptive kernel</strong>: above + the +current process can be preempted by other processes</li> +<li><strong>multi-core systems</strong>: above + the current process can run +in parallel with another process or with an interrupt running on +another processor</li> +</ul> + + + + +</article> +<article class="admonition-atomic-operations slide level-2"> + +<h2>Atomic operations</h2> + +<ul class="simple"> +<li>integer based:<ul> +<li>simple: <code class="xref c c-func docutils literal"><span class="pre">atomic_inc()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">atomic_dec()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">atomic_add()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">atomic_sub()</span></code></li> +<li>conditional: <code class="xref c c-func docutils literal"><span class="pre">atomic_dec_and_test()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">atomic_sub_and_test()</span></code></li> +</ul> +</li> +<li>bit based:<ul> +<li>simple: <code class="xref c c-func docutils literal"><span class="pre">test_bit()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">set_bit()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">change_bit()</span></code></li> +<li>conditional: <code class="xref c c-func docutils literal"><span class="pre">test_and_set_bit()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">test_and_clear_bit()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">test_and_change_bit()</span></code></li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-using-c-func-atomic-dec-and-test-to-implement-resource-counter-release slide level-2"> + +<h2>Using <code class="xref c c-func docutils literal"><span class="pre">atomic_dec_and_test()</span></code> to implement resource counter release</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">release_resource</span><span class="p">()</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">atomic_dec_and_test</span><span class="p">(</span><span class="o">&</span><span class="n">counter</span><span class="p">))</span> + <span class="n">free_resource</span><span class="p">();</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-atomic-operations-may-not-be-atomic-on-smp-systems slide level-2"> + +<h2>Atomic operations may not be atomic on SMP systems</h2> + +<p> </p> +<img alt="../_images/ditaa-ddd14be50300088958e86912bc5f396797634a3a.png" src="../_images/ditaa-ddd14be50300088958e86912bc5f396797634a3a.png" /> + + + + +</article> +<article class="admonition-fixing-atomic-operations-for-smp-systems-x86 slide level-2"> + +<h2>Fixing atomic operations for SMP systems (x86)</h2> + +<p> </p> +<img alt="../_images/ditaa-c11fccb956cdf115910f9f72e1dc14cd7ed549ff.png" src="../_images/ditaa-c11fccb956cdf115910f9f72e1dc14cd7ed549ff.png" /> + + + + +</article> +<article class="admonition-synchronization-with-interrupts-x86 slide level-2"> + +<h2>Synchronization with interrupts (x86)</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span> <span class="cp">#define local_irq_disable() \</span> +<span class="cp"> asm volatile („cli” : : : „memory”)</span> + +<span class="cp">#define local_irq_enable() \</span> +<span class="cp"> asm volatile („sti” : : : „memory”)</span> + +<span class="cp">#define local_irq_save(flags) \</span> +<span class="cp"> asm volatile ("pushf ; pop %0" :"=g" (flags)</span> + <span class="o">:</span> <span class="cm">/* no input */</span><span class="o">:</span> <span class="s">"memory"</span><span class="p">)</span> \ + <span class="k">asm</span> <span class="k">volatile</span><span class="p">(</span><span class="s">"cli"</span><span class="o">:</span> <span class="o">:</span> <span class="o">:</span><span class="s">"memory"</span><span class="p">)</span> + +<span class="cp">#define local_irq_restore(flags) \</span> +<span class="cp"> asm volatile ("push %0 ; popf"</span> + <span class="o">:</span> <span class="cm">/* no output */</span> + <span class="o">:</span> <span class="s">"g"</span> <span class="p">(</span><span class="n">flags</span><span class="p">)</span> <span class="o">:</span><span class="s">"memory"</span><span class="p">,</span> <span class="s">"cc"</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-spin-lock-implementation-example-x86 slide level-2"> + +<h2>Spin Lock Implementation Example (x86)</h2> + +<div class="highlight-asm"><div class="highlight"><pre><span></span>spin_lock: + lock bts [my_lock], 0 + jc spin_lock + +/* critical section */ + +spin_unlock: + mov [my_lock], 0 +</pre></div> +</div> +<p><strong>bts dts, src</strong> - bit test and set; it copies the src bit from the dts +memory address to the carry flag and then sets it:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">CF</span> <span class="o"><-</span> <span class="n">dts</span><span class="p">[</span><span class="n">src</span><span class="p">]</span> +<span class="n">dts</span><span class="p">[</span><span class="n">src</span><span class="p">]</span> <span class="o"><-</span> <span class="mi">1</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-lock-contention slide level-2"> + +<h2>Lock Contention</h2> + +<ul class="simple"> +<li>There is lock contention when at least one core spins trying to +enter the critical section lock</li> +<li>Lock contention grows with the critical section size, time spent +in the critical section and the number of cores in the system</li> +</ul> + + + + +</article> +<article class="admonition-cache-thrashing slide level-2"> + +<h2>Cache Thrashing</h2> + +<p>Cache thrashing occurs when multiple cores are trying to read and +write to the same memory resulting in excessive cache misses.</p> +<p>Since spin locks continuously access memory during lock contention, +cache thrashing is a common occurrence due to the way cache +coherency is implemented.</p> + + + + +</article> +<article class="admonition-synchronized-caches-and-memory slide level-2"> + +<h2>Synchronized caches and memory</h2> + +<p> </p> +<img alt="../_images/ditaa-4d63c157487ff8291f2a6e93fe680ec38c1a3212.png" src="../_images/ditaa-4d63c157487ff8291f2a6e93fe680ec38c1a3212.png" /> + + + + +</article> +<article class="admonition-unsynchronized-caches-and-memory slide level-2"> + +<h2>Unsynchronized caches and memory</h2> + +<p> </p> +<img alt="../_images/ditaa-7ee0f9bb5f5af586e043afd47cfbad0adcc34888.png" src="../_images/ditaa-7ee0f9bb5f5af586e043afd47cfbad0adcc34888.png" /> + + + + +</article> +<article class="admonition-cache-coherency-protocols slide level-2"> + +<h2>Cache Coherency Protocols</h2> + +<ul class="simple"> +<li>Bus snooping (sniffing) based: memory bus transactions are +monitored by caches and they take actions to preserve +coherency</li> +<li>Directory based: there is a separate entity (directory) that +maintains the state of caches; caches interact with directory +to preserve coherency</li> +</ul> +<p>Bus snooping is simpler but it performs poorly when the number of +cores goes beyond 32-64.</p> +<p>Directory based cache coherence protocols scale much better (up +to thousands of cores) and are usually used in NUMA systems.</p> + + + + +</article> +<article class="admonition-mesi-cache-coherence-protocol slide level-2"> + +<h2>MESI Cache Coherence Protocol</h2> + +<ul class="simple"> +<li>Caching policy: write back</li> +<li>Cache line states<ul> +<li>Modified: owned by a single core and dirty</li> +<li>Exclusive: owned by a single core and clean</li> +<li>Shared: shared between multiple cores and clean</li> +<li>Invalid : the line is not cached</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-mesi-state-transitions slide level-2"> + +<h2>MESI State Transitions</h2> + +<ul class="simple"> +<li>Invalid -> Exclusive: read request, all other cores have the line +in Invalid; line loaded from memory</li> +<li>Invalid -> Shared: read request, at least one core has the line +in Shared or Exclusive; line loaded from sibling cache</li> +<li>Invalid/Shared/Exclusive -> Modified: write request; <strong>all +other</strong> cores <strong>invalidate</strong> the line</li> +<li>Modified -> Invalid: write request from other core; line is +flushed to memory</li> +</ul> + + + + +</article> +<article class="admonition-cache-thrashing-due-to-spin-lock-contention slide level-2"> + +<h2>Cache thrashing due to spin lock contention</h2> + +<p> </p> +<img alt="../_images/ditaa-b26d802c286bda6c559b4dcfa8a7fb27f840463e.png" src="../_images/ditaa-b26d802c286bda6c559b4dcfa8a7fb27f840463e.png" /> + + + + +</article> +<article class="admonition-optimized-spin-lock-keacquirespinlock slide level-2"> + +<h2>Optimized spin lock (KeAcquireSpinLock)</h2> + +<p> </p> +<div class="highlight-asm"><div class="highlight"><pre><span></span><span class="nl">spin_lock:</span> + <span class="na">rep</span> <span class="c">; nop</span> + <span class="nf">test</span> <span class="no">lock_addr</span><span class="p">,</span> <span class="mi">1</span> + <span class="nf">jnz</span> <span class="no">spin_lock</span> + <span class="na">lock</span> <span class="nf">bts</span> <span class="no">lock_addr</span> + <span class="nf">jc</span> <span class="no">spin_lock</span> +</pre></div> +</div> +<ul class="simple"> +<li>we first test the lock read only, using a non atomic +instructions, to avoid writes and thus invalidate operations +while we spin</li> +<li>only when the lock <em>might</em> be free, we try to acquire it</li> +</ul> + + + + +</article> +<article class="admonition-queued-spin-locks slide level-2"> + +<h2>Queued Spin Locks</h2> + +<p> </p> +<img alt="../_images/ditaa-58545831034f050660727be99cede213bc4a53c7.png" src="../_images/ditaa-58545831034f050660727be99cede213bc4a53c7.png" /> + + + + +</article> +<article class="admonition-process-and-interrupt-handler-synchronization-deadlock slide level-2"> + +<h2>Process and Interrupt Handler Synchronization Deadlock</h2> + +<ul class="simple"> +<li>In the process context we take the spin lock</li> +<li>An interrupt occurs and it is scheduled on the same CPU core</li> +<li>The interrupt handler runs and tries to take the spin lock</li> +<li>The current CPU will deadlock</li> +</ul> + + + + +</article> +<article class="admonition-interrupt-synchronization-for-smp slide level-2"> + +<h2>Interrupt Synchronization for SMP</h2> + +<ul class="simple"> +<li>In process context: disable interrupts and acquire a spin lock; +this will protect both against interrupt or other CPU cores race +conditions (<code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_lock_restore()</span></code> combine the two operations)</li> +<li>In interrupt context: take a spin lock; this will will protect +against race conditions with other interrupt handlers or process +context running on different processors</li> +</ul> + + + + +</article> +<article class="admonition-bottom-half-synchronization-for-smp slide level-2"> + +<h2>Bottom-Half Synchronization for SMP</h2> + +<ul class="simple"> +<li>In process context use <code class="xref c c-func docutils literal"><span class="pre">spin_lock_bh()</span></code> (which combines +<code class="xref c c-func docutils literal"><span class="pre">local_bh_disable()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">spin_lock()</span></code>) and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock_bh()</span></code> (which combines <code class="xref c c-func docutils literal"><span class="pre">spin_unlock()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">local_bh_enable()</span></code>)</li> +<li>In bottom half context use: <code class="xref c c-func docutils literal"><span class="pre">spin_lock()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock()</span></code> (or <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqrestore()</span></code> if sharing data with interrupt +handlers)</li> +</ul> + + + + +</article> +<article class="admonition-preemption slide level-2"> + +<h2>Preemption</h2> + +<p> </p> +<p>Preemption is configurable: when active it provides better latency +and response time, while when deactivated it provides better +throughput.</p> +<p>Preemption is disabled by spin locks and mutexes but it can be +manually disabled as well (by core kernel code).</p> + + + + +</article> +<article class="admonition-preemption-and-bottom-half-masking slide level-2"> + +<h2>Preemption and Bottom-Half Masking</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define PREEMPT_BITS 8</span> +<span class="cp">#define SOFTIRQ_BITS 8</span> +<span class="cp">#define HARDIRQ_BITS 4</span> +<span class="cp">#define NMI_BITS 1</span> + +<span class="cp">#define preempt_disable() preempt_count_inc()</span> + +<span class="cp">#define local_bh_disable() add_preempt_count(SOFTIRQ_OFFSET)</span> + +<span class="cp">#define local_bh_enable() sub_preempt_count(SOFTIRQ_OFFSET)</span> + +<span class="cp">#define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK))</span> + +<span class="cp">#define in_interrupt() irq_count()</span> + +<span class="n">asmlinkage</span> <span class="kt">void</span> <span class="nf">do_softirq</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">in_interrupt</span><span class="p">())</span> <span class="k">return</span><span class="p">;</span> + <span class="p">...</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-mutexes slide level-2"> + +<h2>Mutexes</h2> + +<ul class="simple"> +<li>They don't "waste" CPU cycles; system throughput is better than +spin locks if context switch overhead is lower than medium +spinning time</li> +<li>They can't be used in interrupt context</li> +<li>They have a higher latency than spin locks</li> +</ul> + + + + +</article> +<article class="admonition-c-func-mutex-lock-fast-path slide level-2"> + +<h2><code class="xref c c-func docutils literal"><span class="pre">mutex_lock()</span></code> fast path</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="n">__sched</span> <span class="nf">mutex_lock</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">might_sleep</span><span class="p">();</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">__mutex_trylock_fast</span><span class="p">(</span><span class="n">lock</span><span class="p">))</span> + <span class="n">__mutex_lock_slowpath</span><span class="p">(</span><span class="n">lock</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="n">__always_inline</span> <span class="kt">bool</span> <span class="nf">__mutex_trylock_fast</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">curr</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)</span><span class="n">current</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">atomic_long_cmpxchg_acquire</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">owner</span><span class="p">,</span> <span class="mi">0UL</span><span class="p">,</span> <span class="n">curr</span><span class="p">))</span> + <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> + + <span class="k">return</span> <span class="nb">false</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-c-func-mutex-lock-slow-path slide level-2"> + +<h2><code class="xref c c-func docutils literal"><span class="pre">mutex_lock()</span></code> slow path</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="p">...</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="p">...</span> + <span class="cm">/* add waiting tasks to the end of the waitqueue (FIFO): */</span> + <span class="n">list_add_tail</span><span class="p">(</span><span class="o">&</span><span class="n">waiter</span><span class="p">.</span><span class="n">list</span><span class="p">,</span> <span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_list</span><span class="p">);</span> +<span class="p">...</span> + <span class="n">waiter</span><span class="p">.</span><span class="n">task</span> <span class="o">=</span> <span class="n">current</span><span class="p">;</span> +<span class="p">...</span> + <span class="k">for</span> <span class="p">(;;)</span> <span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">__mutex_trylock</span><span class="p">(</span><span class="n">lock</span><span class="p">))</span> + <span class="k">goto</span> <span class="n">acquired</span><span class="p">;</span> + <span class="p">...</span> + <span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> + <span class="p">...</span> + <span class="n">set_current_state</span><span class="p">(</span><span class="n">state</span><span class="p">);</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> + <span class="p">}</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="nl">acquired</span><span class="p">:</span> + <span class="n">__set_current_state</span><span class="p">(</span><span class="n">TASK_RUNNING</span><span class="p">);</span> + <span class="n">mutex_remove_waiter</span><span class="p">(</span><span class="n">lock</span><span class="p">,</span> <span class="o">&</span><span class="n">waiter</span><span class="p">,</span> <span class="n">current</span><span class="p">);</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="p">...</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-c-func-mutex-unlock-fast-path slide level-2"> + +<h2><code class="xref c c-func docutils literal"><span class="pre">mutex_unlock()</span></code> fast path</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="n">__sched</span> <span class="nf">mutex_unlock</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">__mutex_unlock_fast</span><span class="p">(</span><span class="n">lock</span><span class="p">))</span> + <span class="k">return</span><span class="p">;</span> + <span class="n">__mutex_unlock_slowpath</span><span class="p">(</span><span class="n">lock</span><span class="p">,</span> <span class="n">_RET_IP_</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="n">__always_inline</span> <span class="kt">bool</span> <span class="nf">__mutex_unlock_fast</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">curr</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)</span><span class="n">current</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">atomic_long_cmpxchg_release</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">owner</span><span class="p">,</span> <span class="n">curr</span><span class="p">,</span> <span class="mi">0UL</span><span class="p">)</span> <span class="o">==</span> <span class="n">curr</span><span class="p">)</span> + <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> + + <span class="k">return</span> <span class="nb">false</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">void</span> <span class="nf">__mutex_lock_slowpath</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> +<span class="p">...</span> + <span class="k">if</span> <span class="p">(</span><span class="n">__mutex_waiter_is_first</span><span class="p">(</span><span class="n">lock</span><span class="p">,</span> <span class="o">&</span><span class="n">waiter</span><span class="p">))</span> + <span class="n">__mutex_set_flag</span><span class="p">(</span><span class="n">lock</span><span class="p">,</span> <span class="n">MUTEX_FLAG_WAITERS</span><span class="p">);</span> +<span class="p">...</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-c-func-mutex-unlock-slow-path slide level-2"> + +<h2><code class="xref c c-func docutils literal"><span class="pre">mutex_unlock()</span></code> slow path</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="p">...</span> +<span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">list_empty</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_list</span><span class="p">))</span> <span class="p">{</span> + <span class="cm">/* get the first entry from the wait-list: */</span> + <span class="k">struct</span> <span class="n">mutex_waiter</span> <span class="o">*</span><span class="n">waiter</span><span class="p">;</span> + <span class="n">waiter</span> <span class="o">=</span> <span class="n">list_first_entry</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_list</span><span class="p">,</span> <span class="k">struct</span> <span class="n">mutex_waiter</span><span class="p">,</span> + <span class="n">list</span><span class="p">);</span> + <span class="n">next</span> <span class="o">=</span> <span class="n">waiter</span><span class="o">-></span><span class="n">task</span><span class="p">;</span> + <span class="n">wake_q_add</span><span class="p">(</span><span class="o">&</span><span class="n">wake_q</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span> +<span class="p">}</span> +<span class="p">...</span> +<span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="p">...</span> +<span class="n">wake_up_q</span><span class="p">(</span><span class="o">&</span><span class="n">wake_q</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-per-cpu-data slide level-2"> + +<h2>Per CPU data</h2> + +<ul class="simple"> +<li>No need to synchronize to access the data</li> +<li>No contention, no performance impact</li> +<li>Well suited for distributed processing where aggregation is only +seldom necessary (e.g. statistics counters)</li> +</ul> + + + + +</article> +<article class="admonition-out-of-order-compiler-generated-code slide level-2"> + +<h2>Out of Order Compiler Generated Code</h2> + +<table border="1" class="docutils"> +<colgroup> +<col width="43%" /> +<col width="57%" /> +</colgroup> +<tbody valign="top"> +<tr class="row-odd"><td>C code</td> +<td>Compiler generated code</td> +</tr> +<tr class="row-even"><td><div class="first last highlight-c"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> +<span class="n">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> +</pre></div> +</div> +</td> +<td><div class="first last highlight-asm"><div class="highlight"><pre><span></span><span class="nf">MOV</span> <span class="no">R10</span><span class="p">,</span> <span class="mi">1</span> +<span class="nf">MOV</span> <span class="no">R11</span><span class="p">,</span> <span class="mi">2</span> +<span class="nf">STORE</span> <span class="no">R11</span><span class="p">,</span> <span class="no">b</span> +<span class="nf">STORE</span> <span class="no">R10</span><span class="p">,</span> <span class="no">a</span> +</pre></div> +</div> +</td> +</tr> +</tbody> +</table> + + + + +</article> +<article class="admonition-barriers slide level-2"> + +<h2>Barriers</h2> + +<ul class="simple"> +<li>A read barrier (<code class="xref c c-func docutils literal"><span class="pre">rmb()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">smp_rmb()</span></code>) is used to +make sure that no read operation crosses the barrier; that is, +all read operation before the barrier are complete before +executing the first instruction after the barrier</li> +<li>A write barrier (<code class="xref c c-func docutils literal"><span class="pre">wmb()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">smp_wmb()</span></code>) is used to +make sure that no write operation crosses the barrier</li> +<li>A simple barrier (<code class="xref c c-func docutils literal"><span class="pre">mb()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">smp_mb()</span></code>) is used +to make sure that no write or read operation crosses the barrier</li> +</ul> + + + + +</article> +<article class="admonition-read-copy-update-rcu slide level-2"> + +<h2>Read Copy Update (RCU)</h2> + +<ul class="simple"> +<li><strong>Read-only</strong> lock-less access at the same time with write access</li> +<li>Write accesses still requires locks in order to avoid races +between writers</li> +<li>Requires unidirectional traversal by readers</li> +</ul> + + + + +</article> +<article class="admonition-removal-and-reclamation slide level-2"> + +<h2>Removal and Reclamation</h2> + +<ul class="simple"> +<li><strong>Removal</strong>: removes references to elements. Some old readers may +still see the old reference so we can't free the element.</li> +<li><strong>Elimination</strong>: free the element. This action is postponed until +all existing readers finish traversal (quiescent cycle). New +readers won't affect the quiescent cycle.</li> +</ul> + + + + +</article> +<article class="admonition-rcu-list-delete slide level-2"> + +<h2>RCU List Delete</h2> + +<p> </p> +<img alt="../_images/ditaa-5193a924360bebc83d2f81188cd0b0093ec01e6a.png" src="../_images/ditaa-5193a924360bebc83d2f81188cd0b0093ec01e6a.png" /> + + + + +</article> +<article class="admonition-rcu-list-apis-cheat-sheet slide level-2"> + +<h2>RCU list APIs cheat sheet</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* list traversal */</span> +<span class="n">rcu_read_lock</span><span class="p">();</span> +<span class="n">list_for_each_entry_rcu</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">head</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* no sleeping, blocking calls or context switch allowed */</span> +<span class="p">}</span> +<span class="n">rcu_read_unlock</span><span class="p">();</span> + + +<span class="cm">/* list element delete */</span> +<span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> +<span class="n">list_del_rcu</span><span class="p">(</span><span class="o">&</span><span class="n">node</span><span class="o">-></span><span class="n">list</span><span class="p">);</span> +<span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> +<span class="n">synchronize_rcu</span><span class="p">();</span> +<span class="n">kfree</span><span class="p">(</span><span class="n">node</span><span class="p">);</span> + +<span class="cm">/* list element add */</span> +<span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> +<span class="n">list_add_rcu</span><span class="p">(</span><span class="n">head</span><span class="p">,</span> <span class="o">&</span><span class="n">node</span><span class="o">-></span><span class="n">list</span><span class="p">);</span> +<span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/smp.html b/refs/pull/405/merge/lectures/smp.html new file mode 100644 index 00000000..b640966b --- /dev/null +++ b/refs/pull/405/merge/lectures/smp.html @@ -0,0 +1,884 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Symmetric Multi-Processing — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Address Space" href="address-space.html" /> + <link rel="prev" title="Interrupts" href="interrupts.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">Interrupts</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Symmetric Multi-Processing</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="#synchronization-basics">Synchronization basics</a></li> +<li class="toctree-l2"><a class="reference internal" href="#linux-kernel-concurrency-sources">Linux kernel concurrency sources</a></li> +<li class="toctree-l2"><a class="reference internal" href="#atomic-operations">Atomic operations</a></li> +<li class="toctree-l2"><a class="reference internal" href="#disabling-preemption-interrupts">Disabling preemption (interrupts)</a></li> +<li class="toctree-l2"><a class="reference internal" href="#spin-locks">Spin Locks</a></li> +<li class="toctree-l2"><a class="reference internal" href="#cache-coherency-in-multi-processor-systems">Cache coherency in multi-processor systems</a></li> +<li class="toctree-l2"><a class="reference internal" href="#optimized-spin-locks">Optimized spin locks</a></li> +<li class="toctree-l2"><a class="reference internal" href="#process-and-interrupt-context-synchronization">Process and Interrupt Context Synchronization</a></li> +<li class="toctree-l2"><a class="reference internal" href="#mutexes">Mutexes</a></li> +<li class="toctree-l2"><a class="reference internal" href="#per-cpu-data">Per CPU data</a></li> +<li class="toctree-l2"><a class="reference internal" href="#memory-ordering-and-barriers">Memory Ordering and Barriers</a></li> +<li class="toctree-l2"><a class="reference internal" href="#read-copy-update-rcu">Read Copy Update (RCU)</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Symmetric Multi-Processing</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/lectures/smp.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="symmetric-multi-processing"> +<h1>Symmetric Multi-Processing<a class="headerlink" href="#symmetric-multi-processing" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="smp-slides.html">View slides</a></p> +<div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-symmetric-multi-processing simple"> +<li>Kernel Concurrency</li> +<li>Atomic operations</li> +<li>Spin locks</li> +<li>Cache thrashing</li> +<li>Optimized spin locks</li> +<li>Process and Interrupt Context Synchronization</li> +<li>Mutexes</li> +<li>Per CPU data</li> +<li>Memory Ordering and Barriers</li> +<li>Read-Copy Update</li> +</ul> +</div> +<div class="section" id="synchronization-basics"> +<h2>Synchronization basics<a class="headerlink" href="#synchronization-basics" title="Permalink to this headline">¶</a></h2> +<p>Because the Linux kernel supports symmetric multi-processing (SMP) it +must use a set of synchronization mechanisms to achieve predictable +results, free of race conditions.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">We will use the terms core, CPU and processor as +interchangeable for the purpose of this lecture.</p> +</div> +<p>Race conditions can occur when the following two conditions happen +simultaneously:</p> +<ul class="admonition-race-conditions simple"> +<li>there are at least two execution contexts that run in "parallel":<ul> +<li>truly run in parallel (e.g. two system calls running on +different processors)</li> +<li>one of the contexts can arbitrary preempt the other (e.g. an +interrupt preempts a system call)</li> +</ul> +</li> +<li>the execution contexts perform read-write accesses to shared +memory</li> +</ul> +<p>Race conditions can lead to erroneous results that are hard to debug, +because they manifest only when the execution contexts are scheduled +on the CPU cores in a very specific order.</p> +<p>A classical race condition example is an incorrect implementation for +a release operation of a resource counter:</p> +<div class="admonition-race-condition-resource-counter-release highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">release_resource</span><span class="p">()</span> +<span class="p">{</span> + <span class="n">counter</span><span class="o">--</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">counter</span><span class="p">)</span> + <span class="n">free_resource</span><span class="p">();</span> +<span class="p">}</span> +</pre></div> +</div> +<p>A resource counter is used to keep a shared resource available until +the last user releases it but the above implementation has a race +condition that can cause freeing the resource twice:</p> +<p class="admonition-race-condition-scenario"> </p> +<img alt="../_images/ditaa-35f7597b35b83bb0025ac2a5f158c9eae23050c8.png" src="../_images/ditaa-35f7597b35b83bb0025ac2a5f158c9eae23050c8.png" /> +<p>In most cases the <cite>release_resource()</cite> function will only free the +resource once. However, in the scenario above, if thread A is +preempted right after decrementing <cite>counter</cite> and thread B calls +<cite>release_resource()</cite> it will cause the resource to be freed. When +resumed, thread A will also free the resource since the counter value +is 0.</p> +<p>To avoid race conditions the programmer must first identify the +critical section that can generate a race condition. The critical +section is the part of the code that reads and writes shared memory +from multiple parallel contexts.</p> +<p>In the example above, the minimal critical section is starting with +the counter decrement and ending with checking the counter's value.</p> +<p>Once the critical section has been identified race conditions can be +avoided by using one of the following approaches:</p> +<ul class="admonition-avoiding-race-conditions simple"> +<li>make the critical section <strong>atomic</strong> (e.g. use atomic +instructions)</li> +<li><strong>disable preemption</strong> during the critical section (e.g. disable +interrupts, bottom-half handlers, or thread preemption)</li> +<li><strong>serialize the access</strong> to the critical section (e.g. use spin +locks or mutexes to allow only one context or thread in the +critical section)</li> +</ul> +</div> +<div class="section" id="linux-kernel-concurrency-sources"> +<h2>Linux kernel concurrency sources<a class="headerlink" href="#linux-kernel-concurrency-sources" title="Permalink to this headline">¶</a></h2> +<p>There are multiple source of concurrency in the Linux kernel that +depend on the kernel configuration as well as the type of system it +runs on:</p> +<ul class="admonition-linux-kernel-concurrency-sources simple"> +<li><strong>single core systems</strong>, <strong>non-preemptive kernel</strong>: the current +process can be preempted by interrupts</li> +<li><strong>single core systems</strong>, <strong>preemptive kernel</strong>: above + the +current process can be preempted by other processes</li> +<li><strong>multi-core systems</strong>: above + the current process can run +in parallel with another process or with an interrupt running on +another processor</li> +</ul> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">We only discuss kernel concurrency and that is why a +non-preemptive kernel running on an single core system +has interrupts as the only source of concurrency.</p> +</div> +</div> +<div class="section" id="atomic-operations"> +<h2>Atomic operations<a class="headerlink" href="#atomic-operations" title="Permalink to this headline">¶</a></h2> +<p>In certain circumstances we can avoid race conditions by using atomic +operations that are provided by hardware. Linux provides a unified API +to access atomic operations:</p> +<ul class="admonition-atomic-operations simple"> +<li>integer based:<ul> +<li>simple: <code class="xref c c-func docutils literal"><span class="pre">atomic_inc()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">atomic_dec()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">atomic_add()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">atomic_sub()</span></code></li> +<li>conditional: <code class="xref c c-func docutils literal"><span class="pre">atomic_dec_and_test()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">atomic_sub_and_test()</span></code></li> +</ul> +</li> +<li>bit based:<ul> +<li>simple: <code class="xref c c-func docutils literal"><span class="pre">test_bit()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">set_bit()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">change_bit()</span></code></li> +<li>conditional: <code class="xref c c-func docutils literal"><span class="pre">test_and_set_bit()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">test_and_clear_bit()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">test_and_change_bit()</span></code></li> +</ul> +</li> +</ul> +<p>For example, we could use <code class="xref c c-func docutils literal"><span class="pre">atomic_dec_and_test()</span></code> to implement +the resource counter decrement and value checking atomic:</p> +<div class="admonition-using-c-func-atomic-dec-and-test-to-implement-resource-counter-release highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">release_resource</span><span class="p">()</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">atomic_dec_and_test</span><span class="p">(</span><span class="o">&</span><span class="n">counter</span><span class="p">))</span> + <span class="n">free_resource</span><span class="p">();</span> +<span class="p">}</span> +</pre></div> +</div> +<p>One complication with atomic operations is encountered in +multi-core systems, where an atomic operation is not longer +atomic at the system level (but still atomic at the core level).</p> +<p>To understand why, we need to decompose the atomic operation in memory +loads and stores. Then we can construct race condition scenarios where +the load and store operations are interleaved across CPUs, like in the +example below where incrementing a value from two processors will +produce an unexpected result:</p> +<p class="admonition-atomic-operations-may-not-be-atomic-on-smp-systems"> </p> +<img alt="../_images/ditaa-ddd14be50300088958e86912bc5f396797634a3a.png" src="../_images/ditaa-ddd14be50300088958e86912bc5f396797634a3a.png" /> +<p>In order to provide atomic operations on SMP systems different +architectures use different techniques. For example, on x86 a LOCK +prefix is used to lock the system bus while executing the prefixed +operation:</p> +<p class="admonition-fixing-atomic-operations-for-smp-systems-x86"> </p> +<img alt="../_images/ditaa-c11fccb956cdf115910f9f72e1dc14cd7ed549ff.png" src="../_images/ditaa-c11fccb956cdf115910f9f72e1dc14cd7ed549ff.png" /> +<p>On ARM the LDREX and STREX instructions are used together to guarantee +atomic access: LDREX loads a value and signals the exclusive monitor +that an atomic operation is in progress. The STREX attempts to store a +new value but only succeeds if the exclusive monitor has not detected +other exclusive operations. So, to implement atomic operations the +programmer must retry the operation (both LDREX and STREX) until the +exclusive monitor signals a success.</p> +<p>Although they are often interpreted as "light" or "efficient" +synchronization mechanisms (because they "don't require spinning or +context switches", or because they "are implemented in hardware so +they must be more efficient", or because they "are just instructions +so they must have similar efficiency as other instructions"), as seen +from the implementation details, atomic operations are actually +expensive.</p> +</div> +<div class="section" id="disabling-preemption-interrupts"> +<h2>Disabling preemption (interrupts)<a class="headerlink" href="#disabling-preemption-interrupts" title="Permalink to this headline">¶</a></h2> +<p>On single core systems and non preemptive kernels the only source of +concurrency is the preemption of the current thread by an +interrupt. To prevent concurrency is thus sufficient to disable +interrupts.</p> +<p>This is done with architecture specific instructions, but Linux offers +architecture independent APIs to disable and enable interrupts:</p> +<div class="admonition-synchronization-with-interrupts-x86 highlight-c"><div class="highlight"><pre><span></span> <span class="cp">#define local_irq_disable() \</span> +<span class="cp"> asm volatile („cli” : : : „memory”)</span> + +<span class="cp">#define local_irq_enable() \</span> +<span class="cp"> asm volatile („sti” : : : „memory”)</span> + +<span class="cp">#define local_irq_save(flags) \</span> +<span class="cp"> asm volatile ("pushf ; pop %0" :"=g" (flags)</span> + <span class="o">:</span> <span class="cm">/* no input */</span><span class="o">:</span> <span class="s">"memory"</span><span class="p">)</span> \ + <span class="k">asm</span> <span class="k">volatile</span><span class="p">(</span><span class="s">"cli"</span><span class="o">:</span> <span class="o">:</span> <span class="o">:</span><span class="s">"memory"</span><span class="p">)</span> + +<span class="cp">#define local_irq_restore(flags) \</span> +<span class="cp"> asm volatile ("push %0 ; popf"</span> + <span class="o">:</span> <span class="cm">/* no output */</span> + <span class="o">:</span> <span class="s">"g"</span> <span class="p">(</span><span class="n">flags</span><span class="p">)</span> <span class="o">:</span><span class="s">"memory"</span><span class="p">,</span> <span class="s">"cc"</span><span class="p">);</span> +</pre></div> +</div> +<p>Although the interrupts can be explicitly disabled and enable with +<code class="xref c c-func docutils literal"><span class="pre">local_irq_disable()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">local_irq_enable()</span></code> these APIs +should only be used when the current state and interrupts is +known. They are usually used in core kernel code (like interrupt +handling).</p> +<p>For typical cases where we want to avoid interrupts due to concurrency +issues it is recommended to use the <code class="xref c c-func docutils literal"><span class="pre">local_irq_save()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">local_irq_restore()</span></code> variants. They take care of saving and +restoring the interrupts states so they can be freely called from +overlapping critical sections without the risk of accidentally +enabling interrupts while still in a critical section, as long as the +calls are balanced.</p> +</div> +<div class="section" id="spin-locks"> +<h2>Spin Locks<a class="headerlink" href="#spin-locks" title="Permalink to this headline">¶</a></h2> +<p>Spin locks are used to serialize access to a critical section. They +are necessary on multi-core systems where we can have true execution +parallelism. This is a typical spin lock implementation:</p> +<div class="admonition-spin-lock-implementation-example-x86 highlight-asm"><div class="highlight"><pre><span></span>spin_lock: + lock bts [my_lock], 0 + jc spin_lock + +/* critical section */ + +spin_unlock: + mov [my_lock], 0 +</pre></div> +</div> +<p><strong>bts dts, src</strong> - bit test and set; it copies the src bit from the dts +memory address to the carry flag and then sets it:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">CF</span> <span class="o"><-</span> <span class="n">dts</span><span class="p">[</span><span class="n">src</span><span class="p">]</span> +<span class="n">dts</span><span class="p">[</span><span class="n">src</span><span class="p">]</span> <span class="o"><-</span> <span class="mi">1</span> +</pre></div> +</div> +<p>As it can be seen, the spin lock uses an atomic instruction to make +sure that only one core can enter the critical section. If there are +multiple cores trying to enter they will continuously "spin" until the +lock is released.</p> +<p>While the spin lock avoids race conditions, it can have a significant +impact on the system's performance due to "lock contention":</p> +<ul class="admonition-lock-contention simple"> +<li>There is lock contention when at least one core spins trying to +enter the critical section lock</li> +<li>Lock contention grows with the critical section size, time spent +in the critical section and the number of cores in the system</li> +</ul> +<p>Another negative side effect of spin locks is cache thrashing.</p> +<p class="admonition-cache-thrashing">Cache thrashing occurs when multiple cores are trying to read and +write to the same memory resulting in excessive cache misses.</p> +<p>Since spin locks continuously access memory during lock contention, +cache thrashing is a common occurrence due to the way cache +coherency is implemented.</p> +</div> +<div class="section" id="cache-coherency-in-multi-processor-systems"> +<h2>Cache coherency in multi-processor systems<a class="headerlink" href="#cache-coherency-in-multi-processor-systems" title="Permalink to this headline">¶</a></h2> +<p>The memory hierarchy in multi-processor systems is composed of local +CPU caches (L1 caches), shared CPU caches (L2 caches) and the main +memory. To explain cache coherency we will ignore the L2 cache and +only consider the L1 caches and main memory.</p> +<p>In the figure below we present a view of the memory hierarchy with two +variables A and B that fall into different cache lines and where +caches and the main memory are synchronized:</p> +<p class="admonition-synchronized-caches-and-memory"> </p> +<img alt="../_images/ditaa-4d63c157487ff8291f2a6e93fe680ec38c1a3212.png" src="../_images/ditaa-4d63c157487ff8291f2a6e93fe680ec38c1a3212.png" /> +<p>In the absence of a synchronization mechanism between the caches and +main memory, when CPU 0 executes <cite>A = A + B</cite> and CPU 1 executes <cite>B = +A + B</cite> we will have the following memory view:</p> +<p class="admonition-unsynchronized-caches-and-memory"> </p> +<img alt="../_images/ditaa-7ee0f9bb5f5af586e043afd47cfbad0adcc34888.png" src="../_images/ditaa-7ee0f9bb5f5af586e043afd47cfbad0adcc34888.png" /> +<p>In order to avoid the situation above multi-processor systems use +cache coherency protocols. There are two main types of cache coherency +protocols:</p> +<ul class="admonition-cache-coherency-protocols simple"> +<li>Bus snooping (sniffing) based: memory bus transactions are +monitored by caches and they take actions to preserve +coherency</li> +<li>Directory based: there is a separate entity (directory) that +maintains the state of caches; caches interact with directory +to preserve coherency</li> +</ul> +<p>Bus snooping is simpler but it performs poorly when the number of +cores goes beyond 32-64.</p> +<p>Directory based cache coherence protocols scale much better (up +to thousands of cores) and are usually used in NUMA systems.</p> +<p>A simple cache coherency protocol that is commonly used in practice is +MESI (named after the acronym of the cache line states names: +<strong>Modified</strong>, <strong>Exclusive</strong>, <strong>Shared</strong> and <strong>Invalid</strong>). It's main +characteristics are:</p> +<ul class="admonition-mesi-cache-coherence-protocol simple"> +<li>Caching policy: write back</li> +<li>Cache line states<ul> +<li>Modified: owned by a single core and dirty</li> +<li>Exclusive: owned by a single core and clean</li> +<li>Shared: shared between multiple cores and clean</li> +<li>Invalid : the line is not cached</li> +</ul> +</li> +</ul> +<p>Issuing read or write requests from CPU cores will trigger state +transitions, as exemplified below:</p> +<ul class="admonition-mesi-state-transitions simple"> +<li>Invalid -> Exclusive: read request, all other cores have the line +in Invalid; line loaded from memory</li> +<li>Invalid -> Shared: read request, at least one core has the line +in Shared or Exclusive; line loaded from sibling cache</li> +<li>Invalid/Shared/Exclusive -> Modified: write request; <strong>all +other</strong> cores <strong>invalidate</strong> the line</li> +<li>Modified -> Invalid: write request from other core; line is +flushed to memory</li> +</ul> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The most important characteristic of the MESI protocol is +that it is a write-invalidate cache protocol. When writing to a +shared location all other caches are invalidated.</p> +</div> +<p>This has important performance impact in certain access patterns, and +one such pattern is contention for a simple spin lock implementation +like we discussed above.</p> +<p>To exemplify this issue lets consider a system with three CPU cores, +where the first has acquired the spin lock and it is running the +critical section while the other two are spinning waiting to enter the +critical section:</p> +<p class="admonition-cache-thrashing-due-to-spin-lock-contention"> </p> +<img alt="../_images/ditaa-b26d802c286bda6c559b4dcfa8a7fb27f840463e.png" src="../_images/ditaa-b26d802c286bda6c559b4dcfa8a7fb27f840463e.png" /> +<p>As it can be seen from the figure above due to the writes issued by +the cores spinning on the lock we see frequent cache line invalidate +operations which means that basically the two waiting cores will flush +and load the cache line while waiting for the lock, creating +unnecessary traffic on the memory bus and slowing down memory accesses +for the first core.</p> +<p>Another issue is that most likely data accessed by the first CPU +during the critical section is stored in the same cache line with the +lock (common optimization to have the data ready in the cache after +the lock is acquired). Which means that the cache invalidation +triggered by the two other spinning cores will slow down the execution +of the critical section which in turn triggers more cache invalidate +actions.</p> +</div> +<div class="section" id="optimized-spin-locks"> +<h2>Optimized spin locks<a class="headerlink" href="#optimized-spin-locks" title="Permalink to this headline">¶</a></h2> +<p>As we have seen simple spin lock implementations can have poor +performance issues due to cache thrashing, especially as the number of +cores increase. To avoid this issue there are two possible strategies:</p> +<ul class="simple"> +<li>reduce the number of writes and thus reduce the number of cache +invalidate operations</li> +<li>avoid the other processors spinning on the same cache line, and thus +avoid the cache invalidate operations</li> +</ul> +<p>An optimized spin lock implementation that uses the first approach is +presented below:</p> +<p class="admonition-optimized-spin-lock-keacquirespinlock"> </p> +<div class="highlight-asm"><div class="highlight"><pre><span></span><span class="nl">spin_lock:</span> + <span class="na">rep</span> <span class="c">; nop</span> + <span class="nf">test</span> <span class="no">lock_addr</span><span class="p">,</span> <span class="mi">1</span> + <span class="nf">jnz</span> <span class="no">spin_lock</span> + <span class="na">lock</span> <span class="nf">bts</span> <span class="no">lock_addr</span> + <span class="nf">jc</span> <span class="no">spin_lock</span> +</pre></div> +</div> +<ul class="simple"> +<li>we first test the lock read only, using a non atomic +instructions, to avoid writes and thus invalidate operations +while we spin</li> +<li>only when the lock <em>might</em> be free, we try to acquire it</li> +</ul> +<p>The implementation also use the <strong>PAUSE</strong> instruction to avoid +pipeline flushes due to (false positive) memory order violations and +to add a small delay (proportional with the memory bus frequency) to +reduce power consumption.</p> +<p>A similar implementation with support for fairness (the CPU cores are +allowed in the critical section based on the time of arrival) is used +in the Linux kernel (the <a class="reference external" href="https://lwn.net/Articles/267968/">ticket spin lock</a>) +for many architectures.</p> +<p>However, for the x86 architecture, the current spin lock +implementation uses a queued spin lock where the CPU cores spin on +different locks (hopefully distributed in different cache lines) to +avoid cache invalidation operations:</p> +<p class="admonition-queued-spin-locks"> </p> +<img alt="../_images/ditaa-58545831034f050660727be99cede213bc4a53c7.png" src="../_images/ditaa-58545831034f050660727be99cede213bc4a53c7.png" /> +<p>Conceptually, when a new CPU core tries to acquire the lock and it +fails it will add its private lock to the list of waiting CPU +cores. When the lock owner exits the critical section it unlocks the +next lock in the list, if any.</p> +<p>While a read spin optimized spin lock reduces most of the cache +invalidation operations, the lock owner can still generate cache +invalidate operations due to writes to data structures close to the +lock and thus part of the same cache line. This in turn generates +memory traffic on subsequent reads on the spinning cores.</p> +<p>Hence, queued spin locks scale much better for large number of cores +as is the case for NUMA systems. And since they have similar fairness +properties as the ticket lock it is the preferred implementation on +the x86 architecture.</p> +</div> +<div class="section" id="process-and-interrupt-context-synchronization"> +<h2>Process and Interrupt Context Synchronization<a class="headerlink" href="#process-and-interrupt-context-synchronization" title="Permalink to this headline">¶</a></h2> +<p>Accessing shared data from both process and interrupt context is a +relatively common scenario. On single core systems we can do this by +disabling interrupts, but that won't work on multi-core systems, +as we can have the process running on one CPU core and the interrupt +context running on a different CPU core.</p> +<p>Using a spin lock, which was designed for multi-processor systems, +seems like the right solution, but doing so can cause common +deadlock conditions, as detailed by the following scenario:</p> +<ul class="admonition-process-and-interrupt-handler-synchronization-deadlock simple"> +<li>In the process context we take the spin lock</li> +<li>An interrupt occurs and it is scheduled on the same CPU core</li> +<li>The interrupt handler runs and tries to take the spin lock</li> +<li>The current CPU will deadlock</li> +</ul> +<p>To avoid this issue a two fold approach is used:</p> +<ul class="admonition-interrupt-synchronization-for-smp simple"> +<li>In process context: disable interrupts and acquire a spin lock; +this will protect both against interrupt or other CPU cores race +conditions (<code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_lock_restore()</span></code> combine the two operations)</li> +<li>In interrupt context: take a spin lock; this will will protect +against race conditions with other interrupt handlers or process +context running on different processors</li> +</ul> +<p>We have the same issue for other interrupt context handlers such as +softirqs, tasklets or timers and while disabling interrupts might +work, it is recommended to use dedicated APIs:</p> +<ul class="admonition-bottom-half-synchronization-for-smp simple"> +<li>In process context use <code class="xref c c-func docutils literal"><span class="pre">spin_lock_bh()</span></code> (which combines +<code class="xref c c-func docutils literal"><span class="pre">local_bh_disable()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">spin_lock()</span></code>) and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock_bh()</span></code> (which combines <code class="xref c c-func docutils literal"><span class="pre">spin_unlock()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">local_bh_enable()</span></code>)</li> +<li>In bottom half context use: <code class="xref c c-func docutils literal"><span class="pre">spin_lock()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock()</span></code> (or <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqrestore()</span></code> if sharing data with interrupt +handlers)</li> +</ul> +<p>As mentioned before, another source of concurrency in the Linux kernel +can be other processes, due to preemption.</p> +<p class="admonition-preemption"> </p> +<p>Preemption is configurable: when active it provides better latency +and response time, while when deactivated it provides better +throughput.</p> +<p>Preemption is disabled by spin locks and mutexes but it can be +manually disabled as well (by core kernel code).</p> +<p>As for local interrupt enabling and disabling APIs, the bottom half +and preemption APIs allows them to be used in overlapping critical +sections. A counter is used to track the state of bottom half and +preemption. In fact the same counter is used, with different increment +values:</p> +<div class="admonition-preemption-and-bottom-half-masking highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define PREEMPT_BITS 8</span> +<span class="cp">#define SOFTIRQ_BITS 8</span> +<span class="cp">#define HARDIRQ_BITS 4</span> +<span class="cp">#define NMI_BITS 1</span> + +<span class="cp">#define preempt_disable() preempt_count_inc()</span> + +<span class="cp">#define local_bh_disable() add_preempt_count(SOFTIRQ_OFFSET)</span> + +<span class="cp">#define local_bh_enable() sub_preempt_count(SOFTIRQ_OFFSET)</span> + +<span class="cp">#define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK))</span> + +<span class="cp">#define in_interrupt() irq_count()</span> + +<span class="n">asmlinkage</span> <span class="kt">void</span> <span class="nf">do_softirq</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">in_interrupt</span><span class="p">())</span> <span class="k">return</span><span class="p">;</span> + <span class="p">...</span> +</pre></div> +</div> +</div> +<div class="section" id="mutexes"> +<h2>Mutexes<a class="headerlink" href="#mutexes" title="Permalink to this headline">¶</a></h2> +<p>Mutexes are used to protect against race conditions from other CPU +cores but they can only be used in <strong>process context</strong>. As opposed to +spin locks, while a thread is waiting to enter the critical section it +will not use CPU time, but instead it will be added to a waiting queue +until the critical section is vacated.</p> +<p>Since mutexes and spin locks usage intersect, it is useful to compare +the two:</p> +<ul class="admonition-mutexes simple"> +<li>They don't "waste" CPU cycles; system throughput is better than +spin locks if context switch overhead is lower than medium +spinning time</li> +<li>They can't be used in interrupt context</li> +<li>They have a higher latency than spin locks</li> +</ul> +<p>Conceptually, the <code class="xref c c-func docutils literal"><span class="pre">mutex_lock()</span></code> operation is relatively simple: +if the mutex is not acquired we can take the fast path via an atomic +exchange operation:</p> +<div class="admonition-c-func-mutex-lock-fast-path highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="n">__sched</span> <span class="nf">mutex_lock</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">might_sleep</span><span class="p">();</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">__mutex_trylock_fast</span><span class="p">(</span><span class="n">lock</span><span class="p">))</span> + <span class="n">__mutex_lock_slowpath</span><span class="p">(</span><span class="n">lock</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="n">__always_inline</span> <span class="kt">bool</span> <span class="nf">__mutex_trylock_fast</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">curr</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)</span><span class="n">current</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">atomic_long_cmpxchg_acquire</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">owner</span><span class="p">,</span> <span class="mi">0UL</span><span class="p">,</span> <span class="n">curr</span><span class="p">))</span> + <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> + + <span class="k">return</span> <span class="nb">false</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>otherwise we take the slow path where we add ourselves to the mutex +waiting list and put ourselves to sleep:</p> +<div class="admonition-c-func-mutex-lock-slow-path highlight-c"><div class="highlight"><pre><span></span><span class="p">...</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="p">...</span> + <span class="cm">/* add waiting tasks to the end of the waitqueue (FIFO): */</span> + <span class="n">list_add_tail</span><span class="p">(</span><span class="o">&</span><span class="n">waiter</span><span class="p">.</span><span class="n">list</span><span class="p">,</span> <span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_list</span><span class="p">);</span> +<span class="p">...</span> + <span class="n">waiter</span><span class="p">.</span><span class="n">task</span> <span class="o">=</span> <span class="n">current</span><span class="p">;</span> +<span class="p">...</span> + <span class="k">for</span> <span class="p">(;;)</span> <span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">__mutex_trylock</span><span class="p">(</span><span class="n">lock</span><span class="p">))</span> + <span class="k">goto</span> <span class="n">acquired</span><span class="p">;</span> + <span class="p">...</span> + <span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> + <span class="p">...</span> + <span class="n">set_current_state</span><span class="p">(</span><span class="n">state</span><span class="p">);</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> + <span class="p">}</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="nl">acquired</span><span class="p">:</span> + <span class="n">__set_current_state</span><span class="p">(</span><span class="n">TASK_RUNNING</span><span class="p">);</span> + <span class="n">mutex_remove_waiter</span><span class="p">(</span><span class="n">lock</span><span class="p">,</span> <span class="o">&</span><span class="n">waiter</span><span class="p">,</span> <span class="n">current</span><span class="p">);</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="p">...</span> +</pre></div> +</div> +<p>The full implementation is a bit more complex: instead of going to +sleep immediately it optimistic spinning if it detects that the lock +owner is currently running on a different CPU as chances are the owner +will release the lock soon. It also checks for signals and handles +mutex debugging for locking dependency engine debug feature.</p> +<p>The <code class="xref c c-func docutils literal"><span class="pre">mutex_unlock()</span></code> operation is symmetric: if there are no +waiters on the mutex then we can take the fast path via an atomic exchange +operation:</p> +<div class="admonition-c-func-mutex-unlock-fast-path highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="n">__sched</span> <span class="nf">mutex_unlock</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">__mutex_unlock_fast</span><span class="p">(</span><span class="n">lock</span><span class="p">))</span> + <span class="k">return</span><span class="p">;</span> + <span class="n">__mutex_unlock_slowpath</span><span class="p">(</span><span class="n">lock</span><span class="p">,</span> <span class="n">_RET_IP_</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="n">__always_inline</span> <span class="kt">bool</span> <span class="nf">__mutex_unlock_fast</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">curr</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)</span><span class="n">current</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">atomic_long_cmpxchg_release</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">owner</span><span class="p">,</span> <span class="n">curr</span><span class="p">,</span> <span class="mi">0UL</span><span class="p">)</span> <span class="o">==</span> <span class="n">curr</span><span class="p">)</span> + <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> + + <span class="k">return</span> <span class="nb">false</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">void</span> <span class="nf">__mutex_lock_slowpath</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> +<span class="p">...</span> + <span class="k">if</span> <span class="p">(</span><span class="n">__mutex_waiter_is_first</span><span class="p">(</span><span class="n">lock</span><span class="p">,</span> <span class="o">&</span><span class="n">waiter</span><span class="p">))</span> + <span class="n">__mutex_set_flag</span><span class="p">(</span><span class="n">lock</span><span class="p">,</span> <span class="n">MUTEX_FLAG_WAITERS</span><span class="p">);</span> +<span class="p">...</span> +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Because <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code> is cached aligned the 7 +lower bits of the owner field can be used for various flags, +such as <code class="xref c c-type docutils literal"><span class="pre">MUTEX_FLAG_WAITERS</span></code>.</p> +</div> +<p>Otherwise we take the slow path where we pick up first waiter from the +list and wake it up:</p> +<div class="admonition-c-func-mutex-unlock-slow-path highlight-c"><div class="highlight"><pre><span></span><span class="p">...</span> +<span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">list_empty</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_list</span><span class="p">))</span> <span class="p">{</span> + <span class="cm">/* get the first entry from the wait-list: */</span> + <span class="k">struct</span> <span class="n">mutex_waiter</span> <span class="o">*</span><span class="n">waiter</span><span class="p">;</span> + <span class="n">waiter</span> <span class="o">=</span> <span class="n">list_first_entry</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_list</span><span class="p">,</span> <span class="k">struct</span> <span class="n">mutex_waiter</span><span class="p">,</span> + <span class="n">list</span><span class="p">);</span> + <span class="n">next</span> <span class="o">=</span> <span class="n">waiter</span><span class="o">-></span><span class="n">task</span><span class="p">;</span> + <span class="n">wake_q_add</span><span class="p">(</span><span class="o">&</span><span class="n">wake_q</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span> +<span class="p">}</span> +<span class="p">...</span> +<span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="p">...</span> +<span class="n">wake_up_q</span><span class="p">(</span><span class="o">&</span><span class="n">wake_q</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="per-cpu-data"> +<h2>Per CPU data<a class="headerlink" href="#per-cpu-data" title="Permalink to this headline">¶</a></h2> +<p>Per CPU data avoids race conditions by avoiding to use shared +data. Instead, an array sized to the maximum possible CPU cores is +used and each core will use its own array entry to read and write +data. This approach certainly has advantages:</p> +<ul class="admonition-per-cpu-data simple"> +<li>No need to synchronize to access the data</li> +<li>No contention, no performance impact</li> +<li>Well suited for distributed processing where aggregation is only +seldom necessary (e.g. statistics counters)</li> +</ul> +</div> +<div class="section" id="memory-ordering-and-barriers"> +<h2>Memory Ordering and Barriers<a class="headerlink" href="#memory-ordering-and-barriers" title="Permalink to this headline">¶</a></h2> +<p>Modern processors and compilers employ out-of-order execution to +improve performance. For example, processors can execute "future" +instructions while waiting for current instruction data to be fetched +from memory.</p> +<p>Here is an example of out of order compiler generated code:</p> +<table border="1" class="admonition-out-of-order-compiler-generated-code docutils"> +<colgroup> +<col width="43%" /> +<col width="57%" /> +</colgroup> +<tbody valign="top"> +<tr class="row-odd"><td>C code</td> +<td>Compiler generated code</td> +</tr> +<tr class="row-even"><td><div class="first last highlight-c"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> +<span class="n">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> +</pre></div> +</div> +</td> +<td><div class="first last highlight-asm"><div class="highlight"><pre><span></span><span class="nf">MOV</span> <span class="no">R10</span><span class="p">,</span> <span class="mi">1</span> +<span class="nf">MOV</span> <span class="no">R11</span><span class="p">,</span> <span class="mi">2</span> +<span class="nf">STORE</span> <span class="no">R11</span><span class="p">,</span> <span class="no">b</span> +<span class="nf">STORE</span> <span class="no">R10</span><span class="p">,</span> <span class="no">a</span> +</pre></div> +</div> +</td> +</tr> +</tbody> +</table> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">When executing instructions out of order the processor makes +sure that data dependency is observed, i.e. it won't execute +instructions whose input depend on the output of a previous +instruction that has not been executed.</p> +</div> +<p>In most cases out of order execution is not an issue. However, in +certain situations (e.g. communicating via shared memory between +processors or between processors and hardware) we must issue some +instructions before others even without data dependency between them.</p> +<p>For this purpose we can use barriers to order memory operations:</p> +<ul class="admonition-barriers simple"> +<li>A read barrier (<code class="xref c c-func docutils literal"><span class="pre">rmb()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">smp_rmb()</span></code>) is used to +make sure that no read operation crosses the barrier; that is, +all read operation before the barrier are complete before +executing the first instruction after the barrier</li> +<li>A write barrier (<code class="xref c c-func docutils literal"><span class="pre">wmb()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">smp_wmb()</span></code>) is used to +make sure that no write operation crosses the barrier</li> +<li>A simple barrier (<code class="xref c c-func docutils literal"><span class="pre">mb()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">smp_mb()</span></code>) is used +to make sure that no write or read operation crosses the barrier</li> +</ul> +</div> +<div class="section" id="read-copy-update-rcu"> +<h2>Read Copy Update (RCU)<a class="headerlink" href="#read-copy-update-rcu" title="Permalink to this headline">¶</a></h2> +<p>Read Copy Update is a special synchronization mechanism similar with +read-write locks but with significant improvements over it (and some +limitations):</p> +<ul class="admonition-read-copy-update-rcu simple"> +<li><strong>Read-only</strong> lock-less access at the same time with write access</li> +<li>Write accesses still requires locks in order to avoid races +between writers</li> +<li>Requires unidirectional traversal by readers</li> +</ul> +<p>In fact, the read-write locks in the Linux kernel have been deprecated +and then removed, in favor of RCU.</p> +<p>Implementing RCU for a new data structure is difficult, but a few +common data structures (lists, queues, trees) do have RCU APIs that +can be used.</p> +<p>RCU splits removal updates to the data structures in two phases:</p> +<ul class="admonition-removal-and-reclamation simple"> +<li><strong>Removal</strong>: removes references to elements. Some old readers may +still see the old reference so we can't free the element.</li> +<li><strong>Elimination</strong>: free the element. This action is postponed until +all existing readers finish traversal (quiescent cycle). New +readers won't affect the quiescent cycle.</li> +</ul> +<p>As an example, lets take a look on how to delete an element from a +list using RCU:</p> +<p class="admonition-rcu-list-delete"> </p> +<img alt="../_images/ditaa-5193a924360bebc83d2f81188cd0b0093ec01e6a.png" src="../_images/ditaa-5193a924360bebc83d2f81188cd0b0093ec01e6a.png" /> +<p>In the first step it can be seen that while readers traverse the list +all elements are referenced. In step two a writer removes +element B. Reclamation is postponed since there are still readers that +hold references to it. In step three a quiescent cycle just expired +and it can be noticed that there are no more references to +element B. Other elements still have references from readers that +started the list traversal after the element was removed. In step 4 we +finally perform reclamation (free the element).</p> +<p>Now that we covered how RCU functions at the high level, lets looks at +the APIs for traversing the list as well as adding and removing an +element to the list:</p> +<div class="admonition-rcu-list-apis-cheat-sheet highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* list traversal */</span> +<span class="n">rcu_read_lock</span><span class="p">();</span> +<span class="n">list_for_each_entry_rcu</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">head</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* no sleeping, blocking calls or context switch allowed */</span> +<span class="p">}</span> +<span class="n">rcu_read_unlock</span><span class="p">();</span> + + +<span class="cm">/* list element delete */</span> +<span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> +<span class="n">list_del_rcu</span><span class="p">(</span><span class="o">&</span><span class="n">node</span><span class="o">-></span><span class="n">list</span><span class="p">);</span> +<span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> +<span class="n">synchronize_rcu</span><span class="p">();</span> +<span class="n">kfree</span><span class="p">(</span><span class="n">node</span><span class="p">);</span> + +<span class="cm">/* list element add */</span> +<span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> +<span class="n">list_add_rcu</span><span class="p">(</span><span class="n">head</span><span class="p">,</span> <span class="o">&</span><span class="n">node</span><span class="o">-></span><span class="n">list</span><span class="p">);</span> +<span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> +</pre></div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="interrupts.html" class="btn btn-neutral float-left" title="Interrupts" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="address-space.html" class="btn btn-neutral float-right" title="Address Space" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/syscalls-slides.html b/refs/pull/405/merge/lectures/syscalls-slides.html new file mode 100644 index 00000000..2eab0d73 --- /dev/null +++ b/refs/pull/405/merge/lectures/syscalls-slides.html @@ -0,0 +1,530 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>System Calls — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="next" title="Processes" href="processes.html" /> + <link rel="prev" title="Introduction" href="intro.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-system-calls slide level-2"> + +<h2>System Calls</h2> + +<ul class="simple"> +<li>Linux system calls implementation</li> +<li>VDSO and virtual syscalls</li> +<li>Accessing user space from system calls</li> +</ul> + + + + +</article> +<article class="admonition-system-calls-as-kernel-services slide level-2"> + +<h2>System Calls as Kernel services</h2> + +<p> </p> +<img alt="../_images/ditaa-e76e44cad2e92f2134ab77f6a09605b29524d039.png" src="../_images/ditaa-e76e44cad2e92f2134ab77f6a09605b29524d039.png" /> + + + + +</article> +<article class="admonition-system-call-setup slide level-2"> + +<h2>System Call Setup</h2> + +<ul class="simple"> +<li>setup information to identify the system call and its parameters</li> +<li>trigger a kernel mode switch</li> +<li>retrieve the result of the system call</li> +</ul> + + + + +</article> +<article class="admonition-linux-system-call-setup slide level-2"> + +<h2>Linux system call setup</h2> + +<ul class="simple"> +<li>System calls are identified by numbers</li> +<li>The parameters for system calls are machine word sized (32 or 64 +bit) and they are limited to a maximum of 6</li> +<li>Uses registers to store them both (e.g. for 32bit x86: EAX for +system call and EBX, ECX, EDX, ESI, EDI, EBP for parameters)</li> +</ul> + + + + +</article> +<article class="admonition-example-of-linux-system-call-setup-and-handling slide level-2"> + +<h2>Example of Linux system call setup and handling</h2> + +<img alt="../_images/ditaa-eeb919cd078d0ba5021028fa628bb47d7d6866e2.png" src="../_images/ditaa-eeb919cd078d0ba5021028fa628bb47d7d6866e2.png" /> + + + + +</article> +<article class="admonition-linux-system-call-dispatcher slide level-2"> + +<h2>Linux System Call Dispatcher</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* Handles int $0x80 */</span> +<span class="n">__visible</span> <span class="kt">void</span> <span class="nf">do_int80_syscall_32</span><span class="p">(</span><span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">enter_from_user_mode</span><span class="p">();</span> + <span class="n">local_irq_enable</span><span class="p">();</span> + <span class="n">do_syscall_32_irqs_on</span><span class="p">(</span><span class="n">regs</span><span class="p">);</span> +<span class="p">}</span> + +<span class="cm">/* simplified version of the Linux x86 32bit System Call Dispatcher */</span> +<span class="k">static</span> <span class="n">__always_inline</span> <span class="kt">void</span> <span class="nf">do_syscall_32_irqs_on</span><span class="p">(</span><span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">nr</span> <span class="o">=</span> <span class="n">regs</span><span class="o">-></span><span class="n">orig_ax</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">nr</span> <span class="o"><</span> <span class="n">IA32_NR_syscalls</span><span class="p">)</span> + <span class="n">regs</span><span class="o">-></span><span class="n">ax</span> <span class="o">=</span> <span class="n">ia32_sys_call_table</span><span class="p">[</span><span class="n">nr</span><span class="p">](</span><span class="n">regs</span><span class="o">-></span><span class="n">bx</span><span class="p">,</span> <span class="n">regs</span><span class="o">-></span><span class="n">cx</span><span class="p">,</span> + <span class="n">regs</span><span class="o">-></span><span class="n">dx</span><span class="p">,</span> <span class="n">regs</span><span class="o">-></span><span class="n">si</span><span class="p">,</span> + <span class="n">regs</span><span class="o">-></span><span class="n">di</span><span class="p">,</span> <span class="n">regs</span><span class="o">-></span><span class="n">bp</span><span class="p">);</span> + <span class="n">syscall_return_slowpath</span><span class="p">(</span><span class="n">regs</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-inspecting-dup2-system-call slide level-2"> + +<h2>Inspecting dup2 system call</h2> + +<p> </p> +<asciinema-player src="../_images/syscalls-inspection.cast"></asciinema-player> + + + +</article> +<article class="admonition-system-call-flow-summary slide level-2"> + +<h2>System Call Flow Summary</h2> + +<ul class="simple"> +<li>The application is setting up the system call number and +parameters and it issues a trap instruction</li> +<li>The execution mode switches from user to kernel; the CPU switches +to a kernel stack; the user stack and the return address to user +space is saved on the kernel stack</li> +<li>The kernel entry point saves registers on the kernel stack</li> +<li>The system call dispatcher identifies the system call function +and runs it</li> +<li>The user space registers are restored and execution is switched +back to user (e.g. calling IRET)</li> +<li>The user space application resumes</li> +</ul> + + + + +</article> +<article class="admonition-system-call-table slide level-2"> + +<h2>System Call Table</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define __SYSCALL_I386(nr, sym, qual) [nr] = sym,</span> + +<span class="k">const</span> <span class="n">sys_call_ptr_t</span> <span class="n">ia32_sys_call_table</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">[</span><span class="mi">0</span> <span class="p">...</span> <span class="n">__NR_syscall_compat_max</span><span class="p">]</span> <span class="o">=</span> <span class="o">&</span><span class="n">sys_ni_syscall</span><span class="p">,</span> + <span class="cp">#include</span> <span class="cpf"><asm/syscalls_32.h></span><span class="cp"></span> +<span class="p">};</span> +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">sys_restart_syscall</span><span class="p">)</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">sys_exit</span><span class="p">)</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">sys_fork</span><span class="p">)</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">sys_read</span><span class="p">)</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="n">sys_write</span><span class="p">)</span> +<span class="cp">#ifdef CONFIG_X86_32</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">sys_open</span><span class="p">)</span> +<span class="cp">#else</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">compat_sys_open</span><span class="p">)</span> +<span class="cp">#endif</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">6</span><span class="p">,</span> <span class="n">sys_close</span><span class="p">)</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-system-calls-pointer-parameters slide level-2"> + +<h2>System Calls Pointer Parameters</h2> + +<ul class="simple"> +<li>Never allow pointers to kernel-space</li> +<li>Check for invalid pointers</li> +</ul> + + + + +</article> +<article class="admonition-pointers-to-kernel-space slide level-2"> + +<h2>Pointers to Kernel Space</h2> + +<ul class="simple"> +<li>User access to kernel data if allowed in a write system call</li> +<li>User corrupting kernel data if allowed in a read system call</li> +</ul> + + + + +</article> +<article class="admonition-invalid-pointers-handling-approaches slide level-2"> + +<h2>Invalid pointers handling approaches</h2> + +<ul class="simple"> +<li>Check the pointer against the user address space before using it, +or</li> +<li>Avoid checking the pointer and rely on the MMU to detect when the +pointer is invalid and use the page fault handler to determine +that the pointer was invalid</li> +</ul> + + + + +</article> +<article class="admonition-page-fault-handling slide level-2"> + +<h2>Page fault handling</h2> + +<blockquote> +<div><ul class="simple"> +<li>Copy on write, demand paging, swapping: both the fault and +faulting addresses are in user space; the fault address is +valid (checked against the user address space)</li> +<li>Invalid pointer used in system call: the faulting address is +in kernel space; the fault address is in user space and it is +invalid</li> +<li>Kernel bug (kernel accesses invalid pointer): same as above</li> +</ul> +</div></blockquote> + + + + +</article> +<article class="admonition-marking-kernel-code-that-accesses-user-space slide level-2"> + +<h2>Marking kernel code that accesses user space</h2> + +<ul class="simple"> +<li>The exact instructions that access user space are recorded in a +table (exception table)</li> +<li>When a page fault occurs the faulting address is checked against +this table</li> +</ul> + + + + +</article> +<article class="admonition-cost-analysis-for-pointer-checks-vs-fault-handling slide level-2"> + +<h2>Cost analysis for pointer checks vs fault handling</h2> + +<table border="1" class="docutils"> +<colgroup> +<col width="28%" /> +<col width="35%" /> +<col width="37%" /> +</colgroup> +<thead valign="bottom"> +<tr class="row-odd"><th class="head">Cost</th> +<th class="head">Pointer checks</th> +<th class="head">Fault handling</th> +</tr> +</thead> +<tbody valign="top"> +<tr class="row-even"><td>Valid address</td> +<td>address space search</td> +<td>negligible</td> +</tr> +<tr class="row-odd"><td>Invalid address</td> +<td>address space search</td> +<td>exception table search</td> +</tr> +</tbody> +</table> + + + + +</article> +<article class="admonition-virtual-dynamic-shared-object-vdso slide level-2"> + +<h2>Virtual Dynamic Shared Object (VDSO)</h2> + +<ul class="simple"> +<li>a stream of instructions to issue the system call is generated by +the kernel in a special memory area (formatted as an ELF shared +object)</li> +<li>that memory area is mapped towards the end of the user address +space</li> +<li>libc searches for VDSO and if present will use it to issue the +system call</li> +</ul> + + + + +</article> +<article class="admonition-inspecting-vdso slide level-2"> + +<h2>Inspecting VDSO</h2> + +<p> </p> +<asciinema-player src="../_images/syscalls-vdso.cast"></asciinema-player> + + + +</article> +<article class="admonition-virtual-system-calls-vsyscalls slide level-2"> + +<h2>Virtual System Calls (vsyscalls)</h2> + +<ul class="simple"> +<li>"System calls" that run directly from user space, part of the VDSO</li> +<li>Static data (e.g. getpid())</li> +<li>Dynamic data update by the kernel a in RW map of the VDSO +(e.g. gettimeofday(), time(), )</li> +</ul> + + + + +</article> +<article class="admonition-accessing-user-space-from-system-calls slide level-2"> + +<h2>Accessing user space from system calls</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* OK: return -EFAULT if user_ptr is invalid */</span> +<span class="k">if</span> <span class="p">(</span><span class="n">copy_from_user</span><span class="p">(</span><span class="o">&</span><span class="n">kernel_buffer</span><span class="p">,</span> <span class="n">user_ptr</span><span class="p">,</span> <span class="n">size</span><span class="p">))</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EFAULT</span><span class="p">;</span> + +<span class="cm">/* NOK: only works if user_ptr is valid otherwise crashes kernel */</span> +<span class="n">memcpy</span><span class="p">(</span><span class="o">&</span><span class="n">kernel_buffer</span><span class="p">,</span> <span class="n">user_ptr</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-get-user-implementation slide level-2"> + +<h2>get_user implementation</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define get_user(x, ptr) \</span> +<span class="cp">({ \</span> +<span class="cp"> int __ret_gu; \</span> +<span class="cp"> register __inttype(*(ptr)) __val_gu asm("%"_ASM_DX); \</span> +<span class="cp"> __chk_user_ptr(ptr); \</span> +<span class="cp"> might_fault(); \</span> +<span class="cp"> asm volatile("call __get_user_%P4" \</span> +<span class="cp"> : "=a" (__ret_gu), "=r" (__val_gu), \</span> +<span class="cp"> ASM_CALL_CONSTRAINT \</span> +<span class="cp"> : "0" (ptr), "i" (sizeof(*(ptr)))); \</span> +<span class="cp"> (x) = (__force __typeof__(*(ptr))) __val_gu; \</span> +<span class="cp"> __builtin_expect(__ret_gu, 0); \</span> +<span class="cp">})</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-get-user-pseudo-code slide level-2"> + +<h2>get_user pseudo code</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define get_user(x, ptr) \</span> +<span class="cp"> movl ptr, %eax \</span> +<span class="cp"> call __get_user_1 \</span> +<span class="cp"> movl %edx, x \</span> +<span class="cp"> movl %eax, result \</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-get-user-1-implementation slide level-2"> + +<h2>get_user_1 implementation</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>.text +ENTRY(__get_user_1) + mov PER_CPU_VAR(current_task), %_ASM_DX + cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX + jae bad_get_user + ASM_STAC +1: movzbl (%_ASM_AX),%edx + xor %eax,%eax + ASM_CLAC + ret +ENDPROC(__get_user_1) + +bad_get_user: + xor %edx,%edx + mov $(-EFAULT),%_ASM_AX + ASM_CLAC + ret +END(bad_get_user) + +_ASM_EXTABLE(1b,bad_get_user) +</pre></div> +</div> + + + + +</article> +<article class="admonition-exception-table-entry slide level-2"> + +<h2>Exception table entry</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* Exception table entry */</span> +<span class="cp"># define _ASM_EXTABLE_HANDLE(from, to, handler) \</span> +<span class="cp"> .pushsection "__ex_table","a" ; \</span> +<span class="cp"> .balign 4 ; \</span> +<span class="cp"> .long (from) - . ; \</span> +<span class="cp"> .long (to) - . ; \</span> +<span class="cp"> .long (handler) - . ; \</span> +<span class="cp"> .popsection</span> + +<span class="cp"># define _ASM_EXTABLE(from, to) \</span> +<span class="cp"> _ASM_EXTABLE_HANDLE(from, to, ex_handler_default)</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-exception-table-building slide level-2"> + +<h2>Exception table building</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define EXCEPTION_TABLE(align) \</span> +<span class="cp"> . = ALIGN(align); \</span> +<span class="cp"> __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { \</span> +<span class="cp"> VMLINUX_SYMBOL(__start___ex_table) = .; \</span> +<span class="cp"> KEEP(*(__ex_table)) \</span> +<span class="cp"> VMLINUX_SYMBOL(__stop___ex_table) = .; \</span> +<span class="cp"> }</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-exception-table-handling slide level-2"> + +<h2>Exception table handling</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">bool</span> <span class="nf">ex_handler_default</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">exception_table_entry</span> <span class="o">*</span><span class="n">fixup</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">,</span> <span class="kt">int</span> <span class="n">trapnr</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">regs</span><span class="o">-></span><span class="n">ip</span> <span class="o">=</span> <span class="n">ex_fixup_addr</span><span class="p">(</span><span class="n">fixup</span><span class="p">);</span> + <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">int</span> <span class="nf">fixup_exception</span><span class="p">(</span><span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">,</span> <span class="kt">int</span> <span class="n">trapnr</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">exception_table_entry</span> <span class="o">*</span><span class="n">e</span><span class="p">;</span> + <span class="n">ex_handler_t</span> <span class="n">handler</span><span class="p">;</span> + + <span class="n">e</span> <span class="o">=</span> <span class="n">search_exception_tables</span><span class="p">(</span><span class="n">regs</span><span class="o">-></span><span class="n">ip</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">e</span><span class="p">)</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> + + <span class="n">handler</span> <span class="o">=</span> <span class="n">ex_fixup_handler</span><span class="p">(</span><span class="n">e</span><span class="p">);</span> + <span class="k">return</span> <span class="n">handler</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">regs</span><span class="p">,</span> <span class="n">trapnr</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/syscalls.html b/refs/pull/405/merge/lectures/syscalls.html new file mode 100644 index 00000000..db0b1bac --- /dev/null +++ b/refs/pull/405/merge/lectures/syscalls.html @@ -0,0 +1,542 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>System Calls — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Processes" href="processes.html" /> + <link rel="prev" title="Introduction" href="intro.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="intro.html">Introduction</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">System Calls</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="#linux-system-calls-implementation">Linux system calls implementation</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#system-call-table">System call table</a></li> +<li class="toctree-l3"><a class="reference internal" href="#system-call-parameters-handling">System call parameters handling</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#virtual-dynamic-shared-object-vdso">Virtual Dynamic Shared Object (VDSO)</a></li> +<li class="toctree-l2"><a class="reference internal" href="#accessing-user-space-from-system-calls">Accessing user space from system calls</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">System Calls</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/lectures/syscalls.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="system-calls"> +<h1>System Calls<a class="headerlink" href="#system-calls" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="syscalls-slides.html">View slides</a></p> +<div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-system-calls simple"> +<li>Linux system calls implementation</li> +<li>VDSO and virtual syscalls</li> +<li>Accessing user space from system calls</li> +</ul> +</div> +<div class="section" id="linux-system-calls-implementation"> +<h2>Linux system calls implementation<a class="headerlink" href="#linux-system-calls-implementation" title="Permalink to this headline">¶</a></h2> +<p>At a high level system calls are "services" offered by the kernel to +user applications and they resemble library APIs in that they are +described as a function call with a name, parameters, and return value.</p> +<p class="admonition-system-calls-as-kernel-services"> </p> +<img alt="../_images/ditaa-e76e44cad2e92f2134ab77f6a09605b29524d039.png" src="../_images/ditaa-e76e44cad2e92f2134ab77f6a09605b29524d039.png" /> +<p>However, on a closer look, we can see that system calls are actually +not function calls, but specific assembly instructions (architecture +and kernel specific) that do the following:</p> +<ul class="admonition-system-call-setup simple"> +<li>setup information to identify the system call and its parameters</li> +<li>trigger a kernel mode switch</li> +<li>retrieve the result of the system call</li> +</ul> +<p>In Linux, system calls are identified by numbers and the parameters +for system calls are machine word sized (32 or 64 bit). There can be a +maximum of 6 system call parameters. Both the system call number and +the parameters are stored in certain registers.</p> +<p>For example, on 32bit x86 architecture, the system call identifier is +stored in the EAX register, while parameters in registers EBX, ECX, +EDX, ESI, EDI, EBP.</p> +<span class="admonition-linux-system-call-setup"></span><p>System libraries (e.g. libc) offers functions that implement the +actual system calls in order to make it easier for applications to use +them.</p> +<p>When a user to kernel mode transition occurs, the execution flow is +interrupted and it is transferred to a kernel entry point. This is +similar to how interrupts and exceptions are handled (in fact on some +architectures this transition happens as a result of an exception).</p> +<p>The system call entry point will save registers (which contains values +from user space, including system call number and system call +parameters) on stack and then it will continue with executing the +system call dispatcher.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">During the user - kernel mode transition the stack is also +switched from the user stack to the kernel stack. This is +explained in more details in the interrupts lecture.</p> +</div> +<img alt="../_images/ditaa-eeb919cd078d0ba5021028fa628bb47d7d6866e2.png" class="admonition-example-of-linux-system-call-setup-and-handling" src="../_images/ditaa-eeb919cd078d0ba5021028fa628bb47d7d6866e2.png" /> +<p>The purpose of the system call dispatcher is to verify the system call +number and run the kernel function associated with the system call.</p> +<div class="admonition-linux-system-call-dispatcher highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* Handles int $0x80 */</span> +<span class="n">__visible</span> <span class="kt">void</span> <span class="nf">do_int80_syscall_32</span><span class="p">(</span><span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">enter_from_user_mode</span><span class="p">();</span> + <span class="n">local_irq_enable</span><span class="p">();</span> + <span class="n">do_syscall_32_irqs_on</span><span class="p">(</span><span class="n">regs</span><span class="p">);</span> +<span class="p">}</span> + +<span class="cm">/* simplified version of the Linux x86 32bit System Call Dispatcher */</span> +<span class="k">static</span> <span class="n">__always_inline</span> <span class="kt">void</span> <span class="nf">do_syscall_32_irqs_on</span><span class="p">(</span><span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">nr</span> <span class="o">=</span> <span class="n">regs</span><span class="o">-></span><span class="n">orig_ax</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">nr</span> <span class="o"><</span> <span class="n">IA32_NR_syscalls</span><span class="p">)</span> + <span class="n">regs</span><span class="o">-></span><span class="n">ax</span> <span class="o">=</span> <span class="n">ia32_sys_call_table</span><span class="p">[</span><span class="n">nr</span><span class="p">](</span><span class="n">regs</span><span class="o">-></span><span class="n">bx</span><span class="p">,</span> <span class="n">regs</span><span class="o">-></span><span class="n">cx</span><span class="p">,</span> + <span class="n">regs</span><span class="o">-></span><span class="n">dx</span><span class="p">,</span> <span class="n">regs</span><span class="o">-></span><span class="n">si</span><span class="p">,</span> + <span class="n">regs</span><span class="o">-></span><span class="n">di</span><span class="p">,</span> <span class="n">regs</span><span class="o">-></span><span class="n">bp</span><span class="p">);</span> + <span class="n">syscall_return_slowpath</span><span class="p">(</span><span class="n">regs</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<p>To demonstrate the system call flow we are going to use the virtual +machine setup, attach gdb to a running kernel, add a breakpoint to the +dup2 system call and inspect the state.</p> +<p class="admonition-inspecting-dup2-system-call"> </p> +<asciinema-player src="../_images/syscalls-inspection.cast"></asciinema-player><p>In summary, this is what happens during a system call:</p> +<ul class="admonition-system-call-flow-summary simple"> +<li>The application is setting up the system call number and +parameters and it issues a trap instruction</li> +<li>The execution mode switches from user to kernel; the CPU switches +to a kernel stack; the user stack and the return address to user +space is saved on the kernel stack</li> +<li>The kernel entry point saves registers on the kernel stack</li> +<li>The system call dispatcher identifies the system call function +and runs it</li> +<li>The user space registers are restored and execution is switched +back to user (e.g. calling IRET)</li> +<li>The user space application resumes</li> +</ul> +<div class="section" id="system-call-table"> +<h3>System call table<a class="headerlink" href="#system-call-table" title="Permalink to this headline">¶</a></h3> +<p>The system call table is what the system call dispatcher uses to map +system call numbers to kernel functions:</p> +<div class="admonition-system-call-table highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define __SYSCALL_I386(nr, sym, qual) [nr] = sym,</span> + +<span class="k">const</span> <span class="n">sys_call_ptr_t</span> <span class="n">ia32_sys_call_table</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">[</span><span class="mi">0</span> <span class="p">...</span> <span class="n">__NR_syscall_compat_max</span><span class="p">]</span> <span class="o">=</span> <span class="o">&</span><span class="n">sys_ni_syscall</span><span class="p">,</span> + <span class="cp">#include</span> <span class="cpf"><asm/syscalls_32.h></span><span class="cp"></span> +<span class="p">};</span> +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">sys_restart_syscall</span><span class="p">)</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">sys_exit</span><span class="p">)</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">sys_fork</span><span class="p">)</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">sys_read</span><span class="p">)</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="n">sys_write</span><span class="p">)</span> +<span class="cp">#ifdef CONFIG_X86_32</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">sys_open</span><span class="p">)</span> +<span class="cp">#else</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">compat_sys_open</span><span class="p">)</span> +<span class="cp">#endif</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">6</span><span class="p">,</span> <span class="n">sys_close</span><span class="p">)</span> +</pre></div> +</div> +</div> +<div class="section" id="system-call-parameters-handling"> +<h3>System call parameters handling<a class="headerlink" href="#system-call-parameters-handling" title="Permalink to this headline">¶</a></h3> +<p>Handling system call parameters is tricky. Since these values are +setup by user space, the kernel can not assume correctness and must +always verify them thoroughly.</p> +<p>Pointers have a few important special cases that must be checked:</p> +<ul class="admonition-system-calls-pointer-parameters simple"> +<li>Never allow pointers to kernel-space</li> +<li>Check for invalid pointers</li> +</ul> +<p>Since system calls are executed in kernel mode, they have access to +kernel space and if pointers are not properly checked user +applications might get read or write access to kernel space.</p> +<p>For example, let's consider the case where such a check is not made for +the read or write system calls. If the user passes a kernel-space +pointer to a write system call then it can get access to kernel data +by later reading the file. If it passes a kernel-space pointer to a +read system call then it can corrupt kernel memory.</p> +<span class="admonition-pointers-to-kernel-space"></span><p>Likewise, if a pointer passed by the application is invalid +(e.g. unmapped, read-only for cases where it is used for writing), it +could "crash" the kernel. Two approaches could be used:</p> +<ul class="admonition-invalid-pointers-handling-approaches simple"> +<li>Check the pointer against the user address space before using it, +or</li> +<li>Avoid checking the pointer and rely on the MMU to detect when the +pointer is invalid and use the page fault handler to determine +that the pointer was invalid</li> +</ul> +<p>Although it sounds tempting, the second approach is not that easy to +implement. The page fault handler uses the fault address (the address +that was accessed), the faulting address (the address of the +instruction that did the access) and information from the user address +space to determine the cause:</p> +<blockquote class="admonition-page-fault-handling"> +<div><ul class="simple"> +<li>Copy on write, demand paging, swapping: both the fault and +faulting addresses are in user space; the fault address is +valid (checked against the user address space)</li> +<li>Invalid pointer used in system call: the faulting address is +in kernel space; the fault address is in user space and it is +invalid</li> +<li>Kernel bug (kernel accesses invalid pointer): same as above</li> +</ul> +</div></blockquote> +<p>But in the last two cases we don't have enough information to +determine the cause of the fault.</p> +<p>In order to solve this issue, Linux uses special APIs (e.g +<code class="xref c c-func docutils literal"><span class="pre">copy_to_user()</span></code>) to accesses user space that are specially +crafted:</p> +<ul class="admonition-marking-kernel-code-that-accesses-user-space simple"> +<li>The exact instructions that access user space are recorded in a +table (exception table)</li> +<li>When a page fault occurs the faulting address is checked against +this table</li> +</ul> +<p>Although the fault handling case may be more costly overall depending +on the address space vs exception table size, and it is more complex, +it is optimized for the common case and that is why it is preferred +and used in Linux.</p> +<table border="1" class="admonition-cost-analysis-for-pointer-checks-vs-fault-handling docutils"> +<colgroup> +<col width="28%" /> +<col width="35%" /> +<col width="37%" /> +</colgroup> +<thead valign="bottom"> +<tr class="row-odd"><th class="head">Cost</th> +<th class="head">Pointer checks</th> +<th class="head">Fault handling</th> +</tr> +</thead> +<tbody valign="top"> +<tr class="row-even"><td>Valid address</td> +<td>address space search</td> +<td>negligible</td> +</tr> +<tr class="row-odd"><td>Invalid address</td> +<td>address space search</td> +<td>exception table search</td> +</tr> +</tbody> +</table> +</div> +</div> +<div class="section" id="virtual-dynamic-shared-object-vdso"> +<h2>Virtual Dynamic Shared Object (VDSO)<a class="headerlink" href="#virtual-dynamic-shared-object-vdso" title="Permalink to this headline">¶</a></h2> +<p>The VDSO mechanism was born out of the necessity of optimizing the +system call implementation, in a way that does not impact libc with +having to track the CPU capabilities in conjunction with the kernel +version.</p> +<p>For example, x86 has two ways of issuing system calls: int 0x80 and +sysenter. The latter is significantly faster so it should be used when +available. However, it is only available for processors newer than +Pentium II and only for kernel versions greater than 2.6.</p> +<p>With VDSO the system call interface is decided by the kernel:</p> +<ul class="admonition-virtual-dynamic-shared-object-vdso simple"> +<li>a stream of instructions to issue the system call is generated by +the kernel in a special memory area (formatted as an ELF shared +object)</li> +<li>that memory area is mapped towards the end of the user address +space</li> +<li>libc searches for VDSO and if present will use it to issue the +system call</li> +</ul> +<p class="admonition-inspecting-vdso"> </p> +<asciinema-player src="../_images/syscalls-vdso.cast"></asciinema-player><p>An interesting development of the VDSO is the virtual system calls +(vsyscalls) which run directly from user space. These vsyscalls are +also part of VDSO and they are accessing data from the VDSO page that +is either static or modified by the kernel in a separate read-write +map of the VDSO page. Examples of system calls that can be implemented +as vsyscalls are: getpid or gettimeofday.</p> +<ul class="admonition-virtual-system-calls-vsyscalls simple"> +<li>"System calls" that run directly from user space, part of the VDSO</li> +<li>Static data (e.g. getpid())</li> +<li>Dynamic data update by the kernel a in RW map of the VDSO +(e.g. gettimeofday(), time(), )</li> +</ul> +</div> +<div class="section" id="accessing-user-space-from-system-calls"> +<h2>Accessing user space from system calls<a class="headerlink" href="#accessing-user-space-from-system-calls" title="Permalink to this headline">¶</a></h2> +<p>As we mentioned earlier, user space must be accessed with special APIs +(<code class="xref c c-func docutils literal"><span class="pre">get_user()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">put_user()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">copy_from_user()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">copy_to_user()</span></code>) that check whether the pointer is in user space +and also handle the fault if the pointer is invalid. In case of invalid +pointers, they return a non-zero value.</p> +<div class="admonition-accessing-user-space-from-system-calls highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* OK: return -EFAULT if user_ptr is invalid */</span> +<span class="k">if</span> <span class="p">(</span><span class="n">copy_from_user</span><span class="p">(</span><span class="o">&</span><span class="n">kernel_buffer</span><span class="p">,</span> <span class="n">user_ptr</span><span class="p">,</span> <span class="n">size</span><span class="p">))</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EFAULT</span><span class="p">;</span> + +<span class="cm">/* NOK: only works if user_ptr is valid otherwise crashes kernel */</span> +<span class="n">memcpy</span><span class="p">(</span><span class="o">&</span><span class="n">kernel_buffer</span><span class="p">,</span> <span class="n">user_ptr</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span> +</pre></div> +</div> +<p>Let's examine the simplest API, get_user, as implemented for x86:</p> +<div class="admonition-get-user-implementation highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define get_user(x, ptr) \</span> +<span class="cp">({ \</span> +<span class="cp"> int __ret_gu; \</span> +<span class="cp"> register __inttype(*(ptr)) __val_gu asm("%"_ASM_DX); \</span> +<span class="cp"> __chk_user_ptr(ptr); \</span> +<span class="cp"> might_fault(); \</span> +<span class="cp"> asm volatile("call __get_user_%P4" \</span> +<span class="cp"> : "=a" (__ret_gu), "=r" (__val_gu), \</span> +<span class="cp"> ASM_CALL_CONSTRAINT \</span> +<span class="cp"> : "0" (ptr), "i" (sizeof(*(ptr)))); \</span> +<span class="cp"> (x) = (__force __typeof__(*(ptr))) __val_gu; \</span> +<span class="cp"> __builtin_expect(__ret_gu, 0); \</span> +<span class="cp">})</span> +</pre></div> +</div> +<p>The implementation uses inline assembly, which allows inserting ASM +sequences in C code and also handles access to/from variables in the +ASM code.</p> +<p>Based on the type size of the x variable, one of __get_user_1, +__get_user_2 or __get_user_4 will be called. Also, before executing +the assembly call, ptr will be moved to the first register EAX while +after the completion of assembly part the value of EAX will be moved +to __ret_gu and the EDX register will be moved to __val_gu.</p> +<p>It is equivalent to the following pseudo code:</p> +<div class="admonition-get-user-pseudo-code highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define get_user(x, ptr) \</span> +<span class="cp"> movl ptr, %eax \</span> +<span class="cp"> call __get_user_1 \</span> +<span class="cp"> movl %edx, x \</span> +<span class="cp"> movl %eax, result \</span> +</pre></div> +</div> +<p>The __get_user_1 implementation for x86 is the following:</p> +<div class="admonition-get-user-1-implementation highlight-none"><div class="highlight"><pre><span></span>.text +ENTRY(__get_user_1) + mov PER_CPU_VAR(current_task), %_ASM_DX + cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX + jae bad_get_user + ASM_STAC +1: movzbl (%_ASM_AX),%edx + xor %eax,%eax + ASM_CLAC + ret +ENDPROC(__get_user_1) + +bad_get_user: + xor %edx,%edx + mov $(-EFAULT),%_ASM_AX + ASM_CLAC + ret +END(bad_get_user) + +_ASM_EXTABLE(1b,bad_get_user) +</pre></div> +</div> +<p>The first two statements check the pointer (which is stored in EDX) +with the addr_limit field of the current task (process) descriptor to +make sure that we don't have a pointer to kernel space.</p> +<p>Then, SMAP is disabled, to allow access to user from kernel, and the +access to user space is done with the instruction at the 1: label. EAX +is then zeroed to mark success, SMAP is enabled, and the call returns.</p> +<p>The movzbl instruction is the one that does the access to user space +and its address is captured with the 1: label and stored in a special +section:</p> +<div class="admonition-exception-table-entry highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* Exception table entry */</span> +<span class="cp"># define _ASM_EXTABLE_HANDLE(from, to, handler) \</span> +<span class="cp"> .pushsection "__ex_table","a" ; \</span> +<span class="cp"> .balign 4 ; \</span> +<span class="cp"> .long (from) - . ; \</span> +<span class="cp"> .long (to) - . ; \</span> +<span class="cp"> .long (handler) - . ; \</span> +<span class="cp"> .popsection</span> + +<span class="cp"># define _ASM_EXTABLE(from, to) \</span> +<span class="cp"> _ASM_EXTABLE_HANDLE(from, to, ex_handler_default)</span> +</pre></div> +</div> +<p>For each address that accesses user space we have an entry in the +exception table, that is made up of: the faulting address(from), where +to jump to in case of a fault, and a handler function (that implements +the jump logic). All of these addresses are stored on 32bit in +relative format to the exception table, so that they work for both 32 +and 64 bit kernels.</p> +<p>All of the exception table entries are then collected in the +__ex_table section by the linker script:</p> +<div class="admonition-exception-table-building highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define EXCEPTION_TABLE(align) \</span> +<span class="cp"> . = ALIGN(align); \</span> +<span class="cp"> __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { \</span> +<span class="cp"> VMLINUX_SYMBOL(__start___ex_table) = .; \</span> +<span class="cp"> KEEP(*(__ex_table)) \</span> +<span class="cp"> VMLINUX_SYMBOL(__stop___ex_table) = .; \</span> +<span class="cp"> }</span> +</pre></div> +</div> +<p>The section is guarded with __start___ex_table and __stop___ex_table +symbols, so that it is easy to find the data from C code. This table +is accessed by the fault handler:</p> +<div class="admonition-exception-table-handling highlight-c"><div class="highlight"><pre><span></span><span class="kt">bool</span> <span class="nf">ex_handler_default</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">exception_table_entry</span> <span class="o">*</span><span class="n">fixup</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">,</span> <span class="kt">int</span> <span class="n">trapnr</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">regs</span><span class="o">-></span><span class="n">ip</span> <span class="o">=</span> <span class="n">ex_fixup_addr</span><span class="p">(</span><span class="n">fixup</span><span class="p">);</span> + <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">int</span> <span class="nf">fixup_exception</span><span class="p">(</span><span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">,</span> <span class="kt">int</span> <span class="n">trapnr</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">exception_table_entry</span> <span class="o">*</span><span class="n">e</span><span class="p">;</span> + <span class="n">ex_handler_t</span> <span class="n">handler</span><span class="p">;</span> + + <span class="n">e</span> <span class="o">=</span> <span class="n">search_exception_tables</span><span class="p">(</span><span class="n">regs</span><span class="o">-></span><span class="n">ip</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">e</span><span class="p">)</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> + + <span class="n">handler</span> <span class="o">=</span> <span class="n">ex_fixup_handler</span><span class="p">(</span><span class="n">e</span><span class="p">);</span> + <span class="k">return</span> <span class="n">handler</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">regs</span><span class="p">,</span> <span class="n">trapnr</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<p>All it does is to set the return address to the one in the field of +the exception table entry which, in case of the get_user exception +table entry, is bad_get_user which return -EFAULT to the caller.</p> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="intro.html" class="btn btn-neutral float-left" title="Introduction" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="processes.html" class="btn btn-neutral float-right" title="Processes" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/virt-slides.html b/refs/pull/405/merge/lectures/virt-slides.html new file mode 100644 index 00000000..74b74990 --- /dev/null +++ b/refs/pull/405/merge/lectures/virt-slides.html @@ -0,0 +1,699 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Virtualization — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="next" title="Infrastructure" href="../labs/infrastructure.html" /> + <link rel="prev" title="Architecture Layer" href="arch.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-virtualization slide level-2"> + +<h2>Virtualization</h2> + +<ul class="simple"> +<li>Emulation basics</li> +<li>Virtualization basics</li> +<li>Paravirtualization basics</li> +<li>Hardware support for virtualization</li> +<li>Overview of the Xen hypervisor</li> +<li>Overview of the KVM hypervisor</li> +</ul> + + + + +</article> +<article class="admonition-emulation-basics slide level-2"> + +<h2>Emulation basics</h2> + +<ul class="simple"> +<li>Instructions are emulated (each time they are executed)</li> +<li>The other system components are also emulated:<ul> +<li>MMU</li> +<li>Physical memory access</li> +<li>Peripherals</li> +</ul> +</li> +<li>Target architecture - the architecture that it is emulated</li> +<li>Host architecture - the architecture that the emulator runs on</li> +<li>For emulation target and host architectures can be different</li> +</ul> + + + + +</article> +<article class="admonition-virtualization-basics slide level-2"> + +<h2>Virtualization basics</h2> + +<ul class="simple"> +<li>Defined in a paper by Popek & Goldberg in 1974</li> +<li>Fidelity</li> +<li>Performance</li> +<li>Security</li> +</ul> +<img alt="../_images/ditaa-91f08f7db4b54069e16694eab8d75c06400fc47b.png" src="../_images/ditaa-91f08f7db4b54069e16694eab8d75c06400fc47b.png" /> + + + + +</article> +<article class="admonition-classic-virtualization slide level-2"> + +<h2>Classic virtualization</h2> + +<ul class="simple"> +<li>Trap & Emulate</li> +<li>Same architecture for host and target</li> +<li>Most of the target instructions are natively executed</li> +<li>Target OS runs in non-privilege mode on the host</li> +<li>Privileged instructions are trapped and emulated</li> +<li>Two machine states: host and guest</li> +</ul> + + + + +</article> +<article class="admonition-software-virtualization slide level-2"> + +<h2>Software virtualization</h2> + +<ul class="simple"> +<li>Not all architecture can be virtualized; e.g. x86:<ul> +<li>CS register encodes the CPL</li> +<li>Some instructions don't generate a trap (e.g. popf)</li> +</ul> +</li> +<li>Solution: emulate instructions using binary translation</li> +</ul> + + + + +</article> +<article class="admonition-mmu-virtualization slide level-2"> + +<h2>MMU virtualization</h2> + +<ul class="simple"> +<li>"Fake" VM physical addresses are translated by the host to actual +physical addresses</li> +<li>Guest virtual address -> Guest physical address -> Host Physical Address</li> +<li>The guest page tables are not directly used by the host hardware</li> +<li>VM page tables are verified then translated into a new set of page +tables on the host (shadow page tables)</li> +</ul> + + + + +</article> +<article class="admonition-shadow-page-tables slide level-2"> + +<h2>Shadow page tables</h2> + +<p> </p> +<img alt="../_images/ditaa-8632e22c6d89bd18f97c9cef127444486b5077df.png" src="../_images/ditaa-8632e22c6d89bd18f97c9cef127444486b5077df.png" /> + + + + +</article> +<article class="admonition-lazy-shadow-sync slide level-2"> + +<h2>Lazy shadow sync</h2> + +<ul class="simple"> +<li>Guest page tables changes are typically batched</li> +<li>To avoid repeated traps, checks and transformations map guest +page table entries with write access</li> +<li>Update the shadow page table when<ul> +<li>The TLB is flushed</li> +<li>In the host page fault handler</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-i-o-emulation slide level-2"> + +<h2>I/O emulation</h2> + +<p> </p> +<img alt="../_images/ditaa-bb69666d75b9670e542682753fb8cc9b77ff8894.png" src="../_images/ditaa-bb69666d75b9670e542682753fb8cc9b77ff8894.png" /> + + + + +</article> +<article class="admonition-example-qemu-sifive-uart-emulation slide level-2"> + +<h2>Example: qemu SiFive UART emulation</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/*</span> +<span class="cm"> * QEMU model of the UART on the SiFive E300 and U500 series SOCs.</span> +<span class="cm"> *</span> +<span class="cm"> * Copyright (c) 2016 Stefan O'Rear</span> +<span class="cm"> *</span> +<span class="cm"> * This program is free software; you can redistribute it and/or modify it</span> +<span class="cm"> * under the terms and conditions of the GNU General Public License,</span> +<span class="cm"> * version 2 or later, as published by the Free Software Foundation.</span> +<span class="cm"> *</span> +<span class="cm"> * This program is distributed in the hope it will be useful, but WITHOUT</span> +<span class="cm"> * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or</span> +<span class="cm"> * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for</span> +<span class="cm"> * more details.</span> +<span class="cm"> *</span> +<span class="cm"> * You should have received a copy of the GNU General Public License along with</span> +<span class="cm"> * this program. If not, see <http://www.gnu.org/licenses/>.</span> +<span class="cm"> */</span> + +<span class="cp">#include</span> <span class="cpf">"qemu/osdep.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"qapi/error.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"qemu/log.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"chardev/char.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"chardev/char-fe.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"hw/irq.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"hw/char/sifive_uart.h"</span><span class="cp"></span> + +<span class="cm">/*</span> +<span class="cm"> * Not yet implemented:</span> +<span class="cm"> *</span> +<span class="cm"> * Transmit FIFO using "qemu/fifo8.h"</span> +<span class="cm"> */</span> + +<span class="cm">/* Returns the state of the IP (interrupt pending) register */</span> +<span class="k">static</span> <span class="kt">uint64_t</span> <span class="nf">uart_ip</span><span class="p">(</span><span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">uint64_t</span> <span class="n">ret</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + + <span class="kt">uint64_t</span> <span class="n">txcnt</span> <span class="o">=</span> <span class="n">SIFIVE_UART_GET_TXCNT</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">txctrl</span><span class="p">);</span> + <span class="kt">uint64_t</span> <span class="n">rxcnt</span> <span class="o">=</span> <span class="n">SIFIVE_UART_GET_RXCNT</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rxctrl</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">txcnt</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="n">ret</span> <span class="o">|=</span> <span class="n">SIFIVE_UART_IP_TXWM</span><span class="p">;</span> + <span class="p">}</span> + <span class="k">if</span> <span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span> <span class="o">></span> <span class="n">rxcnt</span><span class="p">)</span> <span class="p">{</span> + <span class="n">ret</span> <span class="o">|=</span> <span class="n">SIFIVE_UART_IP_RXWM</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="n">ret</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">update_irq</span><span class="p">(</span><span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">cond</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="k">if</span> <span class="p">((</span><span class="n">s</span><span class="o">-></span><span class="n">ie</span> <span class="o">&</span> <span class="n">SIFIVE_UART_IE_TXWM</span><span class="p">)</span> <span class="o">||</span> + <span class="p">((</span><span class="n">s</span><span class="o">-></span><span class="n">ie</span> <span class="o">&</span> <span class="n">SIFIVE_UART_IE_RXWM</span><span class="p">)</span> <span class="o">&&</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span><span class="p">))</span> <span class="p">{</span> + <span class="n">cond</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> + <span class="p">}</span> + <span class="k">if</span> <span class="p">(</span><span class="n">cond</span><span class="p">)</span> <span class="p">{</span> + <span class="n">qemu_irq_raise</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">irq</span><span class="p">);</span> + <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> + <span class="n">qemu_irq_lower</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">irq</span><span class="p">);</span> + <span class="p">}</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">uint64_t</span> +<span class="nf">uart_read</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">,</span> <span class="n">hwaddr</span> <span class="n">addr</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">size</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">r</span><span class="p">;</span> + <span class="k">switch</span> <span class="p">(</span><span class="n">addr</span><span class="p">)</span> <span class="p">{</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_RXFIFO</span><span class="p">:</span> + <span class="k">if</span> <span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span><span class="p">)</span> <span class="p">{</span> + <span class="n">r</span> <span class="o">=</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> + <span class="n">memmove</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">,</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span> + <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span><span class="o">--</span><span class="p">;</span> + <span class="n">qemu_chr_fe_accept_input</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">);</span> + <span class="n">update_irq</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> + <span class="k">return</span> <span class="n">r</span><span class="p">;</span> + <span class="p">}</span> + <span class="k">return</span> <span class="mh">0x80000000</span><span class="p">;</span> + + <span class="k">case</span> <span class="nl">SIFIVE_UART_TXFIFO</span><span class="p">:</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="cm">/* Should check tx fifo */</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_IE</span><span class="p">:</span> + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">ie</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_IP</span><span class="p">:</span> + <span class="k">return</span> <span class="n">uart_ip</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_TXCTRL</span><span class="p">:</span> + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">txctrl</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_RXCTRL</span><span class="p">:</span> + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">rxctrl</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_DIV</span><span class="p">:</span> + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">div</span><span class="p">;</span> + <span class="p">}</span> + + <span class="n">qemu_log_mask</span><span class="p">(</span><span class="n">LOG_GUEST_ERROR</span><span class="p">,</span> <span class="s">"%s: bad read: addr=0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> + <span class="n">__func__</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">addr</span><span class="p">);</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> +<span class="nf">uart_write</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">,</span> <span class="n">hwaddr</span> <span class="n">addr</span><span class="p">,</span> + <span class="kt">uint64_t</span> <span class="n">val64</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">size</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + <span class="kt">uint32_t</span> <span class="n">value</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">ch</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span> + + <span class="k">switch</span> <span class="p">(</span><span class="n">addr</span><span class="p">)</span> <span class="p">{</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_TXFIFO</span><span class="p">:</span> + <span class="n">qemu_chr_fe_write</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">,</span> <span class="o">&</span><span class="n">ch</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> + <span class="n">update_irq</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> + <span class="k">return</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_IE</span><span class="p">:</span> + <span class="n">s</span><span class="o">-></span><span class="n">ie</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="n">update_irq</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> + <span class="k">return</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_TXCTRL</span><span class="p">:</span> + <span class="n">s</span><span class="o">-></span><span class="n">txctrl</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="k">return</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_RXCTRL</span><span class="p">:</span> + <span class="n">s</span><span class="o">-></span><span class="n">rxctrl</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="k">return</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_DIV</span><span class="p">:</span> + <span class="n">s</span><span class="o">-></span><span class="n">div</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="k">return</span><span class="p">;</span> + <span class="p">}</span> + <span class="n">qemu_log_mask</span><span class="p">(</span><span class="n">LOG_GUEST_ERROR</span><span class="p">,</span> <span class="s">"%s: bad write: addr=0x%x v=0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> + <span class="n">__func__</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">addr</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">value</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="k">const</span> <span class="n">MemoryRegionOps</span> <span class="n">uart_ops</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">read</span> <span class="o">=</span> <span class="n">uart_read</span><span class="p">,</span> + <span class="p">.</span><span class="n">write</span> <span class="o">=</span> <span class="n">uart_write</span><span class="p">,</span> + <span class="p">.</span><span class="n">endianness</span> <span class="o">=</span> <span class="n">DEVICE_NATIVE_ENDIAN</span><span class="p">,</span> + <span class="p">.</span><span class="n">valid</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">min_access_size</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span> + <span class="p">.</span><span class="n">max_access_size</span> <span class="o">=</span> <span class="mi">4</span> + <span class="p">}</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">uart_rx</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">,</span> <span class="k">const</span> <span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buf</span><span class="p">,</span> <span class="kt">int</span> <span class="n">size</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + + <span class="cm">/* Got a byte. */</span> + <span class="k">if</span> <span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span> <span class="o">>=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">))</span> <span class="p">{</span> + <span class="n">printf</span><span class="p">(</span><span class="s">"WARNING: UART dropped char.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="k">return</span><span class="p">;</span> + <span class="p">}</span> + <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">[</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="o">*</span><span class="n">buf</span><span class="p">;</span> + + <span class="n">update_irq</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">uart_can_rx</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span> <span class="o"><</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">uart_event</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">,</span> <span class="n">QEMUChrEvent</span> <span class="n">event</span><span class="p">)</span> +<span class="p">{</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">uart_be_change</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + + <span class="n">qemu_chr_fe_set_handlers</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">,</span> <span class="n">uart_can_rx</span><span class="p">,</span> <span class="n">uart_rx</span><span class="p">,</span> <span class="n">uart_event</span><span class="p">,</span> + <span class="n">uart_be_change</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">true</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="cm">/*</span> +<span class="cm"> * Create UART device.</span> +<span class="cm"> */</span> +<span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="nf">sifive_uart_create</span><span class="p">(</span><span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">address_space</span><span class="p">,</span> <span class="n">hwaddr</span> <span class="n">base</span><span class="p">,</span> + <span class="n">Chardev</span> <span class="o">*</span><span class="n">chr</span><span class="p">,</span> <span class="n">qemu_irq</span> <span class="n">irq</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">g_malloc0</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">SiFiveUARTState</span><span class="p">));</span> + <span class="n">s</span><span class="o">-></span><span class="n">irq</span> <span class="o">=</span> <span class="n">irq</span><span class="p">;</span> + <span class="n">qemu_chr_fe_init</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">,</span> <span class="n">chr</span><span class="p">,</span> <span class="o">&</span><span class="n">error_abort</span><span class="p">);</span> + <span class="n">qemu_chr_fe_set_handlers</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">,</span> <span class="n">uart_can_rx</span><span class="p">,</span> <span class="n">uart_rx</span><span class="p">,</span> <span class="n">uart_event</span><span class="p">,</span> + <span class="n">uart_be_change</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">true</span><span class="p">);</span> + <span class="n">memory_region_init_io</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">mmio</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">&</span><span class="n">uart_ops</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> + <span class="n">TYPE_SIFIVE_UART</span><span class="p">,</span> <span class="n">SIFIVE_UART_MAX</span><span class="p">);</span> + <span class="n">memory_region_add_subregion</span><span class="p">(</span><span class="n">address_space</span><span class="p">,</span> <span class="n">base</span><span class="p">,</span> <span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">mmio</span><span class="p">);</span> + <span class="k">return</span> <span class="n">s</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-paravirtualization slide level-2"> + +<h2>Paravirtualization</h2> + +<ul class="simple"> +<li>Change the guest OS so that it cooperates with the VMM<ul> +<li>CPU paravirtualization</li> +<li>MMU paravirtualization</li> +<li>I/O paravirtualization</li> +</ul> +</li> +<li>VMM exposes hypercalls for:<ul> +<li>activate / deactivate the interrupts</li> +<li>changing page tables</li> +<li>accessing virtualized peripherals</li> +</ul> +</li> +<li>VMM uses events to trigger interrupts in the VM</li> +</ul> + + + + +</article> +<article class="admonition-intel-vt-x slide level-2"> + +<h2>Intel VT-x</h2> + +<ul class="simple"> +<li>Hardware extension to transform x86 to the point it can be +virtualized "classically"</li> +<li>New execution mode: non-root mode</li> +<li>Each non-root mode instance uses a Virtual Machine Control +Structure (VMCS) to store its state</li> +<li>VMM runs in root mode</li> +<li>VM-entry and VM-exit are used to transition between the two modes</li> +</ul> + + + + +</article> +<article class="admonition-virtual-machine-control-structure slide level-2"> + +<h2>Virtual Machine Control Structure</h2> + +<ul class="simple"> +<li>Guest information: state of the virtual CPU</li> +<li>Host information: state of the physical CPU</li> +<li>Saved information:<ul> +<li>visible state: segment registers, CR3, IDTR, etc.</li> +<li>internal state</li> +</ul> +</li> +<li>VMCS can not be accessed directly but certain information can be +accessed with special instructions</li> +</ul> + + + + +</article> +<article class="admonition-vm-entry-exit slide level-2"> + +<h2>VM entry & exit</h2> + +<ul class="simple"> +<li>VM entry - new instructions that switches the CPU in non-root +mode and loads the VM state from a VMCS; host state is saved in +VMCS</li> +<li>Allows injecting interrupts and exceptions in the guest</li> +<li>VM exit will be automatically triggered based on the VMCS +configuration</li> +<li>When VM exit occurs host state is loaded from VMCS, guest state +is saved in VMCS</li> +</ul> + + + + +</article> +<article class="admonition-vm-execution-control-fields slide level-2"> + +<h2>VM execution control fields</h2> + +<ul class="simple"> +<li>Selects conditions which triggers a VM exit; examples:<ul> +<li>If an external interrupt is generated</li> +<li>If an external interrupt is generated and EFLAGS.IF is set</li> +<li>If CR0-CR4 registers are modified</li> +</ul> +</li> +<li>Exception bitmap - selects which exceptions will generate a VM +exit</li> +<li>IO bitmap - selects which I/O addresses (IN/OUT accesses) +generates a VM exit</li> +<li>MSR bitmaps - selects which RDMSR or WRMSR instructions will +generate a VM exit</li> +</ul> + + + + +</article> +<article class="admonition-extend-page-tables slide level-2"> + +<h2>Extend Page Tables</h2> + +<ul class="simple"> +<li>Reduces the complexity of MMU virtualization and improves +performance</li> +<li>Access to CR3, INVLPG and page faults do not require VM exit +anymore</li> +<li>The EPT page table is controlled by the VMM</li> +</ul> +<img alt="../_images/ditaa-cc9a2e995be74ee99646ea4bf0e551d766fa92ef.png" src="../_images/ditaa-cc9a2e995be74ee99646ea4bf0e551d766fa92ef.png" /> + + + + +</article> +<article class="admonition-vpid slide level-2"> + +<h2>VPID</h2> + +<ul class="simple"> +<li>VM entry and VM exit forces a TLB flush - loses VMM / VM translations</li> +<li>To avoid this issue a VPID (Virtual Processor ID) tag is +associated with each VM (VPID 0 is reserved for the VMM)</li> +<li>All TLB entries are tagged</li> +<li>At VM entry and exit just the entries associated with the tags +are flushed</li> +<li>When searching the TLB just the current VPID is used</li> +</ul> + + + + +</article> +<article class="admonition-i-o-virtualization slide level-2"> + +<h2>I/O virtualization</h2> + +<img alt="../_images/ditaa-3901edd823cdc7a6f429ebc37cbc541e650abc96.png" src="../_images/ditaa-3901edd823cdc7a6f429ebc37cbc541e650abc96.png" /> + + + + +</article> +<article class="admonition-i-o-mmu slide level-2"> + +<h2>I/O MMU</h2> + +<p>VT-d protects and translates VM physical addresses using an I/O +MMU (DMA remaping)</p> +<img alt="../_images/ditaa-d880751969de8642b2613caaca345d71acea4500.png" src="../_images/ditaa-d880751969de8642b2613caaca345d71acea4500.png" /> + + + + +</article> +<article class="admonition-interrupt-posting slide level-2"> + +<h2>Interrupt posting</h2> + +<ul class="simple"> +<li>Messsage Signaled Interrupts (MSI) = DMA writes to the host +address range of the IRQ controller (e.g. 0xFEExxxxx)</li> +<li>Low bits of the address and the data indicate which interrupt +vector to deliver to which CPU</li> +<li>Interrupt remapping table points to the virtual CPU (VMCS) that +should receive the interrupt</li> +<li>I/O MMU will trap the IRQ controller write and look it up in the +interrupt remmaping table<ul> +<li>if that virtual CPU is currently running it will take the +interrupt directly</li> +<li>otherwise a bit is set in a table (Posted Interrupt Descriptor +table) and the interrupt will be inject next time that vCPU is +run</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-i-o-virtualization slide level-2"> + +<h2>I/O virtualization</h2> + +<img alt="../_images/ditaa-2cb0eb0056bb775d1446843d62241fd660662c96.png" src="../_images/ditaa-2cb0eb0056bb775d1446843d62241fd660662c96.png" /> + + + + +</article> +<article class="admonition-sr-iov slide level-2"> + +<h2>SR-IOV</h2> + +<ul class="simple"> +<li>Single Root - Input Output Virtualization</li> +<li>Physical device with multiple Ethernet ports will be shown as +multiple device on the PCI bus</li> +<li>Physical Function is used for the control and can be configured<ul> +<li>to present itself as a new PCI device</li> +<li>which VLAN to use</li> +</ul> +</li> +<li>The new virtual function is enumerated on the bus and can be +assigned to a particular guest</li> +</ul> + + + + +</article> +<article class="admonition-qemu slide level-2"> + +<h2>qemu</h2> + +<ul class="simple"> +<li>Uses binary translation via Tiny Code Generator (TCG) for +efficient emulation</li> +<li>Supports different target and host architectures (e.g. running +ARM VMs on x86)</li> +<li>Both process and full system level emulation</li> +<li>MMU emulation</li> +<li>I/O emulation</li> +<li>Can be used with KVM for accelerated virtualization</li> +</ul> + + + + +</article> +<article class="admonition-kvm slide level-2"> + +<h2>KVM</h2> + +<img alt="../_images/ditaa-f8fcc760ef5dad50d1038ed3426d0fcce12fd3e6.png" src="../_images/ditaa-f8fcc760ef5dad50d1038ed3426d0fcce12fd3e6.png" /> + + + + +</article> +<article class="admonition-kvm slide level-2"> + +<h2>KVM</h2> + +<ul class="simple"> +<li>Linux device driver for hardware virtualization (e.g. Intel VT-x, SVM)</li> +<li>IOCTL based interface for managing and running virtual CPUs</li> +<li>VMM components implemented inside the Linux kernel +(e.g. interrupt controller, timers)</li> +<li>Shadow page tables or EPT if present</li> +<li>Uses qemu or virtio for I/O virtualization</li> +</ul> + + + + +</article> +<article class="admonition-xen slide level-2"> + +<h2>Xen</h2> + +<ul class="simple"> +<li>Type 1 = Bare Metal Hypervisor</li> +<li>Type 2 = Hypervisor embedded in an exist kernel / OS</li> +</ul> + + + + +</article> +<article class="admonition-xen slide level-2"> + +<h2>Xen</h2> + +<img alt="../_images/xen-overview.png" src="../_images/xen-overview.png" /> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/lectures/virt.html b/refs/pull/405/merge/lectures/virt.html new file mode 100644 index 00000000..6aeacce8 --- /dev/null +++ b/refs/pull/405/merge/lectures/virt.html @@ -0,0 +1,661 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Virtualization — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Infrastructure" href="../labs/infrastructure.html" /> + <link rel="prev" title="Architecture Layer" href="arch.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="../so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="arch.html">Architecture Layer</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Virtualization</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l2"><a class="reference internal" href="#emulation-basics">Emulation basics</a></li> +<li class="toctree-l2"><a class="reference internal" href="#virtualization-basics">Virtualization basics</a></li> +<li class="toctree-l2"><a class="reference internal" href="#classic-virtualization">Classic virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="#software-virtualization">Software virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="#mmu-virtualization">MMU virtualization</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#shadow-page-tables">Shadow page tables</a></li> +<li class="toctree-l3"><a class="reference internal" href="#lazy-shadow-sync">Lazy shadow sync</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#i-o-emulation">I/O emulation</a></li> +<li class="toctree-l2"><a class="reference internal" href="#paravirtualization">Paravirtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="#intel-vt-x">Intel VT-x</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#virtual-machine-control-structure">Virtual Machine Control Structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="#vm-entry-exit">VM entry & exit</a></li> +<li class="toctree-l3"><a class="reference internal" href="#vm-execution-control-fields">VM execution control fields</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#extend-page-tables">Extend Page Tables</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#vpid">VPID</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#i-o-virtualization">I/O virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="#qemu">qemu</a></li> +<li class="toctree-l2"><a class="reference internal" href="#kvm">KVM</a></li> +<li class="toctree-l2"><a class="reference internal" href="#type-1-vs-type-2-hypervisors">Type 1 vs Type 2 Hypervisors</a></li> +<li class="toctree-l2"><a class="reference internal" href="#xen">Xen</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Virtualization</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/lectures/virt.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="virtualization"> +<h1>Virtualization<a class="headerlink" href="#virtualization" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="virt-slides.html">View slides</a></p> +<div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-virtualization simple"> +<li>Emulation basics</li> +<li>Virtualization basics</li> +<li>Paravirtualization basics</li> +<li>Hardware support for virtualization</li> +<li>Overview of the Xen hypervisor</li> +<li>Overview of the KVM hypervisor</li> +</ul> +</div> +<div class="section" id="emulation-basics"> +<h2>Emulation basics<a class="headerlink" href="#emulation-basics" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-emulation-basics simple"> +<li>Instructions are emulated (each time they are executed)</li> +<li>The other system components are also emulated:<ul> +<li>MMU</li> +<li>Physical memory access</li> +<li>Peripherals</li> +</ul> +</li> +<li>Target architecture - the architecture that it is emulated</li> +<li>Host architecture - the architecture that the emulator runs on</li> +<li>For emulation target and host architectures can be different</li> +</ul> +</div> +<div class="section" id="virtualization-basics"> +<h2>Virtualization basics<a class="headerlink" href="#virtualization-basics" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-virtualization-basics simple"> +<li>Defined in a paper by Popek & Goldberg in 1974</li> +<li>Fidelity</li> +<li>Performance</li> +<li>Security</li> +</ul> +<img alt="../_images/ditaa-91f08f7db4b54069e16694eab8d75c06400fc47b.png" src="../_images/ditaa-91f08f7db4b54069e16694eab8d75c06400fc47b.png" /> +</div> +<div class="section" id="classic-virtualization"> +<h2>Classic virtualization<a class="headerlink" href="#classic-virtualization" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-classic-virtualization simple"> +<li>Trap & Emulate</li> +<li>Same architecture for host and target</li> +<li>Most of the target instructions are natively executed</li> +<li>Target OS runs in non-privilege mode on the host</li> +<li>Privileged instructions are trapped and emulated</li> +<li>Two machine states: host and guest</li> +</ul> +</div> +<div class="section" id="software-virtualization"> +<h2>Software virtualization<a class="headerlink" href="#software-virtualization" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-software-virtualization simple"> +<li>Not all architecture can be virtualized; e.g. x86:<ul> +<li>CS register encodes the CPL</li> +<li>Some instructions don't generate a trap (e.g. popf)</li> +</ul> +</li> +<li>Solution: emulate instructions using binary translation</li> +</ul> +</div> +<div class="section" id="mmu-virtualization"> +<h2>MMU virtualization<a class="headerlink" href="#mmu-virtualization" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-mmu-virtualization simple"> +<li>"Fake" VM physical addresses are translated by the host to actual +physical addresses</li> +<li>Guest virtual address -> Guest physical address -> Host Physical Address</li> +<li>The guest page tables are not directly used by the host hardware</li> +<li>VM page tables are verified then translated into a new set of page +tables on the host (shadow page tables)</li> +</ul> +<div class="section" id="shadow-page-tables"> +<h3>Shadow page tables<a class="headerlink" href="#shadow-page-tables" title="Permalink to this headline">¶</a></h3> +<p class="admonition-shadow-page-tables"> </p> +<img alt="../_images/ditaa-8632e22c6d89bd18f97c9cef127444486b5077df.png" src="../_images/ditaa-8632e22c6d89bd18f97c9cef127444486b5077df.png" /> +</div> +<div class="section" id="lazy-shadow-sync"> +<h3>Lazy shadow sync<a class="headerlink" href="#lazy-shadow-sync" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-lazy-shadow-sync simple"> +<li>Guest page tables changes are typically batched</li> +<li>To avoid repeated traps, checks and transformations map guest +page table entries with write access</li> +<li>Update the shadow page table when<ul> +<li>The TLB is flushed</li> +<li>In the host page fault handler</li> +</ul> +</li> +</ul> +</div> +</div> +<div class="section" id="i-o-emulation"> +<h2>I/O emulation<a class="headerlink" href="#i-o-emulation" title="Permalink to this headline">¶</a></h2> +<p class="admonition-i-o-emulation"> </p> +<img alt="../_images/ditaa-bb69666d75b9670e542682753fb8cc9b77ff8894.png" src="../_images/ditaa-bb69666d75b9670e542682753fb8cc9b77ff8894.png" /> +<div class="admonition-example-qemu-sifive-uart-emulation highlight-c"><div class="highlight"><pre><span></span><span class="cm">/*</span> +<span class="cm"> * QEMU model of the UART on the SiFive E300 and U500 series SOCs.</span> +<span class="cm"> *</span> +<span class="cm"> * Copyright (c) 2016 Stefan O'Rear</span> +<span class="cm"> *</span> +<span class="cm"> * This program is free software; you can redistribute it and/or modify it</span> +<span class="cm"> * under the terms and conditions of the GNU General Public License,</span> +<span class="cm"> * version 2 or later, as published by the Free Software Foundation.</span> +<span class="cm"> *</span> +<span class="cm"> * This program is distributed in the hope it will be useful, but WITHOUT</span> +<span class="cm"> * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or</span> +<span class="cm"> * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for</span> +<span class="cm"> * more details.</span> +<span class="cm"> *</span> +<span class="cm"> * You should have received a copy of the GNU General Public License along with</span> +<span class="cm"> * this program. If not, see <http://www.gnu.org/licenses/>.</span> +<span class="cm"> */</span> + +<span class="cp">#include</span> <span class="cpf">"qemu/osdep.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"qapi/error.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"qemu/log.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"chardev/char.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"chardev/char-fe.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"hw/irq.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"hw/char/sifive_uart.h"</span><span class="cp"></span> + +<span class="cm">/*</span> +<span class="cm"> * Not yet implemented:</span> +<span class="cm"> *</span> +<span class="cm"> * Transmit FIFO using "qemu/fifo8.h"</span> +<span class="cm"> */</span> + +<span class="cm">/* Returns the state of the IP (interrupt pending) register */</span> +<span class="k">static</span> <span class="kt">uint64_t</span> <span class="nf">uart_ip</span><span class="p">(</span><span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">uint64_t</span> <span class="n">ret</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + + <span class="kt">uint64_t</span> <span class="n">txcnt</span> <span class="o">=</span> <span class="n">SIFIVE_UART_GET_TXCNT</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">txctrl</span><span class="p">);</span> + <span class="kt">uint64_t</span> <span class="n">rxcnt</span> <span class="o">=</span> <span class="n">SIFIVE_UART_GET_RXCNT</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rxctrl</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">txcnt</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="n">ret</span> <span class="o">|=</span> <span class="n">SIFIVE_UART_IP_TXWM</span><span class="p">;</span> + <span class="p">}</span> + <span class="k">if</span> <span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span> <span class="o">></span> <span class="n">rxcnt</span><span class="p">)</span> <span class="p">{</span> + <span class="n">ret</span> <span class="o">|=</span> <span class="n">SIFIVE_UART_IP_RXWM</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="n">ret</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">update_irq</span><span class="p">(</span><span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">cond</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="k">if</span> <span class="p">((</span><span class="n">s</span><span class="o">-></span><span class="n">ie</span> <span class="o">&</span> <span class="n">SIFIVE_UART_IE_TXWM</span><span class="p">)</span> <span class="o">||</span> + <span class="p">((</span><span class="n">s</span><span class="o">-></span><span class="n">ie</span> <span class="o">&</span> <span class="n">SIFIVE_UART_IE_RXWM</span><span class="p">)</span> <span class="o">&&</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span><span class="p">))</span> <span class="p">{</span> + <span class="n">cond</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> + <span class="p">}</span> + <span class="k">if</span> <span class="p">(</span><span class="n">cond</span><span class="p">)</span> <span class="p">{</span> + <span class="n">qemu_irq_raise</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">irq</span><span class="p">);</span> + <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> + <span class="n">qemu_irq_lower</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">irq</span><span class="p">);</span> + <span class="p">}</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">uint64_t</span> +<span class="nf">uart_read</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">,</span> <span class="n">hwaddr</span> <span class="n">addr</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">size</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">r</span><span class="p">;</span> + <span class="k">switch</span> <span class="p">(</span><span class="n">addr</span><span class="p">)</span> <span class="p">{</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_RXFIFO</span><span class="p">:</span> + <span class="k">if</span> <span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span><span class="p">)</span> <span class="p">{</span> + <span class="n">r</span> <span class="o">=</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> + <span class="n">memmove</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">,</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span> + <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span><span class="o">--</span><span class="p">;</span> + <span class="n">qemu_chr_fe_accept_input</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">);</span> + <span class="n">update_irq</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> + <span class="k">return</span> <span class="n">r</span><span class="p">;</span> + <span class="p">}</span> + <span class="k">return</span> <span class="mh">0x80000000</span><span class="p">;</span> + + <span class="k">case</span> <span class="nl">SIFIVE_UART_TXFIFO</span><span class="p">:</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="cm">/* Should check tx fifo */</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_IE</span><span class="p">:</span> + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">ie</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_IP</span><span class="p">:</span> + <span class="k">return</span> <span class="n">uart_ip</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_TXCTRL</span><span class="p">:</span> + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">txctrl</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_RXCTRL</span><span class="p">:</span> + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">rxctrl</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_DIV</span><span class="p">:</span> + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">div</span><span class="p">;</span> + <span class="p">}</span> + + <span class="n">qemu_log_mask</span><span class="p">(</span><span class="n">LOG_GUEST_ERROR</span><span class="p">,</span> <span class="s">"%s: bad read: addr=0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> + <span class="n">__func__</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">addr</span><span class="p">);</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> +<span class="nf">uart_write</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">,</span> <span class="n">hwaddr</span> <span class="n">addr</span><span class="p">,</span> + <span class="kt">uint64_t</span> <span class="n">val64</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">size</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + <span class="kt">uint32_t</span> <span class="n">value</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">ch</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span> + + <span class="k">switch</span> <span class="p">(</span><span class="n">addr</span><span class="p">)</span> <span class="p">{</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_TXFIFO</span><span class="p">:</span> + <span class="n">qemu_chr_fe_write</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">,</span> <span class="o">&</span><span class="n">ch</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> + <span class="n">update_irq</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> + <span class="k">return</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_IE</span><span class="p">:</span> + <span class="n">s</span><span class="o">-></span><span class="n">ie</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="n">update_irq</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> + <span class="k">return</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_TXCTRL</span><span class="p">:</span> + <span class="n">s</span><span class="o">-></span><span class="n">txctrl</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="k">return</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_RXCTRL</span><span class="p">:</span> + <span class="n">s</span><span class="o">-></span><span class="n">rxctrl</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="k">return</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_DIV</span><span class="p">:</span> + <span class="n">s</span><span class="o">-></span><span class="n">div</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="k">return</span><span class="p">;</span> + <span class="p">}</span> + <span class="n">qemu_log_mask</span><span class="p">(</span><span class="n">LOG_GUEST_ERROR</span><span class="p">,</span> <span class="s">"%s: bad write: addr=0x%x v=0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> + <span class="n">__func__</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">addr</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">value</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="k">const</span> <span class="n">MemoryRegionOps</span> <span class="n">uart_ops</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">read</span> <span class="o">=</span> <span class="n">uart_read</span><span class="p">,</span> + <span class="p">.</span><span class="n">write</span> <span class="o">=</span> <span class="n">uart_write</span><span class="p">,</span> + <span class="p">.</span><span class="n">endianness</span> <span class="o">=</span> <span class="n">DEVICE_NATIVE_ENDIAN</span><span class="p">,</span> + <span class="p">.</span><span class="n">valid</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">min_access_size</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span> + <span class="p">.</span><span class="n">max_access_size</span> <span class="o">=</span> <span class="mi">4</span> + <span class="p">}</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">uart_rx</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">,</span> <span class="k">const</span> <span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buf</span><span class="p">,</span> <span class="kt">int</span> <span class="n">size</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + + <span class="cm">/* Got a byte. */</span> + <span class="k">if</span> <span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span> <span class="o">>=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">))</span> <span class="p">{</span> + <span class="n">printf</span><span class="p">(</span><span class="s">"WARNING: UART dropped char.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="k">return</span><span class="p">;</span> + <span class="p">}</span> + <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">[</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="o">*</span><span class="n">buf</span><span class="p">;</span> + + <span class="n">update_irq</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">uart_can_rx</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span> <span class="o"><</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">uart_event</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">,</span> <span class="n">QEMUChrEvent</span> <span class="n">event</span><span class="p">)</span> +<span class="p">{</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">uart_be_change</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + + <span class="n">qemu_chr_fe_set_handlers</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">,</span> <span class="n">uart_can_rx</span><span class="p">,</span> <span class="n">uart_rx</span><span class="p">,</span> <span class="n">uart_event</span><span class="p">,</span> + <span class="n">uart_be_change</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">true</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="cm">/*</span> +<span class="cm"> * Create UART device.</span> +<span class="cm"> */</span> +<span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="nf">sifive_uart_create</span><span class="p">(</span><span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">address_space</span><span class="p">,</span> <span class="n">hwaddr</span> <span class="n">base</span><span class="p">,</span> + <span class="n">Chardev</span> <span class="o">*</span><span class="n">chr</span><span class="p">,</span> <span class="n">qemu_irq</span> <span class="n">irq</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">g_malloc0</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">SiFiveUARTState</span><span class="p">));</span> + <span class="n">s</span><span class="o">-></span><span class="n">irq</span> <span class="o">=</span> <span class="n">irq</span><span class="p">;</span> + <span class="n">qemu_chr_fe_init</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">,</span> <span class="n">chr</span><span class="p">,</span> <span class="o">&</span><span class="n">error_abort</span><span class="p">);</span> + <span class="n">qemu_chr_fe_set_handlers</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">,</span> <span class="n">uart_can_rx</span><span class="p">,</span> <span class="n">uart_rx</span><span class="p">,</span> <span class="n">uart_event</span><span class="p">,</span> + <span class="n">uart_be_change</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">true</span><span class="p">);</span> + <span class="n">memory_region_init_io</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">mmio</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">&</span><span class="n">uart_ops</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> + <span class="n">TYPE_SIFIVE_UART</span><span class="p">,</span> <span class="n">SIFIVE_UART_MAX</span><span class="p">);</span> + <span class="n">memory_region_add_subregion</span><span class="p">(</span><span class="n">address_space</span><span class="p">,</span> <span class="n">base</span><span class="p">,</span> <span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">mmio</span><span class="p">);</span> + <span class="k">return</span> <span class="n">s</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="paravirtualization"> +<h2>Paravirtualization<a class="headerlink" href="#paravirtualization" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-paravirtualization simple"> +<li>Change the guest OS so that it cooperates with the VMM<ul> +<li>CPU paravirtualization</li> +<li>MMU paravirtualization</li> +<li>I/O paravirtualization</li> +</ul> +</li> +<li>VMM exposes hypercalls for:<ul> +<li>activate / deactivate the interrupts</li> +<li>changing page tables</li> +<li>accessing virtualized peripherals</li> +</ul> +</li> +<li>VMM uses events to trigger interrupts in the VM</li> +</ul> +</div> +<div class="section" id="intel-vt-x"> +<h2>Intel VT-x<a class="headerlink" href="#intel-vt-x" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-intel-vt-x simple"> +<li>Hardware extension to transform x86 to the point it can be +virtualized "classically"</li> +<li>New execution mode: non-root mode</li> +<li>Each non-root mode instance uses a Virtual Machine Control +Structure (VMCS) to store its state</li> +<li>VMM runs in root mode</li> +<li>VM-entry and VM-exit are used to transition between the two modes</li> +</ul> +<div class="section" id="virtual-machine-control-structure"> +<h3>Virtual Machine Control Structure<a class="headerlink" href="#virtual-machine-control-structure" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-virtual-machine-control-structure simple"> +<li>Guest information: state of the virtual CPU</li> +<li>Host information: state of the physical CPU</li> +<li>Saved information:<ul> +<li>visible state: segment registers, CR3, IDTR, etc.</li> +<li>internal state</li> +</ul> +</li> +<li>VMCS can not be accessed directly but certain information can be +accessed with special instructions</li> +</ul> +</div> +<div class="section" id="vm-entry-exit"> +<h3>VM entry & exit<a class="headerlink" href="#vm-entry-exit" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-vm-entry-exit simple"> +<li>VM entry - new instructions that switches the CPU in non-root +mode and loads the VM state from a VMCS; host state is saved in +VMCS</li> +<li>Allows injecting interrupts and exceptions in the guest</li> +<li>VM exit will be automatically triggered based on the VMCS +configuration</li> +<li>When VM exit occurs host state is loaded from VMCS, guest state +is saved in VMCS</li> +</ul> +</div> +<div class="section" id="vm-execution-control-fields"> +<h3>VM execution control fields<a class="headerlink" href="#vm-execution-control-fields" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-vm-execution-control-fields simple"> +<li>Selects conditions which triggers a VM exit; examples:<ul> +<li>If an external interrupt is generated</li> +<li>If an external interrupt is generated and EFLAGS.IF is set</li> +<li>If CR0-CR4 registers are modified</li> +</ul> +</li> +<li>Exception bitmap - selects which exceptions will generate a VM +exit</li> +<li>IO bitmap - selects which I/O addresses (IN/OUT accesses) +generates a VM exit</li> +<li>MSR bitmaps - selects which RDMSR or WRMSR instructions will +generate a VM exit</li> +</ul> +</div> +</div> +<div class="section" id="extend-page-tables"> +<h2>Extend Page Tables<a class="headerlink" href="#extend-page-tables" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-extend-page-tables simple"> +<li>Reduces the complexity of MMU virtualization and improves +performance</li> +<li>Access to CR3, INVLPG and page faults do not require VM exit +anymore</li> +<li>The EPT page table is controlled by the VMM</li> +</ul> +<img alt="../_images/ditaa-cc9a2e995be74ee99646ea4bf0e551d766fa92ef.png" src="../_images/ditaa-cc9a2e995be74ee99646ea4bf0e551d766fa92ef.png" /> +<div class="section" id="vpid"> +<h3>VPID<a class="headerlink" href="#vpid" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-vpid simple"> +<li>VM entry and VM exit forces a TLB flush - loses VMM / VM translations</li> +<li>To avoid this issue a VPID (Virtual Processor ID) tag is +associated with each VM (VPID 0 is reserved for the VMM)</li> +<li>All TLB entries are tagged</li> +<li>At VM entry and exit just the entries associated with the tags +are flushed</li> +<li>When searching the TLB just the current VPID is used</li> +</ul> +</div> +</div> +<div class="section" id="i-o-virtualization"> +<h2>I/O virtualization<a class="headerlink" href="#i-o-virtualization" title="Permalink to this headline">¶</a></h2> +<blockquote> +<div><ul class="simple"> +<li>Direct access to hardware from a VM - in a controlled fashion<ul> +<li>Map the MMIO host directly to the guest</li> +<li>Forward interrupts</li> +</ul> +</li> +</ul> +</div></blockquote> +<img alt="../_images/ditaa-3901edd823cdc7a6f429ebc37cbc541e650abc96.png" class="admonition-i-o-virtualization" src="../_images/ditaa-3901edd823cdc7a6f429ebc37cbc541e650abc96.png" /> +<p>Instead of trapping MMIO as with emulated devices we can allow the +guest to access the MMIO directly by mapping through its page tables.</p> +<p>Interrupts from the device are handled by the host kernel and a signal +is send to the VMM which injects the interrupt to the guest just as +for the emulated devices.</p> +<p class="admonition-i-o-mmu">VT-d protects and translates VM physical addresses using an I/O +MMU (DMA remaping)</p> +<img alt="../_images/ditaa-d880751969de8642b2613caaca345d71acea4500.png" src="../_images/ditaa-d880751969de8642b2613caaca345d71acea4500.png" /> +<ul class="admonition-interrupt-posting simple"> +<li>Messsage Signaled Interrupts (MSI) = DMA writes to the host +address range of the IRQ controller (e.g. 0xFEExxxxx)</li> +<li>Low bits of the address and the data indicate which interrupt +vector to deliver to which CPU</li> +<li>Interrupt remapping table points to the virtual CPU (VMCS) that +should receive the interrupt</li> +<li>I/O MMU will trap the IRQ controller write and look it up in the +interrupt remmaping table<ul> +<li>if that virtual CPU is currently running it will take the +interrupt directly</li> +<li>otherwise a bit is set in a table (Posted Interrupt Descriptor +table) and the interrupt will be inject next time that vCPU is +run</li> +</ul> +</li> +</ul> +<img alt="../_images/ditaa-2cb0eb0056bb775d1446843d62241fd660662c96.png" class="admonition-i-o-virtualization" src="../_images/ditaa-2cb0eb0056bb775d1446843d62241fd660662c96.png" /> +<ul class="admonition-sr-iov simple"> +<li>Single Root - Input Output Virtualization</li> +<li>Physical device with multiple Ethernet ports will be shown as +multiple device on the PCI bus</li> +<li>Physical Function is used for the control and can be configured<ul> +<li>to present itself as a new PCI device</li> +<li>which VLAN to use</li> +</ul> +</li> +<li>The new virtual function is enumerated on the bus and can be +assigned to a particular guest</li> +</ul> +</div> +<div class="section" id="qemu"> +<h2>qemu<a class="headerlink" href="#qemu" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-qemu simple"> +<li>Uses binary translation via Tiny Code Generator (TCG) for +efficient emulation</li> +<li>Supports different target and host architectures (e.g. running +ARM VMs on x86)</li> +<li>Both process and full system level emulation</li> +<li>MMU emulation</li> +<li>I/O emulation</li> +<li>Can be used with KVM for accelerated virtualization</li> +</ul> +</div> +<div class="section" id="kvm"> +<h2>KVM<a class="headerlink" href="#kvm" title="Permalink to this headline">¶</a></h2> +<img alt="../_images/ditaa-f8fcc760ef5dad50d1038ed3426d0fcce12fd3e6.png" class="admonition-kvm" src="../_images/ditaa-f8fcc760ef5dad50d1038ed3426d0fcce12fd3e6.png" /> +<ul class="admonition-kvm simple"> +<li>Linux device driver for hardware virtualization (e.g. Intel VT-x, SVM)</li> +<li>IOCTL based interface for managing and running virtual CPUs</li> +<li>VMM components implemented inside the Linux kernel +(e.g. interrupt controller, timers)</li> +<li>Shadow page tables or EPT if present</li> +<li>Uses qemu or virtio for I/O virtualization</li> +</ul> +</div> +<div class="section" id="type-1-vs-type-2-hypervisors"> +<h2>Type 1 vs Type 2 Hypervisors<a class="headerlink" href="#type-1-vs-type-2-hypervisors" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-xen simple"> +<li>Type 1 = Bare Metal Hypervisor</li> +<li>Type 2 = Hypervisor embedded in an exist kernel / OS</li> +</ul> +</div> +<div class="section" id="xen"> +<h2>Xen<a class="headerlink" href="#xen" title="Permalink to this headline">¶</a></h2> +<img alt="../_images/xen-overview.png" class="admonition-xen" src="../_images/xen-overview.png" /> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="arch.html" class="btn btn-neutral float-left" title="Architecture Layer" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../labs/infrastructure.html" class="btn btn-neutral float-right" title="Infrastructure" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/objects.inv b/refs/pull/405/merge/objects.inv new file mode 100644 index 00000000..fd87c455 Binary files /dev/null and b/refs/pull/405/merge/objects.inv differ diff --git a/refs/pull/405/merge/search.html b/refs/pull/405/merge/search.html new file mode 100644 index 00000000..cb9bb85d --- /dev/null +++ b/refs/pull/405/merge/search.html @@ -0,0 +1,173 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Search — The Linux Kernel documentation</title><link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" /> + + <!--[if lt IE 9]> + <script src="_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'./', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="_static/jquery.js"></script> + <script src="_static/underscore.js"></script> + <script src="_static/doctools.js"></script> + <script src="_static/asciinema-player.js"></script> + <script src="_static/js/theme.js"></script> + <script src="_static/searchtools.js"></script> + <script src="_static/language_data.js"></script> + <link rel="index" title="Index" href="genindex.html" /> + <link rel="search" title="Search" href="#" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="#" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="so2/index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Search</li> + <li class="wy-breadcrumbs-aside"> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <noscript> + <div id="fallback" class="admonition warning"> + <p class="last"> + Please activate JavaScript to enable the search functionality. + </p> + </div> + </noscript> + + + <div id="search-results"> + + </div> + + </div> + </div> + <footer> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + <script> + jQuery(function() { Search.loadIndex("searchindex.js"); }); + </script> + + <script id="searchindexloader"></script> + + + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/searchindex.js b/refs/pull/405/merge/searchindex.js new file mode 100644 index 00000000..d74a26a7 --- /dev/null +++ b/refs/pull/405/merge/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["index","info/contributing","info/extra-vm","info/vm","labs/arm_kernel_development","labs/block_device_drivers","labs/deferred_work","labs/device_drivers","labs/device_model","labs/filesystems_part1","labs/filesystems_part2","labs/infrastructure","labs/interrupts","labs/introduction","labs/kernel_api","labs/kernel_modules","labs/kernel_profiling","labs/memory_mapping","labs/networking","lectures/address-space","lectures/arch","lectures/debugging","lectures/fs","lectures/interrupts","lectures/intro","lectures/memory-management","lectures/networking","lectures/processes","lectures/smp","lectures/syscalls","lectures/virt","so2/assign-collaboration","so2/assign0-kernel-api","so2/assign1-kprobe-based-tracer","so2/assign2-driver-uart","so2/assign3-software-raid","so2/assign4-transport-protocol","so2/assign5-pitix","so2/assign7-kvm-vmm","so2/grading","so2/index","so2/lab1-intro","so2/lab10-networking","so2/lab11-arm-kernel-development","so2/lab12-kernel-profiling","so2/lab2-kernel-api","so2/lab3-device-drivers","so2/lab4-interrupts","so2/lab5-deferred-work","so2/lab6-memory-mapping","so2/lab7-block-device-drivers","so2/lab8-filesystems-part1","so2/lab9-filesystems-part2","so2/lec1-intro","so2/lec10-networking","so2/lec11-arch","so2/lec12-profiling","so2/lec12-virtualization","so2/lec2-syscalls","so2/lec3-processes","so2/lec4-interrupts","so2/lec5-smp","so2/lec6-address-space","so2/lec7-memory-management","so2/lec8-filesystems","so2/lec9-debugging"],envversion:53,filenames:["index.rst","info/contributing.rst","info/extra-vm.rst","info/vm.rst","labs/arm_kernel_development.rst","labs/block_device_drivers.rst","labs/deferred_work.rst","labs/device_drivers.rst","labs/device_model.rst","labs/filesystems_part1.rst","labs/filesystems_part2.rst","labs/infrastructure.rst","labs/interrupts.rst","labs/introduction.rst","labs/kernel_api.rst","labs/kernel_modules.rst","labs/kernel_profiling.rst","labs/memory_mapping.rst","labs/networking.rst","lectures/address-space.rst","lectures/arch.rst","lectures/debugging.rst","lectures/fs.rst","lectures/interrupts.rst","lectures/intro.rst","lectures/memory-management.rst","lectures/networking.rst","lectures/processes.rst","lectures/smp.rst","lectures/syscalls.rst","lectures/virt.rst","so2/assign-collaboration.rst","so2/assign0-kernel-api.rst","so2/assign1-kprobe-based-tracer.rst","so2/assign2-driver-uart.rst","so2/assign3-software-raid.rst","so2/assign4-transport-protocol.rst","so2/assign5-pitix.rst","so2/assign7-kvm-vmm.rst","so2/grading.rst","so2/index.rst","so2/lab1-intro.rst","so2/lab10-networking.rst","so2/lab11-arm-kernel-development.rst","so2/lab12-kernel-profiling.rst","so2/lab2-kernel-api.rst","so2/lab3-device-drivers.rst","so2/lab4-interrupts.rst","so2/lab5-deferred-work.rst","so2/lab6-memory-mapping.rst","so2/lab7-block-device-drivers.rst","so2/lab8-filesystems-part1.rst","so2/lab9-filesystems-part2.rst","so2/lec1-intro.rst","so2/lec10-networking.rst","so2/lec11-arch.rst","so2/lec12-profiling.rst","so2/lec12-virtualization.rst","so2/lec2-syscalls.rst","so2/lec3-processes.rst","so2/lec4-interrupts.rst","so2/lec5-smp.rst","so2/lec6-address-space.rst","so2/lec7-memory-management.rst","so2/lec8-filesystems.rst","so2/lec9-debugging.rst"],objects:{},objnames:{},objtypes:{},terms:{"0000000c":[15,41],"000002d8":[21,65],"0000eef4":[21,65],"0001b000":[27,59],"001f":[12,47],"001s":[16,44],"005f":[12,47],"006f":[12,47],"007b":[15,21,41,65],"008f":[12,47],"0091ffff":[4,43],"00a0":[12,47],"00a1":[12,47],"00c0":[12,47],"00d8":[21,65],"00df":[12,47],"00f0":[12,47],"00ff":[12,47],"011848be72f8bb42":[21,65],"015s":[16,44],"01f0":[12,47],"01f7":[12,47],"0209c000":[4,43],"0209ffff":[4,43],"020s":[16,44],"021a0000":[4,43],"021a3fff":[4,43],"02x":[5,50],"037a":[12,47],"037b":[12,47],"037f":[12,47],"03c0":[12,47],"03df":[12,47],"03f6":[12,47],"03f8":[12,47],"03ff":[12,47],"0716b000":[21,65],"0785f000":[21,65],"0804c000":[27,59],"0804d000":[27,59],"0806e000":[27,59],"08afb008":[21,65],"08afb050":[21,65],"092e1000":[17,49],"0m0":[16,44],"0ubuntu1":2,"0ul":[28,61],"0x0":[13,15,21,27,38,41,59,65],"0x00000000":[2,13,41],"0x00001234":[15,41],"0x0001234":[15,41],"0x0092":[19,62],"0x009a":[19,62],"0x01":[12,47],"0x08":[12,21,47,65],"0x10":[13,15,21,41,65],"0x100":[21,65],"0x1000":[21,65],"0x100000":38,"0x105":[21,65],"0x106":[15,41],"0x11":[13,41],"0x119":[21,65],"0x11c":[21,65],"0x12":[15,41],"0x120":[21,65],"0x1234":[15,41],"0x12c":[21,65],"0x140":[15,41],"0x14f":[21,65],"0x150":[15,41],"0x15f":[21,65],"0x163":[21,65],"0x164":[21,65],"0x17":[21,65],"0x170":[15,21,41,65],"0x17a0":[21,65],"0x180":[21,65],"0x19":[21,65],"0x190":[21,65],"0x19b8":[15,41],"0x1a":[15,41],"0x1a0":[21,65],"0x1a40":[15,41],"0x1b":[21,65],"0x1b0":[15,41],"0x1be":[21,65],"0x1c":[12,21,47,65],"0x1c2":[21,65],"0x1d":[12,21,47,65],"0x1e":[12,47],"0x1e0":[21,65],"0x1e3":[21,65],"0x1ee":[21,65],"0x1f0":[21,65],"0x1f2":[21,65],"0x1f45":[21,65],"0x2":38,"0x20":[15,21,41,65],"0x200":[21,65],"0x201a":[21,65],"0x21":[15,41],"0x2380":[21,65],"0x25":[21,65],"0x2590":[21,65],"0x27":[21,65],"0x2a":[12,47],"0x2b":[21,65],"0x2d":[15,41],"0x2e":[12,21,47,65],"0x2e0":[21,65],"0x2f":[21,65],"0x2f0":[21,65],"0x2f8":34,"0x2ff":34,"0x3":[15,41],"0x30":[12,15,21,41,47,65],"0x305":[21,65],"0x30a":[21,65],"0x31":[21,65],"0x310":[21,65],"0x317":[21,65],"0x32":[21,65],"0x35":[21,65],"0x37":[21,65],"0x378":[12,47],"0x379":[12,47],"0x37a":[12,47],"0x38":[13,21,41,65],"0x3824548b":[13,41],"0x39":[21,65],"0x3a":[21,65],"0x3f":[21,65],"0x3f8":[12,34,47],"0x3ff":34,"0x4":38,"0x40":[21,65],"0x400":38,"0x4092":[19,62],"0x409a":[19,62],"0x42":[21,65],"0x43":[15,41],"0x44902cc2":[21,65],"0x46":[21,65],"0x48":[21,65],"0x4b":[21,65],"0x4b4":[21,65],"0x4c":[21,65],"0x4f":[21,65],"0x5":[15,41],"0x50":[21,65],"0x52":[21,65],"0x57":[21,65],"0x5ea":[21,65],"0x6":[15,21,41,65],"0x60":[12,21,47,65],"0x61":[12,21,47,65],"0x63":[21,65],"0x64":[12,47],"0x640":[21,65],"0x65":[12,47],"0x66":[21,65],"0x6a":[21,65],"0x6c":[21,65],"0x7":[21,65],"0x70":[21,65],"0x71":[21,65],"0x72":[21,65],"0x74726976":38,"0x7d":[21,65],"0x7ffc3349ba50":[16,44],"0x8":[21,65],"0x80":[12,21,29,47,58,65],"0x8000":38,"0x80000000":[30,57],"0x830":[21,65],"0x858458f6":[9,51],"0x8a":[15,41],"0x8d":[21,65],"0x9":[21,65],"0x90":[21,65],"0x93":[21,65],"0x95":[21,65],"0x96":[21,65],"0x99":[21,65],"0x9b":[21,65],"0x9c":[12,47],"0x9d":[12,47],"0x9e":[12,47],"0xa":[21,65],"0xa09b":[19,62],"0xa0fb":[19,62],"0xa4":[15,21,41,65],"0xa9":[21,65],"0xaa":[12,17,47,49],"0xae":[12,47],"0xaf":[21,65],"0xb":[21,65],"0xb0":[12,21,47,65],"0xbb":[17,49],"0xc":[13,15,21,41,65],"0xc01013d3":[13,41],"0xc01013d7":[13,41],"0xc01013dc":[13,41],"0xc01013de":[13,41],"0xc01013e0":[13,41],"0xc01013e2":[13,41],"0xc01013e6":[13,41],"0xc01013eb":[13,41],"0xc01013ee":[13,41],"0xc0101431":[13,41],"0xc0111aab":[13,41],"0xc011482a":[13,41],"0xc011548b":[13,41],"0xc0115c6c":[13,41],"0xc011bc58":[13,41],"0xc014249e":[13,41],"0xc0142725":[13,41],"0xc0142d4e":[13,41],"0xc0142d7d":[13,41],"0xc0142de5":[13,41],"0xc014363d":[13,41],"0xc014369f":[13,41],"0xc014fee7":[13,41],"0xc015042c":[13,41],"0xc01507a1":[13,41],"0xc02e535c":[13,41],"0xc02e536c":[13,41],"0xc02e537c":[13,41],"0xc02e538c":[13,41],"0xc092":[19,62],"0xc093":[19,62],"0xc09a":[19,62],"0xc09b":[19,62],"0xc0f2":[19,62],"0xc0f3":[19,62],"0xc0fa":[19,62],"0xc0fb":[19,62],"0xc10001da":2,"0xc101f136":2,"0xc106a6dd":2,"0xc106a8c5":2,"0xc1244138":[21,65],"0xc13cb14a":2,"0xc13cf2f2":2,"0xc1507a7a":2,"0xc15de780":[23,60],"0xc15de874":[23,60],"0xc8816000":[21,65],"0xc8817000":[21,65],"0xc886d000":[15,41],"0xc888a000":[15,41],"0xc8903000":[15,41],"0xc895a000":[15,41],"0xc89ad000":[15,41],"0xc89d4000":[15,41],"0xc8d":[21,65],"0xcc":[17,49],"0xd":[21,65],"0xd5":[15,41],"0xd7871500":[21,65],"0xd84156c5635688c0":[21,65],"0xdd":[17,49],"0xde":[21,65],"0xe5":[21,65],"0xe77":[21,65],"0xe9":38,"0xeb":[21,65],"0xf0":[15,21,41,65],"0xfd":[21,65],"0xfeexxxxx":[30,57],"0xff":[12,47],"0xff800000":[23,60],"0xff801000":[23,60],"0xffe000ba":[13,41],"0xfffbd000":38,"0xffff":[19,23,60,62],"0xffffe000ul":[19,62],"0xfffff":[19,62],"0xfffff000":[19,62],"100m":[24,53],"10p":38,"12k":[14,45],"14x14":[4,43],"17ec19e9b5bf":[27,59],"1980s":[14,45],"1ubuntu1":[21,65],"209c000":[4,43],"20min":53,"20p":38,"2115503fc3e3":31,"21a0000":[4,43],"2981ce73ae801363":[15,41],"2mb":38,"30p":38,"31s":8,"32bit":[0,4,17,24,27,29,43,49,53,58,59],"32byte":[25,63],"34xc3":39,"3c92a02cc527":31,"3c92a02cc52700d2cd7c50a20297eef8553c207a":31,"3gbp":[26,54],"3nd":53,"3rd":[5,6,9,10,12,13,17,41,47,48,49,50,51,52,53],"400mb":2,"4480c000":[17,49],"4482e000":[17,49],"4482f000":[17,49],"449a9000":[17,49],"449ab000":[17,49],"449ac000":[17,49],"449af000":[17,49],"45eeb3d6ea8ff1":[15,41],"4gb":[19,62],"4kb":[19,24,53,62],"4mb":[19,25,62,63],"4umkcismqm":11,"512m":[4,43],"53asm":2,"5a5a5a5a":[21,65],"60k":[26,54],"628s":[21,65],"64bit":[4,19,43,62],"64k":[17,19,49,62],"6b6b6b6b":[21,65],"738mbp":[26,54],"77f49f83f2e42f91":[21,65],"7e43c163832f":[27,59],"7rwv63e9wf":3,"7th":[16,44],"8kb":[27,59],"978mbp":[26,54],"9f680e8136bf":31,"9fffffff":[4,43],"9gbp":[26,54],"\u00een\u0163ele":53,"\u00een\u021belegerea":53,"\u00eenaint":53,"\u00eensu\u0219irea":53,"\u00eentreb\u0103ril":53,"\u00eentreba\u0163i":53,"\u00eentreruperi":53,"\u015fi":53,"\u0219erb\u0103nescu":53,"\u0219i":53,"\u0219tefan":53,"a\u0163i":53,"abstract":[0,8,9,18,20,24,27,35,42,51,53,55,59],"activit\u0103\u021bi":53,"activita\u021bi":53,"adun\u0103ri":53,"ajust\u0103ri":53,"b\u0103lu\u021b\u0103":53,"baz\u0103":53,"break":[6,7,13,27,41,46,48,59],"byte":[4,5,7,9,10,12,14,15,16,17,18,19,21,22,23,27,30,34,35,36,37,38,41,42,43,44,45,46,47,49,50,51,52,57,59,60,62,64,65],"c\u00e2nd":53,"c\u00e2te":53,"c\u0103lduro":53,"cas\u0103":53,"case":[1,5,6,7,8,9,10,12,13,14,15,16,17,18,19,21,23,24,27,28,29,30,32,33,34,35,36,37,38,39,41,42,44,45,46,47,48,49,50,51,52,53,57,58,59,60,61,62,65],"catch":[19,21,62,65],"char":[3,5,6,7,8,9,10,12,14,15,17,18,21,26,30,31,33,37,38,41,42,45,46,47,48,49,50,51,52,54,57,65],"class":[0,6,7,19,21,22,24,27,46,48,53,59,62,64,65],"compara\u0163ii":53,"condi\u0163ii":53,"const":[5,6,7,8,9,10,12,18,19,22,26,29,30,31,36,42,46,47,48,50,51,52,54,57,58,62,64],"const\u0103":53,"contribu\u021bii":53,"corec\u021bii":53,"cuno\u0219tin\u021belor":53,"default":[2,3,7,8,10,13,14,15,16,19,24,26,27,34,36,39,41,44,45,46,52,53,54,59,62],"dep\u0103se\u0219t":53,"discu\u0163ii":53,"discu\u021bi":53,"discu\u021bii":53,"dup\u0103":53,"echilibra\u021bi":53,"enum":[6,18,19,22,23,42,48,60,62,64],"exerci\u021bii":53,"export":[8,14,32,45],"fi\u0219ier":[37,53],"fi\u0219ierelor":53,"final":[0,6,17,20,21,23,27,28,31,38,48,49,55,59,60,61,65],"final\u0103":53,"function":[0,2,3,6,7,10,12,13,14,15,16,17,18,19,20,21,22,23,24,25,27,28,29,30,31,33,34,35,36,37,38,41,42,44,45,46,47,48,49,52,53,55,57,58,59,60,61,62,63,64,65],"ghi\u021b\u0103":53,"goto":[5,18,27,28,42,50,59,61],"implement\u0103rii":53,"import":[0,5,6,7,8,9,10,13,14,15,16,17,18,21,22,24,27,28,29,39,41,42,44,45,46,48,49,50,51,52,53,58,59,61,64,65],"informa\u021bii":53,"instruc\u021biuni":53,"int":[4,5,6,7,8,9,10,12,14,15,17,18,19,21,22,23,25,26,27,29,30,31,38,41,42,43,45,46,47,48,49,50,51,52,54,57,58,59,60,62,63,64,65],"lauren\u021biu":53,"leg\u0103tur\u0103":53,"list\u0103":53,"long":[0,2,5,6,7,9,10,12,17,18,19,22,23,27,28,29,31,37,39,42,46,47,48,49,50,51,52,58,59,60,61,62,64],"mi\u0219u":53,"minim\u0103":53,"new":[0,1,2,5,6,7,9,10,11,13,14,15,17,18,19,21,22,23,24,25,27,28,30,37,38,41,42,45,46,48,49,50,51,52,53,57,59,60,61,62,63,64,65],"null":[6,7,8,9,10,12,14,15,16,17,18,19,21,22,27,30,41,42,44,45,46,47,48,49,51,52,57,59,62,64,65],"participa\u0163i":53,"pozi\u021bionar":0,"preciz\u0103ri":53,"primi\u021bi":53,"propune\u021bi":53,"pu\u0163in":53,"public":[18,24,30,37,39,42,53,57],"puncteaz\u0103":53,"purdil\u0103":53,"r\u0103ducanu":53,"r\u0103spunde\u021bi":53,"r\u0103zvan":53,"re\u021belei":53,"recomand\u0103":53,"return":[0,5,6,7,8,9,10,12,13,14,15,17,18,19,21,22,25,27,28,29,30,31,33,35,38,41,42,45,46,47,48,49,50,51,52,57,58,59,61,62,63,64,65],"short":[12,18,36,42,47,51],"socke\u021bi":53,"static":[4,5,7,8,9,10,12,13,14,15,16,17,18,19,21,23,27,28,29,30,31,32,33,34,35,36,37,38,41,42,43,44,45,46,47,49,50,51,52,57,58,59,60,61,62,65],"super":[9,10,27,51,52,59],"switch":[0,7,9,16,19,21,22,23,28,29,30,38,44,46,51,57,58,60,61,62,64,65],"true":[4,6,8,18,22,23,27,28,29,30,42,43,48,57,58,59,60,61,64],"try":[6,8,9,10,12,13,15,16,21,24,25,27,28,31,41,44,47,48,51,52,53,59,61,63,65],"var":[4,15,16,41,43,44],"virtual\u0103":53,"vo\u0219tri":53,"void":[5,6,7,8,9,10,12,14,15,17,18,19,21,22,23,25,26,27,28,29,30,31,41,42,45,46,47,48,49,50,51,52,54,57,58,59,60,61,62,63,64,65],"while":[5,6,7,8,9,10,12,13,14,15,16,17,18,19,22,23,24,27,28,29,41,42,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,64],AND:[12,47],Adding:[0,5,50],And:[6,7,15,19,28,31,41,46,48,61,62],Are:2,BHs:[23,60],BUS:[8,24,53],Bus:[0,28,61],But:[12,14,27,29,38,45,47,58,59],CDs:[9,51],FOR:[30,57],For:[1,2,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,21,22,23,24,25,27,28,29,30,32,33,34,35,36,37,39,41,42,44,45,46,47,48,49,50,51,52,53,57,58,59,60,61,62,63,64,65],HFS:[10,52],I2S:[4,43],IDE:[7,8,46],IDs:8,Into:[18,42],Its:[7,8,10,46,52],MIS:[12,47],NOT:[4,5,6,7,8,9,10,12,14,15,16,17,18,41,42,43,44,45,46,47,48,49,50,51,52],Not:[15,21,23,25,30,41,57,60,63,65],ORed:[26,54],OSes:[23,60],One:[5,7,8,10,14,15,16,21,24,25,27,28,41,44,45,46,50,52,53,59,61,63,65],PCs:[24,53],Such:[8,10,14,15,18,24,41,42,45,52,53],TLS:[19,62],TOS:[26,54],That:[6,7,9,13,15,18,19,41,42,46,48,51,62],The:[0,1,2,3,4,5,6,7,11,12,13,14,15,16,17,19,20,21,23,24,25,26,28,29,30,31,32,33,34,35,36,37,38,39,41,43,44,45,46,47,48,49,50,53,54,55,57,58,60,61,62,63,65],Their:[12,18,24,42,47,53],Then:[4,5,6,7,8,9,10,12,13,14,15,16,17,18,21,23,27,28,29,31,41,42,43,44,45,46,47,48,49,50,51,52,58,59,60,61,65],There:[2,4,5,6,8,9,10,12,13,15,17,18,19,21,22,23,24,25,27,28,29,33,34,35,36,39,41,42,43,47,48,49,50,51,52,53,58,59,60,61,62,63,64,65],These:[5,6,7,8,9,10,11,13,14,15,16,18,19,22,23,24,29,37,41,42,44,45,46,48,50,51,52,53,58,60,62,64],Use:[0,4,5,6,7,8,9,10,12,13,15,16,17,18,19,24,27,38,41,42,43,44,46,47,48,49,50,51,52,53,59,62],Used:[13,22,24,25,41,53,63,64],Useful:[0,15,41],Uses:[22,25,27,30,57,59,63,64],Using:[0,5,6,7,8,12,13,14,15,17,18,23,25,28,39,41,42,45,46,47,48,49,50,60,61,63],VCS:31,VFS:[0,10,22,24,52,53,64],VMs:[27,30,38,57,59],Will:[6,23,48,60],With:[4,6,13,15,24,27,29,33,41,43,48,53,58,59],___wait_cond_timeout:[27,59],___wait_ev:[27,59],___wait_is_interrupt:[27,59],__add_wait_queu:[27,59],__add_wait_queue_entry_tail:[27,59],__align:[18,42],__aligned__:[27,59],__always_inlin:[19,27,28,29,58,59,61,62],__assembly__:[19,62],__attribute__:[22,27,59,64],__attribute_used__:[27,59],__be16:[18,36,42],__be32:[18,42],__big_endian_bitfield:[18,42],__bread:[9,51],__builtin_expect:[29,58],__cache_fre:[21,65],__chk_user_ptr:[29,58],__data_len:[5,50],__do_softirq:[21,65],__end_of_fixed_address:[19,62],__ex_tabl:[29,58],__exit:[8,18,31,42],__file__:[15,41],__fix_to_virt:[19,62],__forc:[29,58],__free_pag:35,__func__:[15,21,30,41,57,65],__function__:[15,41],__get_dma_pag:[25,63],__get_free_pag:[25,63],__get_user_1:[29,58],__get_user_2:[29,58],__get_user_4:[29,58],__get_user_:[29,58],__get_zero_pag:[25,63],__ia32_sys_writ:[16,44],__init:[8,9,18,31,42,51],__init__:[27,59],__int:[27,59],__inttyp:[29,58],__irqentry_text_end:[16,21,44,65],__kernel_vsyscal:[16,44],__kmalloc:33,__kmap_atomic_idx:[19,62],__label__:[27,59],__libc_start_main:[16,44],__line__:[15,41],__list_del:[21,65],__list_del_entri:[21,65],__little_endian_bitfield:[18,42],__lock_acquir:[21,65],__might_sleep:[21,65],__mutex_lock:[21,65],__mutex_lock_slowpath:[28,61],__mutex_set_flag:[28,61],__mutex_trylock:[28,61],__mutex_trylock_fast:[28,61],__mutex_unlock_fast:[28,61],__mutex_unlock_slowpath:[15,28,41,61],__mutex_waiter_is_first:[28,61],__noinstr_text_start:[16,44],__nr_syscall_compat_max:[29,58],__out:[27,59],__randomize_layout:[22,64],__rcu:[18,42],__request_region:[12,47],__ret:[27,59],__ret_gu:[29,58],__sched:[28,61],__sector:[5,50],__set_current_st:[27,28,59,61],__slab_error:[21,65],__sock_creat:[18,42],__start___ex_t:[29,58],__stop___ex_t:[29,58],__sum16:[18,42],__switch_to:[27,59],__switch_to_asm:[27,59],__syscall_i386:[29,58],__test_and_set_bit:[10,52],__this_cpu_inc_return:[19,62],__this_fixmap_does_not_exist:[19,62],__typeof__:[29,58],__u16:[18,26,37,42,54],__u32:[18,37,42],__u8:[18,36,37,42],__user:[7,18,31,42,46],__val_gu:[29,58],__virt_to_fix:[19,62],__visibl:[29,58],__vunmap:[15,41],__wait_ev:[27,59],__wake_up:[27,59],__wake_up_common:[27,59],__wake_up_common_lock:[27,59],__wq_entri:[27,59],_asm_ax:[29,58],_asm_dx:[29,58],_asm_ext:[29,58],_asm_extable_handl:[29,58],_checker:[32,33,34,35,36],_delai:[6,48],_devic:35,_iget:[10,52],_inode_info:[10,52],_ioc:[7,46],_ioc_non:[7,46],_ioc_read:[7,46],_ioc_writ:[7,46],_one_:[27,59],_raw_spin_lock:[21,65],_really_:[23,60],_register_driv:8,_ret_ip_:[28,61],_skb_refdst:[18,42],_stext:[15,41],_vimrc:[13,41],a_op:[10,22,52,64],aarch64:[4,43],abbrevi:[22,64],abc:[5,50],abil:[7,8,23,24,46,53,60],abl:[5,6,8,9,10,12,21,25,36,47,48,50,51,52,63,65],abnorm:[21,23,60,65],abort:[23,60],about:[0,5,6,7,8,9,10,12,15,17,18,21,22,27,32,33,34,35,36,37,38,39,42,46,47,48,49,50,51,52,59,64,65],abov:[2,5,6,7,8,9,10,12,13,14,15,16,18,21,28,29,32,33,34,35,36,37,38,41,42,44,45,46,47,48,50,51,52,58,61,65],absenc:[28,61],absent:[3,19,62],absolut:[6,12,15,19,41,47,48,62],ac1af6d88a25:31,academ:39,academia:[24,53],acceler:[0,30,57],accept:[0,5,6,24,35,36,39,48,50,53],access:[0,3,5,6,8,9,10,13,15,16,17,18,19,20,21,22,23,24,28,30,31,32,34,35,37,39,40,41,42,44,48,49,50,51,52,53,55,57,60,61,62,64,65],accessor:[5,20,50,55],accident:[28,61],accomplish:[7,9,12,18,23,27,42,46,47,51,59,60],accord:[5,6,7,8,10,14,15,37,38,39,41,45,46,48,50,52],accordingli:[5,7,10,46,50,52],account:[6,7,13,18,27,33,42,46,48,59],accur:[7,46],achiev:[3,8,14,24,27,28,39,45,53,59,61],ack:[18,42],ack_seq:[18,42],acknowledg:[12,23,47,60],acomodarea:53,acpi:[8,12,20,47,55],acquir:[5,6,9,10,12,13,14,18,21,28,35,39,41,42,45,47,48,50,51,52,61,65],acronym:[28,61],across:[18,19,24,28,42,53,61,62],act:[5,36,50],action:[0,5,6,7,8,12,14,26,28,45,46,47,48,50,54,61],activ:[5,10,12,13,15,16,18,21,23,24,27,28,30,35,39,41,42,44,47,50,51,52,53,57,59,60,61,65],active_mm:[27,59],activit:53,activitatea:53,actual:[5,6,7,8,10,12,15,27,28,29,30,37,41,46,47,48,50,52,57,58,59,61],adapt:[26,54],add:[0,1,4,5,6,7,9,10,12,13,14,15,16,20,22,25,26,27,28,29,32,33,34,35,36,38,41,43,44,45,46,47,48,50,51,52,54,55,58,59,61,63,64],add_disk:[5,50],add_pid:[14,45],add_preempt_count:[28,61],add_stor:8,add_tim:13,add_to_buff:[14,45],add_uevent_var:8,added:[2,5,6,7,8,9,10,12,13,14,15,27,28,33,41,45,46,47,48,50,51,52,59,61],addf:32,adding:[5,8,10,15,18,28,32,41,42,50,52,61],addison:53,addit:[1,6,7,8,9,10,12,13,14,15,16,21,33,34,35,36,41,44,45,46,47,48,51,52,65],addition:[5,9,50,51],addr2lin:[0,13],addr:[14,17,18,19,26,29,30,36,42,45,49,54,57,58,62],addr_len:[18,42],addr_limit:[29,58],addreess:[26,54],addres:[26,54],address:[0,2,3,4,5,6,8,12,13,14,15,17,20,21,25,26,27,28,29,30,33,34,36,38,39,40,41,43,45,47,48,49,50,54,55,57,58,59,61,63,65],address_spac:[10,22,30,52,57,64],address_space_oper:[10,22,52,64],adher:[14,45],adjac:[5,21,35,50,65],adjust:[15,18,21,39,41,42,65],admin:[7,46],adresarea:53,advanc:[7,15,24,35,39,41,46,53],advantag:[6,7,8,13,15,19,24,28,41,46,48,53,61,62],advic:[13,41],advoc:[24,53],af_inet:[18,26,42,54],af_stp:36,affect:[13,16,24,28,41,44,51,53,61],aften:[6,48],after:[0,1,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,21,23,24,27,28,29,35,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,65],afterward:[13,15],again:[4,5,6,7,8,9,10,12,13,14,15,16,17,18,41,42,43,44,45,46,47,48,49,50,51,52],against:[19,27,28,29,39,58,59,61,62],age:[21,65],aggreg:[26,28,54,61],agnost:[18,42],ago:[14,23,45,60],agre:31,ahead:[22,64],aid:[15,41],aim:[12,16,33,44,47],albeit:3,alessandro:53,alex:53,alexandru:53,algorithm:[24,25,53,63],alia:[18,42],alic:[15,41],align:[5,17,22,27,28,29,49,50,58,59,61,64],all:[1,2,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,54,57,58,59,60,61,62,63,64,65],alloc:[0,4,5,6,7,8,9,10,12,13,17,19,20,21,22,23,24,27,33,35,37,38,39,41,43,46,47,48,49,50,51,52,53,55,59,60,62,64,65],alloc_chrdev_region:[7,46],alloc_disk:[5,50],alloc_inod:[9,10,51,52],alloc_io:[6,48],alloc_memori:[14,45],alloc_mmap_pag:[17,49],alloc_pag:[5,17,25,35,49,50,63],alloc_skb:[18,42],allow:[2,4,5,6,7,8,10,13,14,15,16,17,18,19,23,24,26,27,28,29,30,31,36,39,41,42,43,44,45,46,48,49,50,52,53,54,57,58,59,60,61,62],almost:[7,10,15,22,23,27,41,46,52,59,60,64],alo:38,alon:[13,14,41,45],along:[7,8,12,14,24,30,35,45,46,47,53,57],alpha:[24,53],alreadi:[0,1,2,3,4,5,6,8,9,10,12,13,14,15,16,17,18,21,27,34,35,36,37,41,42,43,44,45,47,48,49,50,51,52,59,65],alsa:[24,53],also:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,21,22,23,24,25,27,28,29,30,32,33,34,35,36,37,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,57,58,59,60,61,62,63,64,65],alt:[7,46],alter:[23,60],altern:[0,6,9,10,13,15,25,34,41,48,51,52,63],although:[4,5,6,7,8,9,10,12,13,14,15,19,21,22,24,28,29,41,43,45,46,47,48,50,51,52,53,58,61,62,64,65],alwai:[5,6,7,10,14,15,19,21,22,23,24,27,29,31,37,38,45,46,48,50,52,53,58,59,60,62,64,65],ambigu:[13,41],amd:[24,53],amend:1,among:[7,8,15,18,22,39,41,42,46,64],amount:[6,7,15,16,33,41,44,46,48],ampersand:[18,42],ana:38,analog:[7,36,46],analogu:[7,46],analysi:[13,15,16,32,33,34,35,36,37,38,41,44,51],analyz:[5,8,12,13,15,16,18,41,42,44,47,50],ani:[1,5,6,8,9,10,12,13,14,15,16,17,18,21,22,23,24,27,28,30,35,36,38,39,41,42,44,45,47,48,49,50,51,52,53,57,59,60,61,64,65],annot:[16,44],announc:[12,39,47],anonym:[16,44],anoth:[2,4,5,6,7,8,12,13,14,16,17,21,23,24,27,28,34,39,43,44,45,46,47,48,49,50,53,59,60,61,65],ansi:[14,15,41,45],answer:[35,36,37,39,51],answer_flag:[18,42],answer_prot:[18,42],anymor:[6,13,21,30,39,41,48,57,65],anyon:[19,62],anyth:[1,9,13,16,44,51],anytim:[14,45],anywai:[27,59],anywher:[23,60],apach:[13,41],apeluri:53,api:[0,5,7,8,9,12,13,17,19,20,23,24,28,29,35,36,38,39,40,41,46,47,49,50,51,53,55,58,60,61,62],api_v:38,apic:[12,19,23,47,60,62],apic_timer_interrupt:[21,65],apm:[19,62],app:[7,16,44,46],apparmor:[24,53],appear:[5,7,8,12,13,15,17,32,41,46,47,49,50],append:[3,4,43],appli:[1,10,18,42,52],applianc:[4,43],applic:[2,4,7,13,16,18,19,24,26,27,29,41,42,43,44,46,53,54,58,59,62],approach:[5,6,8,10,12,16,17,19,24,28,29,39,44,47,48,49,50,52,53,58,61,62],appropri:[5,7,8,9,10,12,35,46,47,50,51,52],approx:[16,44],apr:[2,3,31],april:[33,34],aprofundar:53,apropo:2,apt:[4,13,32,33,34,35,36,37,38,43],arbitrari:[17,19,28,49,61,62],arbitrarili:[17,49],arbori:53,arch:[0,2,3,4,11,12,13,15,41,43,47],arch_cpu_idl:[2,21,65],arch_flush_lazy_mmu_mod:[19,62],arch_safe_halt:2,arch_start_context_switch:[27,59],architectur:[0,4,7,12,13,18,19,21,25,27,28,29,30,40,41,42,43,46,47,57,58,59,61,62,63,65],archiv:[16,32,33,34,35,36,37,38,44],area:[5,7,8,9,12,13,14,15,17,18,19,22,24,25,27,29,33,35,37,41,42,45,46,47,49,50,51,53,58,59,62,63,64],aren:[16,44],arg:[7,16,27,31,44,46,59],argument:[5,6,7,9,10,12,13,14,15,16,17,18,20,33,41,42,44,45,46,47,48,49,50,51,52,55],aris:8,arithmet:[10,52],arm32:[4,43],arm64:[4,24,43,53],arm:[0,3,6,16,20,24,28,30,40,44,48,53,55,57,61],arm_kernel_develop:[4,43],armi:[18,42],around:2,arpeggio:[7,46],arrai:[4,5,10,19,23,28,36,43,50,52,60,61,62],arrang:[4,23,43,60],array_map:[10,52],arriv:[23,28,60,61],art:[14,45],articl:[7,12,24,38,46,47,53],as_:[22,64],ascend:[18,42],ascii:[0,37,38],asgard:[15,41],asid:0,ask:[18,35,36,37,39,42,51],asm:[2,7,10,12,14,15,18,24,27,28,29,41,42,45,46,47,52,53,58,59,61],asm_call_constraint:[29,58],asm_clac:[29,58],asm_stac:[29,58],asmlinkag:[28,61],asmp:0,aspect:[10,13,16,41,44,52],asrc:[4,43],assembl:[13,15,29,41,58],assig:[0,39],assign:[0,3,5,7,8,17,30,40,46,49,50,57],assignment_grad:39,assist:39,associ:[5,6,7,8,9,10,12,13,14,15,17,18,19,21,22,23,24,25,29,30,33,34,35,36,37,41,42,45,46,47,48,49,50,51,52,53,57,58,60,62,63,64,65],assum:[5,6,7,10,11,29,32,33,34,35,36,46,48,50,52,58],assumpt:[5,37,50],asymmetr:0,asynchron:[5,6,22,23,48,50,60,64],ata:8,atkbd:[12,47],atkbd_interrupt:[12,47],atm:[18,42],atom:[0,5,6,7,10,12,19,27,46,47,48,50,52,59,62],atomic_add:[14,28,45,61],atomic_cmpxchg:[7,14,45,46],atomic_dec:[14,28,45,61],atomic_dec_and_test:[14,28,45,61],atomic_inc:[14,28,45,61],atomic_inc_and_test:[14,45],atomic_kmap:[19,62],atomic_long_cmpxchg_acquir:[28,61],atomic_long_cmpxchg_releas:[28,61],atomic_read:[14,45],atomic_set:[14,45],atomic_sub:[14,28,45,61],atomic_sub_and_test:[28,61],atomic_t:[7,14,22,26,45,46,54,64],attach:[8,13,18,24,29,42,53,58],attack:[27,59],attempt:[9,24,28,51,53,61],attend:39,attent:[16,23,24,44,53,60],attr:[8,10,52],attr_siz:[10,52],attribut:[0,6,7,17,24,46,48,49,53],atunci:53,audio:[4,43],augment:[6,16,44,48],authent:2,author:31,auto:[16,27,44,59],autogener:11,automat:[0,5,7,8,9,10,13,18,27,30,32,33,34,35,36,37,39,41,42,46,50,51,52,57,59],automot:[4,43],autoremove_wake_funct:[27,59],aux:[12,16,44,47],auxiliari:13,avail:[7,8,10,12,15,17,19,20,21,22,24,27,28,29,38,39,41,46,47,49,52,53,55,58,59,61,62,64,65],avoid:[5,6,11,12,14,15,17,19,22,23,24,25,28,29,30,39,41,45,47,48,49,50,53,57,58,60,61,62,63,64],awai:[27,59],awaken:[27,59],awar:[15,24,41,53],award:53,axp:[24,53],b31a257fd8b8:31,b7761000:[17,49],b7763000:[17,49],b7766000:[17,49],b7767000:[17,49],b7f46000:[27,59],b7f49000:[27,59],b7f59000:[27,59],b7f5b000:[27,59],b7f77000:[27,59],b7f79000:[27,59],b_bdev:[9,51],b_blocknr:[9,51],b_data:[9,10,51,52],b_size:[9,51],b_state:[9,51],back:[5,18,22,24,27,28,29,42,50,53,58,59,61,64],backend:[27,59],background:0,backlog:[18,42],backlog_rcv:[18,42],backtrac:[13,15,21,41,65],backup:[13,15,41],backward:[19,62],bad:[0,21,30,57,65],bad_elf:[16,44],bad_get_us:[29,58],badli:[27,59],balanc:[6,27,28,48,59,61],balign:[29,58],bare:[30,38,57],barrier:[0,27,59],base:[0,1,3,4,5,6,7,8,9,10,12,13,14,15,16,18,19,21,22,23,24,26,28,29,30,36,38,39,40,41,42,43,44,45,46,47,48,50,51,52,53,54,57,58,60,61,62,64,65],bash:37,basi:[6,8,24,48,53],basic:[0,5,6,9,10,13,14,15,16,17,18,19,21,27,36,37,41,42,44,45,48,49,50,51,52,59,62,65],batch:[30,35,57],bcm2835:[4,43],bd_disk:[5,50],bdev:[5,50],bdflush:[9,51],beagl:[4,43],beat:13,becam:[15,41],becaus:[1,2,4,5,6,7,9,10,12,13,14,15,16,17,19,21,22,23,24,27,28,33,36,39,41,43,44,45,46,47,48,49,50,51,52,53,59,60,61,62,64,65],bechler:53,becom:[7,15,41,46],beej:[18,42],been:[5,6,7,9,10,12,13,14,15,16,19,21,23,28,33,41,44,45,46,47,48,50,51,52,60,61,62,65],befor:[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,23,26,27,28,29,31,35,36,37,38,39,41,42,43,44,45,46,47,48,49,50,51,52,54,55,58,59,60,61,62,65],begin:[5,7,9,10,12,15,17,18,21,22,39,41,42,46,47,49,50,51,52,64,65],beginn:[10,52],behalf:[16,44],behav:[12,38,47],behavior:[4,5,7,8,9,14,16,21,39,43,44,45,46,50,51,65],behaviour:[6,12,16,44,47,48],behind:[7,46],being:[5,6,7,8,9,10,12,13,14,15,16,19,23,25,39,41,44,45,46,47,48,50,51,52,60,62,63],believ:39,bellow:[13,18,21,41,42,65],belong:[8,10,14,45,52],below:[4,5,6,7,8,9,10,14,15,17,18,19,21,22,23,24,27,28,38,41,42,43,45,46,48,49,50,51,52,53,59,60,61,62,64,65],bench:[16,44],benchmark:[16,44],benefit:39,benvenuti:53,besid:[3,19,62],best:[13,16,23,31,41,44,60],better:[1,13,15,16,19,21,28,41,44,51,61,62,65],between:[0,5,7,8,9,10,12,13,14,15,16,17,18,19,21,22,23,24,25,27,28,30,34,35,36,38,39,41,42,44,45,46,47,49,50,51,52,53,57,59,60,61,62,63,64,65],bex:0,bex_add_dev:8,bex_del_dev:8,bex_dev:8,bex_dev_attr:8,bex_devic:8,bex_misc:0,bex_misc_prob:8,bex_misc_remov:8,beyond:[28,39,61],bf914c1c:[21,65],bf914dbc:[21,65],bfa05000:[27,59],bfa15000:[17,49],bfa1a000:[27,59],bfa36000:[17,49],bffeb000:[27,59],bfree:37,bh_dirti:[9,51],bi_disk:[5,50],bi_end_io:[5,50],bi_io_vec:[5,50],bi_it:[5,50],bi_opf:[5,50],bi_priv:[5,50],bi_sector:[5,50],bibliograf:53,bibliografi:0,big:[7,16,18,42,44,46],bin:[4,9,27,36,43,51,59],binari:[4,13,16,24,30,41,43,44,53,57],bind:[3,10,13,18,20,24,36,41,42,52,53,55],bio:[0,8,16,19,21,35,44,62,65],bio_add_pag:[5,35,50],bio_alloc:[5,13,35,50],bio_alloc_bioset:13,bio_clon:[5,50],bio_data:[5,50],bio_data_dir:[5,50],bio_endio:35,bio_for_each_seg:[5,50],bio_put:[5,35,50],bio_structur:[5,50],bio_vec:[5,50],bio_write_messag:[5,50],biodoc:[5,50],bird:[15,41],bison:3,bit:[4,5,7,9,10,12,13,14,15,17,18,19,22,24,27,28,29,30,37,38,41,42,43,45,46,47,49,50,51,52,53,57,58,59,61,62,64],bitfield:[27,59],bitmap:[0,9,20,22,24,30,37,51,53,55,57,64],bitop:[10,14,45,52],bitwis:[0,10,52],black:[25,63],blackhol:[26,54],blk_cleanup_queu:[5,50],blk_mq_alloc_tag_set:[5,50],blk_mq_end_request:[5,50],blk_mq_f_should_merg:[5,50],blk_mq_free_tag_set:[5,50],blk_mq_hw_ctx:[5,50],blk_mq_init_queu:[5,50],blk_mq_op:[5,50],blk_mq_queue_data:[5,50],blk_mq_requeue_request:[5,50],blk_mq_start_request:[5,50],blk_mq_tag:[5,50],blk_mq_tag_set:[5,50],blk_qc_t:[5,50],blk_queue_logical_block_s:[5,50],blk_rq_byte:[5,50],blk_rq_cur_byt:[5,50],blk_rq_is_passthrough:[5,50],blk_rq_po:[5,50],blk_status_t:[5,50],blk_sts_ioerr:[5,50],blk_sts_ok:[5,50],blkdev:[5,50],blkdev_get_by_path:[5,35,50],blkdev_put:[5,35,50],blob:[4,13,37,41,43],block:[0,4,7,8,9,10,12,14,15,16,19,20,22,25,28,34,35,37,40,41,43,44,45,46,47,51,52,55,61,62,63,64],block_dev:[5,50],block_devic:[1,5,22,50,64],block_device_driv:[5,50],block_device_oper:[0,35],block_iopoll_softirq:[6,48],block_read_full_pag:[10,22,52,64],block_siz:37,block_size_bit:37,block_softirq:[6,23,48,60],block_truncate_pag:[10,52],block_write_begin:[10,52],block_write_full_pag:[10,52],bmap:[10,22,52,64],bmx_misc:8,board:0,bob:[15,41],bone:38,bonu:[16,39,44],book:39,bookmark:[27,59],bool:[6,18,22,28,29,42,48,58,61,64],boot:[0,2,3,6,8,12,14,15,19,24,35,37,41,45,47,48,53,62],bootlin:[13,41,53],bootload:[4,20,43,55],bootmem:[20,55],born:[29,58],both:[5,6,7,8,9,10,12,13,14,15,16,18,19,20,21,22,24,25,27,28,29,30,34,35,39,41,42,44,45,46,47,48,50,51,52,53,55,57,58,59,61,62,63,64,65],bottom:[5,6,12,16,23,24,28,44,47,48,50,53,60,61],bound:[21,24,39,53,65],boundari:[17,24,27,49,53,59],bovet:53,bpf:[16,44],bph:[15,41],brace:[13,41],braid:13,brain:[15,41],branch:1,brd:[2,5,50],breakpoint:[13,15,23,29,41,58,60],brels:[9,51],bridg:[24,53],brief:39,briefli:[31,38],bring:[9,16,44,51],brk:[24,53],broadcast:[2,26,54],broadcom:[4,43],broken:1,brows:[12,14,41,45,47],browser:0,brw:[7,46],bsd:[18,24,42,53],bsp:[4,43],btrace:[13,41],btrf:[13,15,22,41,64],bts:[28,61],bucharest:0,buddi:[25,63],buf:[8,12,30,47,57],bufer:[5,50],buff:[14,18,42,45],buffer:[0,5,7,8,10,14,16,18,21,22,23,25,38,42,44,45,46,50,52,60,63,64,65],buffer_head:[9,10,51,52],buffer_overflow:[21,65],buffer_s:[7,46],bug:[2,14,15,19,21,23,24,29,41,45,53,58,60,62,65],bug_on:[19,62],build:[0,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,24,33,35,37,38,41,42,43,44,45,46,47,48,49,50,51,52,53],build_bug_on:[18,19,42,62],buildid:[16,44],built:[2,3,8,9,13,14,15,27,41,45,51,59],builtin:[13,18,42],bullet:[13,41],bundl:[4,43],bus:[0,4,12,24,27,28,30,43,47,53,57,59,61],bus_attr:8,bus_attr_descr:8,bus_attribut:8,bus_create_fil:8,bus_for_each_dev:8,bus_for_each_drv:8,bus_regist:8,bus_remove_fil:8,bus_typ:8,bus_unregist:8,buse:[0,24,53],busi:[6,7,10,12,14,45,46,47,48,52],busybox:[13,41],bv_len:[5,50],bv_offset:[5,50],bv_page:[5,50],bvec:[5,50],bvec_alloc:13,bvec_it:[5,50],bye:[15,41],byteord:[18,42],bytestream:[12,47],bzimag:[2,3,13],c010102d:[15,41],c0103407:[15,41],c0140da6:[15,41],c014b698:[15,41],c014b7aa:[15,41],c01708e4:[15,41],c0170981:[15,41],c0240a08:[15,41],c02e535c:[13,41],c035d083:[15,41],c035e965:[15,41],c1001072:[21,65],c106b8ae:[21,65],c10cc1de:[21,65],c10cc7ca:[21,65],c10ccaba:[21,65],c1225063:[21,65],c12250a8:[21,65],c14d7d18:[21,65],c15c3f48:[21,65],c15c97c0:[21,65],c2c:[16,44],c5799000:[15,41],c5799e24:[15,41],c5799e58:[15,41],c5799e60:[15,41],c5799f20:[15,41],c5799f78:[15,41],c5799f8c:[15,41],c57b9280:[15,41],c57cb000:[15,41],c57cbe1c:[15,41],c57cbe24:[15,41],c57cbe34:[15,41],c57cbe58:[15,41],c57cbe60:[15,41],c57cbf20:[15,41],c57cbf78:[15,41],c57cbf8c:[15,41],c5db1d38:[15,41],c665c780:[15,41],c665cb00:[15,41],c66ec780:[15,41],c716c908:[21,65],c724f448:[15,41],c7257df0:[21,65],c72b51d8:[15,41],c780ff34:[21,65],c7ece8dc:[21,65],c7ed3584:[21,65],c8816000:[21,65],c8816005:[21,65],c8816006:[21,65],c8816008:[21,65],c8816010:[21,65],c8817000:[21,65],c8819200:[21,65],c89c3010:[15,41],c89c3016:[15,41],c89c3020:[15,41],c89c3380:[15,41],c89d4000:[15,41],c89d4001:[15,41],c89d4003:[15,41],c89d4005:[15,41],c89d400c:[15,41],c89d400f:[15,41],c89d4010:[15,41],c89d4011:[15,41],c89d4013:[15,41],c89d4014:[15,41],c89d4015:[15,41],c89d4016:[15,41],c89d4017:[15,41],c89d4018:[15,41],c89d4019:[15,41],c89d401a:[15,41],c89d401b:[15,41],c89d401c:[15,41],c89d401d:[15,41],c89d401e:[15,41],c89d401f:[15,41],c89d4020:[15,41],c89d4021:[15,41],c89d4023:[15,41],c89d4024:[15,41],c89d4025:[15,41],c89d4026:[15,41],c89d4027:[15,41],c89d4300:[15,41],c99:[7,15,41,46],cach:[0,7,10,16,19,21,24,25,44,46,52,53,62,63,65],cache_alloc_debugcheck_aft:[21,65],cacheabl:[22,64],cachedtyp:[27,59],cachelin:[19,27,59,62],caddr_t:[17,49],calcul:[6,18,35,36,39,42,48],calendar:53,call:[0,4,5,6,7,8,9,10,12,13,15,16,17,18,19,21,22,23,24,25,28,32,33,34,35,36,38,40,41,42,43,44,46,47,48,49,50,51,52,53,60,61,62,63,64,65],call_timer_f0:[21,65],call_timer_fn:[21,65],callback:[13,18,23,31,42,60],calle:[27,59],caller:[10,12,16,27,29,44,47,52,58,59],cam:53,can:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,54,57,58,59,60,61,62,63,64,65],cancel:[6,48],cancel_delayed_work:[6,48],cancel_delayed_work_sync:[6,48],cancel_work:[6,48],cancel_work_sync:[6,48],candid:[24,53],cannot:[12,21,23,27,35,36,37,39,47,59,60,65],capabl:[4,13,29,41,43,58],capac:[5,7,35,46,50],captur:[8,12,16,18,27,29,42,44,47,58,59],card:[7,8,23,24,46,53,60],card_id:8,care:[12,13,19,27,28,47,53,59,61,62],carefulli:[5,13,15,41,50],carri:[5,28,39,50,61],cast:[9,10,18,42,51,52],cat:[4,7,10,12,13,15,17,21,27,32,33,34,41,43,46,47,49,52,59,65],catalog:[39,53],categori:[7,14,23,45,46,60],caught:[19,62],caus:[5,6,14,15,16,18,21,23,28,29,38,41,42,44,45,48,50,58,60,61,65],cbea:31,cclose:[13,41],ccnext:[13,41],cdev:[7,8,31,46],cdev_add:[7,46],cdev_del:[7,46],cdev_init:[7,46],cdrom:[7,15,41,46],central:[4,5,12,43,47,50],cert:[24,53],certain:[4,6,7,8,11,12,13,14,16,23,24,28,29,30,39,41,43,44,45,46,47,48,53,57,58,60,61],certainli:[15,28,41,61],certif:[24,53],cesati:53,cfg:[13,41],cfile:[13,41],cgroup:[24,27,53,59],chain:[6,17,21,24,48,49,53,65],challeng:37,chanc:[12,24,28,32,33,34,35,36,37,38,47,53,61],chang:[0,2,3,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,23,24,25,27,30,34,41,42,43,44,45,46,47,48,49,50,51,52,53,57,59,60,62,63],change_bit:[14,28,45,61],channel:[8,18,32,33,34,35,36,42],chapter:[5,9,10,17,36,49,50,51,52],charact:[0,5,6,8,9,10,13,15,34,37,40,41,48,50,51,52],character:[5,17,49,50],characterist:[23,27,28,59,60,61],chardev:[3,30,57],charg:[12,47],chart:[18,42],chatgpt:39,cheat:[23,39,60],check:[4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,21,22,23,24,25,26,27,28,29,30,38,41,42,43,44,45,46,47,48,49,50,51,52,53,54,57,58,59,60,61,62,63,64,65],checker:[0,18,37,39,42],checkout:1,checkpatch:[21,24,32,33,34,35,36,37,38,53,65],checksum:[24,26,35,36,53,54],child:[4,43],children:[14,45],chip:0,chmod:[5,9,10,36,50,51,52],chocol:[10,52],choos:[7,8,9,37,39,46,51],chosen:[7,46],chr:[30,57],chrdev:13,christian:53,chunk:[19,62],cif:[9,51],circ_bbuf_pop:38,circ_bbuf_push:38,circuit:[4,43],circular:[12,15,21,47,65],circumst:[27,28,59,61],clac:[27,59],claim:[24,53],clang:[13,41],clangd:0,clarif:39,clarifi:[9,39,51],class_attr:8,class_attribut:8,class_dev_attr:8,class_device_attribut:8,class_regist:8,class_releas:8,class_unregist:8,classic:[0,12,14,18,28,42,45,47,61],claudiu:53,clean:[1,4,5,6,7,8,9,10,11,12,14,15,16,17,18,23,27,28,41,42,43,44,45,46,47,48,49,50,51,52,59,60,61],cleanup:[6,9,12,47,48,51],cleanup_modul:[7,15,41,46],clear:[10,12,15,17,18,21,23,38,41,42,47,49,52,60,65],clear_bit:[10,14,45,52],clear_buffer_uptod:[22,64],clear_inod:[10,52],clearli:[11,31],clearpagereserv:[17,49],cli:[23,28,60,61],click:1,client:[5,13,41,50],clk:[27,59],clock:[4,13,16,43,44],clock_event_devic:[20,55],clock_update_flag:[27,59],clocksourc:[20,55],clone:[0,1,4,5,24,37,43,50,53],clone_f:[27,59],clone_fil:[27,59],clone_newipc:[27,59],clone_newn:[27,59],clone_newnet:[27,59],clone_vm:[27,59],close:[0,10,13,14,16,24,26,27,28,34,39,41,44,45,52,53,54,59,61],close_disk:[5,50],closer:[6,7,27,29,46,48,58,59],closest:[9,10,51,52],clue:11,cma:[24,53],cmd:[6,7,11,15,27,31,41,46,48,59],cmd_flag:[5,50],cmd_mod:[15,41],cmd_size:[5,50],cmdline:[27,59],cmp:[29,58],cnext:[13,41],cnt:[27,59],coalesc:[25,26,54,63],coc:[13,41],coccinel:[21,65],cod:53,code:[0,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,21,22,23,27,28,29,30,31,32,33,34,35,36,37,39,42,43,44,45,46,47,48,49,50,51,52,57,58,59,60,61,62,64,65],coder:39,coher:0,colegilor:53,collabor:[0,39,40],colleagu:39,collect:[0,6,12,21,29,47,48,58,65],collector:[21,65],color:[25,63],column:[7,12,16,36,44,46,47],com1:[12,15,34,41,47],com2:34,com:[0,1,4,13,31,37,38,41,43,53],combin:[5,13,15,27,28,36,41,50,59,61],come:[5,15,16,18,19,27,41,42,44,50,59,62],comm:[6,15,16,21,27,41,44,48,59,65],command:[1,2,3,4,5,6,7,8,9,10,12,13,14,15,16,17,18,22,23,24,27,32,35,36,37,41,42,43,44,45,46,47,48,49,50,51,52,53,59,60,64],command_data:[27,59],comment:[5,7,8,10,14,15,18,27,41,42,45,46,50,52,59],commit:[0,1],common:[4,5,6,7,8,9,12,14,15,18,19,22,24,28,29,39,41,42,43,45,46,47,48,50,51,53,58,61,62,64],commonli:[10,14,16,18,19,28,42,44,45,52,61,62],commun:[5,7,8,9,12,18,24,28,34,36,38,42,46,47,50,51,53,61],compani:[24,53],compaq:[24,53],compar:[1,8,13,15,16,17,18,19,25,28,41,42,44,49,61,62,63],comparison:8,compat:[4,7,24,34,43,46,53],compat_ioctl:[5,50],compat_sys_open:[29,58],compet:[24,53],compil:[0,3,5,6,7,9,10,12,13,14,18,19,21,24,28,33,34,35,36,39,42,45,46,47,48,50,51,52,53,61,62,65],compiled_sourc:[13,41],complain:[16,44],complement:[6,48],complet:[0,2,4,6,7,8,10,11,12,13,14,15,16,17,18,21,22,23,25,27,28,29,34,35,39,41,42,43,44,45,46,47,48,49,52,58,59,60,61,63,64,65],complex:[10,13,15,17,22,23,24,25,27,28,29,30,38,41,49,52,53,57,58,59,60,61,63,64],compli:[32,33,34,35,36,37,38],complic:[5,10,15,28,38,41,50,52,61],compon:[1,4,7,9,10,16,18,24,30,38,39,42,43,44,46,51,52,53,57],componentel:53,compos:[0,1,2,28,61],comprehens:[13,41],compress:[4,24,43,53],compris:[22,64],compromis:[13,25,41,63],comput:[0,4,13,14,17,18,19,41,42,43,45,49,62],comunit:0,concept:[0,7,8,9,13,14,41,45,46,51],conceptu:[27,28,59,61],concern:[27,59],conclud:[17,49],conclus:[14,39,45],concret:[9,51],concurr:[0,23,27,59,60],cond:[30,57],condit:[6,7,8,14,21,22,23,24,27,28,30,39,45,46,48,53,57,59,60,61,64,65],conduct:[16,44],confid:39,config:[4,13,15,16,21,38,41,43,44,65],config_btrfs_f:[15,41],config_debug_highmem:[19,62],config_debug_info:[21,65],config_debug_kmemleak:[21,65],config_debug_lock_alloc:33,config_debug_lockdep:[21,65],config_debug_slab:[21,65],config_dynamic_debug:[15,41],config_netconsole_dynam:[15,41],config_netfilt:[18,42],config_pci_mmconfig:[19,62],config_provide_ohci1394_dma_init:[19,62],config_read_only_thp_for_f:[22,64],config_retpolin:[27,59],config_sched_debug:[27,59],config_stackprotector:[27,59],config_x86_32:[19,29,58,62],config_x86_64:[19,62],config_x86_io_ap:[19,62],config_x86_local_ap:[19,62],config_x86_vsyscall_emul:[19,62],configdump:[27,59],configur:[1,2,3,4,5,7,8,10,12,13,15,16,18,24,27,28,30,38,41,42,43,44,46,47,50,52,53,57,59,61],confirm:[3,7,46],conflict:[1,8],conform:[24,26,53,54],confus:[8,14,45],conjunct:[10,29,52,58],connect:[0,5,7,8,12,13,15,16,23,24,26,27,36,41,44,46,47,50,53,54,59,60],connectionless:[18,42],consecut:[5,7,10,12,21,23,46,47,50,52,60,65],consequ:[5,7,8,18,27,37,42,46,50,59],consid:[5,7,8,14,17,21,23,28,29,34,35,36,39,45,46,49,50,58,60,61,65],consider:[5,50],consist:[5,7,9,18,19,35,39,42,46,50,51,62],consol:[3,4,5,6,7,8,9,10,12,13,14,15,16,17,18,35,41,42,43,44,45,46,47,48,49,50,51,52],console_loglevel:[15,41],consolid:34,constant:[15,16,18,19,41,42,44,62],constantin:53,constraint:[23,60],construct:[7,10,12,13,18,24,27,28,42,46,47,52,53,59,61],constructor:[25,63],consult:[15,32,33,34,35,36,37,39,41],consum:[4,5,12,15,27,34,38,41,43,47,50,59],consumpt:[28,61],contact:39,contain:[0,1,4,5,6,7,8,9,10,11,12,13,14,15,17,18,21,22,24,25,29,32,35,36,37,39,41,42,43,45,46,47,48,49,50,51,52,53,58,63,64,65],container:2,container_of:[6,7,8,9,10,14,27,45,46,48,51,52,59],content:[0,7,8,9,10,12,13,14,15,16,18,19,22,23,24,28,32,33,37,41,42,44,45,46,47,51,52,53,60,61,62,64],context:[0,5,6,10,12,15,16,19,21,26,34,41,44,47,48,50,52,54,62,65],context_switch:[27,59],contigu:[0,19,25,62,63],continu:[1,2,5,6,8,9,10,12,13,15,16,21,23,24,27,28,29,39,41,44,47,48,50,51,52,53,58,59,60,61,65],contradict:[14,45],contrast:[18,42],contribut:[0,16,24,39,44,53],control:[0,4,5,7,8,9,13,15,18,20,22,24,27,31,33,36,41,42,43,46,50,51,53,55,59,64],convent:0,convention:[10,52],convers:[0,5,19,50,62],convert:[6,13,17,18,22,23,41,42,48,49,60,64],cool:[24,53],cooper:[24,30,53,57],cope:[4,43],copen:[13,41],copi:[0,2,4,5,7,9,10,11,12,13,14,15,16,17,18,19,20,22,24,25,27,29,30,36,37,38,41,42,43,44,45,46,47,49,50,51,52,53,55,57,58,59,62,63,64],copy_from_us:[6,7,13,18,29,42,46,48,58],copy_thread:[20,55],copy_to_us:[6,7,12,20,29,46,47,48,55,58],copyright:[2,30,57],corbet:53,core:[2,3,4,13,16,23,24,27,28,41,43,44,53,59,60,61],corelat:53,coroutin:[27,59],correct:[7,9,10,18,23,24,27,29,35,39,42,46,51,52,53,58,59,60],correctli:[9,39,51],correl:8,correspond:[4,5,7,8,9,10,12,13,15,18,23,36,41,42,43,46,47,50,51,52,60],corrobor:[14,45],corrupt:[11,14,21,29,35,45,58,65],cortex:[4,43],cost:[24,29,53,58],costli:[22,29,58,64],could:[5,6,10,14,17,21,27,28,29,36,45,48,49,50,52,58,59,61,65],couldn:[16,44],count:[5,7,8,9,12,14,16,17,38,44,45,46,47,49,50,51],counter:[6,8,10,12,14,15,16,17,21,22,25,28,41,44,45,47,48,49,52,61,63,64,65],counterpart:[14,45],coupl:[27,59],cours:[0,13,16,23,24,32,33,34,35,36,39,40,41,44,60],course_grad:39,cover:[10,28,35,39,52,61],cpl:[30,57],cppcheck:[32,33,34,35,36,37,38],cprev:[13,41],cpu0:[4,12,21,43,47,65],cpu1:[21,65],cpu:[0,5,6,12,13,14,15,16,17,19,21,23,25,27,29,30,34,37,41,44,45,47,48,49,50,57,58,59,60,62,63,65],cpu_startup_entri:[2,21,65],cpufreq:[4,43],cpuidle_idle_cal:2,cpuinfo:[4,43],cpuinfo_max_freq:[4,43],cpuinfo_min_freq:[4,43],cpus_ptr:[27,59],cr0:[21,30,57,65],cr0_et:38,cr0_mp:38,cr0_pe:38,cr2:[21,65],cr3:[19,21,30,57,62,65],cr4:[21,30,57,65],craft:[29,58],crash:[5,21,24,29,50,53,58,65],crc32:[15,35,41],crc:35,creat:[0,3,4,6,7,8,12,13,14,15,16,17,18,19,24,25,26,27,28,30,31,32,33,36,37,38,41,42,43,44,45,46,47,48,49,53,54,57,59,61,62,63],create_block_devic:[5,50],create_net:3,create_singlethread_workqueu:[6,48],create_workqueu:[6,48],creation:[0,5,8,9,10,50,51,52],cri:[24,53],critic:[4,12,14,15,23,24,27,28,41,43,45,47,53,59,60,61],crop:[10,52],cross:[0,4,28,43,61],cross_compil:[4,43],crosstool:[4,43],crush:[21,65],crush_it:[21,65],crusher:[21,65],crw:[7,46],cryptic:[15,41],crypto:[3,24,53],crypto_engin:3,cryptographi:[24,53],cscope:[0,15],cscopequickfix:[13,41],cst:[13,41],csto:[13,41],csum:36,csumerr:36,csverb:[13,41],ctag:[13,41],ctl:38,ctrl:[3,7,12,13,15,16,18,41,42,44,46,47],ctx:[10,52],cur:[0,16,44],curr:[27,28,59,61],current:[0,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,22,23,24,28,29,30,36,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,57,58,60,61,62,64],current_jiffi:[6,48],current_stack_point:[27,59],current_task:[29,58],current_thread_info:[27,59],current_tim:[9,51],cursor:[9,13,14,41,45,51],cursului:0,cursuri:0,custom:[0,24,53],cwd:[27,59],cword:[13,41],cwr:[18,42],cycl:[19,21,28,61,62,65],d_add:[10,52],d_fsdata:[10,52],d_inod:[10,22,52,64],d_instanti:[10,52],d_make_root:[9,10,51,52],d_name:[10,52],d_op:[10,52],d_parent:[10,52],d_sb:[10,52],d_state:[22,64],daddr:[18,42],daemon:[7,15,41,46],dai:[16,24,39,44,53],daniel:53,dar:53,dashboard:13,data:[0,6,8,9,10,13,14,16,18,19,23,24,25,26,27,29,30,32,33,34,35,36,37,38,41,42,44,45,48,51,52,53,54,57,58,59,60,62,63],data_block:[10,52],data_len:[18,26,42,54],data_reg:[12,47],databas:[0,13,15,41],datagram:36,datagram_pol:36,datasheet:34,dataw:[15,41],date:[1,31,39],davem:[24,53],david:[24,53],dax:[22,64],ddvlad:[13,41],deaconescu:53,deactiv:[6,10,12,15,28,30,34,39,41,47,48,52,57,61],deadlin:[0,32,33,34,35,36,37,38],deadlock:[6,12,21,27,28,47,48,59,61,65],deal:[9,16,22,24,44,51,53,64],dealloc:[5,9,18,22,25,33,42,50,51,63,64],dealt:[22,64],debian:3,debug:[0,2,14,16,23,27,28,40,44,45,53,59,60,61],debug_pagealloc:[0,15,41],debugf:[15,21,41,65],debugg:[0,13,21,27,59,65],dec:[24,53],decapsul:[26,54],decid:[14,21,27,29,45,58,59,65],decim:[13,41],decis:[18,42],declar:[4,5,6,8,13,14,41,43,45,48,50],declare_delayed_work:[6,48],declare_tasklet:[6,48],declare_tasklet_dis:[6,48],declare_wait_queue_head:[6,7,46,48],declare_work:[6,48],decod:[0,12,15,41,47],decompos:[28,61],decompress:[24,53],decreas:[16,32,33,34,35,36,37,38,44],decrement:[6,8,10,17,22,28,48,49,52,61,64],dedic:[10,17,19,23,24,28,32,33,34,35,36,37,49,52,53,60,61,62],deduct:39,deep:[18,42],deepen:[13,36,39,41],deeper:[27,59],def:[27,59],default_idl:[2,21,65],default_idle_cal:[21,65],default_wake_funct:[27,59],defconfig:[4,13,41,43],defer:[0,12,19,23,34,40,47,60,62],deferr:[0,6,7,14,45,46,48],deferred_work:[6,48],defin:[2,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,20,23,27,28,29,30,34,35,36,38,41,42,43,44,45,46,47,48,49,50,51,52,55,57,58,59,60,61,62],define_mutex:[14,45],define_per_cpu_page_align:[19,62],define_rwlock:[14,45],define_spinlock:[14,21,45,65],define_tim:[21,65],definit:[5,6,7,8,9,10,12,13,14,15,24,33,34,35,36,41,45,46,47,48,50,51,52,53],deiniti:8,del:0,del_gendisk:[5,50],del_pid:[14,45],del_tim:[6,48],del_timer_sync:[6,48],dela:32,delai:[6,12,28,39,47,48,61],delayed_work:[6,48],delet:[0,6,7,8,9,14,15,17,28,32,36,41,45,46,48,49,51,61],delete_block_devic:[5,50],delf:32,deliv:[30,57],delloc:[21,65],demand:[14,23,24,25,29,45,53,58,60,63],demo:0,demonstr:[4,27,29,43,58,59],den:53,denomin:[9,51],dentri:[0,24,53],dentry_oper:[9,10,51,52],depart:0,depend:[0,1,4,5,6,7,8,12,13,14,21,23,24,28,29,34,41,43,45,46,47,48,50,53,58,60,61,65],depict:[22,64],deploi:3,deploy:[7,10,46,52],depmod:3,deprec:[20,28,55,61],depth:[0,11,13,22,23,35,41,60,64],dequeu:[23,27,59,60],derefer:[21,65],dereferenc:[7,46],deregist:[5,8,50],deregistr:[7,9,46,51],descr:8,describ:[4,5,6,7,8,9,10,12,14,15,17,18,23,24,29,32,33,34,35,36,37,38,41,42,43,45,46,47,48,49,50,51,52,53,58,60],descript:[1,4,5,14,15,16,17,18,24,33,41,42,43,44,45,49,50,53],descriptor:[0,5,7,10,17,22,24,25,27,29,30,38,46,49,50,52,53,57,58,59,63,64],design:[3,7,12,14,19,21,23,24,28,31,45,46,47,53,60,61,62,65],desir:[7,12,15,34,41,46,47],desktop:[26,54],despr:0,dest:[18,42],destin:[0,15,16,22,26,36,39,41,44,54,64],destroi:[0,6,8,10,48,52],destroy_inod:[9,10,51,52],destroy_list:[14,45],destroy_workqueu:[6,48],destruct:[6,48],destructor:[18,25,26,42,54,63],destul:53,detail:[0,2,4,5,6,7,8,9,10,12,13,14,15,16,17,18,27,28,29,30,32,41,42,43,44,45,46,47,48,49,50,51,52,57,58,59,61],detect:[8,9,13,14,15,16,21,23,28,29,34,41,44,45,51,58,60,61,65],detector:[21,65],determin:[0,2,5,7,8,10,12,13,15,17,19,20,21,22,23,29,33,41,46,47,49,50,52,55,58,60,62,64,65],dev:[2,3,4,5,6,7,8,9,10,12,13,15,16,17,18,26,27,31,33,35,38,41,42,43,44,46,47,48,49,50,51,52,54,59],dev_add_pack:36,dev_attr:8,dev_attr_:8,dev_dbg:[15,41],dev_id:[8,12,47],dev_kobj:8,dev_nam:[8,9,12,47,51],dev_releas:8,dev_root:8,dev_scratch:[18,42],dev_set_drvdata:8,dev_set_nam:8,dev_t:[7,8,9,46,51],dev_uev:8,develop:[0,3,5,8,9,10,12,13,15,18,21,22,29,37,40,41,42,47,50,51,52,58,64,65],devic:[0,3,6,9,10,13,14,15,16,18,19,20,22,23,27,30,33,34,35,37,40,41,42,44,45,48,51,52,55,57,59,60,62,64],device_address:38,device_attr:8,device_attr_ro:8,device_attribut:8,device_config:38,device_cr:8,device_create_fil:8,device_destroi:8,device_driv:[7,8,46],device_model:8,device_native_endian:[30,57],device_priv:8,device_readi:38,device_regist:8,device_remove_fil:8,device_reset:38,device_statu:38,device_t:38,device_table_t:38,device_unregist:8,devnam:8,devtmpf:13,diagram:[4,9,10,18,19,21,22,23,27,42,43,51,52,59,60,62,64,65],dialout:[7,46],dictat:39,did:[6,7,8,9,10,16,21,23,29,39,44,46,48,51,52,58,60,65],didact:[17,49],didn:[16,44],diff:[16,27,44,59],differ:[4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,22,23,24,26,27,28,30,34,39,41,42,43,44,45,46,47,48,49,50,51,52,53,54,57,59,60,61,62,64],differenti:[4,5,6,12,16,43,44,47,48,50],difficult:[13,14,23,24,28,37,41,45,53,60,61],dificil:53,dificultatea:53,digit:[4,43],dimens:[10,12,47,52],din:53,dinca:53,dir:[5,7,10,13,41,46,50,52],dir_emit:[10,52],direct:[5,7,8,9,10,15,16,17,30,32,33,34,35,36,37,38,39,41,44,46,49,50,51,52,53,57],direct_access:[5,50],direct_data_block:37,direct_io:[22,64],directli:[0,5,6,7,8,9,11,12,13,14,15,17,19,22,24,25,27,29,30,36,37,41,45,46,47,48,49,50,51,53,57,58,59,62,63,64],director:[10,52],directori:[0,1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,24,27,28,32,33,34,35,36,37,41,42,43,44,45,46,47,48,49,50,51,53,59,61,62],dirti:[9,10,19,21,22,28,51,52,61,62,64,65],disabl:[0,4,6,12,19,20,21,23,24,27,29,34,43,47,48,53,55,58,59,60,62,65],disable_irq:[12,47],disable_irq_nosync:[12,47],disadvantag:[13,15,19,24,41,53,62],disapear:8,disass:[13,41],disassembl:[13,15,41],disc:[10,52],discard:[4,5,6,7,8,9,10,12,14,15,16,17,18,26,41,42,43,44,45,46,47,48,49,50,51,52,54],disciplina:53,disconnect:36,discourag:[14,45],discov:[4,8,13,43],discover:[4,43],discoveri:[24,53],discret:[18,42],discuss:[5,8,10,12,17,28,38,39,47,49,50,52,61],discutii:53,dishonest:39,disk1:[3,13],disk2:[3,13],disk:[0,7,8,9,10,15,16,22,24,35,37,41,44,46,51,52,53,64],disk_nam:[5,50],dismiss:[24,53],dispatch:[0,29,33,58],dispersi:53,displac:[7,46],displai:[0,3,5,6,7,9,10,12,13,14,15,16,33,41,44,45,46,47,48,50,51,52],dispos:33,distinguish:[12,14,45,47],distribut:[5,23,24,25,28,30,50,53,57,60,61,63],distro:[2,3,4,13,43],div:[30,57],dive:[18,42],divers:[24,53],divid:[17,23,24,39,49,53,60],divis:[7,23,39,46,60],divisor:37,dkogan:[13,41],dma1:[12,47],dma2:[12,47],dma32:[25,63],dma:[8,12,17,19,25,30,47,49,57,62,63],dmap:[22,37,64],dmap_block:37,dmesg:[6,12,14,15,18,27,41,42,45,47,48,59],dnsmasq:3,do_exit:[6,48],do_fast_syscall_32:[16,44],do_fork:[13,41],do_idl:[2,21,65],do_init_modul:[21,65],do_int80_syscall_32:[21,29,58,65],do_one_initcal:[21,65],do_oop:[21,65],do_pan:[21,65],do_softirq:[23,28,60,61],do_softirq_own_stack:[21,65],do_syscall_32_irqs_on:[29,58],do_sysenter_32:[16,44],doc:[0,1,4,38,43],docker:[0,1,27,36,59],dockerfil:0,document:[0,2,5,6,7,9,10,15,18,24,32,33,34,35,36,37,38,42,46,48,50,51,52,53],doe:[5,6,7,8,9,10,12,13,14,15,16,17,23,24,27,29,31,32,33,34,35,36,37,38,39,41,44,45,46,47,48,49,50,51,52,53,58,59,60],doesn:[2,4,5,13,16,22,41,43,44,50,64],doff:[18,42],doing:[6,12,13,16,23,24,28,44,47,48,53,60,61],don:[6,8,13,15,16,19,22,27,28,29,30,37,38,41,44,48,57,58,59,61,62,64],donald:[14,45],done:[1,2,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,23,24,27,28,29,32,33,34,35,36,37,39,41,42,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62],dot:37,doubl:[5,14,19,45,50,62],down:[7,14,15,18,24,28,33,41,42,45,46,53,61],down_interrupt:33,download:[2,3,4,13,15,16,39,41,43,44],downscript:3,downstream:[24,53],dpl:[19,23,60,62],drastic:[14,45],draw:39,drive:[3,5,7,9,13,46,50,51],driver:[0,3,4,6,11,13,14,15,16,18,22,23,26,27,30,31,37,38,39,40,41,42,43,44,45,48,54,57,59,60,64],driver_ack:38,driver_attr:8,driver_attribut:8,driver_create_fil:8,driver_data:[5,8,50],driver_ok:38,driver_priv:8,driver_regist:8,driver_remove_fil:8,driver_reset:38,driver_statu:38,driver_unregist:8,drm_mxsfb:[4,43],drop:[23,26,30,54,57,60],drop_inod:[9,51],drv:8,drv_attr:8,dsr:[21,65],dst:36,dt_dir:[10,52],dt_reg:[10,52],dt_unknown:[10,52],dtb:[4,43],dts:[4,28,43,61],dtsi:[4,43],due:[14,16,18,19,23,28,39,42,44,45,60,61,62],dummi:[21,31,65],dummy_exit:[15,41],dummy_init:[15,41],dump:[13,15,16,21,27,41,44,59,65],dump_stack:[13,21,41,65],dup2:[29,58],dup:[22,64],duplic:[22,24,53,64],durat:[23,60],dure:[0,5,12,16,19,23,24,27,28,29,38,39,41,44,47,50,53,58,59,60,61,62],dvd:[9,51],dwarv:[27,59],dynam:[0,5,6,7,9,13,14,16,21,23,24,44,45,46,48,50,51,53,60,65],dynamic_debug:[15,41],dyndbg:0,dyndbg_init:15,dzone:[22,37,64],dzone_block:37,e100:3,e300:[30,57],eabi5:[4,43],eabi:[4,43],each:[0,4,5,6,7,8,9,10,11,12,13,14,15,17,18,19,21,22,23,24,25,26,27,28,29,30,32,33,34,35,39,41,42,43,45,46,47,48,49,50,51,52,53,54,57,58,59,60,61,62,63,64,65],eagain:[22,64],earli:[15,41],earlier:[5,15,29,41,50,58],earlycon:[4,43],eas:[13,41],easi:[6,10,13,16,19,29,41,44,48,52,58,62],easier:[9,13,23,24,29,41,51,53,58,60],easiest:[15,41],easili:[9,13,15,17,21,25,41,49,51,63,65],eax:[13,15,19,21,27,29,41,58,59,62,65],eb002bf8:[21,65],ebp:[15,21,27,29,41,58,59,65],ebusi:[5,7,12,14,45,46,47,50],ebx:[15,21,27,29,41,58,59,65],ece:[18,42],echipa:0,echo:[5,7,8,10,11,12,15,21,32,41,46,47,50,52,65],ecp:8,ecx:[13,15,21,29,41,58,65],ed612000:[21,65],edg:[12,47],edi:[15,21,27,29,41,58,59,65],edit:[1,5,9,10,11,13,15,17,41,49,50,51,52,53],editor:[13,41],edx:[13,15,21,27,29,41,58,59,65],eest:2,efault:[7,29,46,58],efect:[13,41],effect:[5,7,10,13,15,16,19,22,23,25,27,28,41,44,46,50,52,59,60,61,62,63,64],effici:[13,15,17,22,24,27,28,30,41,49,53,57,59,61,64],effort:[27,59],eflag:[15,21,23,30,41,57,60,65],eg106:[1,10,13,39,41,52],eg306:39,egrep:[12,47],ehci:[15,41],eigh:[21,65],einval:[8,14,16,18,42,44,45],eio:[10,17,49,52],eip:[15,21,23,27,41,59,60,65],either:[6,10,11,12,14,16,18,19,21,22,23,24,25,27,29,34,37,42,44,45,47,48,52,53,58,59,60,62,63,64,65],elcdif:[4,43],electron:[4,43],elem:[14,45],element:[5,6,14,18,21,28,32,33,34,36,37,38,42,45,48,50,61,65],elf32:[15,41],elf:[0,4,13,29,36,41,43,58],elif:[15,18,41,42],elimin:[6,13,17,28,39,41,48,49,61],elixir:[13,41,53],els:[1,6,7,8,10,12,13,14,15,18,19,27,29,30,39,41,42,45,46,47,48,52,57,58,59,62],elsewher:[7,39,46],emac:[13,41],emb:[17,49],embed:[4,10,15,18,20,24,27,30,41,42,43,52,53,55,57,59],emerg:[6,48],emploi:[25,28,61,63],empti:[4,10,12,19,22,25,27,34,43,47,52,59,62,63,64],emul:[0,3,4,43],enabl:[3,6,12,13,15,17,18,19,21,23,24,28,29,33,37,38,41,42,47,48,49,53,58,60,61,62,65],enable_irq:[12,47],encapsul:[18,42],encod:[5,21,26,30,50,54,57,65],encompass:[17,49],encount:[5,15,24,28,39,41,50,53,61],encourag:[4,5,6,7,8,9,10,12,14,15,16,17,18,31,39,41,42,43,44,45,46,47,48,49,50,51,52],encrypt:[24,53],end:[5,6,7,8,9,10,12,13,15,16,17,18,19,21,22,23,24,26,28,29,32,33,35,37,39,41,42,44,46,47,48,49,50,51,52,53,54,58,60,61,62,64,65],endian:[18,30,42,57],endif:[13,15,18,19,22,27,29,41,42,58,59,62,64],endpoint:[18,42],endproc:[29,58],endwhil:[13,41],enforc:[24,53],engin:[0,28,61],enhancednf:[15,41],enhancen:[24,53],enobuf:[18,42],enodev:[8,12,47],enomem:[5,9,10,14,45,50,51,52],enospc:[10,52],enotempti:[10,52],enotti:[7,46],enough:[7,10,12,14,23,24,25,29,33,39,45,46,47,52,53,58,60,63],enqueu:[27,59],ensur:[7,8,10,14,27,35,39,45,46,52,59],enter:[2,3,10,11,12,13,14,15,22,28,41,45,47,52,61,64],enter_from_user_mod:[29,58],enter_lazy_tlb:[27,59],entir:[4,5,8,9,12,15,17,34,35,36,39,41,43,47,49,50,51],entiti:[7,8,9,10,14,28,45,46,51,52,61],entri:[0,5,7,8,9,12,13,14,17,19,20,21,22,23,25,26,27,28,29,33,36,37,38,45,46,47,49,50,51,54,55,58,59,60,61,62,63,64,65],entry_handl:33,entry_int80_32:[21,23,60,65],entry_sysenter_32:[23,60],enumer:[20,30,55,57],env:[8,15,41],environ:[2,8,9,13,27,36,39,41,51,59],ept:[30,57],equal:[10,14,18,26,39,42,45,52,54],equat:[15,41],equival:[5,9,14,15,18,29,39,41,42,45,50,51,58],eras:[22,64],erestartsi:[27,59],ernno:[14,45],err:[5,7,8,9,12,18,42,46,47,50,51],err_ptr:[10,52],errno:[3,7,14,45,46],erron:[5,28,50,61],error:[0,5,6,7,8,9,10,11,12,13,16,18,19,21,22,23,24,30,35,36,39,42,44,46,47,48,50,51,52,53,57,60,62,64,65],error_abort:[30,57],error_remove_pag:[22,64],errseq_t:[22,64],esi:[15,21,27,29,41,58,59,65],esp:[13,15,21,23,27,41,59,60,65],especi:[10,13,24,28,41,52,53,61],espfix:[19,62],essenti:[3,6,10,13,18,21,24,31,41,42,48,52,53,65],establish:[2,18,42],estim:51,etc:[4,5,6,7,8,9,10,11,12,13,14,15,18,22,23,24,25,26,27,30,38,39,41,42,43,45,46,47,48,50,51,52,53,54,57,59,60,63,64],eth0:[2,15,26,41,54],ether:[2,12,47],ethernet:[4,24,26,30,36,43,53,54,57],ethi:8,evalu:[4,13,16,26,27,32,33,34,35,36,37,41,43,44,54,59],even:[5,6,8,10,13,14,15,17,18,21,22,23,24,27,28,30,39,41,42,45,48,49,50,52,53,57,59,60,61,64,65],evenli:31,event:[6,7,8,12,16,21,23,27,30,44,46,47,48,57,59,60,65],events_list:[6,48],events_lock:[6,48],eventu:[9,13,15,23,41,51,60],everi:[2,5,6,7,8,13,15,18,19,22,24,25,26,27,41,42,46,48,50,53,54,59,62,63,64],everyon:39,everyth:[9,13,17,27,34,49,51,59],evict_inod:[10,22,52,64],evk:[4,43],evlist:[16,44],evolut:[14,45],ewouldblock:[7,46],ex_fixup_addr:[29,58],ex_fixup_handl:[29,58],ex_handler_default:[29,58],ex_handler_t:[29,58],exact:[21,29,58,65],exactli:[15,27,41,59],exam:39,examen:53,examin:[13,23,27,29,41,58,59,60],exampl:[0,1,4,5,6,7,8,9,10,11,12,13,14,16,17,18,19,21,22,24,27,28,29,30,33,34,35,36,38,39,42,43,44,45,46,47,48,49,50,51,52,53,57,58,59,61,62,64,65],exce:[5,14,39,45,50],exceed:[7,46],except:[0,9,12,14,21,24,25,29,30,32,33,34,35,36,37,38,39,45,47,51,53,57,58,63,65],exception_t:[29,58],exception_table_entri:[29,58],excess:[28,61],exchang:[8,23,28,60,61],exclus:[5,7,10,14,27,28,36,45,46,50,52,59,61],exe:[27,59],exec:[24,53],execut:[0,4,5,6,7,8,9,10,12,13,15,16,18,19,21,23,27,28,29,33,36,38,41,42,43,44,46,47,48,50,51,52,58,59,60,61,62,65],execv:[16,44],exemplifi:[28,61],exemplificar:53,exercic:[13,41],exercis:[0,1,11,39],exhaust:[14,45],exist:[5,6,8,9,10,11,13,14,15,21,22,24,27,28,30,36,39,41,45,48,50,51,52,53,57,59,61,64,65],exit:[0,3,5,6,7,12,14,17,18,21,27,28,31,38,42,45,46,47,48,49,50,59,61,65],exit_reason:38,expand:[13,18,33,41,42],expect:[2,8,12,15,16,17,19,23,38,41,44,47,49,60,62],expens:[28,61],experi:[16,44],experienc:[16,44],expert:[24,53],expir:[6,14,27,28,39,45,48,59,61],expiri:[6,48],explain:[14,18,28,29,31,42,45,58,61],explan:[14,39,45],explicit:[27,59],explicitli:[7,27,28,39,46,59,61],explor:[0,13],exponenti:[18,42],export_per_cpu_symbol_gpl:[19,62],export_symbol:[8,14,19,45,62],expos:[9,13,14,30,33,38,45,51,57],express:[13,27,41,59],ext2:[9,51],ext3:[9,51],ext4:[2,3,4,9,10,22,43,51,52,64],ext4_buffered_write_it:[16,44],ext4_file_write_it:[16,44],ext4_inode_info:[10,52],ext4_statf:[9,51],extend:[0,15,18,19,24,25,38,41,42,53,62,63],extens:[13,15,24,30,41,53,57],extent:2,extern:[12,14,18,23,25,30,39,42,45,47,57,60,63],extra:[0,2,5,10,17,19,23,27,49,50,52,53,59,60,62],extra_cflag:[15,41],extract:[5,10,14,15,18,41,42,45,50,52],extracurricular:51,eye:[4,43],f1de81a2:[21,65],f1de8265:[21,65],f1de82d6:[21,65],f1de82d:[21,65],f27f1138:[21,65],f27f12aa:[21,65],f27f12ef:[21,65],f4c6816a:[21,65],f4c6827f:[21,65],f4c682d6:[21,65],f4c682de:[21,65],f5118b873294:31,f_flag:[7,18,42,46],f_mode:[7,46],f_op:[7,10,46,52],f_po:[7,46],face:[16,39,44],facebook:53,facil:[6,14,17,45,48,49],facilit:[11,13,15,41],fact:[10,13,14,16,28,29,34,41,44,45,52,58,61],factor:51,faculti:[0,37],fail:[1,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,27,28,39,41,42,43,44,45,46,47,48,49,50,51,52,59,61,62],failur:[5,12,14,45,47,50],fair:[24,28,53,61],fairli:[23,60],fake:[15,30,57],fall:[7,14,28,39,45,46,61],fals:[7,27,28,46,59,61],famili:[0,18,36,42],familiar:[4,9,10,13,14,15,16,18,19,32,33,42,43,44,45,51,52,62],fane:53,faq:[35,36,37],far:8,fashion:[12,23,30,47,57,60],fast:[12,13,19,27,28,41,47,59,61,62],fastcal:[6,48],faster:[1,3,12,15,16,25,29,41,44,47,58,63],fat:[9,10,22,51,52,64],fatal:[15,21,41,65],fault:[0,15,16,19,21,23,29,30,39,41,44,57,58,60,62,65],faulti:[23,60],faust:[15,41],favor:[28,61],fdinfo:[27,59],fdtdump:[27,59],fe12:2,fe80:2,featur:[2,8,9,12,13,14,15,17,19,24,27,28,41,45,47,49,51,53,59,61,62],feb:[15,41],feedback:[1,16,39,44,53],feel:[4,39,43],fer:[16,44],fetch:[1,7,19,26,28,46,54,61,62],fetch_head:1,few:[0,13,15,19,21,22,23,24,27,28,29,38,41,53,58,59,60,61,62,64,65],ffffe000:[27,59],fffff000:[27,59],ffffffda:[21,65],fffffffc:[15,41],ffree:37,fiber:[27,59],fibmap:[22,64],fidel:[30,57],fiecar:53,field:[0,5,6,7,8,9,10,12,13,14,15,17,19,23,25,26,27,28,29,33,35,36,41,45,46,47,48,49,50,51,52,54,58,59,60,61,62,63],fifo8:[30,57],fifo:[9,10,28,30,51,52,57,61],figur:[7,14,21,23,24,28,45,46,53,60,61,65],file:[0,1,2,3,4,5,6,8,12,13,14,15,16,17,18,21,24,25,29,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,47,48,49,50,53,58,63,65],file_oper:[0,5,8,9,10,17,31,49,50,51,52],file_system:13,file_system_typ:[9,13,51],filenam:[9,10,27,51,52,59],fileread:[13,41],filesystem:[0,4,10,11,13,27,40,41,43,52,59],fileystem:[22,24,53,64],fill:[5,7,9,10,11,12,16,17,18,21,36,42,44,46,47,49,50,51,52,65],fill_return_buff:[27,59],fill_sup:[0,10,22,52,64],filp:[17,22,49,64],filsystem:[22,64],filter:[0,15,16,24,26,41,44,53,54],fin:[18,42],final_d:[10,52],find:[2,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,21,22,23,29,32,33,34,35,36,37,39,41,42,43,44,45,46,47,48,49,50,51,52,58,60,62,64,65],find_first_bit:[10,52],find_first_zero_bit:[9,10,51,52],fine:[9,24,51,53],fingerprint:2,finish:[5,6,7,9,10,12,13,16,23,28,38,44,46,47,48,50,51,52,60,61],finish_task_switch:[27,59],finish_wait:[27,59],firewal:[18,42],firmwar:[8,24,53],first:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,23,24,25,28,29,31,32,33,35,36,37,38,41,42,43,44,45,46,47,48,49,50,51,52,53,55,58,60,61,62,63,65],first_minor:[5,50],fit:[30,57],fix:[0,1,5,6,7,14,18,23,24,25,42,45,46,48,50,53,60,63],fix_apic_bas:[19,62],fix_dbgp_bas:[19,62],fix_earlycon_mem_bas:[19,62],fix_hol:[19,62],fix_io_apic_base_0:[19,62],fix_io_apic_base_end:[19,62],fix_kmap_begin:[19,62],fix_kmap_end:[19,62],fix_ohci1394_bas:[19,62],fix_pcie_mcfg:[19,62],fix_to_virt:[19,62],fixaddr_start:[19,62],fixaddr_top:[19,62],fixed_address:[19,62],fixmap:[19,62],fixup:[29,58],fixup_except:[29,58],fl_owner_t:[7,46],flag:[5,6,7,9,10,12,14,15,17,18,20,22,23,25,27,28,36,38,41,42,45,46,47,48,49,50,51,52,55,59,60,61,63,64],flash:[22,64],flex:3,flexibl:[5,19,26,50,54,62],flood:0,floppi:[12,47],flow:[15,23,26,29,36,41,54,58,60],flush:[5,7,19,20,25,28,30,46,50,55,57,61,62,63],flush_scheduled_work:[6,48],flush_workqueu:[6,48],fly:[13,41],fmode_excl:[5,50],fmode_read:[5,7,46,50],fmode_t:[5,50],fmode_writ:[5,7,46,50],fmt:[14,45],focu:[0,11,16,44],fold:[28,61],folder:[3,15,16,24,38,41,44,53],follow:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,21,22,23,24,26,27,28,29,31,32,33,34,35,36,37,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,54,58,59,60,61,62,64,65],follow_link:[22,64],foot:[25,63],fop:[5,7,46,50],for_each:15,for_each_process:15,forc:[1,14,15,27,30,41,45,57,59],forcefulli:[14,24,45,53],forest:[10,52],forev:[2,8],forget:[6,7,15,38,46,48],forgotten:[10,52],fork:[0,24,27,53,59],form:[6,7,9,12,15,16,17,19,27,36,39,41,44,46,47,48,49,51,59,62],formal:39,format:[3,4,5,9,10,12,13,15,18,24,27,29,32,36,37,41,42,43,47,50,51,52,53,58,59],format_str:[27,59],formerli:8,formula:[6,39,48],forum:39,forward:[0,13,18,24,30,42,53,57],found:[1,4,6,7,8,9,10,12,13,14,15,16,17,18,25,27,32,33,34,35,36,37,38,41,42,43,44,45,46,47,48,49,51,52,59,63],foundat:[2,18,30,42,57],four:[12,14,23,45,47,60],fpu:[12,47],fput_light:[18,42],fput_need:[18,42],frag_off:[18,42],fragment:[19,25,62,63],frame:[17,19,26,49,54,62],framebuff:[24,53],framework:[13,16,18,24,26,41,42,44,53,54],frank:53,free:[0,2,6,9,10,13,14,17,18,19,20,21,22,24,25,28,30,34,35,37,39,41,42,45,48,49,51,52,53,55,57,61,62,63,64,65],free_irq:[12,47],free_mmap_pag:[17,49],free_resourc:[28,61],freebsd:[13,41],freed:[21,25,28,33,61,63,65],freeli:[28,39,61],freepag:[22,64],freestand:[13,41],freez:[15,41],freezer:[15,41],frequenc:[4,23,25,28,43,60,61,63],frequent:[6,7,16,24,25,27,28,44,46,48,53,59,61,63],friendli:13,from:[0,1,2,4,6,7,8,9,10,11,13,14,15,16,17,18,19,21,24,25,26,27,28,30,32,33,34,35,36,37,38,39,41,42,43,44,45,46,48,49,51,52,53,54,57,59,61,62,63,65],from_tti:[27,59],frontend:[13,41],frozen:39,fs_flag:[9,51],fs_requires_dev:[9,51],fs_super:[9,51],fs_type:[9,51],fs_userns_mount:[9,51],fsdata:[10,22,52,64],fsi:[9,51],fsl_asrc:[4,43],fsname:[10,52],ftdi:[15,41],ftp:[18,42],ftrace:[16,21,44,65],fulfil:[5,50],full:[2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,23,25,26,27,28,30,34,36,41,42,43,44,45,46,47,48,49,50,51,52,54,57,59,60,61,62,63],fulli:[5,12,13,19,24,39,41,47,50,53,62],fun:32,func:[15,27,41,59],funcion:[10,52],further:[0,8,19,24,39,53,62],furthermor:[15,41],futur:[5,6,28,48,50,61],g_malloc0:[30,57],ga4a6b62:[21,65],gain:[12,13,33,36,39,41,47],game:[4,43],garbag:[21,65],gate:[19,23,60,62],gather:[5,16,26,44,50,54],gcc:[3,4,7,43,46],gdb:[0,2,15,23,29,58,60],gdbinit:[13,27,59],gdt:[19,23,60,62],gdt_entry_apmbios_bas:[19,62],gdt_entry_default_user32_c:[19,62],gdt_entry_default_user_c:[19,62],gdt_entry_default_user_d:[19,62],gdt_entry_espfix_ss:[19,62],gdt_entry_init:[19,62],gdt_entry_kernel32_c:[19,62],gdt_entry_kernel_c:[19,62],gdt_entry_kernel_d:[19,62],gdt_entry_percpu:[19,62],gdt_entry_pnpbios_cs16:[19,62],gdt_entry_pnpbios_cs32:[19,62],gdt_entry_pnpbios_d:[19,62],gdt_entry_pnpbios_ts1:[19,62],gdt_entry_pnpbios_ts2:[19,62],gdt_page:[19,62],gdt_stack_canary_init:[19,62],gdtr:[19,62],gen_compile_command:[13,41],gendisk:[0,35],gener:[0,1,4,5,6,7,8,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,27,28,29,30,32,33,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,52,53,55,57,58,59,60,61,62,63,64,65],generic_block_bmap:[10,52],generic_delete_inod:[9,51],generic_file_llseek:[10,52],generic_file_mmap:[10,52],generic_file_read_it:[10,22,52,64],generic_file_write_it:[10,52],generic_read_dir:[10,52],generic_ro_fop:[7,46],generic_write_end:[10,52],genhd:[5,50],genpd:[27,59],geometr:[25,63],gestiunea:53,get:[0,1,3,4,5,6,7,8,9,12,14,15,16,18,24,27,28,29,31,32,33,34,35,36,37,38,42,43,44,45,46,47,48,50,51,53,58,59,61],get_ascii:[12,47],get_block:[22,64],get_block_t:[22,64],get_char:[12,47],get_idx:[12,47],get_next_ev:[6,48],get_proc:[6,48],get_task_mm:[17,49],get_typ:[27,59],get_us:[7,29,46,58],getattr:[10,52],getcwd:[13,41],getgeo:[5,50],getitng:41,getnam:[18,36,42],getpid:[29,58],getsockopt:36,gettimeofdai:[29,58],gfp:[25,63],gfp_atom:[14,45],gfp_kernel:[9,14,18,21,42,45,51,65],gfp_mask:[22,25,63,64],gfp_noio:[5,50],gfp_t:[22,64],ghioc:53,gid:[9,10,27,37,51,52,59],gid_t:37,git:[1,3,4,5,6,7,8,9,10,12,13,14,15,16,17,18,24,27,31,37,41,42,43,44,45,46,47,48,49,50,51,52,53,59],github:[0,1,4,13,37,39,41,43,53],gitlab:[0,4,32,33,34,35,36,37,43],give:[3,10,16,36,44,52],given:[5,6,7,8,9,10,13,14,15,16,21,23,26,27,34,39,41,44,45,46,48,50,51,52,54,59,60,65],glanc:[16,44],glibc:[19,62],global:[2,5,6,9,12,13,14,19,27,31,41,45,47,48,50,51,59,62],gnu:[2,4,15,30,41,43,57],gnueabihf:[4,43],goal:[1,8,16,24,39,44,53],goe:[17,26,28,49,54,61],going:[1,10,13,15,16,24,27,28,29,41,44,52,53,58,59,61],goldberg:[30,57],gonzui:[13,41],good:[0,16,24,31,40,44,53],goodi:[13,41],googl:[37,53],got:[30,57],gpio1:[4,43],gpio:[4,43],gpl:[2,15,21,31,41,65],gplv2:[24,53],gplv3:2,gpu:[4,43],grade:[0,16,32,33,34,35,36,37,38,40,44],gradual:[7,46],graduat:39,grain:[24,53],grant:[16,44],granular:[19,21,62,65],graph:[13,41],graphic:[4,13,24,43,53],greater:[14,29,45,58],greatli:[14,45],greg:53,grep:[12,13,15,34,41,47],grossli:[24,53],group:[7,8,9,22,23,24,25,27,39,46,51,53,59,60,63,64],grow:[28,61],gtk:[3,12,13,47],guarante:[5,6,12,19,24,28,37,47,48,50,53,61,62],guard:[19,21,29,58,62,65],guest16:38,guest16_end:38,guest:[0,16,30,44,57],guest_16_bit:38,guest_32_bit:38,guest_cod:38,guest_code_s:38,gui:[13,41],guid:[6,7,10,18,31,42,46,48,52],guidelin:[13,41],hack:[13,18,41,42],had:[5,7,21,24,46,50,53,65],half:[6,12,23,27,28,47,48,59,60,61],hall:53,halt:38,hand:[0,5,11,18,23,42,50,60],handl:[0,5,6,7,8,9,10,15,18,21,24,26,27,28,30,34,35,38,41,42,46,48,50,51,52,53,54,57,59,61,65],handler:[0,5,6,18,19,20,24,26,27,28,29,30,33,42,48,50,53,54,55,57,58,59,61,62],happen:[6,7,8,10,12,13,14,16,21,22,23,27,28,29,44,45,46,47,48,52,58,59,60,61,64,65],happend:[21,65],hard:[4,5,6,7,8,9,10,12,14,15,16,17,18,22,27,28,35,37,41,42,43,44,45,46,47,48,49,50,51,52,59,61,64],hardirq_bit:[28,61],hardirq_mask:[28,61],hardlink:[9,51],hardwar:[0,4,7,8,9,15,19,21,24,25,28,30,34,36,41,43,46,51,53,57,61,62,63,65],hartman:53,hartmut:53,has:[0,2,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,21,22,23,24,25,26,27,28,29,33,35,37,38,39,41,42,44,45,46,47,48,49,50,51,52,53,54,58,59,60,61,62,63,64,65],hash:[10,21,22,33,36,52,64,65],hashtabl:[33,36],have:[1,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,21,22,23,24,25,27,28,29,30,32,33,34,35,36,37,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,57,58,59,60,61,62,63,64,65],have_pid:[14,45],haven:[1,27,59],hc0:[21,65],hctx:[5,50],hd_geometri:[5,50],hda1:[7,46],hda2:[7,46],hda3:[13,41],hda:[7,46],hdr_len:[18,26,42,54],hdrerr:36,he1:[21,65],head:[1,9,14,18,25,26,27,28,31,38,42,45,51,53,54,59,61,63],head_32:2,header:[9,10,12,14,15,16,18,24,33,34,35,36,37,41,42,44,45,47,51,52,53],headers_end:[18,42],heap:[17,27,49,59],heavi:[25,63],heavili:[24,53],held:[14,21,39,45,65],hello:[0,38],hello_kdb:15,hello_kdb_break:15,hello_kdb_bug:15,help:[1,2,8,13,14,15,16,17,21,23,32,33,34,35,36,37,38,39,41,44,45,49,60,65],helper:[9,12,17,25,27,47,49,51,59,63],henc:[4,18,24,27,28,42,43,53,59,61],here:[2,4,7,8,9,15,17,18,19,21,22,23,27,28,31,35,41,42,43,46,49,51,59,60,61,62,64,65],heterogen:[13,41],hex:[21,24,53,65],hexadecim:[5,13,41,50],hexdump:[18,42],hi_softirq:[6,23,48,60],hierarch:[8,24,53],hierarchi:[0,4,8,9,10,28,43,51,52,61],high:[6,8,16,19,22,23,24,25,27,28,29,39,44,48,53,58,59,60,61,62,63,64],higher:[5,8,10,12,15,16,19,23,24,28,39,41,44,47,50,52,53,60,61,62],highest:[6,19,26,32,33,34,35,36,37,38,48,54,62],highmem:[0,17,25,49,63],hint:[9,15,41,51],hitachi:[24,53],hitm:[16,44],hlist_head:[9,51],hlt:[2,38],hog:[6,16,44,48],hold:[4,5,6,8,9,10,12,13,14,17,18,19,21,23,28,33,42,43,45,47,48,49,50,51,52,60,61,62,65],holder:[5,50],hole:[27,59],home:[2,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,21,24,39,41,42,43,44,45,46,47,48,49,50,51,52,53,65],homework:[9,13,32,33,34,35,36,37,38,39,51],honest:39,hook:[18,24,26,42,53,54],hooknum:[18,42],hop:[26,54],hope:[30,57],hopefulli:[19,28,61,62],host:[0,1,2,3,7,10,13,15,18,22,26,30,36,38,41,42,46,52,54,57,64],hostnam:[18,42],hotkei:[16,44],hotplug:0,hour:39,housekeep:[19,62],hover:[13,41],how:[0,4,6,7,8,9,10,11,12,13,14,15,16,17,18,19,21,22,23,24,25,26,27,28,29,31,34,35,38,41,42,43,44,45,46,47,48,49,51,52,53,54,58,59,60,61,62,63,64,65],howev:[5,6,9,12,13,15,18,19,23,24,28,29,39,41,42,47,48,50,51,53,58,60,61,62],howto:[0,13,41],hpf:[9,51],hrtimer_softirq:[6,23,48,60],html:[0,2,38,53],hton:[18,42],htonl:[18,42],htop:[16,44],http:[0,1,2,4,7,13,18,24,30,31,36,37,38,41,42,43,46,53,57],hundr:[19,62],hvc0:[2,3,13,15,16,41,44],hwaddr:[30,57],hybrid:[24,53],hypercal:[27,30,57,59],hypervisor:[0,21,24,27,53,59,65],i2c1:[4,43],i2c:[4,12,43,47],i386:[3,15,19,41,62],i386_start_kernel:[21,65],i440fx:[21,65],i686:2,i8042:[12,47],i8042_data_reg:[12,47],i8042_kbd_irq:[12,47],i8042_read_data:[12,47],i8042_setup_kbd:[12,47],i8042_status_reg:[12,47],i82559er:3,i_atim:[9,10,51,52],i_blkbit:[10,52],i_block:[10,52],i_cdev:[7,46],i_count:[10,52],i_ctim:[9,10,51,52],i_dev:[10,52],i_fop:[9,10,51,52],i_gid:[9,10,51,52],i_gid_writ:[9,51],i_ino:[10,52],i_map:[10,52],i_mmap:[22,64],i_mmap_rwsem:[22,64],i_mmap_writ:[22,64],i_mod:[9,10,51,52],i_mtim:[9,10,51,52],i_new:[10,52],i_nlink:[10,52],i_op:[9,10,51,52],i_pag:[22,64],i_priv:[10,52],i_rdev:[10,52],i_sb:[10,52],i_siz:[9,10,51,52],i_size_read:[10,52],i_stat:[10,52],i_uid:[9,10,51,52],i_uid_writ:[9,51],ia32_nr_syscal:[29,58],ia32_sys_call_t:[29,58],ia_siz:[10,52],ia_valid:[10,52],iattr:[10,52],ibm:[24,53],icmp:[26,54],id_tabl:8,ide0:[12,47],ide1:[12,47],ide:8,ide_cd_mod:[15,41],idea:[9,14,21,39,45,51,65],ident:[7,13,46],identif:8,identifi:[4,5,6,7,8,9,10,12,13,14,15,16,17,21,22,23,25,28,29,31,41,43,44,45,46,47,48,49,50,51,52,58,60,61,63,64,65],idl:[2,6,48],ids:[16,24,44,53],idt:[23,60],idtr:[23,30,57,60],idtr_addr:[23,60],idtr_entri:[23,60],idx:[10,19,52,62],ier:[12,47],ifdef:[19,22,27,29,58,59,62,64],iff:[27,59],ifnam:3,ifndef:[19,62],iget_fail:[10,52],iget_lock:[10,52],ignor:[3,7,10,12,15,17,18,23,28,41,42,46,47,49,52,60,61],ignore_loglevel:15,ihl:[18,42],iir:[12,47],illeg:[19,62],illustr:[7,46],imag:[0,3,5,6,7,9,11,12,13,16,24,41,44,46,47,48,50,51,53],imap:[10,22,37,52,64],imap_block:37,img:[3,5,9,13,35,50,51],immedi:[5,14,23,28,35,45,50,60,61],impact:[24,28,29,53,58,61],implement:[0,4,5,6,9,10,14,16,17,18,19,20,22,23,24,25,28,30,31,32,37,38,39,42,43,44,45,48,49,50,51,52,53,55,57,60,61,62,63,64],impli:[24,30,53,57],implic:51,implicitli:[9,18,42,51],import_single_rang:[18,42],importantli:[19,62],impos:[18,24,42,53],imposs:[15,35,41],improv:[5,10,16,28,30,39,44,50,51,52,57,61],imx6ul:[4,43],imx8mm:[4,43],imx8mp:[4,43],imx_v6_v7_defconfig:[4,43],in_interrupt:[28,61],in_irq:[19,62],inactive_task_fram:[27,59],inaddr_loopback:[18,42],inappropri:[12,47],inb:[12,38,47],inb_p:[12,47],inc:2,inc_nlink:[9,51],includ:[1,2,4,5,6,7,8,9,10,12,14,15,16,17,18,21,23,24,25,29,30,36,39,41,42,43,44,45,46,47,48,49,50,51,52,53,57,58,60,63,65],incom:[12,19,27,47,59,62],incomplet:39,inconsist:[13,21,27,41,59,65],incorpor:8,incorrect:[7,21,28,35,39,46,61,65],increas:[0,6,9,16,18,23,24,26,28,32,33,34,35,36,37,38,42,44,48,51,53,54,60,61],increasingli:[23,60],increment:[8,9,10,11,14,15,19,23,28,45,51,52,60,61,62],incur:[24,39,53],indefinit:[16,44],independ:[5,8,12,14,18,24,25,28,42,45,47,50,53,61,63],index:[0,1,5,9,10,12,13,19,22,23,27,36,37,38,41,47,50,51,52,59,60,62,64],indic:[0,5,7,9,10,12,15,17,18,19,22,30,37,39,41,42,46,47,49,50,51,52,57,62,64],indirect:37,indirect_data_block:37,indirectli:[10,52],individu:[0,5,12,17,21,23,34,39,47,49,50,60,65],induct:[9,51],industri:[4,43],ineffici:[5,10,12,47,50,52],inet6:2,inet:[2,18,42],inet_cr:[18,42],inet_protosw_reus:[18,42],inet_sock_destruct:[18,42],inetd:3,infinit:[12,38,47],info:[0,4,5,6,9,12,13,14,21,23,43,45,47,48,50,51,53,60,65],inform:[0,1,5,7,8,9,10,13,14,15,16,17,18,19,21,22,23,24,25,27,29,30,32,33,34,35,36,37,38,39,41,42,44,45,46,49,50,51,52,53,57,58,59,60,62,63,64,65],infrastructur:[0,1,2,13,32,33,34,35,36,37,39],init:[2,4,6,7,8,14,15,16,17,23,24,31,41,43,44,45,46,48,49,53,60],init_delayed_work:[6,48],init_list_head:[14,27,45,59],init_modul:[7,12,15,18,21,41,42,46,47,65],init_nam:8,init_net:[18,27,42,59],init_onc:[10,52],init_ramfs_f:[9,51],init_task:[27,59],init_wait_entri:[27,59],init_waitqueue_head:[7,46],init_work:[6,23,48,60],initi:[0,1,6,7,8,10,12,13,14,17,18,20,21,22,23,24,27,31,36,37,42,45,46,47,48,49,52,53,55,59,60,64,65],initial_flag:[14,45],initrd:[24,53],inject:[16,30,44,57],inl:[12,47],inlin:[19,21,24,27,29,33,53,58,59,62,65],ino:[10,37,52],inod:[0,17,24,31,37,49,53],inode_direct_data_bl:37,inode_direct_data_block:37,inode_init_onc:[9,10,51,52],inode_init_own:[9,10,51,52],inode_newsize_ok:[10,52],inode_oper:[0,9,51],inode_vers:[10,52],inoi:37,input:[4,8,12,14,18,22,24,26,28,30,42,43,45,47,53,54,57,61,64],insert:[5,8,9,10,12,14,15,16,25,26,27,29,41,44,45,47,50,51,52,54,58,59,63],insert_inode_hash:[10,52],insid:[0,4,5,6,7,8,9,10,12,13,14,15,16,17,18,21,23,30,41,42,43,44,45,46,47,48,49,50,51,52,57,60,65],insight:[10,16,27,44,52,59],insmod:[7,8,9,10,12,14,15,18,21,41,42,45,46,47,51,52,65],inspect:[0,2,4,5,8,9,10,12,13,15,16,17,21,29,33,41,43,44,47,49,50,51,52,58,65],inspir:39,instal:[0,1,2,3,4,7,13,15,16,27,32,33,34,35,36,37,38,41,43,44,46,59],install_mod_path:3,instanc:[2,7,9,13,15,16,22,23,27,30,33,37,39,41,44,46,51,57,59,60,64],instanti:[10,18,42,52],instead:[1,5,7,12,14,15,18,19,24,27,28,30,36,41,42,45,46,47,50,53,57,59,61,62],instruct:[2,4,5,12,13,15,17,19,21,23,27,28,29,30,32,33,34,35,36,37,38,39,41,43,47,49,50,57,58,59,60,61,62,65],instructor:39,instrument:[4,16,21,33,43,44,65],insuffici:[12,47],int80:[23,60],int_max:[18,42],int_min:[18,42],integ:[9,10,14,18,25,28,42,45,51,52,61,63],integr:[1,4,8,9,13,15,16,39,41,43,44,51],intel:[0,12,13,24,38,41,47,53],intend:[13,18,41,42],intent:[11,39],inter:[24,53],interact:[7,8,9,10,15,16,17,18,22,24,28,32,36,38,41,42,44,46,49,51,52,53,61,64],interactiv:53,intercept:[15,18,33,41,42],interchang:[28,61],interconnect:[18,42],interest:[5,10,13,14,15,16,17,29,41,44,45,49,50,52,58],interfac:[2,4,5,6,7,8,9,12,13,15,16,17,18,21,23,24,26,27,29,30,32,33,35,36,37,39,41,42,43,44,46,47,48,49,50,51,53,54,57,58,59,60,65],interleav:[15,28,41,61],intern:[5,6,7,8,10,12,17,18,22,24,25,30,32,36,42,46,47,48,49,50,52,53,57,63,64],internet:[13,18,39,41,42],interpret:[0,28,61],interract:38,interrog:[12,47],interrupt:[0,4,6,7,8,14,15,19,20,21,24,26,27,29,30,34,40,41,43,45,46,48,53,54,55,57,58,59,62,65],intersect:[28,61],interv:[6,24,48,53],intr:[12,23,47,60],intricaci:[16,44],intro:0,introduc:[4,10,12,13,14,22,24,41,43,45,47,52,53,64],introducer:53,introduct:[0,22,40,64],intuit:[22,64],invalid:[10,14,15,16,19,20,21,28,29,35,41,44,45,52,55,58,61,62,65],invalidatepag:[22,64],inversio:[21,65],invert:[9,51],investig:[0,9,13,15,21,51,65],invit:[16,44],invlpg:[19,30,57,62],invoc:[15,41],invok:[6,9,10,27,48,51,52,59],involv:[5,8,9,10,12,14,19,39,45,47,50,51,52,62],inw:[12,47],iobas:8,ioc0:[12,47],iocb:[22,64],iocb_noio:[22,64],iocb_nowait:[22,64],iocla:53,ioctl:[0,4,5,18,30,31,33,34,36,38,42,43,50,57],ioctl_messag:[7,46],ioctl_set_addr:[18,42],iomem:[4,27,43,59],ionut:31,ioperm:[12,47],iopl:[12,47],iopol:[6,48],ioport:[12,27,34,47,59],ioremap:[19,62],iosnoop:[16,44],iounmap:[19,62],iov:[18,42],iov_it:[22,64],iovec:[18,42],ip_hdr:[18,42],ipc:[24,27,53,59],iph:[18,42],iphdr:[18,42],ipproto_tcp:[18,42],ipproto_udp:[18,42],iptabl:[18,42],iput:[9,10,51,52],ipv4:[18,24,42,53],ipv6:[24,53],iret:[19,23,29,58,60,62],irq:[0,8,12,24,30,47,53,57],irq_com1:34,irq_com2:34,irq_count:[28,61],irq_exit:[21,65],irq_handl:[12,47],irq_handler_t:[12,47],irq_no:[12,47],irq_non:[12,47],irq_poll_softirq:[6,23,48,60],irq_wake_thread:[12,47],irqf_oneshot:[12,47],irqf_shar:[12,47],irqflag:2,irqn:[23,60],irqreturn_t:[12,47],irqs_dis:[19,62],irrepar:[15,41],is_dirty_writeback:[22,64],is_en:[27,59],is_err:[5,50],is_key_press:[12,47],is_partially_uptod:[22,64],isa:8,isapnp:8,isn:8,iso9660:[9,51],isol:[24,27,53,59],isolate_mode_t:[22,64],isolate_pag:[22,64],isra:[21,65],issu:[1,5,6,7,11,12,13,15,16,17,19,21,23,24,26,27,28,29,30,33,39,41,44,46,47,48,49,50,53,54,57,58,59,60,61,62,65],item:[6,14,15,32,45,48],iter:[0,5,6,8,14,17,22,37,45,48,49,50,64],its:[5,6,7,8,9,10,12,13,14,15,16,17,18,22,23,24,25,27,28,29,30,33,35,37,38,39,41,42,44,45,46,47,48,49,50,51,52,53,57,58,59,60,61,63,64],itself:[3,16,21,23,24,25,30,44,53,57,60,63,65],izon:[22,37,64],izone_block:37,jae:[29,58],jbd2:[16,44],jetson:[4,43],jiffi:[6,13,14,21,45,48,65],jiffies_64:13,jiffies_valu:[6,48],jmp:[15,27,41,59],jnz:[28,61],job:[13,23,24,53,60],john:31,join:[13,41],jonathan:53,joystick:[7,46],json:[13,41],jtag:[21,65],jump:[12,13,23,29,41,47,58,60],june:[16,39,44],just:[1,5,6,8,9,10,12,13,15,17,19,21,22,23,24,27,28,30,41,47,48,49,50,51,52,53,57,59,60,61,62,64,65],juwucd7ldvurncamopepmhqejfftunlaqo:2,kacpid:[6,48],kallsym:[14,16,44,45],karma:53,kasan:0,kate:[13,41],kbd:[12,47],kbd_exit:[12,47],kbd_fop:[12,47],kbd_init:[12,47],kbd_interrupt_handl:[12,47],kbd_major:[12,47],kbd_minor:[12,47],kbd_read:[12,47],kblockd:[6,48],kbuild:[11,15,33,34,35,36,41],kconfig:[24,53],kcore:[13,41],kdb:[0,11],kdb_write_address:15,kde:[13,41],kdir:[2,15,41],keep:[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,24,25,28,29,37,39,41,42,43,44,45,46,47,48,49,50,51,52,53,58,61,63],kei:[0,2,13,15,26,27,41,54,59],kept:[9,23,51,60],kern:[15,18,41,42],kern_alert:[10,14,15,41,45,52],kern_crit:[14,15,41,45],kern_debug:[14,15,41,45],kern_emerg:[14,15,41,45],kern_err:[5,14,15,41,45,50],kern_info:[14,15,41,45],kern_level:[15,41],kern_notic:[5,14,15,41,45,50],kern_warn:[14,15,41,45],kernel:[3,5,7,8,9,10,12,17,19,20,22,23,25,26,29,30,33,34,35,36,37,38,39,40,46,47,49,50,51,52,54,55,57,58,60,62,63,64],kernel_:[18,42],kernel_api:[14,45],kernel_buff:[7,29,46,58],kernel_modul:[11,15,41],kernel_profil:[16,44],kernel_recvmsg:[18,42],kernel_sector_s:[5,35,50],kernel_sendmsg:[18,42],kernel_thread:13,kernelnewbi:[13,41],kernelsocket:[18,42],keyboard:[0,3,7,8,13,15,41,46],keycod:[12,47],keylogg:[12,47],keystrok:[12,47],keyword:[0,6,11,12,17,47,48,49],kfifo:[0,34],kfree:[9,14,17,21,28,33,45,49,51,61,65],kfree_mem:33,kgdboc:[15,41],khelper:[6,48],ki_flag:[22,64],kib:[16,44],kill:[15,16,18,21,27,41,42,44,59,65],kill_anon_sup:[9,51],kill_block_sup:[9,51],kill_litter_sup:[9,51],kill_sb:0,killabl:[27,59],kilobyt:[5,50],kiocb:[22,64],kit:[4,43],kkeil:[19,62],klau:53,klogd:[15,41],kludg:[22,64],km_type_nr:[19,62],kmalloc:[10,14,17,21,25,33,45,49,52,63,65],kmalloc_area:[17,49],kmalloc_mem:33,kmalloc_prob:33,kmalloc_probe_entry_handl:33,kmalloc_probe_handl:33,kmalloc_ptr:[17,49],kmap:[17,19,49,62],kmap_atom:[5,19,50,62],kmap_atomic_high_prot:[19,62],kmap_atomic_idx_push:[19,62],kmap_atomic_prot:[19,62],kmap_prot:[19,62],kmap_pt:[19,62],kmem:[16,44],kmem_cach:[21,65],kmem_cache_alloc:[10,13,21,52,65],kmem_cache_alloc_trac:[21,65],kmem_cache_cr:[21,65],kmem_cache_fre:[21,65],kmemcheck:[21,65],kmemleak:0,kmmap:[17,49],knife:[18,42],know:[0,5,12,14,15,16,18,21,24,40,42,44,45,47,50,53,65],knowledg:[5,9,10,13,33,34,36,39,41,50,51,52],known:[2,6,9,10,13,14,23,28,41,45,48,51,52,60,61],knuth:[14,45],kob:8,kobj:8,kobj_typ:8,kobj_uevent_env:8,kobject:0,kobject_get:8,kobject_init:8,kobject_put:8,kobject_set_nam:8,korner:[18,42],kprobe:[0,11,16,21,39,40,44,53,65],kref:8,kretprob:33,kroah:53,kscope:0,kset:8,ksoftirqd:[6,21,23,48,60,65],kstatf:[9,51],ksys_writ:[16,44],kthread:[6,21,48,65],kthread_creat:[6,48],kthread_run:[6,48],kthreadd:[16,44],ktime_t:[18,26,42,54],ktype:8,kunmap_atom:[5,19,50,62],kvec:[18,42],kvm:[0,3,16,24,39,40,44,53],kvm_api:38,kvm_api_vers:38,kvm_create_vcpu:38,kvm_create_vm:38,kvm_exit_hlt:38,kvm_exit_io:38,kvm_exit_mmio:38,kvm_fd:38,kvm_get_api_vers:38,kvm_get_sreg:38,kvm_get_vcpu_mmap_s:38,kvm_reg:38,kvm_run:38,kvm_set_sreg:38,kvm_set_tss_addr:38,kvm_set_user_memory_region:38,kworker:[16,44],kzalloc:[9,51],l12:39,lab10:[9,51],lab9:[9,51],lab:[0,2,3,7,8,11,21,27,36,37,39,40,53,59,65],label:[3,4,12,15,18,24,29,41,42,43,47,53,58],labor:0,laboratoar:13,laboratori:[0,2,5,9,10,32,50,51,52],laboratorului:0,lack:[5,15,41,50],laddr:[19,62],languag:[13,14,15,41,45],laptop:39,larg:[6,7,9,14,16,19,22,23,24,26,27,28,44,45,46,48,51,53,54,59,60,61,62,64],larger:[2,8,10,13,19,25,26,41,52,54,62,63],largest:[24,53],last:[6,7,10,12,13,15,18,22,23,25,27,28,29,38,39,41,42,46,47,48,52,58,59,60,61,63,64],late:39,latenc:[0,23,28,34,60,61],later:[2,6,7,8,9,10,21,23,29,30,46,48,51,52,57,58,60,65],latest:[0,1,4,5,6,7,8,9,10,12,14,15,16,17,18,38,41,42,43,44,45,46,47,48,49,50,51,52],latm:[16,44],latter:[18,23,29,42,58,60],launch:[0,13],launder_pag:[22,64],law:2,layer:[0,18,26,36,40,42,54],layout:[0,19,23,35,60,62],lazi:[0,27,59],lcd:[4,43],lcdif:[4,43],ld_preload:[13,41],ldrex:[28,61],ldt:[19,23,60,62],ldtr:[19,62],lea:[13,41],lead:[4,7,8,12,14,15,16,23,25,28,39,41,43,44,45,46,47,60,61,63],leak:[21,65],leak_init:[21,65],leakag:[27,59],learn:[11,16,17,21,34,41,44,49,53,65],least:[4,5,6,10,15,18,19,23,24,28,34,39,41,42,43,48,50,52,53,60,61,62],leav:[3,11,15,18,22,25,41,42,63,64],lectur:[0,36,40],led:[18,42],left:[1,5,10,18,23,42,50,52,60],legaci:8,len:[5,7,10,17,18,21,22,26,36,38,42,46,49,50,52,54,64,65],length:[7,9,10,17,22,36,37,46,49,51,52,64],less:[7,10,13,15,19,25,28,37,41,46,52,61,62,63],let:[6,12,13,16,18,19,21,23,24,27,28,29,38,39,41,42,44,47,48,53,58,59,60,61,62,65],letter:[5,38,50],level:[0,1,7,8,10,12,13,14,15,16,18,19,21,22,23,24,25,27,28,29,30,33,35,36,39,41,42,44,45,46,47,52,53,57,58,59,60,61,62,63,64,65],lib:[4,13,14,15,17,21,24,27,41,43,45,49,53,59,65],libc:[14,17,29,45,49,58],libncurses5:[3,13],librari:[4,13,14,15,24,29,41,43,45,53,58],libsw:[13,41],libthread_db:[13,41],licens:[2,24,30,31,53,57],life:[16,44],light:[6,28,48,61],lighter:[10,52],lightweight:[13,27,41,59],like:[4,6,7,8,9,10,11,12,13,16,17,18,19,21,23,27,28,39,41,42,43,44,46,47,48,49,51,52,59,60,61,62,65],likewis:[29,58],limit:[6,9,10,12,14,19,21,23,24,28,39,45,47,48,51,52,53,60,61,62,65],lin:[15,41],line:[1,6,7,8,12,13,14,15,16,18,21,23,24,28,32,36,38,41,42,44,45,46,47,48,53,60,61,65],linear:[0,25,63],linearli:[25,63],link:[0,2,3,4,5,8,9,13,14,15,16,21,22,24,25,26,27,36,37,41,43,44,45,50,51,53,54,59,63,64,65],linker:[29,38,58],linu:[24,53],linux:[2,3,5,6,7,9,10,11,15,16,17,21,26,27,30,32,33,34,35,36,37,38,40,44,46,48,49,50,51,52,54,57,59,65],list:[0,2,3,4,5,6,7,8,9,10,11,13,15,16,17,18,22,25,26,27,28,32,33,34,35,36,37,38,39,41,42,43,44,46,48,49,50,51,52,53,54,59,61,63,64],list_add:[6,14,27,45,48,59],list_add_rcu:[28,61],list_add_tail:[27,28,59,61],list_del:[6,14,21,27,45,48,59,65],list_del_init:[27,59],list_del_init_car:[27,59],list_del_rcu:[28,61],list_empti:[27,28,59,61],list_empty_car:[27,59],list_entri:[10,14,45,52],list_exit:[14,45],list_first_entri:[6,27,28,48,59,61],list_for_each:[14,45],list_for_each_entry_rcu:[28,61],list_for_each_entry_saf:[14,45],list_for_each_entry_safe_from:[27,59],list_for_each_saf:[14,45],list_head:[5,6,8,13,14,18,21,22,42,45,48,50,64,65],list_m:[21,65],list_next_entri:[27,59],list_poison1:[21,65],list_poison2:[21,65],lista:0,listen:[0,3,13,36],listen_backlog:[18,42],littl:[14,18,24,42,45,53],live:[15,41],lld:[7,46],llseek:[7,10,46,52],lnet_sock_accept:[18,42],load:[0,4,5,6,7,8,9,10,12,13,14,16,17,21,22,27,28,30,32,34,43,44,45,46,47,48,49,50,51,52,57,59,61,64,65],load_modul:[15,21,41,65],load_offset:[29,58],loadabl:[15,24,41,53],loader:[24,53],loc:[12,47],local:[0,1,2,4,5,6,7,8,10,12,13,14,15,16,17,18,19,23,24,25,26,28,36,37,41,42,43,44,45,46,47,48,49,50,52,53,54,60,61,62,63],local_bh_dis:[6,23,28,48,60,61],local_bh_en:[6,23,28,48,60,61],local_irq_dis:[12,28,47,61],local_irq_en:[12,28,29,47,58,61],local_irq_restor:[28,61],local_irq_sav:[28,61],localhost:[2,18,42],locat:[1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,22,23,24,28,41,42,43,44,45,46,47,48,49,50,51,52,53,55,60,61,62,64],lock1:[14,45],lock2:[14,45],lock:[0,5,7,10,16,18,19,21,22,24,27,33,42,44,46,50,52,53,59,62,64,65],lock_acquir:[21,65],lock_addr:[28,61],lock_class_kei:[9,51],lockdep:0,lockdep_assert_held:[27,59],locked_ioctl:[5,50],locking2:[21,65],loff_t:[7,9,10,22,31,46,51,52,64],log:[1,8,10,12,13,14,15,16,21,30,41,44,45,47,52,57,65],log_guest_error:[30,57],logic:[5,19,24,26,29,35,50,53,54,58,62],logical_disk_nam:35,logical_disk_s:35,logical_disk_sector:35,login:[2,3,13],loglevel:[3,4,15,41,43],longer:[3,4,5,6,8,12,13,14,15,28,36,41,43,45,47,48,50,61],look:[0,4,6,7,9,12,13,14,15,16,18,21,22,23,25,27,28,29,30,32,41,42,43,44,45,46,47,48,51,57,58,59,60,61,63,64,65],lookup:[0,22,26,37,54,64],loop:[3,10,12,14,16,17,37,38,44,45,47,49,52],loopback:[2,18,36,37,42],lose:[30,57],lost:[15,16,41,44],lot:[12,15,20,27,38,41,47,55,59],love:[9,10,51,52,53],low:[5,16,22,23,24,30,44,50,53,57,60,64],lower:[16,21,23,24,25,28,44,53,60,61,63,65],lower_up:2,lowercas:34,lowest:[6,8,17,19,48,49,62],lowmem:[17,19,25,49,62,63],lpt:8,lro:[26,54],lru:[25,63],lrwx:[27,59],lrwxrwxrwx:3,lsb:[4,13,41,43],lsc:[13,41],lseek:[7,10,46,52],lsmod:[14,15,27,41,45,59],lsof:[16,44],lsp:[13,41],lucru:53,lucrul:53,lvm:[24,53],lwn:[7,24,46,53],lxc:[27,59],lxn:[17,49],lxp:[27,59],lxr:[0,1,2,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65],mac:[15,24,36,41,53],mac_head:[18,26,42,54],mac_len:[18,26,42,54],machin:[0,1,4,5,6,7,9,10,12,14,15,16,18,24,27,29,33,34,35,36,39,40,41,42,43,44,45,46,47,48,50,51,52,53,58,59],macro:[0,5,6,7,8,10,12,13,14,15,18,19,24,27,33,35,36,37,38,41,42,45,46,47,48,50,52,53,59,62],macrodefinit:[5,9,50,51],made:[5,6,7,12,13,14,17,18,22,24,29,32,33,34,35,36,38,39,42,45,46,47,48,49,50,53,58,64],madv_merg:38,madvis:38,magic:[7,9,21,22,37,38,46,51,64,65],magic_valu:38,magnet:[7,46],magnitud:[16,44],mai:[5,6,7,8,11,12,14,16,19,22,23,24,25,27,28,29,32,33,34,35,36,37,38,39,44,45,46,47,48,50,53,58,59,60,61,62,63,64],mail:[13,31,32,33,34,35,36,37,41,53],main:[0,1,2,5,6,8,10,12,13,15,16,19,21,22,26,28,37,38,41,44,47,48,50,52,54,61,62,64,65],mainli:[10,19,52,62],mainlin:[15,41],maintain:[0,5,6,8,9,14,18,21,22,25,28,42,45,48,50,51,61,63,64,65],maintainership:[24,53],major:[0,5,8,23,33,34,35,50,60],make:[0,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,23,24,27,28,29,31,32,33,34,35,36,37,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62],make_bad_inod:[10,52],makefil:[2,3,5,9,13,15,16,41,44,50,51],makenod:[6,8,48],malloc:[14,45],man:[13,18,41,42],manag:[0,5,7,8,10,12,14,15,16,17,18,21,30,31,32,39,40,41,42,44,45,46,47,49,50,52,57,65],mandat:[19,62],mandatori:[5,32,33,34,35,36,50],mani:[5,6,7,8,10,12,13,14,16,17,19,22,24,25,27,28,33,34,35,36,41,44,45,46,47,48,49,50,52,53,59,61,62,63,64],manifest:[28,61],manipul:[14,20,22,24,45,53,55,64],manner:[24,53],mantain:[13,41],manual:[1,2,6,7,13,16,18,28,42,44,46,48,61],manufactur:[4,43],map:[0,5,7,9,10,12,13,16,20,22,24,25,27,29,30,40,41,44,46,47,50,51,52,53,55,57,58,59,63,64],map_anonym:38,map_bh:[9,10,51,52],map_noreserv:38,map_priv:38,mappabl:[22,64],marc:53,march:32,marco:53,marginea:53,mark:[5,6,7,8,9,10,11,12,14,15,16,17,18,29,36,41,42,44,45,46,47,48,49,50,51,52,58],mark_buffer_dirti:[9,10,51,52],mark_inode_dirti:[10,52],mark_lock:[21,65],marker:[15,21,41,65],market:[24,53],mask:[6,23,25,26,27,48,54,59,60,63],maskabl:[23,60],master:[1,4,5,6,7,8,9,10,12,13,14,15,16,17,18,37,41,42,43,44,45,46,47,48,49,50,51,52,53],match:[8,12,13,17,26,27,41,47,49,54,59],match_devic:8,materi:39,matter:1,max:[7,9,36,38,46,51],max_access_s:[30,57],max_io_ap:[19,62],max_lfs_files:[9,51],max_number_devic:31,max_queue_len:38,max_siz:[14,45],max_softirq_restart:[23,60],max_softirq_tim:[23,60],maxact:33,maxim:[5,50],maximum:[4,7,9,10,24,28,29,37,39,43,46,51,52,53,58,61],maxlen:38,maxsiz:[7,46],mcimx6ul:[4,43],mcr:[12,47],mean:[1,4,5,6,7,8,9,10,12,13,15,16,18,19,23,24,28,34,35,37,38,39,41,42,43,44,46,47,48,50,51,52,53,60,61,62],meaning:38,meaningless:[24,53],meant:[4,43],meantim:[6,48],measur:[14,16,38,39,44,45],mechan:[5,6,8,14,16,17,23,24,28,29,33,44,45,48,49,50,53,58,60,61],media_chang:[5,50],mediat:[7,46],medic:[4,43],mediu:53,medium:[28,61],meet:[8,34,35,39],megabyt:[16,44],mem:[14,16,17,27,38,44,45,49,59],mem_map:[25,63],membarrier_switch_mm:[27,59],member:[1,7,8,14,18,27,31,42,45,46,59],memblock:[20,55],memcmp:[14,45],memcpi:[5,14,24,29,38,45,50,53,58],memmov:[14,30,45,57],memori:[0,2,5,6,7,8,9,10,12,13,16,19,22,23,27,29,30,33,38,40,41,44,46,47,48,50,51,52,57,58,59,60,62,64],memoriei:53,memory_exit:[14,45],memory_init:[14,45],memory_map:[17,49],memory_region_add_subregion:[30,57],memory_region_init_io:[30,57],memoryregion:[30,57],memoryregionop:[30,57],memset:[14,21,45,65],mention:[4,5,7,28,29,32,33,34,35,36,37,38,43,46,50,58,61],menuconfig:[4,13,15,18,37,41,42,43],merchant:[30,57],mere:38,merg:[0,1,5,16,24,44,50,53],merit:[24,53],mesag:31,mesi:[28,61],messag:[0,1,4,5,6,9,10,12,13,14,15,16,17,21,24,26,27,31,38,41,43,44,45,47,48,49,50,51,52,53,54,59,65],messsag:[30,57],meta:[22,64],metadata:[9,10,24,51,52,53],metainform:[9,36,51],metal:[30,57],method:[5,7,8,9,13,15,20,22,23,38,41,46,50,51,55,60,64],methodolog:0,micro:0,microkernel:[15,24,41,53],mid10:[21,65],mid:[7,46],might:[1,4,15,16,17,18,21,22,24,27,28,29,31,42,43,44,49,53,58,59,61,64,65],might_fault:[29,58],might_sleep:[27,28,59,61],migrat:[22,27,59,64],migrate_async:[22,64],migrate_mod:[22,64],migratepag:[22,64],mihai:53,militaru:53,miller:[24,53],million:[24,53],min:[7,39,46,53],min_access_s:[30,57],mind:[9,12,14,16,18,24,31,42,44,45,47,51,53],minf:0,minfs_add_link:[10,52],minfs_alloc_inod:[9,51],minfs_creat:[10,52],minfs_destroy_inod:[9,51],minfs_dir_entri:[10,52],minfs_dir_inode_oper:[10,52],minfs_dir_oper:[10,52],minfs_fill_sup:[9,51],minfs_find_entri:[10,52],minfs_fs_typ:[9,51],minfs_iget:[9,51],minfs_inod:[9,10,51,52],minfs_inode_info:[9,10,51,52],minfs_lookup:[10,52],minfs_mount:[9,51],minfs_new_inod:[10,52],minfs_num_entri:[10,52],minfs_op:[9,51],minfs_readdir:[10,52],minfs_sb_info:[9,51],minfs_super_block:[9,51],minicom:[0,2,3,13],minim:[2,3,4,9,13,28,41,43,51,61],minimalist:[10,52],minimum:[4,6,19,23,43,48,60,62],minix:[9,10,37,51,52],minix_add_link:[10,52],minix_alloc_inod:[9,51],minix_aop:[10,52],minix_bmap:[10,52],minix_cr:[10,52],minix_destroy_inod:[9,51],minix_dir_inode_oper:[10,52],minix_dir_oper:[10,52],minix_evict_inod:[10,52],minix_file_inode_oper:[10,52],minix_file_oper:[10,52],minix_fill_sup:[9,51],minix_find_entri:[10,52],minix_get_block:[10,37,52],minix_getattr:[10,52],minix_i:[10,52],minix_iget:[10,52],minix_inod:[10,52],minix_inode_info:[10,52],minix_link:[10,52],minix_lookup:[10,52],minix_mkdir:[10,52],minix_mknod:[10,52],minix_mount:[9,51],minix_new_inod:[10,52],minix_readdir:[10,52],minix_readpag:[10,52],minix_rmdir:[10,52],minix_sb_info:[9,51],minix_setattr:[10,52],minix_symlink:[10,52],minix_trunc:[10,52],minix_unlink:[10,52],minix_v1:[10,52],minix_v1_raw_inod:[10,52],minix_write_begin:[10,52],minix_write_fail:[10,52],minix_write_inod:[10,52],minix_writepag:[10,52],minor:[0,5,8,12,33,34,35,47,50],minu:[15,41],minut:[13,39,41,51,53],mip:[24,25,53,63],misc:0,misc_deregist:8,misc_regist:8,miscdevic:33,miss:[8,14,19,21,23,27,28,33,45,59,60,61,62,65],mistak:[6,15,32,33,34,35,36,37,41,48],mix:[19,62],mk_pte:[19,62],mkdev:[7,46],mkdir:[1,3,9,10,13,22,37,51,52,64],mkf:[9,10,51,52],mknod:[5,6,7,10,12,46,47,48,50,52],mm_struct:[0,13,15,25,63],mmap:[7,10,16,17,22,24,25,36,38,44,46,49,52,53,63,64],mmcblk0:[4,43],mmdrop:[27,59],mmgrab:[27,59],mmio:[30,38,57],mmput:[17,49],mmu:[0,17,25,29,49,58,63],mnt:[4,9,10,43,51,52],mobil:[4,39,43],mod1:[15,41],mod2:[15,41],mod:[11,15,41],mod_nam:8,mod_tim:[6,21,23,48,60,65],mode:[0,3,5,6,7,9,10,12,13,14,15,17,18,19,24,27,29,30,37,39,41,42,45,46,47,48,49,50,51,52,53,57,58,59,62],mode_nam:[15,41],model:[0,3,6,10,30,48,52,57],modem:[12,47],modern:[15,18,24,28,41,42,53,61],modif:[13,24,34,37,41,53],modifi:[1,4,5,6,7,8,9,10,14,15,17,18,19,21,22,27,28,29,30,39,41,42,43,45,46,48,49,50,51,52,57,58,59,61,62,64,65],modinst:3,modpost:[11,15,41],modprob:[15,41],modul:[0,2,4,5,6,7,8,9,10,11,12,13,16,17,18,21,31,32,33,34,35,36,37,42,43,44,46,47,48,49,50,51,52,65],modular:[10,15,24,41,52,53],module_author:[15,31,41],module_descript:[15,31,41],module_device_t:8,module_exit:[15,18,21,31,41,42,65],module_init:[15,18,21,31,41,42,65],module_licens:[15,21,41,65],module_nam:[12,47],module_put:[18,42],modules_instal:3,moment:[9,10,12,13,41,47,51,52],momentarili:[19,62],mon:31,mon_proc:[6,48],mondai:[32,33,34,36],monitor:[0,6,15,16,23,24,28,33,41,44,48,53,60,61],monolit:53,monolith:[0,15,41],month:[24,53],moodl:[32,33,34,35,36,38,39],more:[2,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,21,22,23,24,25,27,28,29,30,32,33,34,35,36,37,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,57,58,59,60,61,62,63,64,65],moreov:[14,45],most:[4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,21,22,23,24,26,28,30,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,54,57,60,61,62,64,65],mostli:[4,10,20,22,23,43,52,55,60,64],motorola:[24,53],mount:[0,2,3,4,5,8,10,13,15,21,27,41,43,50,52,59,65],mount_bdev:[9,51],mount_nodev:[9,51],mount_opt:[9,51],mount_pseudo:[9,51],mount_singl:[9,51],mountain:[10,52],mous:[7,8,46],mov:[13,15,19,21,28,29,41,58,61,62,65],movabl:[25,63],move:[5,7,13,20,23,27,29,41,46,50,55,58,59,60],move_addr_to_kernel:[18,42],movl:[15,27,29,41,58,59],movzbl:[29,58],mozilla:[13,41],ms_remountm:[9,51],msg:[18,42],msg_control:[18,42],msg_controllen:[18,42],msg_dontwait:[18,42],msg_flag:[18,42],msg_iter:[18,42],msg_name:[18,42],msg_namelen:[18,42],msghdr:[18,42],msi:[30,57],msleep:[12,47],msr:[30,57],mss:[26,54],msust:[10,52],mtu:2,much:[5,6,7,10,13,15,16,23,24,25,27,28,41,44,46,48,50,52,53,59,60,61,63],muller:53,mult:53,multi:[0,11,15,19,27,40,41,59,62],multi_mod:[15,41],multicast:2,multilib:[3,7,46],multipl:[2,5,6,8,9,10,11,12,13,14,15,16,19,22,23,24,25,27,28,30,33,35,41,44,45,47,48,50,51,52,53,57,59,60,61,62,63,64],multiplex:36,multiprocess:0,multiprocessor:[6,48],multitask:[14,24,45,53],must:[1,5,6,7,8,9,10,12,13,14,15,17,18,19,22,24,27,28,29,31,32,34,35,36,37,38,39,41,42,45,46,47,48,49,50,51,52,53,58,59,61,62,64],mutex:[0,6,48],mutex_flag_wait:[28,61],mutex_init:[14,45],mutex_lock:[12,14,21,28,33,45,47,61,65],mutex_lock_nest:[21,33,65],mutex_remove_wait:[28,61],mutex_unlock:[14,21,28,33,45,61,65],mutex_wait:[28,61],mutual:[5,14,45,50],mvar:[15,41],mx6ul:[4,43],my_access:[12,47],my_acquir:[14,45],my_baseport:[12,47],my_blkdev_nam:[5,50],my_block_dev:[5,50],my_block_exit:[5,50],my_block_init:[5,50],my_block_major:[5,50],my_block_minor:[5,50],my_block_op:[5,50],my_block_open:[5,50],my_block_releas:[5,50],my_block_request:[5,50],my_block_transf:[5,50],my_bu:8,my_bus_descr:8,my_bus_devic:8,my_bus_device_releas:8,my_bus_exit:8,my_bus_init:8,my_bus_typ:8,my_class:8,my_classdev:8,my_cleanup:8,my_data:[6,7,12,46,47,48],my_debug_func:15,my_dev_releas:8,my_devic:[7,8,46],my_device_data:[6,7,12,46,47,48],my_device_driv:[7,46],my_driv:8,my_exit:8,my_first_minor:[7,46],my_fop:[7,46],my_fork:1,my_handl:[12,47],my_hook_exit:[18,42],my_hook_init:[18,42],my_init:[8,12,14,45,47],my_ioctl:[7,18,42,46],my_ioctl_data:[7,46],my_ioctl_down:[7,46],my_ioctl_filter_address:[18,42],my_ioctl_get_buff:[7,46],my_ioctl_in:[7,46],my_ioctl_print:[7,46],my_ioctl_set_buff:[7,46],my_ioctl_timer_alloc:[6,48],my_ioctl_timer_cancel:[6,48],my_ioctl_timer_mon:[6,48],my_ioctl_timer_set:[6,48],my_ioctl_up:[7,46],my_irq:[12,47],my_list:[14,45],my_lock:[28,61],my_major:[7,46],my_match:8,my_max_minor:[7,46],my_minor:[7,46],my_minor_count:[7,46],my_modul:[14,45],my_nf_hookfn:[18,42],my_nfho:[18,42],my_nr_port:[12,47],my_oops_exit:[15,41],my_oops_init:[15,41],my_open:[7,46],my_pnp_driv:8,my_pnp_prob:8,my_pnp_remov:8,my_pnp_tbl:8,my_port:[18,42],my_proc_file_op:[17,49],my_queue_op:[5,50],my_read:[7,46],my_register_devic:8,my_register_driv:8,my_releas:[7,14,45,46],my_seq_open:[17,49],my_seq_show:[17,49],my_show_bus_descr:8,my_submit_bio:[5,50],my_test_messag:[18,42],my_thread_f:[6,48],my_uev:8,my_unregister_devic:8,my_unregister_driv:8,my_work:[6,48],my_work_handl:[6,48],my_workqueu:[6,48],my_writ:[7,46],my_xfer_bio:[5,50],my_xfer_request:[5,50],myaddr:[18,42],mybdev:[5,7,46,50],myblock:[5,50],mybu:8,mybus0:8,mycdev:[7,46],myclass0:8,myclass:8,mydev0:8,mydev:8,mydisk:[5,9,13,50,51],mydriv:8,myf:0,myfs_aop:[10,52],myfs_creat:[10,52],myfs_dir_inode_oper:[10,52],myfs_file_inode_oper:[10,52],myfs_file_oper:[10,52],myfs_fill_sup:[9,51],myfs_get_inod:[9,10,51,52],myfs_mkdir:[10,52],myfs_mknod:[10,52],myfs_mount:[9,51],mykthread0:[6,48],myrul:8,name:[3,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,21,22,23,24,25,27,28,29,32,33,34,35,36,37,38,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,64,65],name_len:[10,52],name_s:8,namefmt:[6,48],namespac:[0,18,24,42,53],nano:[4,43],nat:[18,26,42,54],nativ:[16,30,44,57],native_safe_halt:2,natur:[6,48],navig:[0,1,15,17,35,49],ncp:[9,51],necesar:0,necess:[19,29,58,62],necessari:[5,7,8,10,12,13,14,15,22,28,31,37,38,41,45,46,47,50,52,61,64],necessarili:[24,53],need:[1,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,27,28,31,32,33,34,35,36,37,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,55,59,60,61,62,63,64,65],neg:[7,12,14,22,28,45,46,47,61,64],neglig:[29,58],neovim:[13,41],nest:[0,6,12,47,48],net:[3,7,8,13,15,18,24,27,36,41,42,46,53,59],net_devic:[18,26,42,54],net_famili:[18,42],net_proto_famili:36,net_rx_softirq:[6,23,48,60],net_softirq:[26,54],net_tx_sofirq:[6,48],net_tx_softirq:[6,23,48,60],netcat:[0,15,41],netconsol:[0,3],netdev:3,netem:[18,42],netfilt:0,netfilter_ipv4:[18,42],network:[0,4,6,8,9,15,23,27,36,40,41,43,48,51,59,60],network_head:[18,26,42,54],neural:[4,43],never:[10,19,29,52,58,62],new_inod:[9,10,51,52],new_sock:[18,42],newer:[29,58],newli:[5,10,18,25,36,42,50,52,63],newlin:[17,49],newsock:[18,42],nex:38,next:[1,6,7,9,10,12,13,14,15,18,19,21,22,23,24,25,26,27,28,30,32,33,34,35,36,38,39,41,42,45,46,47,48,51,52,53,54,57,59,60,61,62,63,64,65],next_jiffi:[6,48],next_task:[14,45],nf_:[18,42],nf_accept:[18,42],nf_drop:[18,42],nf_hook_op:[18,42],nf_hook_stat:[18,42],nf_hookfn:[18,42],nf_inet_forward:[18,42],nf_inet_hook:[18,42],nf_inet_local_in:[18,42],nf_inet_local_out:[18,42],nf_inet_numhook:[18,42],nf_inet_post_rout:[18,42],nf_inet_pre_rout:[18,42],nf_ip_forward:[26,54],nf_ip_hook_prior:[18,42],nf_ip_local_in:[26,54],nf_ip_local_out:[26,54],nf_ip_numhook:[26,54],nf_ip_post_rout:[26,54],nf_ip_pre_rout:[26,54],nf_ip_pri_conntrack:[18,42],nf_ip_pri_conntrack_confirm:[18,42],nf_ip_pri_conntrack_defrag:[18,42],nf_ip_pri_conntrack_help:[18,42],nf_ip_pri_filt:[18,42],nf_ip_pri_first:[18,42],nf_ip_pri_last:[18,42],nf_ip_pri_mangl:[18,42],nf_ip_pri_nat_dst:[18,42],nf_ip_pri_nat_src:[18,42],nf_ip_pri_raw:[18,42],nf_ip_pri_secur:[18,42],nf_ip_pri_selinux_first:[18,42],nf_ip_pri_selinux_last:[18,42],nf_max_verdict:[18,42],nf_queue:[18,42],nf_register_net_hook:[18,42],nf_repeat:[18,42],nf_stolen:[18,42],nf_stop:[18,42],nf_unregister_net_hook:[18,42],nfs:[9,51],nfsd:[15,41],nic:3,nicknam:[18,42],nmap:[13,41],nmi:[12,23,47,60],nmi_bit:[28,61],noarp:2,nobodi:[6,19,48,62],nobuff:36,node1:[4,43],node:[4,5,7,8,9,10,14,24,25,28,43,45,46,50,51,52,53,61,63],nodev:[21,65],nograph:[4,43],noinlin:[21,65],nok:[29,58],non:[0,4,5,7,12,14,15,18,19,22,23,24,28,29,30,34,41,42,43,45,46,47,50,53,57,58,60,61,62,64],none:[2,3,4,8,9,10,15,41,43,51,52],nonetheless:[16,44],nonmask:[23,60],noop:2,nop:[15,28,41,61],noqueu:2,noret_typ:[6,48],normal:[8,9,14,22,23,25,27,45,51,59,60,63,64],nosock:36,nota:53,notabl:[5,50],notar:0,note:[5,6,7,8,12,13,14,15,16,17,19,21,22,24,27,38,39,41,44,45,46,47,48,49,50,53,59,62,64,65],noteworthi:[15,18,41,42],noth:[1,6,18,22,42,48,64],notic:[4,5,7,8,10,12,13,14,15,19,21,23,27,28,31,41,43,45,46,47,50,52,59,60,61,62,65],notif:[0,5,12,47,50],notifi:[5,7,8,10,46,50,52],notion:[13,14,36,39,41,45],noul:53,now:[1,4,6,9,10,12,13,14,15,16,22,23,24,25,27,28,38,41,43,44,45,47,48,51,52,53,59,60,61,63,64],nowdai:38,npage:[17,49],npu:[4,43],nr_cpu:[19,62],nr_exclus:[27,59],nr_hw_queue:[5,50],nr_page:[22,64],nr_port:8,nr_sector:[5,50],nr_softirq:[6,23,48,60],nr_thp:[22,64],nrexcept:[22,64],nrpage:[22,64],nsproxi:[27,59],ntf:[9,10,22,51,52,64],ntoh:[18,42],ntohl:[18,42],nttcp:3,num:[7,18,42,46],num_byt:[10,52],numa:[5,20,28,50,55,61],numa_no_nod:[5,50],numa_nod:[5,50],number:[5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,21,22,23,24,25,26,27,28,29,33,34,36,37,38,41,42,44,45,46,47,48,49,50,51,52,53,54,58,59,60,61,62,63,64,65],numer:[18,37,42],nutshel:53,nvidia:[4,43],nvim:[13,41],nxp:[4,43],o_append:[7,46],o_cloexec:[18,42],o_nonblock:[0,18,42],o_rdonli:[7,46],o_rdwr:38,o_sync:[7,46],o_trunc:[7,46],obiectivel:0,obj:[11,15,41],objdump:0,object:[0,8,39],objtool:[27,59],observ:[6,8,12,14,15,16,18,28,42,44,45,47,48,61],obtain:[5,7,10,12,15,17,18,27,33,36,39,42,46,47,49,50,52,59],obviou:39,obvious:[15,41,51],occupi:[9,10,14,37,45,51,52],occur:[6,7,8,12,14,15,19,22,23,25,27,28,29,30,39,41,45,46,47,48,57,58,59,60,61,62,63,64],occurr:[28,32,61],octavian:53,octob:39,odroid:[4,43],off:[6,7,15,31,38,39,41,46,48],off_t:[17,49],offend:[21,65],offer:[7,8,12,13,15,16,18,23,24,28,29,39,41,42,44,46,47,53,58,60,61],offici:[4,39,43],offlin:39,offload:[24,26,53,54],offset:[5,7,15,17,18,19,21,22,23,25,26,31,41,42,46,49,50,54,60,62,63,64,65],offsetof:[14,45],often:[6,7,8,10,12,14,15,18,22,23,24,28,41,42,45,46,47,48,52,53,60,61,64],okfn:[18,42],old:[7,9,10,14,19,23,24,27,28,45,46,51,52,53,59,60,61,62],oldconfig:[13,41],older:39,oldest:[15,41],onc:[1,2,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,21,22,23,26,28,36,41,42,43,44,45,46,47,48,49,50,51,52,54,60,61,62,64,65],one:[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,22,23,24,25,27,28,29,31,32,33,34,35,36,37,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,64],ones:[9,10,14,18,42,45,51,52],onli:[3,5,6,7,8,9,10,11,12,13,14,15,17,18,19,21,22,23,24,25,26,27,28,29,31,32,33,34,35,36,37,38,39,41,42,45,46,47,48,49,50,51,52,53,54,58,59,60,61,62,63,64,65],onlin:[2,39],onto:[4,43],oop:[0,6,7,11,19,46,48,62],oops:[15,41],oops_init:[21,65],op_oop:[15,41],op_read:[15,41],op_writ:[15,41],opaqu:[30,57],open:[0,1,4,5,9,10,12,13,14,17,24,31,34,38,39,41,43,45,47,49,50,51,52,53],open_disk:[5,50],open_softirq:[23,60],opengrok:[13,41],oper:[0,4,5,12,13,15,16,19,21,25,27,31,33,34,35,36,37,39,41,43,44,47,50,59,62,63,65],operar:53,operst:[15,41],opinion:[16,44],oppos:[16,19,24,27,28,38,44,53,59,61,62],ops:[5,8,18,36,42,50],optim:[0,2,5,10,19,24,25,29,50,52,53,58,62,63],optimist:[28,61],option:[0,3,5,6,7,9,10,13,16,18,21,24,25,33,34,37,38,39,42,44,46,48,50,51,52,53,63,65],option_both:34,option_com1:34,option_com2:34,order:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19,21,22,23,24,25,27,29,31,32,33,34,35,36,37,41,42,43,44,45,46,47,48,50,51,52,53,58,59,60,62,63,64,65],orderli:[12,47],org:[2,13,18,24,30,38,42,53,57],organ:[5,7,8,18,19,22,24,42,46,50,53,62,64],orient:[7,36,46],orig_ax:[29,58],origin:[1,12,13,22,27,41,47,59,64],osc:[4,43],osdep:[30,57],osdev:38,osi:36,oss:[24,53],other:[0,2,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,22,23,24,26,27,28,30,36,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,54,57,59,60,61,62,64],otherwis:[6,7,8,9,10,12,13,19,27,28,29,30,39,41,46,47,48,51,52,57,58,59,61,62],our:[0,4,7,12,13,15,16,24,35,38,39,41,43,44,46,47,53],ourselv:[14,28,45,61],out:[2,5,7,9,10,12,13,15,16,17,18,21,28,29,30,39,41,42,44,46,47,49,50,51,52,57,58,61,65],out_blk_init:[5,50],out_err:[5,50],out_module_put:[18,42],out_put:[18,42],outb:[12,38,47],outb_p:[12,47],outbound:[18,42],outl:[12,47],output:[0,3,4,5,7,8,12,15,16,18,22,23,26,28,30,41,42,43,44,46,47,50,54,57,60,61,64],outsid:[18,19,21,24,27,42,53,59,62,65],outw:[12,47],over:[6,7,8,9,10,13,14,15,16,17,18,24,25,27,28,36,41,42,44,45,46,48,49,51,52,53,59,61,63],overal:[29,31,58],overflow:[19,21,23,60,62,65],overhead:[14,16,17,21,24,28,44,45,49,53,61,65],overlap:[19,28,61,62],overload:[24,53],overview:[0,19,22,25,30,40,57,62,63,64],overwrit:[5,27,50,59],overwritten:[21,65],own:[1,4,9,15,18,19,22,24,25,27,28,41,42,43,51,53,59,61,62,63,64],owner:[5,7,8,9,12,18,22,28,31,36,42,46,47,50,51,61,64],packag:[0,1,2,3,7,13,15,16,18,27,36,41,42,44,46,59],packet:[0,24,36,53],packet_typ:36,pad:[27,59],paddr:[19,62],page:[0,1,4,5,10,12,14,15,16,18,20,21,23,24,27,29,32,33,34,35,36,37,38,39,41,42,43,44,45,47,50,52,53,55,58,59,60,65],page_address:[17,19,49,62],page_align:[17,49],page_mask:[19,62],page_offset:[17,49],page_s:[8,9,17,49,51],page_shift:[9,17,19,49,51,62],page_to_pfn:[17,49],pageabl:0,pagecach:[22,64],pagemap:[9,51],pagep:[10,22,52,64],pager:[16,44],pagin:[19,62],pahlk:53,pahol:[27,59],pai:[24,53],panel:[4,13,41,43],panic:[0,15,41],panic_init:[21,65],panic_tim:[21,65],paper:[30,57],paragraph:39,parallel:[0,5,8,13,14,15,16,19,23,28,41,44,45,50,60,61,62],paramet:[0,5,6,7,8,9,10,12,13,14,16,17,18,22,34,38,42,44,45,46,47,48,49,50,51,52,64],paravirt:[27,59],paravirtu:0,parcur:53,parcurgerea:53,parent:[8,9,10,13,14,16,17,22,27,41,44,45,49,51,52,59,64],parport0:[12,47],parport_pc:8,parport_pc_exit:8,parport_pc_init:8,parport_pc_pnp_driv:8,parport_pc_pnp_prob:8,parport_pc_pnp_remov:8,parport_pc_pnp_tbl:8,pars:8,parse_and_ev:[27,59],part:[0,5,7,14,15,16,18,19,21,22,23,24,25,27,28,29,36,37,39,40,41,42,44,45,46,50,53,58,59,60,61,62,63,64,65],partial:[7,22,25,46,63,64],particip:39,particular:[6,8,9,10,11,12,18,19,22,23,24,30,42,47,48,51,52,53,57,60,62,64],particularli:[16,24,44,53],partit:[5,8,13,22,27,35,50,59,64],partner:31,pass:[5,6,7,8,9,10,13,15,16,18,24,27,29,32,33,34,35,36,37,38,39,41,42,44,46,48,50,51,52,53,58,59],password:[3,13],past:[10,19,52,62],patch:[24,53],path:[2,7,9,13,15,16,18,22,26,27,28,32,33,34,35,36,37,38,41,42,44,46,51,54,59,61,64],pathnam:[17,49],pattern:[21,28,61,65],paus:[28,61],payment:39,pcb:[27,59],pcd:[19,62],pci:[8,30,57],pcnet32:[15,41],pde:[21,65],peak:[16,44],peanut:[10,52],peculiar:[6,24,48,53],peer:[18,39,42],penal:39,penalti:[0,19,24,53,62],pend:[12,16,23,27,30,44,47,57,59,60],pentium:[29,58],pentru:53,peopl:[16,24,39,44,53],per:[0,5,15,19,27,38,39,41,50,59,62],per_cpu_var:[27,29,58,59],percentag:[16,44],perf:0,perform:[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,21,23,24,26,27,28,30,41,42,43,44,45,46,47,48,49,50,51,52,53,54,57,59,60,61,62,65],period:[0,15,19,24,41,53,62],peripher:[4,12,19,30,43,47,57,62],perm:[17,49],perman:[0,2],permiss:[9,10,12,13,16,17,18,36,42,44,47,49,51,52],permit:[2,12,23,39,47,60],perror:38,person:[16,44],perspect:[5,7,46,50],pf_:[18,42],pf_inet:[18,42],pf_packet:[18,36,42],pf_stp:36,pfifo_fast:2,pfn:[17,19,49,62],pfn_to_pag:[17,49],pg_buddi:[25,63],pg_reserv:[17,49],pgd:[19,62],pgd_offset:[19,62],pgd_t:[19,62],pgoff_t:[22,64],pgprot_t:[17,19,49,62],phase:[0,12,13,15,23,28,38,41,47,60,61],phone:[4,39,43],phy:[19,62],phys_addr:[19,62],physic:[0,5,7,8,9,10,12,13,14,15,18,19,20,21,23,24,30,35,41,42,45,46,47,50,51,52,53,55,57,60,62,65],physical_disk1_nam:35,physical_disk2_nam:35,physical_disk_nam:[5,50],pi4:[18,42],pi_lock:[27,59],pic1:[12,47],pic2:[12,47],pic:[23,60],pick:[25,27,28,31,59,61,63],picocom:[15,41],pid:[6,14,15,16,17,18,21,27,33,41,42,44,45,48,49,59,65],pid_list:[14,45],pid_t:[14,45],piec:39,piix:[21,65],pin:[23,60],pio:38,pipe1:3,pipe2:3,pipe:[3,9,10,37,51,52],pipef:[9,51],pipelin:[28,61],pitix_dir_entri:37,pitix_inod:37,pitix_mag:37,pitix_name_len:37,pitix_super_block:37,pitix_vers:37,place:[4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,21,23,25,26,27,39,41,42,43,44,45,46,47,48,49,50,51,52,54,59,60,62,63,65],plagiar:0,plai:[0,15,41],plan:[6,9,12,13,31,47,48,51],platform:[0,1,4,6,7,8,12,15,16,17,18,19,41,42,43,44,46,47,48,49,62],ple:[14,45],pleas:[2,4,5,6,7,8,9,10,12,14,15,16,17,18,23,31,37,39,41,42,43,44,45,46,47,48,49,50,51,52,60],pll:[4,43],plu:[4,43],plug:0,plugin:13,pm_message_t:8,pmap:[17,49],pmd:[19,62],pmd_offset:[19,62],pmd_t:[19,62],pnp0400:8,pnp0401:8,pnp:[0,19,62],pnp_bu:8,pnp_bus_match:8,pnp_bus_typ:8,pnp_dev:8,pnp_device_id:8,pnp_device_prob:8,pnp_driver:8,pnp_id:8,pnp_irq:8,pnp_irq_valid:8,pnp_port_len:8,pnp_port_start:8,pnp_port_valid:8,pnp_register_driv:8,pnp_register_drvi:8,pnp_unregister_driv:8,pnpbio:[8,19,62],point:[0,4,5,7,8,9,10,13,14,15,16,17,18,19,20,22,23,24,25,26,27,29,30,34,37,41,42,43,44,45,46,49,50,51,52,53,54,55,57,58,59,60,62,63,64],pointer:[0,5,6,7,8,9,10,12,14,15,17,18,21,22,24,25,27,29,38,41,42,45,46,47,48,49,50,51,52,53,58,59,63,64,65],poison:[21,65],poki:[2,3,13],polici:[0,28,61],politehnica:0,poll:[12,36,47],pool:[6,25,38,48,63],poor:[23,28,60,61],poorli:[28,61],pop:[4,5,6,7,8,9,10,12,14,15,16,17,18,19,23,27,28,41,42,43,44,45,46,47,48,49,50,51,52,59,60,61,62],popek:[30,57],popescu:[31,53],popf:[28,30,57,61],popfl:[27,59],popl:[27,59],popsect:[27,29,58,59],popul:[15,25,27,38,41,59,63],popular:[4,43],port:[0,3,4,6,7,8,13,15,17,18,23,26,30,34,36,38,41,42,43,46,48,49,54,57,60],portabl:[0,15,41],portal:53,portion:[5,14,45,50],portul:53,pos:[10,14,22,45,52,64],posit:[5,7,9,10,25,28,46,50,51,52,61,63],posix:[14,24,27,45,53,59],possibl:[5,6,7,8,9,10,12,13,14,15,17,18,21,22,23,24,27,28,33,36,39,41,42,45,46,47,48,49,50,51,52,53,59,60,61,64,65],post:[30,38,57],postpon:[23,28,60,61],potenti:[1,21,23,27,59,60,65],power:[5,8,24,25,28,50,53,61,63],powerpc64:[24,53],powerpc:[20,24,53,55],ppid:[27,59],ppph:[16,44],pps:[26,54],pr706:39,pr_alert:[14,45],pr_crit:[14,45],pr_debug:[14,15,41,45],pr_emerg:[14,45],pr_err:[14,17,45,49],pr_fmt:[14,45],pr_info:[6,7,12,14,17,21,45,46,47,48,49,65],pr_notic:[14,45],pr_warn:[14,45],practic:[3,16,18,24,28,39,42,44,53,61],pre:[6,48],prebuild:3,preced:[5,13,41,50],precis:[6,48],predefin:[6,7,15,27,36,41,46,48,59],predict:[28,61],preempt:[0,6,15,19,23,24,28,41,48,53,60,61,62],preempt_bit:[28,61],preempt_count:[28,61],preempt_count_inc:[28,61],preempt_dis:[27,28,59,61],preempt_en:[27,59],preemption:[0,27,59],preemptiv:[0,6,28,48,61],prefer:[12,23,28,29,39,47,58,60,61],preferred_lft:2,prefix:[11,13,15,18,27,28,41,42,59,61],prentic:53,prepar:[2,4,5,6,7,8,9,10,12,13,14,15,16,17,18,41,42,43,44,45,46,47,48,49,50,51,52],prepare_lock_switch:[27,59],prepare_task_switch:[27,59],prepare_to_wait_ev:[27,59],presenc:[5,9,10,34,50,51,52],present:[0,5,6,7,8,9,10,13,14,15,17,18,19,21,22,24,28,29,30,35,36,37,38,41,42,45,46,48,49,50,51,52,53,57,58,61,62,64,65],preserv:[7,28,46,61],press:[3,12,13,47],pressur:[22,64],pretti:[24,27,53,59],prev:[14,18,21,26,27,42,45,54,59,65],prev_mm:[27,59],prevent:[5,6,14,22,24,27,28,39,45,48,50,53,59,61,64],preview:32,previou:[0,5,6,7,8,9,10,12,13,14,15,17,18,21,23,28,38,39,41,42,45,46,47,48,49,50,51,52,60,61,65],previous:[4,5,9,10,17,19,22,27,43,49,50,51,52,59,62,64],prezentar:53,prezentarea:53,price:[19,62],primari:[8,39],primit:[6,12,14,15,20,24,27,41,45,47,48,53,55,59],prin:53,principl:[15,18,41,42],print:[4,5,6,12,13,14,15,16,17,18,21,23,25,38,41,42,43,44,45,47,48,49,50,60,63,65],print_debug:[15,41],print_hex_dump_byt:[15,41],print_hex_dump_debug:[15,41],print_sock_address:[18,42],print_usage_bug:[21,65],printer:8,printf:[6,14,15,30,41,45,48,57],printk:[0,1,4,5,10,18,21,42,43,50,52,65],prior:[8,18,42],prioriti:[0,6,15,18,20,26,39,41,42,48,54,55],priv:[18,42],privat:[5,6,7,8,9,10,12,18,22,25,27,28,31,37,39,42,46,47,48,50,51,52,59,61,63,64],private_data:[5,7,22,46,50,64],private_list:[22,64],private_lock:[22,64],priviledg:[19,62],privileg:[19,23,24,30,53,57,60,62],privilleg:[16,44],probabl:[13,15,41],probe:[0,12,16,33,44,47],problem:[0,5,7,12,13,14,15,21,34,39,41,45,46,47,50,65],problemat:39,proc:[0,4,5,6,7,9,11,12,13,14,17,21,27,32,33,34,36,43,45,46,47,48,49,50,51,59,65],proc_creat:[17,36,49],proc_entry_nam:[17,49],proc_remov:36,procedur:[38,39],proceed:[12,47],proces:53,procesor:53,process:[0,2,4,8,9,10,12,13,15,16,17,18,19,21,23,29,30,32,33,34,35,36,37,38,40,41,42,43,44,47,49,51,52,57,58,60,62,65],process_timeout:[21,65],processor:[0,4,6,8,12,14,23,24,25,27,29,30,43,45,47,48,53,57,58,59,60,63],procf:[0,9,32,33,36,51],produc:[4,21,28,34,38,43,61,65],product:[15,18,41,42],profession:51,profil:[0,21,38,40,53,65],profunzim:53,program:[5,6,7,8,10,12,13,14,15,16,17,18,19,23,24,30,38,41,42,44,45,46,47,48,49,50,52,53,57,60,62],programar:53,programm:[0,7,9,14,24,28,45,46,51,53,61],progress:[27,28,31,59,61],project:[1,2,3,4,9,10,13,18,24,39,41,42,43,51,52,53],promovar:53,prompt:[3,13],propag:[22,64],proper:[7,33,46],properli:[9,10,12,15,24,27,29,41,47,51,52,53,58,59],properti:[4,5,16,19,22,23,24,27,28,43,44,50,53,59,60,61,62,64],proport:[26,28,53,54,61],proportion:39,propuneri:53,prot:[17,19,49,62],prot_writ:38,protect:[6,12,14,15,17,19,22,24,28,30,38,41,45,47,48,49,53,57,61,62,64],protector:[19,62],proto:[26,54],proto_op:[0,36],protocol:[0,8,13,16,18,28,38,39,40,41,42,44,53,61],prototyp:[7,18,42,46],proven:[15,41],provid:[2,3,4,5,8,9,10,12,13,14,15,16,18,19,20,21,23,24,27,28,33,34,35,36,38,39,41,42,43,44,45,47,50,51,52,53,55,59,60,61,62,65],pseudo:[9,13,15,29,41,51,58],psh:[18,42],psi_ttwu_dequeu:[27,59],pso:[15,41],pt_reg:[29,58],pte:[19,62],pte_non:[19,62],pte_offset:[19,62],pte_pag:[19,62],pte_t:[19,62],pthread_creat:[27,59],pthread_mutex_trylock:[14,45],ptr:[14,29,38,45,58],ptrace:[14,45],ptrval:[21,65],pts:[2,3,13,15,16,27,41,44,59],pty:3,pub:[13,24,36,53],publicli:[24,39,53],publish:[30,39,57],pud:[19,62],pud_offet:[19,62],pud_offset:[19,62],pud_t:[19,62],pull:[0,4,5,6,7,8,9,10,12,14,15,16,17,18,24,31,41,42,43,44,45,46,47,48,49,50,51,52,53],punct:53,punctajul:53,punish:39,punit:39,pure:[22,64],purpos:[5,6,8,12,13,17,22,23,24,27,28,29,30,39,41,47,48,49,50,53,57,58,59,60,61,64],push:[1,13,15,19,21,23,26,28,41,54,60,61,62,65],pushf:[28,61],pushfl:[27,59],pushl:[27,59],pushsect:[27,29,58,59],put:[7,14,18,23,24,27,28,42,45,46,53,59,60,61],put_char:[12,47],put_idx:[12,47],put_link:[22,64],put_sup:[9,22,51,64],put_task_struct:[6,48],put_us:[7,12,29,46,47,58],putback_pag:[22,64],pwd:[15,41],pwt:[19,62],python3:3,python:13,q_ctrl:38,q_elem_t:38,qapi:[30,57],qdisc:2,qemu:[0,1,2,3,5,7,9,15,16,21,32,41,44,46,50,51,65],qemu_chr_fe_accept_input:[30,57],qemu_chr_fe_init:[30,57],qemu_chr_fe_set_handl:[30,57],qemu_chr_fe_writ:[30,57],qemu_displai:[3,12,13,47],qemu_irq:[30,57],qemu_irq_low:[30,57],qemu_irq_rais:[30,57],qemu_log_mask:[30,57],qemu_opt:[5,9,13,50,51],qemuarm:[4,43],qemuchrev:[30,57],qemux86:[2,3,12,13,16,17,21,44,47,49,65],qlen:2,qnx6_find_entri:[10,52],qnx6_readdir:[10,52],qstr:[10,52],qt4:[13,41],qual:[29,58],qualifi:[24,53],qualiti:[16,44],quantiti:33,quantum:[14,45],que:[5,50],queri:[0,7,13,41,46],question:[0,39],queu:[7,18,27,28,42,46,59,61],queue:[0,6,12,18,24,26,27,28,34,36,42,47,48,53,54,59,61],queue_control:38,queue_control_t:38,queue_delayed_work:[6,48],queue_depth:[5,50],queue_rq:[5,50],queue_work:[6,48],queuedata:[5,50],quick:[8,13,15,35,41],quickfix:[13,41],quickli:[15,24,41,53],quickstart:0,quiescent:[28,61],quiet:[13,41],quit:[10,15,18,41,42,52],quiz:[0,39],quizz:39,quota:[10,52],r10:[28,61],r11:[28,61],race:[6,12,24,27,28,47,48,53,59,61],raddr:[18,42],radix:[22,64],raid:[0,24,39,40,53],rais:[23,60],raise_softirq:[23,60],ram:[0,4,7,24,43,46,53],ramdisk:[5,50],ramf:[9,10,51,52],ramfs_aop:[10,52],ramfs_creat:[10,52],ramfs_dir_inode_oper:[10,52],ramfs_file_inode_oper:[10,52],ramfs_file_oper:[10,52],ramfs_fill_sup:[9,51],ramfs_fs_info:[9,51],ramfs_fs_typ:[9,51],ramfs_get_inod:[9,51],ramfs_kill_sb:[9,51],ramfs_mag:[9,51],ramfs_mkdir:[10,52],ramfs_mknod:[10,52],ramfs_mount:[9,51],ramfs_op:[9,51],ramfs_parse_opt:[9,51],ramfs_show_opt:[9,51],random:[5,50],rang:[12,17,19,20,30,34,37,47,49,55,57,62],rare:[24,27,53,59],raspberri:[4,43],rather:[10,18,42,52],raw:[3,5,9,13,18,42,50,51],raw_inod:[10,52],rax:38,razvan:[3,9,51],rb_node:[18,42],rb_root_cach:[22,64],rbnode:[18,42],rc1:[24,53],rc2:[18,24,42,53],rci:[15,41],rcu:[0,6,23,48,60],rcu_read_lock:[28,61],rcu_read_unlock:[28,61],rcu_softirq:[6,23,48,60],rdai:[12,47],rdmsr:[30,57],reach:[7,8,13,15,17,18,22,23,41,42,46,49,60,64],reachabl:[21,65],react:[23,60],reactiv:[6,12,27,47,48,59],read:[0,2,4,8,13,14,15,16,19,20,21,23,24,25,29,30,31,32,33,34,35,36,37,38,41,43,44,45,53,55,57,58,60,62,63,65],read_inod:[10,22,52,64],read_it:[10,22,52,64],read_lock:[14,45],read_lock_irq:[12,47],read_lock_irqsav:[12,47],read_unlock:[14,45],read_unlock_irq:[12,47],read_unlock_irqrestor:[12,47],readahead:[22,64],readahead_control:[22,64],readdir:[10,52],readelf:[16,44],reader:[14,28,45,61],readi:[5,7,27,28,46,50,59,61],readlink:[22,64],readm:[32,33,34,35,36,37,38],readpag:[10,22,52,64],real:[0,5,13,15,16,41,44,50],real_mod:38,real_par:[14,45],realiti:[5,50],realli:[27,59],realloc:[21,65],rear:[30,57],rearm:[6,48],reason:[5,6,7,8,9,10,12,13,14,15,17,39,41,45,46,47,48,49,50,51,52],reassert:[23,60],rebas:1,reboot:[8,15,41],rebuild:[0,4,5,6,7,8,9,10,12,14,15,16,17,18,41,42,43,44,45,46,47,48,49,50,51,52],receiv:[0,1,5,6,7,8,10,12,13,14,15,22,26,30,33,36,38,39,41,45,46,47,48,50,52,54,57,64],recent:[7,22,46,64],recept:[18,34,42],recheck:[27,59],reciproc:8,reclam:[28,61],recommend:[0,4,5,6,7,9,10,11,12,13,14,15,16,18,28,32,33,34,35,36,37,38,39,41,42,43,44,45,46,47,48,50,51,52,61],recompil:[4,13,34,43],record:[7,16,21,29,33,39,44,46,58,65],recoveri:35,recurs:[14,24,45,53],recv:[18,36,42],recvfrom:[18,36,42],recvmsg:[18,36,42],red:[25,63],redirect:[3,7,15,39,41,46],redistribut:[2,30,57],redo:[0,35],redon:39,reduc:[0,8,9,14,15,19,24,25,28,30,32,33,34,35,36,37,41,45,51,53,57,61,62,63],redzon:[21,65],ref:53,refcount_t:[18,42],refer:[0,2,3,4,5,6,7,8,9,10,12,14,15,17,18,19,22,24,28,36,37,38,39,42,43,45,46,47,48,49,50,51,52,53,61,62,64],referenc:[7,10,13,28,37,41,46,52,61],reflect:[8,24,53],refresh:[16,44],refus:8,reg:[12,18,29,38,42,47,58],regard:[8,9,24,33,39,51,53],regardless:[23,39,60],regener:[13,41],region:[12,14,20,21,25,27,34,45,47,55,59,63,65],regist:[0,4,13,15,17,18,19,21,23,27,29,30,34,36,37,38,41,42,43,49,57,58,59,60,62,65],register_blkdev:[5,50],register_chrdev_region:[7,46],register_devic:8,register_filesystem:[9,51],registr:[0,8,9,51,53],registri:[12,47],regular:[0,2,9,13,15,16,19,24,26,41,44,51,53,54,62],regularli:[24,53],reilli:53,reiserf:[9,51],reiter:39,rel:[5,12,14,15,24,28,29,37,39,41,45,47,50,53,58,61],relai:[5,50],relat:[2,8,9,13,14,16,17,18,22,24,32,33,34,35,36,41,42,44,45,49,51,53,64],relationship:[22,64],relativ:53,relax:[6,48],relay_exit:[5,50],relay_init:[5,50],releas:[0,5,8,9,10,12,14,15,17,18,19,21,24,28,31,35,36,37,41,42,45,47,49,50,51,52,53,61,62,65],release_region:[12,47],release_resourc:[28,61],releasepag:[22,64],relev:[1,14,15,41,45],reli:[19,27,29,39,58,59,62],reliabl:[21,65],relinquish:[24,53],reload:[12,14,27,45,47,59],reloc:[20,55],remain:[6,7,9,13,24,41,46,48,51,53],remap:[17,30,49,57],remap_pfn_rang:[17,49],remark:0,rememb:[6,18,36,42,48],remmap:[30,57],remot:[1,2,13,18,36,42],remount:[9,51],remount_f:[9,22,51,64],remov:[0,2,4,5,6,7,10,12,14,15,18,22,23,24,25,27,28,33,41,42,43,45,46,47,48,50,52,53,59,60,61,63,64],remove_from_buff:[14,45],remove_proc_entri:[17,49],renam:[10,22,52,64],rent:39,reorder:[5,50],rep:[28,61],repeat:[13,15,16,30,41,44,57],repeatedli:[12,47],replac:[6,7,9,15,41,46,48,51],replace_lxr:[9,51],repo:[1,3,4,5,6,7,8,9,10,12,14,15,16,17,18,31,32,33,34,35,36,37,41,42,43,44,45,46,47,48,49,50,51,52],report:[2,7,12,14,16,21,23,39,44,45,46,47,60,65],repositori:[0,2,4,5,6,7,8,9,10,12,14,15,16,17,18,37,41,42,43,44,45,46,47,48,49,50,51,52],repres:[5,6,7,8,9,10,12,13,14,15,16,17,18,19,23,24,35,37,38,39,41,42,44,45,46,47,48,49,50,51,52,53,60,62],represant:[4,43],represent:[8,18,42],req:[5,50],req_iter:[5,50],req_op:[5,50],req_op_read:[5,50],req_op_writ:[5,50],request:[0,6,7,9,10,15,16,21,22,24,28,31,33,35,38,39,41,44,46,48,51,52,53,61,64,65],request_irq:[12,47],request_queu:[5,35,50],request_region:[12,47],request_threaded_irq:[12,47],requests_irq:[12,47],requir:[1,2,3,5,6,7,8,9,12,13,14,15,16,17,18,19,22,23,24,25,27,28,30,32,33,34,35,36,37,38,39,41,42,44,45,46,47,48,49,50,51,53,57,59,60,61,62,63,64],rerun:13,res1:[18,42],res:[13,18,36,42],reschedul:[6,23,48,60],resembl:[0,19,29,58,62],reser:38,reserv:[6,7,10,12,15,19,23,24,25,26,30,36,39,41,46,47,48,52,53,54,57,60,62,63],reset:[0,4,5,6,7,8,9,10,14,15,16,17,18,38,39,41,42,43,44,45,46,48,49,50,51,52],reset_buff:[12,14,45,47],resid:[7,8,9,14,17,23,45,46,49,51,60],resolv:[0,11],resort:39,resourc:[0,2,6,7,8,9,12,13,14,16,18,24,28,39,41,42,44,45,46,47,48,51,53,61],respect:[4,5,7,8,9,13,14,15,17,18,25,35,36,39,42,43,45,46,49,50,51,63],respond:[5,7,8,15,41,46,50],respons:[0,5,7,8,9,10,18,23,24,28,42,46,50,51,52,53,60,61],rest:[5,6,7,9,12,18,22,23,31,33,34,35,36,37,42,46,47,48,50,51,60,64],rest_init:[2,21,65],restart:[13,15,24,41,53],restor:[5,23,27,28,29,50,58,59,60,61],restore_al:[21,65],restrict:[0,6,18,19,23,42,48,60,62],resubmit:39,result:[4,5,7,10,13,14,15,16,17,18,23,24,25,27,28,29,31,32,33,35,38,39,41,42,43,44,45,46,49,50,52,53,58,59,60,61,63],resum:[8,11,23,27,28,29,58,59,60,61],resurs:0,ret:[8,10,13,15,17,23,27,29,30,41,49,52,57,58,59,60],ret_from_fork:[21,65],retain:[5,9,10,33,39,50,51,52],retak:0,retaken:39,retri:[7,28,46,61],retriev:[7,14,18,26,27,29,42,45,46,54,58,59],retroact:39,retval:[18,42],reus:[24,53],revalidate_disk:[5,50],revers:[18,21,42,65],review:[0,1,4,5,6,7,8,9,10,12,14,15,16,17,18,41,42,43,44,45,46,47,48,49,50,51,52],revis:15,revisit:[12,47],rework:[6,48],rezolvarea:53,rflag:38,right:[1,7,9,10,12,13,17,18,19,21,22,23,28,31,37,38,39,42,46,47,49,51,52,60,61,62,64,65],ring:[26,54],rip:38,risc:[4,24,25,43,53,63],risk:[28,61],ritter:53,rmb:[28,61],rmdir:[3,10,22,37,52,64],rmmod:[7,10,12,14,15,18,41,42,45,46,47,52],robert:[9,10,51,52,53],rol:53,role:[5,7,8,9,10,39,46,50,51,52],rom:[5,50],room:[26,39,54],root:[0,2,3,4,5,6,7,8,10,11,12,13,14,15,16,17,18,21,22,24,27,30,37,41,42,43,44,45,46,47,48,49,50,52,53,57,59,64,65],rootf:[0,36],rootkit:[13,41],round:31,rout:[0,15,18,23,24,27,37,41,42,53,59,60],routin:[0,6,7,14,15,18,22,34,41,42,45,46,48,64],row:36,rpi:[4,43],rpl:[19,62],rq_data_dir:[5,50],rq_flag:[27,59],rq_for_each_seg:[5,50],rqcf_act_skip:[27,59],rqcf_req_skip:[27,59],rs232:[12,47],rsa:2,rsb:[27,59],rsb_clear_loop:[27,59],rsp:38,rss:[16,44],rst:[1,18,42],rtc:[12,47],rto:[23,60],rubini:53,rule:[0,4,5,8,13,14,23,26,31,37,38,40,41,43,45,50,54,60],run:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,27,28,29,30,35,41,42,43,44,45,46,47,48,49,50,51,52,53,55,57,58,59,60,61,62,64,65],run_timer_softirq:[21,65],runnabl:[27,59],runqueu:[27,59],runtim:[15,24,41,53],rw_semaphor:[22,64],rwlock_init:[14,45],rwlock_t:[14,45],rx_fifo:[30,57],rx_fifo_len:[30,57],rxcnt:[30,57],rxctrl:[30,57],rxpkt:36,s_blocksiz:[9,51],s_blocksize_bit:[9,51],s_dev:[9,51],s_dirt:[9,51],s_flag:[9,51],s_fs_info:[9,51],s_id:[9,51],s_ifdir:[9,51],s_isdir:[9,10,51,52],s_isreg:[9,10,51,52],s_iwusr:8,s_lock_kei:[9,51],s_magic:[9,51],s_maxbyt:[9,51],s_op:[9,51],s_root:[9,10,51,52],s_time_gran:[9,51],s_type:[9,51],s_umount_kei:[9,51],sad:[27,59],saddr:[18,42],safe:[6,19,21,27,48,59,62,65],safest:39,sai:[16,44],said:[23,24,53,60],salturi:53,same:[1,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,22,23,24,25,27,28,29,30,35,36,37,39,41,42,43,44,45,46,47,48,49,50,51,52,53,57,58,59,60,61,62,63,64],sampl:[0,6,16,18,21,24,33,42,44,48,53,65],sanit:[21,65],saniti:[16,18,42,44],sat:2,satisfi:[7,14,45,46],sato:[2,3,16,44],satur:[16,44],save:[7,9,10,12,13,15,16,23,27,28,29,30,41,44,46,47,51,52,57,58,59,60,61],save_mount_opt:[9,51],saw:8,sb_bread:[9,10,51,52],sb_read:[10,52],sbh:[10,52],sbi:[10,52],sbin:[4,8,15,17,41,43,49],sc1:[21,65],scalabl:0,scale:[24,26,28,53,54,61],scan:[12,21,27,47,59,65],scancod:0,scatter:[5,26,50,54],scenario:[5,15,21,23,28,50,60,61,65],sched:[2,6,7,14,15,16,33,41,44,45,46,48],sched_class:[27,59],sched_softirq:[6,23,48,60],sched_task_group:[27,59],schedul:[5,6,7,12,14,16,20,23,24,27,28,33,44,45,46,47,48,50,53,55,59,60,61],schedule_delayed_work:[6,48],schedule_delayed_work_on:[6,48],schedule_on_each_cpu:[6,48],schedule_timeout:[7,13,14,45,46],schedule_work:[6,23,48,60],schemat:[14,45],scheme:[0,23,35,37,60],school:[3,9,51],scienc:0,scientif:[24,53],scm:[24,53],scope:[2,26,54],score:39,scratch:[4,38,39,43],screen:[13,15,39,41],screencast:[23,27,59,60],scri:53,script:[0,3,5,6,9,10,13,16,18,24,29,32,33,34,35,36,37,38,41,42,44,48,50,51,52,53,58],scroll:13,scsi:[7,8,24,46,53],sdb:[5,50],sdk:[3,16,44],se0:[21,65],search:[0,2,7,9,13,14,15,16,19,22,25,29,30,41,44,45,46,51,57,58,62,63,64],search_exception_t:[29,58],second:[5,6,7,9,10,12,14,15,18,23,29,33,35,36,41,42,45,46,47,48,50,51,52,58,60],secondari:13,seconds_valu:[6,48],section:[1,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,22,23,24,27,28,29,39,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,64],sector1:35,sector2:35,sector3:35,sector:[5,9,35,50,51],sector_t:[5,10,22,50,52,64],secur:[0,7,26,30,46,54,57],see:[0,1,2,4,5,6,7,8,9,10,12,13,14,15,16,17,18,21,23,24,27,28,29,30,34,37,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,57,58,59,60,61,65],seed:35,seek:[7,39,46],seem:[7,28,46,61],seen:[2,5,7,8,12,14,16,18,23,27,28,37,42,44,45,46,47,50,59,60,61],segment:[0,5,14,16,23,25,26,30,39,44,45,50,54,57,60,63],seldom:[28,61],select:[4,11,12,19,21,23,27,30,31,43,47,57,59,60,62,65],select_task_rq:[27,59],selector:[0,23,26,38,54,60],self:[27,59],selinux:[24,53],semant:[13,41],semaphor:[13,14,24,27,45,53,59],semest:39,semestru:53,semiconductor:[4,43],send:[0,5,10,12,15,16,30,35,36,37,41,44,47,50,51,52,57],send_ev:[6,48],send_test_bio:[5,50],sender:0,sendmsg:[18,36,42],sendpag:36,sendto:[18,36,42],sens:[9,39,51],sensor:[12,23,47,60],sent:[5,6,7,9,12,14,15,17,18,36,41,42,45,46,47,48,49,50,51],sentinel:[14,45],separ:[4,6,9,17,24,27,28,29,35,43,48,49,51,53,58,59,61],septemb:39,seq:[18,42],seq_fil:[17,49],seq_printf:[17,49],sequenc:[6,7,10,12,13,18,23,27,29,42,46,47,48,52,58,59,60],sequenti:[7,46],sergiu:[2,53],seri:[5,15,30,41,50,57],serial:[0,2,3,7,8,13,15,23,24,27,28,34,41,46,53,59,60,61],serio:[12,47],seriou:[10,14,45,52],serv:[7,19,46,62],server:[13,18,24,41,42,53],servic:[3,8,23,24,26,29,53,54,58,60],session:[13,15,16,39,41,44],set:[0,3,4,6,7,8,9,10,12,13,14,15,16,17,18,19,21,22,23,24,25,27,28,29,30,34,37,38,39,41,42,43,44,45,46,47,48,49,51,52,53,57,58,59,60,61,62,63,64,65],set_bit:[10,14,28,45,52,61],set_buffer_new:[10,52],set_capac:[5,35,50],set_current_st:[7,14,27,28,45,46,59,61],set_fixmap:[19,62],set_fixmap_nocach:[19,62],set_page_dirti:[10,22,52,64],set_pt:[19,62],set_task_cpu:[27,59],set_thread_area:[19,62],setattr:[10,15,41,52],setattr_copi:[10,52],setattr_prepar:[10,52],setpagereserv:[17,49],setsockopt:36,setting_up_long_mod:38,setup:[0,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,21,24,25,27,29,32,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,62,63,65],setup_tim:[23,60],seven:31,sever:[4,7,9,10,12,14,15,18,21,23,24,38,41,42,43,45,46,47,51,52,53,60,65],sgi:[15,41],sha256:2,shadow:[0,21,22,27,59,64,65],shall:[22,64],shallow:[27,59],share:[0,4,5,7,8,9,10,12,14,15,16,17,18,19,22,23,27,28,31,38,39,41,42,43,44,45,46,47,49,50,51,52,59,60,61,62,64],sheet:[23,60],shell:[2,4,15,18,41,42,43],shift:[12,17,47,49],ship:[24,53],shmem:[22,64],shortcut:[13,41],should:[0,1,4,5,6,7,8,10,12,14,15,16,17,18,19,23,24,27,28,29,30,31,32,33,34,35,36,38,39,41,42,43,44,45,46,47,48,49,50,52,53,57,58,59,60,61,62],show:[2,3,6,7,8,9,12,13,14,15,16,17,18,19,21,22,23,27,38,41,42,44,45,46,47,48,49,51,59,60,62,64,65],show_opt:[9,51],showkei:[12,47],shown:[4,8,10,12,13,14,15,18,21,30,33,41,42,43,45,47,52,57,65],shut:[7,14,45,46],shutdown:[8,36],si_addr:[16,44],si_cod:[16,44],si_kernel:[16,44],si_signo:[16,44],sibl:[28,61],side:[1,22,28,61,64],sifiv:[30,57],sifive_uart:[30,57],sifive_uart_cr:[30,57],sifive_uart_div:[30,57],sifive_uart_get_rxcnt:[30,57],sifive_uart_get_txcnt:[30,57],sifive_uart_i:[30,57],sifive_uart_ie_rxwm:[30,57],sifive_uart_ie_txwm:[30,57],sifive_uart_ip:[30,57],sifive_uart_ip_rxwm:[30,57],sifive_uart_ip_txwm:[30,57],sifive_uart_max:[30,57],sifive_uart_rxctrl:[30,57],sifive_uart_rxfifo:[30,57],sifive_uart_txctrl:[30,57],sifive_uart_txfifo:[30,57],sifiveuartst:[30,57],sign:31,signal:[7,16,23,27,28,30,35,44,46,57,59,60,61],signal_pending_st:[27,59],signatur:[7,12,17,24,46,47,49,53],signifi:[10,52],signific:[6,12,14,16,18,19,24,28,42,44,45,47,48,53,61,62],significantli:[15,24,29,41,53,58],sigsegv:[16,44],silent:[9,39,51],similar:[6,7,8,9,10,12,13,14,15,18,21,23,28,29,35,39,41,42,45,46,47,48,51,52,58,60,61,65],similarli:[7,9,13,15,41,46,51],simpl:[0,5,6,7,8,9,10,13,14,15,16,17,21,22,24,25,28,31,36,37,38,41,44,45,46,48,49,50,51,52,53,61,63,64,65],simple_:[10,52],simple_device_id:[4,43],simple_dir_inode_oper:[9,51],simple_dir_oper:[9,10,51,52],simple_driv:[4,43],simple_lookup:[10,52],simple_statf:[9,51],simpler:[13,15,22,27,28,41,59,61,64],simplest:[1,3,5,29,50,58],simpli:[2,3,9,13,14,24,41,45,51,53],simplic:[12,37,47],simplifi:[4,5,7,8,9,22,23,24,27,29,32,33,34,35,36,37,38,43,46,50,51,53,58,59,60,64],simplist:[15,41],simqueu:38,simqueue_t:38,simul:[6,7,15,46,48],simultan:[24,28,53,61],simvirtio:38,sin_addr:[18,42],sin_famili:[18,42],sin_port:[18,42],sinc:[1,5,6,8,9,12,13,14,15,16,17,18,19,21,22,23,24,25,27,28,29,33,35,38,41,42,44,45,47,48,49,50,51,53,58,59,60,61,62,63,64,65],sincronizar:53,singl:[4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,25,27,28,30,35,37,41,42,43,44,45,46,47,48,49,50,51,52,57,59,61,62,63],single_open:[17,49],singular:[19,62],sis:[22,64],sistem:[37,53],sit0:2,sit:[2,7,46],site:[13,37,39,41],situat:[8,12,13,14,15,18,28,39,41,42,45,47,61],size:[4,5,7,9,10,12,13,14,16,17,18,19,21,22,24,25,27,28,29,30,31,33,35,37,38,41,42,43,44,45,46,47,49,50,51,52,53,57,58,59,61,62,63,64,65],size_t:[5,7,8,10,17,18,31,42,46,49,50,52],sizeof:[7,9,14,18,21,22,26,29,30,42,45,46,51,54,57,58,64,65],sk_:[18,42],sk_alloc:[18,42],sk_backlog_rcv:[18,42],sk_buff:[0,36],sk_buff_data_t:[18,26,42,54],sk_can_reus:[18,42],sk_data_readi:[18,42],sk_destruct:[18,42],sk_error_report:[18,42],sk_no_check_rx:[18,42],sk_no_check_tx:[18,42],sk_pad:[18,42],sk_prot:[18,42],sk_protocol:[18,42],sk_reus:[18,42],sk_send_head:[18,42],sk_socket:[18,42],sk_state_chang:[18,42],sk_type:[18,42],sk_userlock:[18,42],sk_write_spac:[18,42],skb:[0,18,42],skb_clone:[18,42],skb_mac_head:[26,54],skb_mac_header_was_set:[26,54],skb_mstamp:[18,42],skb_network_head:[26,54],skb_pull:[26,54],skb_push:[26,54],skb_put:[26,54],skb_reserv:[26,54],skb_reset_mac_head:[26,54],skb_reset_network_head:[26,54],skb_reset_transport_head:[26,54],skb_set_mac_head:[26,54],skb_set_network_head:[26,54],skb_set_transport_head:[26,54],skb_transport_head:[26,54],skb_trim:[26,54],skbuff:[18,42],skel:[4,5,6,7,8,9,10,11,12,14,15,16,17,18,21,37,41,42,43,44,45,46,47,48,49,50,51,52,65],skeleton:[0,1,4,5,6,7,8,9,10,11,12,14,15,16,17,18,32,33,34,35,36,39,41,42,43,44,45,46,47,48,49,50,51,52],skelton:11,skill:[5,13,16,18,35,36,39,41,42,44,50],skip:[5,50],skthread:[6,48],slab:[0,10,14,25,45,52,63],slab_alloc:13,slash:[13,41],sleep:[0,3,5,7,16,17,18,23,27,28,42,44,46,49,50,59,60,61],slice:[14,24,27,45,53,59],slide:[13,19,20,21,22,23,24,25,26,27,28,29,30,39,41,53,54,55,56,57,58,59,60,61,62,63,64,65],slightli:[18,22,42,64],slot:[10,37,39,52],slow:[7,15,16,28,41,44,46,61],slowdown:[16,44],slower:[3,12,21,47,65],slowest:[16,44],slub:[21,65],slub_debug:0,smack:[24,53],small:[0,6,7,8,19,24,26,27,28,38,46,48,53,54,59,61,62],smaller:[7,10,15,24,25,26,41,46,52,53,54,63],smallest:[5,50],smap:[29,58],smbf:[9,51],smp:[0,2,14,19,21,27,28,45,59,61,62,65],smp_apic_timer_interrupt:[21,65],smp_mb:[27,28,59,61],smp_processor_id:[19,62],smp_rmb:[28,61],smp_wmb:[28,61],snif:[28,61],snippet:[5,12,18,19,27,38,42,47,50,59,62],snoop:[28,61],snprintf:[5,8,50],so2:[0,2,3,4,8,9,13,16,27,31,37,40],so2_cdev:[7,46],so2_cdev_test:[7,46],so2_dev:[7,46],so2_device_data:[7,46],so2_oops_exit:[21,65],so2_oops_init:[21,65],so2_panic_init:[21,65],soc:[4,30,43,57],sock1:[18,42],sock2:[18,42],sock:[0,26,54],sock_:[18,42],sock_cloexec:[18,42],sock_creat:[18,42],sock_create_kern:[18,42],sock_create_lit:[18,42],sock_dgram:[18,26,42,54],sock_init_data:[18,42],sock_map_fd:[18,42],sock_max:[18,42],sock_no_:36,sock_no_accept:36,sock_no_getnam:36,sock_no_getsockopt:36,sock_no_ioctl:36,sock_no_listen:36,sock_no_mmap:36,sock_no_sendpag:36,sock_no_setsockopt:36,sock_no_shutdown:36,sock_no_socketpair:36,sock_nonblock:[18,42],sock_nospac:[18,42],sock_recvmsg:[18,42],sock_regist:[18,42],sock_releas:[18,42],sock_sendmsg:[18,42],sock_stream:[18,42],sock_type_mask:[18,42],sock_unregist:[18,42],sockaddr:[18,26,42,54],sockaddr_in:[18,26,42,54],sockaddr_len:[18,42],sockaddr_storag:[18,42],sockaddr_stp:36,socket:[0,3,24,27,36,53,59],socket_st:[18,42],socket_wq:[18,42],socketpair:[18,36,42],sockf:[9,51],sockfd_lookup_light:[18,42],sofirq:[6,48],sofitrq:[6,48],soft:0,softirq:[0,19,21,23,28,60,61,62,65],softirq_bit:[28,61],softirq_mask:[28,61],softirq_offset:[28,61],softmmu:[4,43],softwar:[0,2,4,8,16,21,24,39,40,43,44,53,65],sole:39,solut:[5,10,14,16,23,25,28,30,35,39,44,45,50,52,57,60,61,63],solv:[0,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,29,39,41,42,43,44,45,46,47,48,49,50,51,52,58],some:[1,2,5,6,7,8,9,10,12,13,14,15,16,17,18,19,20,21,22,23,24,25,27,28,29,30,33,39,41,42,44,45,46,47,48,49,50,51,52,53,55,57,58,59,60,61,62,63,64,65],someon:[1,12,16,39,44,47],someth:[8,12,17,47,49],sometim:[7,13,22,23,24,25,27,41,46,53,59,60,63,64],soon:[6,7,28,46,48,61],sophist:[4,43],sort:[5,22,24,50,53,64],sound:[4,7,8,24,29,43,46,53,58],sourc:[0,1,4,5,6,7,8,9,10,11,12,14,15,16,17,18,20,23,26,27,31,33,34,35,36,37,39,42,43,44,45,46,47,48,49,50,51,52,54,55,59,60],sourceforg:[13,41],sourceweb:0,space:[0,4,5,6,8,12,13,14,15,16,17,20,21,22,25,27,34,35,38,40,41,43,44,45,47,48,49,50,55,59,63,64,65],span:[22,25,63,64],sparc:[24,53],spars:[21,32,33,34,35,36,37,38,65],spdx:31,special:[5,6,7,9,10,12,14,15,18,19,21,22,23,24,25,26,27,28,29,30,34,37,39,41,42,45,46,47,48,50,51,52,53,54,57,58,59,60,61,62,63,64,65],specif:[0,5,6,7,8,9,10,11,12,13,14,15,16,18,24,25,26,27,28,29,33,34,36,39,41,42,44,45,46,47,48,50,51,52,53,54,58,59,61,63],specifi:[5,6,7,8,9,10,12,13,14,15,16,18,19,22,34,36,39,41,42,44,45,46,47,48,50,51,52,62,64],specul:[27,59],speed:[5,7,15,16,18,19,41,42,44,46,50,62],spelunk:0,spend:[16,23,44,60],spent:[16,28,44,61],spi:[4,12,43,47],spike:[16,44],spin:[0,14,24,45,53],spin_lock:[6,12,14,21,28,45,47,48,61,65],spin_lock_bh:[6,28,48,61],spin_lock_init:[12,14,45,47],spin_lock_irq:[12,47],spin_lock_irqrestor:[28,61],spin_lock_irqsav:[12,27,28,47,59,61],spin_lock_restor:[28,61],spin_unlock:[6,12,14,21,27,28,45,47,48,59,61,65],spin_unlock_bh:[6,28,48,61],spin_unlock_irq:[12,47],spin_unlock_irqrestor:[12,27,47,59],spinlock:[0,6,12,27,47,48,59],spinlock_t:[5,6,12,13,14,22,45,47,48,50,64],split:[0,5,13,19,24,25,26,27,28,38,41,50,53,54,59,61,62,63],spot:39,spread:[9,51],sprintf:8,sram:[4,43],src:[1,2,10,11,13,15,21,26,28,33,34,35,36,41,52,54,61,65],ss_connect:[18,42],sscanf:8,ssd:[22,64],ssh:[0,7,11,16,18,42,44,46],sshd:[16,44],ssignment:31,ssize_t:[7,8,22,31,46,64],ssr:35,ssr_first_minor:35,ssr_major:35,stabil:[27,59],stabl:[15,41],stac:[27,59],stack:[0,9,14,15,16,17,18,19,21,22,26,27,29,35,36,38,42,44,45,49,51,54,58,59,62,64,65],stack_canari:[19,27,59,62],stack_canary_offset:[27,59],stackexchang:39,stacktrac:15,stage:[0,11,15,41],stand:[13,14,41,45],standard:[3,4,5,6,7,8,12,14,15,18,21,24,34,36,41,42,43,45,46,47,48,50,53,65],start:[0,1,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,21,22,23,24,26,27,28,32,33,34,35,36,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,54,59,60,61,62,64,65],start_kernel:[2,21,65],startup:[5,8,50],startup_32_smp:[2,21,65],starv:[16,44],starvat:[23,60],stash:[4,5,6,7,8,9,10,12,14,15,16,17,18,41,42,43,44,45,46,47,48,49,50,51,52],stat:[9,12,16,25,27,44,47,51,59,63],state:[0,2,5,6,7,8,12,13,14,15,18,21,22,24,25,28,29,30,39,41,42,45,46,47,48,50,53,57,58,61,63,64,65],state_add_uevent_s:8,state_in_sysf:8,state_initi:8,state_remove_uevent_s:8,statement:[0,23,27,29,39,58,59,60],statf:[9,22,51,64],station:[15,41],statist:[0,9,16,22,28,36,44,51,61,64],statm:[27,59],statu:[1,4,5,6,7,8,9,10,12,13,14,15,16,17,18,21,24,25,27,38,41,42,43,44,45,46,47,48,49,50,51,52,53,59,63,65],status_reg:[12,47],stdout:38,stduent:[13,41],stefan:[30,57],step:[1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,21,22,28,38,41,42,43,44,45,46,47,48,49,50,51,52,61,64,65],sti:[2,23,28,60,61],still:[1,3,5,7,12,13,16,23,24,27,28,44,46,47,50,53,59,60,61],stone:[24,53],stop:[2,4,5,6,7,8,9,10,12,14,15,16,17,18,21,41,42,43,44,45,46,47,48,49,50,51,52,65],storag:[4,5,18,19,22,42,43,50,62,64],store:[0,4,5,7,8,9,10,13,14,15,17,18,19,22,23,25,27,28,29,30,32,33,34,35,36,37,38,41,42,43,45,46,49,50,51,52,57,58,59,60,61,62,63,64],stp:36,stp_bind:36,stp_connect:36,stp_header:36,stp_op:36,stp_proc_full_filenam:36,stp_recvmsg:36,stp_releas:36,stp_sendmsg:36,stp_stat:36,str:[15,41],strace:[16,44],straight:[24,53],strap:0,strategi:[28,61],strcat:[14,45],strchr:[14,45],strcmp:[10,14,45,52],strcpy:[14,45],stream:[16,29,44,58],strength:[16,44],strex:[28,61],strict:[24,53],stricter:[15,41],strictli:[3,15,41],string:[0,4,8,9,10,12,13,15,18,24,27,32,37,41,42,43,47,51,52,53,59],string_len:[14,45],strip:[4,43],strlcat:[14,45],strlcpy:[14,45],strlen:[8,14,45],strncat:[14,45],strnchr:[14,45],strncmp:[8,14,45],strncpy:[14,45],strnicmp:[14,45],strongli:[4,5,6,7,8,9,10,12,14,15,16,17,18,41,42,43,44,45,46,47,48,49,50,51,52],strrchr:[14,45],strstr:[14,45],struc:[13,41],struct:[0,6,8,10,12,13,14,15,19,20,21,22,24,25,28,29,31,33,35,36,37,38,41,45,47,48,52,53,55,58,61,62,63,64,65],structur:[0,4,6,12,13,14,15,22,23,24,25,27,28,31,33,35,36,37,41,43,45,47,48,53,59,60,61,63,64],structura:53,structurii:53,struggl:1,stub:36,student:[0,1,9,10,13,15,36,38,39,41,51,52],studi:[13,16,41,44],stutter:[16,44],style:[0,24,32,33,34,35,36,37,38,53],sub:[0,21,24,53,65],sub_preempt_count:[28,61],subcommand:[16,44],subdirectori:[8,9,10,13,51,52],subgroup:39,subiect:53,subject:[16,44],submiss:[5,32,33,34,35,36,39,50],submit:[0,24,53],submit_bio:[5,35,50],submit_bio_wait:[5,35,50],subnet:[26,54],subsequ:[1,3,6,10,25,28,48,52,61,63],subsys_priv:8,subsystem:[5,6,7,8,9,10,13,15,17,18,22,23,24,25,33,35,36,41,42,46,48,49,50,51,52,53,60,63,64],subtask:38,subtract:39,subtre:[9,51],succ:53,succe:[28,61],success:[4,7,8,9,12,14,18,27,28,29,42,43,45,46,47,51,58,59,61],successfulli:[5,7,8,9,13,46,50,51],sudo:[3,4,13,32,33,34,35,36,37,38,43],suffic:[6,48],suffici:[6,9,13,17,28,41,48,49,51,61],suffix:[15,41],sugestii:53,suggest:[16,24,44,53],suit:[16,28,37,44,61],suitabl:[8,9,21,51,65],sum:[16,27,39,44,59],sum_of_assignment_scor:39,summar:[23,60],summari:[0,13,14,18,19,21,22,27,29,41,42,45,58,59,62,64,65],summer:39,sun:[24,53],sunrpc:[15,41],super_block:[0,10,52],super_oper:[9,10,51,52],superblock:[0,10,24,37,52,53],superh:[24,53],superior:[5,24,50,53],supermodul:[15,41],superoper:0,supervisor:[19,62],suport:53,suportului:53,support:[0,3,5,7,8,9,10,12,13,14,15,16,17,18,19,20,21,22,23,24,27,28,30,32,34,35,36,37,39,41,42,44,45,46,47,49,50,51,52,53,55,57,59,60,61,62,64,65],sure:[1,2,4,5,6,7,8,9,10,12,14,15,16,17,18,23,27,28,29,35,36,37,38,41,42,43,44,45,46,47,48,49,50,51,52,58,59,60,61],survei:51,surveil:33,suspect:[21,65],suspend:[6,8,13,14,16,23,44,45,48,60],svc_tcp_accept:[15,41],svcsock:[15,41],svm:[30,57],swap:[14,17,24,25,29,45,49,53,58,63],swap_activ:[22,64],swap_deactiv:[22,64],swap_info_struct:[22,64],swapfil:[22,64],swapper:[6,21,48,65],swiss:[18,42],switch_context:[20,55],switch_mm:[27,59],switch_mm_irqs_off:[27,59],switch_to:[27,59],sym:[29,58],sym_code_end:[27,59],sym_code_start:[27,59],symbol:[0,2,3,5,6,7,8,12,13,14,15,16,22,27,29,33,37,41,44,45,46,47,48,50,58,59,64],symbol_nam:[13,41],symlink:[10,13,22,52,64],symmetr:[0,40],symver:[15,41],syn:[18,42],sync:[0,14,21,27,45,59,65],synchron:[0,5,6,12,23,24,27,33,34,35,47,48,50,53,59,60],synchronize_rcu:[28,61],syntax:[6,13,14,45,48],synthes:[16,44],sys:[4,5,8,12,15,16,21,41,43,44,47,50,65],sys_accept4:[18,42],sys_access:13,sys_bind:[18,42],sys_call_ptr_t:[29,58],sys_call_t:[13,41],sys_clos:[29,58],sys_exit:[29,58],sys_fd:38,sys_fork:[13,29,41,58],sys_getpeernam:[18,42],sys_init_modul:[15,21,41,65],sys_listen:[18,42],sys_membarri:[27,59],sys_ni_syscal:[29,58],sys_open:[29,58],sys_read:[29,58],sys_restart_syscal:[13,29,41,58],sys_send:[18,42],sys_sendto:[18,42],sys_socket:[18,42],sys_writ:[29,58],syscal:[23,29,58,60],syscall_cal:[21,65],syscall_define3:[18,42],syscall_define6:[18,42],syscall_return_slowpath:[29,58],syscalls_32:[29,58],sysent:[29,58],sysenter_do_cal:[15,41],sysf:[0,5,9,15,24,41,50,51,53],sysfs_dir:8,syslog:[15,41],syslogd:[15,27,41,59],sysret:[19,62],sysrq:[15,41],system:[0,3,5,6,7,8,12,13,14,15,16,17,18,21,30,31,33,35,36,37,39,41,42,44,45,46,47,48,49,50,57,65],sysv:[4,43],sysvinit:[17,49],tab:[2,27,59],tabel:53,tabl:[0,8,9,10,12,16,17,20,22,25,27,33,34,36,44,47,49,51,52,55,59,63,64],tablet:39,tag:[0,30,57],tag_list:[5,50],tag_set:[5,50],tail:[15,18,26,38,41,42,54],tailor:[24,53],taint:[12,15,21,41,47,65],take:[1,2,3,5,6,7,8,9,10,12,13,14,15,16,17,18,21,22,24,26,27,28,30,32,39,41,42,44,45,46,47,48,49,50,51,52,53,54,57,59,61,64,65],taken:[6,9,12,14,33,45,47,48,51],tap0:3,tap1:3,tap:3,tape:[7,46],target:[2,4,11,13,15,22,23,30,41,43,53,57,60,64],task:[0,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,21,23,28,29,31,41,42,43,44,45,46,47,48,49,50,51,52,58,60,61,62,65],task_addr_limit:[29,58],task_dead:[6,48],task_info:[14,45],task_info_add_for_curr:[14,45],task_info_add_to_list:[14,45],task_info_find_pid:[14,45],task_info_purge_list:[14,45],task_info_remove_expir:[14,45],task_interrupt:[6,7,27,46,48,59],task_list:[27,59],task_nam:[4,5,6,7,8,9,10,12,14,15,16,17,18,41,42,43,44,45,46,47,48,49,50,51,52],task_norm:[27,59],task_ptr_typ:[27,59],task_readi:[27,59],task_rq:[27,59],task_run:[7,27,28,46,59,61],task_stack_canari:[27,59],task_struct:[0,6,13,14,15,17,24,25,28,41,45,48,49,53,61,63],task_threadsp:[27,59],task_typ:[27,59],task_uinterrupt:[27,59],task_uninterrupt:[7,27,46,59],tasklet:[0,19,28,61,62],tasklet_dis:[6,23,48,60],tasklet_en:[6,23,48,60],tasklet_hi_schedul:[6,48],tasklet_init:[6,23,48,60],tasklet_schedul:[6,23,48,60],tasklet_sofitirq:[23,60],tasklet_softirq:[6,23,48,60],tasklet_struct:[6,48],tavi:[2,11,21,26,27,53,54,59,65],tcg:[30,57],tcp:[0,26,54],tcp_hdr:[18,42],tcp_sock:[18,42],tcp_tsorted_anchor:[18,42],tcpdump:0,tcph:[18,42],tcphdr:[18,42],teach:[1,51],team:[0,1,16,32,33,34,35,36,38,39,44],teamwork:39,techniqu:[0,12,13,21,25,28,41,47,61,63,65],technolog:[8,27,59],tell:[10,15,41,52],tema2:31,tema:53,teme:[0,36],temel:53,temelor:0,templat:[1,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,37,41,42,43,44,45,46,47,48,49,50,51,52],temporari:[0,14,23,45,60],temporarili:[23,60],tempt:[29,58],teo:53,teodora:53,teodorescu:53,term:[0,7,8,23,28,30,46,57,60,61],termin:[6,9,15,25,41,48,51,63],terminolog:[0,18,42],ters:[32,33,34,35,36,37,38],test2:8,test:[0,4,5,6,7,8,11,12,13,15,16,17,18,21,24,28,38,39,41,42,43,44,46,47,48,49,50,53,61,65],test_addr:[18,42],test_and_change_bit:[9,14,28,45,51,61],test_and_clear_bit:[9,10,14,28,45,51,52,61],test_and_set_bit:[9,10,14,28,45,51,52,61],test_bit:[28,61],test_daddr:[18,42],test_kasan:[21,65],test_pan:[21,65],testar:53,testului:53,texa:[4,43],text:[13,15,27,29,41,58,59],tgid:[27,59],than:[2,5,7,9,10,12,13,14,15,18,19,21,23,24,25,28,29,32,33,34,35,36,37,38,41,42,45,46,47,50,51,52,53,58,60,61,62,63,65],thei:[0,1,5,6,7,8,9,10,11,12,14,15,17,18,19,22,23,24,25,27,28,29,30,36,39,41,42,45,46,47,48,49,50,51,52,53,57,58,59,60,61,62,63,64],them:[1,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,22,23,24,25,27,28,29,36,37,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,64],themselv:[6,23,48,60],theoret:0,therefor:[5,6,9,12,14,15,18,41,42,45,47,48,50,51],thermal:[23,60],thi:[0,1,2,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,21,22,23,24,25,26,27,28,29,30,31,33,34,36,37,38,39,42,43,44,45,46,47,48,49,50,51,52,53,54,57,58,59,60,61,62,63,64,65],thing:[4,8,9,12,14,16,18,21,22,24,38,42,43,44,45,47,51,53,64,65],think:[16,44],third:[9,12,17,39,47,49,51],this_modul:[5,7,8,9,31,36,46,50,51],thoroughli:[29,58],those:[6,8,9,10,12,15,17,18,19,23,24,27,39,41,42,47,48,49,51,52,53,59,60,62],though:[10,15,19,41,52,62],thought:[16,44],thousand:[24,28,53,61],thp:[22,64],thrash:[28,61],thread:[0,7,9,12,13,14,15,19,21,23,24,28,35,41,45,46,47,51,53,60,61,62,65],thread_a:[21,65],thread_b:[21,65],thread_fn:[12,47],thread_group:[27,59],thread_info:[20,27,55,59],thread_siz:[27,59],thread_struct:[27,59],threadfn:[6,48],three:[6,7,12,18,19,22,23,28,38,42,46,47,48,60,61,62,64],through:[0,5,7,8,12,13,15,16,17,18,19,24,26,27,30,31,32,36,38,39,41,42,44,46,47,49,50,53,54,57,59,62],throughput:[24,28,53,61],thu:[5,6,7,8,12,13,14,15,18,19,22,23,27,28,33,41,42,45,46,47,48,50,59,60,61,62,64],thursdai:35,tick:[6,13,14,20,27,45,48,55,59],ticket:[28,61],time:[0,1,2,4,5,6,7,8,9,10,12,13,14,15,17,18,19,21,22,23,24,25,27,28,29,30,34,35,37,39,41,42,43,45,46,47,48,49,50,51,52,53,57,58,59,60,61,62,63,64,65],timechart:[16,44],timeout:[6,7,27,46,48,59],timer:[0,4,12,20,21,27,28,30,43,47,55,57,59,61,65],timer_funct:[6,48],timer_list:[6,21,48,65],timer_setup:[6,21,48,65],timer_softirq:[6,23,48,60],timer_timeout:[6,48],timer_type_acct:[6,48],timer_type_alloc:[6,48],timer_type_non:[6,48],timer_type_set:[6,48],timerfn:[21,65],timerlist:[27,59],timestamp:[14,45],tini:[30,57],tip:0,tire:[15,41],tlb:[19,20,21,25,30,53,55,57,62,63,65],tldp:34,tldr:0,tls:[13,41],tmp:[3,11,14,45],to_bex_devic:8,to_my_driv:8,todo1:11,todo2:11,todo:[4,5,6,7,8,9,10,11,12,14,15,16,17,18,31,32,39,41,42,43,44,45,46,47,48,49,50,51,52],togeth:[4,5,10,16,19,22,24,27,28,37,39,43,44,50,52,53,59,61,62,64],tomoyo:[24,53],too:[12,15,16,18,19,23,36,39,41,42,44,47,60,62],tool:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,18,24,27,32,33,34,35,36,37,38,41,42,43,45,46,47,48,49,50,51,52,53,59],toolchain:0,top:[0,1,4,5,6,23,24,26,27,31,32,43,48,50,53,54,59,60],topic:[0,11,19,32,33,34,35,36,39,62],torvald:[24,53],tos:[18,42],tot_len:[18,42],total:[5,9,10,12,14,16,17,22,33,39,44,45,47,49,50,51,52,64],touch:[3,9,10,51,52],toward:[24,29,53,58],trace:[0,14,15,16,21,24,44,45,53,65],trace_hardirqs_off_thunk:[21,65],trace_hardirqs_on_cal:[15,21,41,65],trace_hardirqs_on_thunk:[15,41],tracepoint:[16,21,44,65],tracer:[0,39,40,53],tracer_add_process:33,tracer_remove_process:33,track:[13,20,21,25,28,29,31,34,36,37,55,58,61,63,65],trade:[15,41],tradit:[7,46],tradition:[7,46],traffic:[18,28,42,61],transact:[28,61],transfer:[5,7,12,16,18,19,23,27,29,34,39,42,44,46,47,50,58,59,60,62],transform:[19,24,30,53,57,62],transit:[20,27,28,29,30,39,55,57,58,59,61],translat:[0,10,12,17,21,22,30,38,47,49,52,57,64,65],transmiss:[18,34,42],transmit:[5,6,7,12,14,15,18,30,32,34,41,42,45,46,47,48,50,57],transpar:[18,42],transport:[0,18,26,39,40,42,53,54],transport_head:[18,26,42,54],trap:[23,29,30,57,58,60],trap_pf:[15,41],trapnr:[29,58],travers:[5,28,50,61],treat:[8,9,51],treatment:[6,48],tree:[0,9,10,12,13,15,18,20,21,22,24,25,27,28,32,33,34,35,36,37,38,41,42,47,51,52,53,55,59,61,63,64,65],tri:[8,13,19,21,27,28,41,59,61,62,65],trick:[12,47],tricki:[12,29,47,58],trigger:[15,16,21,22,23,28,29,30,38,41,44,57,58,60,61,64,65],troubleshoot:[13,15,36,39,41],truesiz:[18,26,42,54],truli:[28,61],truncat:[10,37,52],truncate_inode_pag:[10,52],truncate_pagecach:[10,52],truncate_sets:[10,52],try_to_wake_up:[27,59],trylock:[14,45],tss:[19,62],tstamp:[18,26,42,54],ttl:[18,42],ttwu_queu:[27,59],ttwu_runn:[27,59],tty:[6,7,16,24,44,46,48,53],ttymxc0:[4,43],ttys0:[7,15,41,46],ttys1:[7,46],ttyusb0:[15,41],ttyusb:[15,41],ttzuiv5k:2,tuesdai:[37,38],tunabl:[16,44],tune:0,ture:[13,41],turn:[5,6,15,28,39,41,48,50,61],tutori:[9,10,18,42,51,52,53],tux:[18,42],twice:[10,12,28,47,52,61],two:[0,4,5,6,7,8,9,12,13,14,15,16,17,18,19,21,22,23,24,25,27,28,29,30,32,33,34,35,36,37,38,39,41,42,43,44,45,46,47,48,49,50,51,53,57,58,59,60,61,62,63,64,65],txcnt:[30,57],txctrl:[30,57],txpkt:36,txt:[5,6,7,9,10,15,33,41,46,48,50,51,52],type:[0,2,4,5,6,7,9,10,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,35,36,37,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,58,59,60,61,62,63,64,65],type_show:8,type_sifive_uart:[30,57],typedef:[7,12,18,38,42,46,47],typic:[0,2,4,5,6,8,9,12,14,18,19,20,22,23,25,27,28,30,42,43,45,47,48,50,51,55,57,59,60,61,62,63,64],typo:1,u16:[18,38,42],u32:[18,38,42],u500:[30,57],u64:[18,42],u_int8_t:[18,42],uaccess:[7,46],uapi:[14,18,42,45],uart16550:[31,34],uart16550_dev:31,uart16550_exit:31,uart16550_fop:31,uart16550_init:31,uart16550_interrupt:31,uart16550_ioctl:31,uart16550_ioctl_set_lin:34,uart16550_open:31,uart16550_read:31,uart16550_releas:31,uart16550_writ:31,uart:[0,4,12,30,39,40,43,47,57],uart_be_chang:[30,57],uart_can_rx:[30,57],uart_ev:[30,57],uart_ip:[30,57],uart_op:[30,57],uart_read:[30,57],uart_rx:[30,57],uart_writ:[30,57],ubuntu:[2,3,21,27,59,65],udev:[4,7,8,43,46],udevadm:8,udevinfo:8,udevmonitor:8,udevtest:8,udf:[9,51],udp:[0,36],udp_hdr:[18,42],udp_sock:[18,42],udph:[18,42],udphdr:[18,42],uevent:0,uevent_suppress:8,uid:[9,10,27,37,51,52,59],uid_t:37,uint16_t:38,uint32_t:[30,38,57],uint64_t:[23,30,38,57,60],uint8_t:[30,38,57],ultim:[15,41],ultrasparc:[24,53],umount:[3,9,10,51,52],unabl:[5,12,15,21,41,47,50,65],unalloc:[7,37,46],unalt:[7,46],unam:[2,15,41],unavoid:[27,59],unblock:[7,46],uncertainti:39,uncom:[14,16,44,45],uncompress:[13,41],undefin:[12,19,47,62],under:[4,5,8,13,16,19,24,30,35,41,43,44,50,53,57,62],underflow:[19,27,59,62],underli:[5,50],understand:[4,6,7,9,10,12,13,15,16,17,18,19,28,31,35,36,38,39,41,42,43,44,46,47,48,49,51,52,53,61,62],understood:[15,41],undesir:[23,60],unexpect:[28,61],unfortun:[22,64],unhandl:39,unicast:[26,54],unidirect:[28,61],unifi:[8,14,24,28,45,53,61],uniform:[0,12,47],unikraft:[16,44],uniniti:[15,21,41,65],union:[18,42],uniqu:[5,7,9,10,12,22,46,47,50,51,52,64],unit:[4,5,6,13,17,19,24,27,41,43,48,49,50,53,59,62],univers:0,unix:[7,9,10,14,17,22,24,45,46,49,51,52,53,64],unknown:[10,15,41,52],unless:[10,15,19,27,41,52,59,62],unlik:[8,9,10,14,15,18,19,21,22,41,42,45,51,52,62,64,65],unlink:[10,22,37,52,64],unload:[0,4,5,6,7,8,9,10,12,14,21,32,43,45,46,47,48,50,51,52,65],unlock:[7,14,18,27,28,33,42,45,46,59,61],unlock_buff:[22,64],unlock_new_inod:[10,52],unlocked_ioctl:[7,31,46],unmap:[5,21,29,50,58,65],unmask:[23,60],unmount:[0,5,22,50,64],unnecessari:[28,61],unplan:[6,48],unpredict:[14,45],unreach:[26,54],unreferenc:[21,65],unregist:[0,5,8,12,18,42,47,50],unregister_blkdev:[5,50],unregister_chrdev_region:[7,46],unregister_filesystem:[9,51],unregistr:[0,8],unrel:[14,39,45],unreli:[6,48],unsaf:[21,65],unshar:[24,53],unsign:[5,6,7,8,9,10,12,14,17,18,19,22,26,27,28,29,30,31,37,38,42,45,46,47,48,49,50,51,52,54,57,58,59,61,62,64],unstrip:[13,41],until:[7,10,12,14,15,16,18,22,23,25,27,28,34,39,41,42,44,45,46,47,52,59,60,61,63,64],unui:53,unus:[10,12,14,19,21,22,36,37,45,47,52,62,64,65],up_prob:33,up_probe_handl:33,upb:[16,44],updat:[0,1,2,3,5,7,10,11,12,14,15,19,22,25,27,29,30,45,46,47,50,52,57,58,59,62,63,64],update_irq:[30,57],upload:39,upon:[5,8,21,50,65],upper:[5,23,50,60],uppercas:34,uprob:[16,21,44,65],ups:[27,59],upstream:[24,53],urandom:[16,44],urg:[18,42],urg_ptr:[18,42],uri:53,usabl:13,usag:[6,10,13,14,15,16,18,21,23,28,34,41,42,44,45,48,52,60,61,65],usb:[4,8,15,24,41,43,53],usdhc:[4,43],use:[0,2,3,4,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,41,42,43,44,45,46,47,48,49,51,52,53,54,55,57,58,59,60,61,62,63,64,65],use_after_fre:[21,65],use_after_free2:[21,65],use_before_init:[21,65],use_bio_transf:[5,50],use_pool:38,used:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,21,22,23,24,25,26,27,28,29,30,33,36,37,38,39,41,42,43,44,45,46,47,48,50,51,52,53,54,55,57,58,59,60,61,62,63,64,65],useful:[0,5,10,12,13,14,15,16,18,21,28,30,35,37,41,42,44,45,47,50,52,57,61,65],usefulli:[19,62],user:[0,5,6,7,8,9,10,12,13,14,15,16,17,19,20,21,22,23,25,26,27,28,34,35,38,41,44,45,46,47,48,49,50,51,52,54,55,59,60,61,62,63,64,65],user_buff:[7,31,46],user_parameter_valid:[14,45],user_ptr:[29,58],usermod:8,usernam:13,userpac:[12,47],userspac:[0,5,6,8,22,25,27,48,50,59,63,64],uses:[3,5,6,7,8,10,12,13,14,15,17,18,19,21,22,23,24,25,26,27,28,29,30,35,37,41,42,45,46,47,48,49,50,52,53,54,57,58,59,60,61,62,63,64,65],using:[0,1,2,3,4,5,7,8,9,10,11,12,14,15,16,17,18,19,21,23,24,25,27,28,29,30,32,33,34,35,36,37,38,39,41,42,43,44,45,46,47,49,50,51,52,53,57,58,59,60,61,62,63,65],usr:[4,13,15,24,41,43,53],usual:[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,23,24,28,41,42,43,44,45,46,47,48,49,50,51,52,53,60,61,62],util:[5,6,8,9,10,13,15,27,36,41,48,50,51,52,53,59],v1_minix_iget:[9,10,51,52],vacat:[28,61],vaddr:[18,19,42,62],val64:[30,57],val:[7,12,46,47],valentin:53,valhalla:[9,51],vali:53,valid:[5,7,9,10,12,16,19,21,22,27,29,30,44,46,47,50,51,52,57,58,59,62,64,65],valid_lft:2,valu:[4,5,6,7,8,9,10,12,13,14,15,16,17,18,21,23,25,27,28,29,30,34,35,37,38,41,42,43,44,45,46,47,48,49,50,51,52,57,58,59,60,61,63,65],valuabl:[15,41],value1:[4,43],value2:[4,43],vanilla:13,vari:[5,50],variabl:[0,2,3,5,6,7,8,9,10,11,12,13,15,16,17,18,24,25,27,28,29,36,38,41,42,44,46,47,48,49,50,51,52,53,58,59,61,63],variant:[6,13,28,41,48,61],varieti:[20,55],variou:[4,5,6,7,8,9,15,18,19,22,24,28,34,36,41,42,43,46,48,50,51,53,61,62,64],vax:[24,53],vcpu:[30,38,57],vda:[3,13,16,44],vdb:[5,10,13,35,50,52],vdc:[13,35],vdd:[9,13,51],vdso:[0,17,27,49,59],vec:[5,18,42,50],vector:[5,9,18,23,25,30,37,42,50,51,57,60,63],vendor:[4,43],verbos:[3,13,41],veri:[6,8,9,10,13,14,15,16,18,19,22,24,28,38,41,42,44,45,48,51,52,53,61,62,64],verif:[5,9,10,17,39,49,50,51,52],verifi:[5,6,8,9,10,12,27,29,30,32,33,34,35,36,37,38,39,47,48,50,51,52,57,58,59],verify_redzone_fre:[21,65],versa:[7,9,17,46,49,51],version:[0,1,2,3,4,5,6,7,9,10,12,13,14,15,16,17,18,27,29,30,31,36,37,38,41,42,43,44,45,46,47,48,49,50,51,52,57,58,59],vfree:[5,15,19,41,50,62],vfs:[9,10,51,52],vfs_inod:[9,51],vfs_read:[7,46],vfs_write:[16,44],vga:[3,12,15,41,47],via:[0,3,6,7,8,12,15,17,18,23,24,26,28,30,33,35,36,38,41,42,46,47,48,49,53,54,57,60,61],vice:[7,9,17,46,49,51],video:[4,31,43],view:[4,6,7,8,9,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,32,41,42,43,44,45,46,48,49,51,53,54,55,56,57,58,59,60,61,62,63,64,65],vim:[1,13,15,41],vimrc:[13,41],violat:[28,61],virt:[24,38,53],virt_to_fix:[19,62],virt_to_pag:[17,49],virt_to_phi:[17,19,49,62],virtconsol:3,virtio:[3,5,9,13,30,38,50,51,57],virtio_crypto:3,virtiocon0:[3,15,41],virtual:[0,1,4,5,6,7,8,10,12,14,15,16,17,18,19,20,27,33,34,35,36,39,40,41,42,43,44,45,46,47,48,49,50,52,55,59,62],virtual_cpu:38,virtual_machin:38,virtualbox:[15,16,41,44],virtualizar:53,visibl:[8,14,15,16,24,27,30,41,44,45,53,57,59],visual:[16,44],vlan:[30,57],vm_area_struct:[0,13,15,25,63],vm_end:[17,49],vm_file:[17,49],vm_flag:[17,49],vm_next:[17,49],vm_op:[17,49],vm_operations_struct:13,vm_page_prot:[17,49],vm_pgoff:[17,49],vm_prev:[17,49],vm_share:[22,64],vm_start:[17,49],vm_struct:[17,25,49,63],vma:[15,17,21,41,49,65],vma_iter:[17,49],vmalloc:[5,13,17,19,24,25,49,50,53,62,63],vmalloc_area:[17,49],vmalloc_to_pag:[17,49],vmalloc_to_pfn:[17,49],vmc:[30,57],vmchecker:[13,32,33,34,35,36,37,39,53],vmexit:38,vmlinux:[2,4,13,21,27,41,43,59,65],vmlinux_symbol:[29,58],vmm:[0,30,57],vmmap:[17,49],vmware:[15,16,41,44],vmxnet:[12,47],volatil:[2,27,28,29,38,58,59,61],volum:[7,46],voluntari:[27,59],voluntarili:[6,39,48],vpcu:38,vpid:0,vscode:[13,41],vsyscal:[29,58],vsyscall_addr:[19,62],vsyscall_pag:[19,62],vsz:[16,44],vvar:[17,49],wai:[1,3,4,5,6,7,8,9,12,13,14,15,16,18,19,21,22,24,28,29,31,39,41,42,43,44,45,46,47,48,50,51,53,58,61,62,64,65],wait:[0,6,12,13,14,16,17,18,22,23,24,27,28,34,35,39,42,44,45,47,48,49,53,59,60,61,64],wait_ev:[6,7,27,46,48,59],wait_event_:[27,59],wait_event_interrupt:[7,46],wait_event_interruptible_timeout:[7,46],wait_event_timeout:[7,46],wait_list:[28,61],wait_lock:[28,61],wait_queue_entri:[27,59],wait_queue_entry_t:[27,59],wait_queue_head:[27,59],wait_queue_head_t:[7,46],waiter:[27,28,59,61],waitqueu:[27,28,59,61],waitqueue_walk_break_cnt:[27,59],wake:[0,7,9,28,46,51,61],wake_flag:[27,59],wake_q:[28,61],wake_q_add:[28,61],wake_up:[6,7,27,46,48,59],wake_up_interrupt:[7,46],wake_up_process:[6,48],wake_up_q:[28,61],wakeup:[27,59],walk:[0,19,62],wall:[15,41],want:[1,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,27,28,39,41,42,43,44,45,46,47,48,49,50,51,52,59,61],warn:[2,14,21,30,39,45,57,65],warn_on_onc:[19,27,59,62],warranti:[2,30,57],wast:[28,61],watch:[15,41],watchdog:[23,60],wb_err:[22,64],wbc:[9,10,22,51,52,64],wchan:[27,59],weak:[16,44],web:[13,18,41,42],websit:[13,41],wednesdai:39,week:[24,39,53],weekli:[24,53],wehrl:53,weight:39,weird:[16,44],weisz:53,welcom:1,well:[4,5,9,10,11,13,14,15,16,17,21,22,23,24,27,28,35,36,37,41,43,44,45,49,50,51,52,53,59,60,61,64,65],were:[5,6,7,12,15,16,19,21,22,27,39,41,44,46,47,48,50,59,62,64,65],weslei:53,wf_:[27,59],wf_sync:[27,59],wget:[13,36],what:[0,4,6,7,8,9,10,12,13,14,15,16,21,24,26,27,29,31,38,41,43,44,45,46,47,48,51,52,53,54,58,59,65],when:[2,3,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,21,22,23,24,27,28,29,30,33,35,36,37,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,57,58,59,60,61,62,64,65],whenc:[7,46],whenev:[14,17,27,45,49,59],where:[5,6,7,8,9,10,12,13,14,15,16,17,18,19,21,22,23,24,25,27,28,29,33,34,35,36,37,39,41,42,44,45,46,47,48,49,50,51,52,53,58,59,60,61,62,63,64,65],wherev:[9,51],whether:[12,14,16,21,29,39,44,45,47,58,65],which:[0,1,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,21,22,23,24,25,27,28,29,30,32,33,34,36,37,38,41,42,43,44,45,46,47,48,49,50,51,52,53,57,58,59,60,61,62,63,64,65],who:[7,39,46],whoever:[18,42],whole:[8,13,16,24,41,44,53],whom:39,whose:[6,9,10,12,13,14,15,24,28,39,41,45,47,48,51,52,53,61],why:[5,6,7,8,9,13,15,16,19,25,28,29,31,41,44,46,48,50,51,58,61,62,63],wide:[24,53],wight:[27,59],wiki:[9,37,38,51],wikibak:[9,51],wikibook:[13,41],win32:[19,62],window:[13,14,15,18,19,24,27,41,42,45,53,59,62],wine:[19,62],wish:[16,39,44],within:[5,6,7,8,9,10,13,14,15,17,18,37,39,41,42,45,46,48,49,50,51,52],without:[5,6,8,9,10,12,13,15,16,18,19,22,24,27,28,30,36,39,41,42,44,47,48,50,51,52,53,57,59,61,62,64],wmb:[28,61],woken:[7,16,23,27,44,46,59,60],won:[6,12,23,24,28,47,48,53,60,61],word:[2,12,13,18,29,41,42,47,58],work:[0,1,2,3,4,5,7,8,9,10,11,12,13,15,16,17,18,19,21,23,24,28,29,34,35,36,38,39,40,41,42,43,44,46,47,49,50,51,52,53,58,60,61,62,65],work_struct:[6,48],worker:[6,48],workload:[16,44],workqueu:[0,24,35,53],workqueue_struct:[6,48],workspac:11,worksqueue_struct:[6,48],workstat:[9,10,51,52],world:[0,7,16,24,31,38,44,46,53],worth:[4,37,43],would:[2,12,13,14,15,18,22,24,25,27,39,41,42,45,47,53,59,63,64],wouldn:[21,65],wq_entri:[27,59],wq_flag_bookmark:[27,59],wq_flag_exclus:[27,59],wq_head:[27,59],wq_name:[7,46],wrap:[16,27,44,59],wrapper:[16,44],writ:[15,41],write:[0,8,9,10,12,14,15,16,18,19,21,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,41,42,44,45,47,51,52,53,54,57,58,59,60,61,62,63,65],write_begin:[10,22,52,64],write_end:[10,22,52,64],write_inod:[9,10,22,51,52,64],write_it:[10,52],write_lock:[14,45],write_lock_irq:[12,47],write_lock_irqsav:[12,47],write_sup:[22,64],write_unlock:[14,45],write_unlock_irq:[12,47],write_unlock_irqrestor:[12,47],writeback:[22,64],writeback_control:[9,10,22,51,52,64],writeback_index:[22,64],writepag:[10,22,52,64],writer:[14,28,45,61],written:[7,9,10,12,16,34,37,44,46,47,51,52],wrmsr:[30,57],wrong:35,wrote:[16,39,44],www:[2,13,30,38,57],x86:[0,2,3,4,11,12,13,15,24,28,29,30,41,43,47,53,57,58,61],x86_32:[19,62],x86_64:2,x86_feature_rsb_ctxsw:[27,59],xarg:[12,47],xarrai:[22,64],xcscope:[13,41],xen:0,xfs:[9,51],xor:[15,29,36,41,58],xu4:[4,43],year:[16,39,44],yes:[2,15,41],yet:[7,9,10,16,22,27,30,39,44,46,51,52,57,59,64],yield:[15,27,41,59],yocto:[2,3,4,13,43],yocto_imag:[2,3,9,51],you:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,21,23,27,30,31,32,33,34,35,36,37,38,39,41,42,43,44,45,46,47,48,49,50,51,52,57,59,60,65],your:[0,1,2,4,5,6,7,13,14,15,16,17,18,31,32,33,34,35,36,37,38,39,41,42,43,44,45,46,48,49,50,51],your_branch_nam:1,your_usernam:1,yourself:[14,15,16,18,42,44,45],yourselv:39,zero:[5,7,9,10,13,23,24,27,29,35,41,46,50,51,52,53,58,59,60],zimag:[2,4,43],zone:[0,17,49],zserg:38,zzzzzzzzzzzzzzz:[21,65],zzzzzzzzzzzzzzzz:[21,65]},titles:["Linux Kernel Teaching","Contributing to linux-kernel-labs","Customizing the Virtual Machine Setup","Recommended Setup","Kernel Development on ARM","Block Device Drivers","Deferred work","Character device drivers","Linux Device Model","File system drivers (Part 1)","File system drivers (Part 2)","Infrastructure","I/O access and Interrupts","Introduction","Kernel API","Kernel modules","Kernel Profiling","Memory mapping","Networking","Address Space","Architecture Layer","Debugging","Filesystem Management","Interrupts","Introduction","Memory Management","Network Management","Processes","Symmetric Multi-Processing","System Calls","Virtualization","Collaboration","Assignment 0 - Kernel API","Assignment 1 - Kprobe based tracer","Assignment 2 - Driver UART","Assignment 3 - Software RAID","Assignment 4 - SO2 Transport Protocol","Assignment 5 - PITIX Filesystem","Assignment 7 - SO2 Virtual Machine Manager with KVM","SO2 - General Rules and Grading","Operating Systems 2","SO2 Lab 01 - Introduction","SO2 Lab 10 - Networking","SO2 Lab 11 - Kernel Development on ARM","SO2 Lab 12 - Kernel Profiling","SO2 Lab 02 - Kernel API","SO2 Lab 03 - Character device drivers","SO2 Lab 04 - I/O access and Interrupts","SO2 Lab 05 - Deferred work","SO2 Lab 06 - Memory Mapping","SO2 Lab 07 - Block Device Drivers","SO2 Lab 08 - File system drivers (Part 1)","SO2 Lab 09 - File system drivers (Part 2)","SO2 Lecture 01 - Course overview and Linux kernel introduction","SO2 Lecture 10 - Networking","SO2 Lecture 11 - Architecture Layer","SO2 Lecture 12 - Profiling","SO2 Lecture 12 - Virtualization","SO2 Lecture 02 - System calls","SO2 Lecture 03 - Processes","SO2 Lecture 04 - Interrupts","SO2 Lecture 05 - Symmetric Multi-Processing","SO2 Lecture 06 - Address Space","SO2 Lecture 07 - Memory Management","SO2 Lecture 08 - Filesystem Management","SO2 Lecture 09 - Kernel debugging"],titleterms:{"32bit":[19,62],"abstract":[22,64],"class":[8,39],"final":39,"function":[5,8,9,50,51],"import":35,"long":38,"new":[8,16,44],"pozi\u021bionar":53,"return":[23,60],"switch":[24,27,53,59],Adding:[8,13],Bus:8,The:[8,9,10,18,22,27,42,51,52,59,64],Use:[14,31,45],Useful:[5,50],Using:[2,27,38,59],VFS:[9,51],about:[13,41],acceler:[26,54],accept:[18,42],access:[7,12,14,25,27,29,45,46,47,58,59,63],action:[23,60],add:[8,31],addr2lin:[15,21,41,65],address:[7,10,18,19,23,24,42,46,52,53,60,62],alloc:[14,25,45,63],alreadi:[7,46],api:[14,32,45],arch:[20,24,53,55],architectur:[20,23,24,53,55,60],arm:[4,43],ascii:[12,47],asid:[19,62],asmp:[24,53],assig:[32,33,34,35,36,37,38],assign:[31,32,33,34,35,36,37,38,39],asymmetr:[24,53],atom:[14,28,45,61],attribut:[8,22,64],background:[6,12,47,48],bad:[16,44],barrier:[28,61],base:33,basic:[8,24,28,30,53,57,61],between:[6,48],bex:8,bex_misc:8,bibliografi:53,bio:[5,50],bitmap:[10,52],bitwis:[14,45],block:[5,6,24,27,48,50,53,59],block_device_oper:[5,50],board:[4,43],boot:[4,13,20,43,55],buffer:[6,9,12,19,34,47,48,51,62],build:1,bus:8,buse:8,cach:[9,22,28,51,61,64],call:[14,20,27,29,45,55,58,59],chang:[1,31],charact:[7,12,14,45,46,47],checker:[21,65],chip:[4,43],clangd:[13,41],classic:[30,57],clone:[27,59],close:[7,18,22,42,46,64],code:[13,20,24,38,41,53,55],coher:[28,61],collabor:31,commit:31,compil:[4,15,41,43],complet:[5,9,50,51],comunit:53,concept:[23,24,53,60],concurr:[28,61],connect:[2,3,18,42],contain:[2,27,59],content:[5,50],context:[14,23,24,27,28,45,53,59,60,61],contigu:[17,49],contribut:1,control:[6,12,23,30,38,47,48,57,60],convent:[14,45],convers:[18,42],copi:[28,61],cours:53,cpu:[4,24,28,38,43,53,61],creat:[1,5,9,10,22,50,51,52,64],creation:[18,42],cross:[13,41],cscope:[13,41],cur:53,current:[27,59],cursului:53,cursuri:53,custom:2,data:[5,7,12,22,28,46,47,50,61,64],databas:[26,54],deadlin:39,debug:[13,15,21,38,41,65],debug_pagealloc:[21,65],debugg:[2,15,41],decod:[21,65],defer:[6,48],deferr:[23,60],del:8,delet:[5,10,22,50,52,64],demo:[16,44],dentri:[9,10,22,51,52,64],descriptor:[19,23,60,62],despr:53,destin:[18,42],destroi:[9,51],detail:[33,34,35,36],determin:[27,59],develop:[4,24,43,53],devic:[4,5,7,8,12,17,24,26,38,43,46,47,49,50,53,54],directori:[10,22,52,64],disabl:[28,61],disk:[5,13,50],dispatch:[5,50],displai:[17,18,42,49],docker:2,document:[1,13,41],driver:[5,7,8,9,10,12,17,20,24,34,46,47,49,50,51,52,53,55],dure:15,dynam:[15,29,41,58],dyndbg:[15,41],each:31,echipa:53,elf:[16,44],emul:[30,57],entri:[10,30,52,57],error:[14,15,41,45],exampl:[15,23,26,41,54,60],except:[20,23,55,60],execut:[14,24,30,45,53,57],exercis:[4,5,6,7,8,9,10,12,13,14,15,16,17,18,41,42,43,44,45,46,47,48,49,50,51,52],exit:[30,57],extend:[30,57],extra:[7,12,15,39,46,47],famili:[26,54],fault:[25,63],field:[18,30,42,57],file:[7,9,10,22,27,46,51,52,59,64],file_oper:[7,46],filesystem:[9,22,24,37,51,53,64],fill_sup:[9,51],filter:[18,42],fix:[19,62],flood:[23,60],fork:1,forward:[26,54],free:[5,50],from:[5,12,22,23,29,47,50,58,60,64],further:[5,6,9,10,12,17,18,42,47,48,49,50,51,52],gdb:[13,21,27,41,59,65],gendisk:[5,50],gener:[9,39,51],get:[10,13,41,52],github:31,gitlab:31,good:41,grade:39,guest:38,handl:[12,14,23,25,29,45,47,58,60,63],handler:[12,23,47,60],hardwar:[5,12,23,26,47,50,54,60],hello:[4,43],hierarchi:[24,53],highmem:[19,62],hotplug:8,how:[5,50],hypervisor:[30,57],imag:[2,4,43],implement:[7,8,12,26,27,29,33,34,35,36,46,47,54,58,59],increas:39,indic:[14,45],individu:31,info:[15,41],inform:[4,6,12,26,43,47,48,54],infrastructur:11,initi:[5,9,15,38,50,51],inod:[7,9,10,22,46,51,52,64],inode_oper:[10,52],insid:31,inspect:[19,23,27,59,60,62],intel:[30,57],interpret:[12,47],interrupt:[12,23,28,47,60,61],intro:[4,5,6,7,8,12,14,15,43,45,46,47,48,50],introduct:[13,24,41,53],investig:[16,44],ioctl:[6,7,46,48],irq:[20,23,55,60],iter:[10,52],kasan:[21,65],kdb:[15,41],kei:[12,47],kernel:[0,1,2,4,6,13,14,15,16,18,21,24,27,28,32,41,42,43,44,45,48,53,59,61,65],keyboard:[12,47],keyword:13,kfifo:[12,47],kill_sb:[9,51],kmemleak:[21,65],know:[35,41],kobject:8,kprobe:33,kscope:[13,41],kvm:[30,38,57],lab:[1,4,5,6,9,10,12,13,14,15,16,17,18,41,42,43,44,45,46,47,48,49,50,51,52],labor:53,laboratori:[7,13,39,41,46],laboratorului:53,latenc:[16,44],launch:[16,44],layer:[5,20,50,55],layout:[24,53],lazi:[30,57],lectur:[19,20,21,22,23,24,25,26,27,28,29,30,39,53,54,55,56,57,58,59,60,61,62,63,64,65],level:[5,50],linear:[19,62],link:[10,52],linux:[0,1,4,8,12,13,14,18,19,22,23,24,28,29,41,42,43,45,47,53,58,60,61,62,64],list:[14,21,45,65],lista:53,listen:[18,42],load:[15,41],local:[9,51],lock:[6,12,14,28,45,47,48,61],lockdep:[21,65],look:[19,62],lookup:[10,52],lxr:[13,41],machin:[2,3,13,20,30,38,55,57],macro:[9,51],maintain:[24,53],major:[7,46],make:1,manag:[20,22,24,25,26,38,53,54,55,63,64],map:[17,19,49,62],memori:[4,14,15,17,20,21,24,25,28,43,45,49,53,55,61,63,65],merg:31,messag:[7,18,42,46],methodolog:[16,44],micro:[24,53],minf:[9,10,51,52],minicom:[15,41],minor:[7,46],misc:8,mm_struct:[17,49],mmu:[19,20,30,55,57,62],mode:38,model:[8,9,24,51,53],modul:[14,15,24,41,45,53],monitor:8,monolith:[24,53],mount:[9,22,51,64],multi:[5,24,28,50,53,61],multiprocess:[24,53],mutex:[14,28,45,61],myf:[9,10,51,52],namespac:[27,59],navig:[13,41],necesar:53,nest:[23,60],netcat:[18,42],netconsol:[15,41],netfilt:[18,26,42,54],network:[18,24,26,42,53,54],non:[17,25,27,49,59,63],notar:53,notif:8,o_nonblock:[7,46],obiectivel:53,objdump:[15,21,41,65],object:[4,5,6,7,9,10,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,32,33,34,35,36,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,57,58,59,60,61,62,63,64,65],oop:[15,21,41,65],open:[7,22,27,46,59,64],oper:[6,7,8,9,10,14,17,18,22,24,28,40,42,45,46,48,49,51,52,53,61,64],optim:[28,61],option:[15,19,41,62],order:[28,61],other:[21,65],our:[14,45],overview:[5,7,8,14,15,16,17,18,20,24,26,27,41,42,44,45,46,49,50,53,54,55,59],packag:[4,43],packet:[18,23,26,42,54,60],page:[17,19,22,25,30,49,57,62,63,64],pageabl:[24,53],panic:[21,65],parallel:[12,47],paramet:[15,29,41,58],paravirtu:[30,57],part:[9,10,51,52],penalti:[32,33,34,35,36,37,38,39],per:[28,61],perf:[16,21,44,65],period:[6,48],perman:[19,62],phase:[26,54],physic:[17,25,49,63],pitix:37,plagiar:39,plai:8,platform:[20,55],plug:8,pnp:8,point:39,polici:[26,54],port:[12,47],portabl:[24,53],preempt:[27,59],preemption:[28,61],preemptiv:[14,24,27,45,53,59],present:39,previou:[27,59],printk:[14,15,41,45],prioriti:[23,60],probe:8,problem:[16,44],proc:[15,41],process:[5,6,7,14,20,24,26,27,28,45,46,48,50,53,54,55,59,61],processor:[28,61],procf:[17,49],profil:[16,44,56],programm:[23,60],proto_op:[18,42],protocol:[26,36,54],pull:1,qemu:[4,13,30,43,57],queri:[22,64],question:[32,33,34,35,36,37],queue:[5,7,38,46,50],quickstart:[32,33,34,35,36],quiz:[23,27,59,60],raid:35,ram:[5,50],rcu:[28,61],read:[5,6,7,9,10,12,17,18,22,28,42,46,47,48,49,50,51,52,61,64],real:38,rebuild:2,receiv:[18,42],recommend:3,redo:39,reduc:[16,44],refer:[13,41],regist:[5,7,8,9,12,46,47,50,51],registr:[5,7,46,50],regular:[10,52],releas:[7,46],remark:[13,41],remov:8,repositori:1,request:[1,5,12,23,47,50,60],reset:[12,47],resourc:[27,32,33,34,35,36,37,59],respons:[16,44],restrict:[7,46],resurs:53,retak:39,review:31,root:[9,51],rootf:[4,43],rout:[26,54],routin:[12,47],rule:39,run:38,sampl:36,scalabl:[24,53],scancod:[12,47],scheme:34,script:[27,59],search:[10,52],secur:[24,53],segment:[19,62],selector:[19,62],send:[18,26,42,54],sender:[18,42],serial:[12,47],set:[5,50],setup:[2,3,20,38,55],shadow:[30,57],share:[6,24,29,48,53,58],simpl:[4,43],sk_buff:[18,26,42,54],skb:[26,54],skeleton:[31,38],slab:[21,65],sleep:[14,45],slub_debug:[21,65],small:[25,63],smp:[23,24,53,60],so2:[36,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65],sock:[18,42],socket:[18,26,42,54],soft:[23,60],softirq:[6,48],softwar:[5,26,30,35,50,54,57],sourc:[13,24,28,41,53,61],sourceweb:[13,41],space:[7,10,18,19,24,29,42,46,52,53,58,62],specif:[20,55],spelunk:13,spin:[28,61],spinlock:[14,45],split:31,ssh:2,stack:[13,23,24,41,53,60],stage:[5,50],start:[3,31],state:[27,59],statement:[32,33,34,35,36,37],statist:[12,47],store:[12,47],strap:[20,55],string:[14,45],struct:[5,7,9,17,18,26,27,42,46,49,50,51,54,59],structur:[1,5,7,8,9,10,17,18,30,38,42,46,49,50,51,52,57],sub:[15,41],submit:[5,32,33,34,35,36,37,38,39,50],summari:[23,60],super_block:[9,51],superblock:[9,22,51,64],superoper:[10,52],support:[4,43],symbol:[10,52],symmetr:[24,28,53,61],sync:[30,57],synchron:[14,28,45,61],sysf:8,system:[4,9,10,19,20,22,23,24,27,28,29,40,43,51,52,53,55,58,59,60,61,62,64],tabl:[19,23,26,29,30,54,57,58,60,62],tag:[5,50],task:[24,27,38,53,59],task_struct:[27,59],tasklet:[6,23,48,60],tcp:[18,42],tcpdump:36,teach:0,team:31,techniqu:[26,54],teme:53,temelor:53,temporari:[19,62],term:[24,53],terminolog:[23,60],test:[9,10,14,32,33,34,35,36,37,45,51,52],thi:[13,41],thread:[6,16,20,27,44,48,55,59],through:[10,52],time:[16,20,44,55],timer:[6,23,48,60],tip:[32,33,34,35,36,37,38],tldr:38,tool:[16,21,44,65],toolchain:[4,43],top:[16,44],trace:[13,41],tracer:33,translat:[19,62],transport:36,tree:[4,43],tune:[16,44],type:[8,30,57],typic:[24,53],uart:34,udp:[18,26,42,54],uevent:8,uniform:[25,63],unload:[15,41],unmount:[9,51],unregist:[7,9,46,51],unregistr:[7,46],updat:[28,61],use:[5,50],used:[17,49],useful:[9,51],user:[18,24,29,42,53,58],userspac:[12,17,47,49],using:[6,13,48],variabl:[14,45],vdso:[29,58],version:8,via:2,virtual:[2,3,9,13,22,24,25,29,30,38,51,53,57,58,63,64],vm_area_struct:[17,49],vmm:38,vpid:[30,57],wait:[5,7,46,50],wake:[27,59],what:[23,60],work:[6,14,31,45,48],workqueu:[6,23,48,60],world:[4,43],write:[5,7,17,22,46,49,50,64],x86:[19,23,27,59,60,62],xen:[30,57],zone:[25,63]}}) \ No newline at end of file diff --git a/refs/pull/405/merge/so2/assign-collaboration.html b/refs/pull/405/merge/so2/assign-collaboration.html new file mode 100644 index 00000000..4e5bbb7b --- /dev/null +++ b/refs/pull/405/merge/so2/assign-collaboration.html @@ -0,0 +1,332 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Collaboration — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Assignment 0 - Kernel API" href="assign0-kernel-api.html" /> + <link rel="prev" title="SO2 Lab 12 - Kernel Profiling" href="lab12-kernel-profiling.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Collaboration</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#use-github-gitlab">1. Use Github / Gitlab</a></li> +<li class="toctree-l3"><a class="reference internal" href="#start-with-a-skeleton-for-the-assignment">2. Start with a skeleton for the assignment</a></li> +<li class="toctree-l3"><a class="reference internal" href="#add-a-commit-for-each-individual-change">3. Add a commit for each individual change</a></li> +<li class="toctree-l3"><a class="reference internal" href="#split-the-work-inside-the-team">4. Split the work inside the team</a></li> +<li class="toctree-l3"><a class="reference internal" href="#do-reviews">5. Do reviews</a></li> +<li class="toctree-l3"><a class="reference internal" href="#merge-the-work">6. Merge the work</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">Collaboration</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/assign-collaboration.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="collaboration"> +<h1>Collaboration<a class="headerlink" href="#collaboration" title="Permalink to this headline">¶</a></h1> +<p>Collaboration is essential in open source world and we encourage you +to pick a team partner to work on selected assignments.</p> +<p>Here is a simple guide to get you started:</p> +<div class="section" id="use-github-gitlab"> +<h2>1. Use Github / Gitlab<a class="headerlink" href="#use-github-gitlab" title="Permalink to this headline">¶</a></h2> +<p>Best way to share your work inside the team is to use a version control system (VCS) +in order to track each change. Mind that you must make your repo private and only allow +read/write access rights to team members.</p> +</div> +<div class="section" id="start-with-a-skeleton-for-the-assignment"> +<h2>2. Start with a skeleton for the assignment<a class="headerlink" href="#start-with-a-skeleton-for-the-assignment" title="Permalink to this headline">¶</a></h2> +<p>Add <cite>init</cite>/<cite>exit</cite> functions, driver operations and global structures that you driver might need.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="c1">// SPDX-License-Identifier: GPL-2.0</span> +<span class="cm">/*</span> +<span class="cm"> * uart16550.c - UART16550 driver</span> +<span class="cm"> *</span> +<span class="cm"> * Author: John Doe <john.doe@mail.com></span> +<span class="cm"> * Author: Ionut Popescu <ionut.popescu@mail.com></span> +<span class="cm"> */</span> +<span class="k">struct</span> <span class="n">uart16550_dev</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">cdev</span> <span class="n">cdev</span><span class="p">;</span> + <span class="cm">/*TODO */</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">uart16550_dev</span> <span class="n">devs</span><span class="p">[</span><span class="n">MAX_NUMBER_DEVICES</span><span class="p">];</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">uart16550_open</span><span class="p">(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">)</span> +<span class="p">{</span> + <span class="cm">/*TODO */</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">uart16550_release</span><span class="p">(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">)</span> +<span class="p">{</span> + <span class="cm">/*TODO */</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">ssize_t</span> <span class="nf">uart16550_read</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> <span class="kt">char</span> <span class="n">__user</span> <span class="o">*</span><span class="n">user_buffer</span><span class="p">,</span> + <span class="kt">size_t</span> <span class="n">size</span><span class="p">,</span> <span class="n">loff_t</span> <span class="o">*</span><span class="n">offset</span><span class="p">)</span> +<span class="p">{</span> + <span class="cm">/*TODO */</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">ssize_t</span> <span class="nf">uart16550_write</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> + <span class="k">const</span> <span class="kt">char</span> <span class="n">__user</span> <span class="o">*</span><span class="n">user_buffer</span><span class="p">,</span> + <span class="kt">size_t</span> <span class="n">size</span><span class="p">,</span> <span class="n">loff_t</span> <span class="o">*</span><span class="n">offset</span><span class="p">)</span> +<span class="p">{</span> + <span class="cm">/*TODO */</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">long</span> +<span class="nf">uart16550_ioctl</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">cmd</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">arg</span><span class="p">)</span> +<span class="p">{</span> + <span class="cm">/*TODO */</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">file_operations</span> <span class="n">uart16550_fops</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">owner</span> <span class="o">=</span> <span class="n">THIS_MODULE</span><span class="p">,</span> + <span class="p">.</span><span class="n">open</span> <span class="o">=</span> <span class="n">uart16550_open</span><span class="p">,</span> + <span class="p">.</span><span class="n">release</span> <span class="o">=</span> <span class="n">uart16550_release</span><span class="p">,</span> + <span class="p">.</span><span class="n">read</span> <span class="o">=</span> <span class="n">uart16550_read</span><span class="p">,</span> + <span class="p">.</span><span class="n">write</span> <span class="o">=</span> <span class="n">uart16550_write</span><span class="p">,</span> + <span class="p">.</span><span class="n">unlocked_ioctl</span> <span class="o">=</span> <span class="n">uart16550_ioctl</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="n">__init</span> <span class="nf">uart16550_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="cm">/* TODO: */</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="n">__exit</span> <span class="nf">uart16550_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="cm">/* TODO: */</span> +<span class="p">}</span> + +<span class="n">module_init</span><span class="p">(</span><span class="n">uart16550_init</span><span class="p">);</span> +<span class="n">module_exit</span><span class="p">(</span><span class="n">uart16550_exit</span><span class="p">);</span> + +<span class="n">MODULE_DESCRIPTION</span><span class="p">(</span><span class="s">"UART16550 Driver"</span><span class="p">);</span> +<span class="n">MODULE_AUTHOR</span><span class="p">(</span><span class="s">"John Doe <john.doe@mail.com"</span><span class="p">);</span> +<span class="n">MODULE_AUTHOR</span><span class="p">(</span><span class="s">"Ionut Popescu <ionut.popescu@mail.com"</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="add-a-commit-for-each-individual-change"> +<h2>3. Add a commit for each individual change<a class="headerlink" href="#add-a-commit-for-each-individual-change" title="Permalink to this headline">¶</a></h2> +<p>First commit must always be the skeleton file. And the rest of the code should be on top of skeleton file. +Please write a good commit mesage. Explain briefly what the commit does and <em>why</em> it is necessary.</p> +<p>Follow the seven rules of writing a good commit message: <a class="reference external" href="https://cbea.ms/git-commit/#seven-rules">https://cbea.ms/git-commit/#seven-rules</a></p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">Commit 3c92a02cc52700d2cd7c50a20297eef8553c207a (HEAD -> tema2)</span> +<span class="go">Author: John Doe <john.doe@mail.com></span> +<span class="go">Date: Mon Apr 4 11:54:39 2022 +0300</span> + +<span class="go"> uart16550: Add initial skeleton for ssignment #2</span> + +<span class="go"> This adds simple skeleton file for uart16550 assignment. Notice</span> +<span class="go"> module init/exit callbacks and file_operations dummy implementation</span> +<span class="go"> for open/release/read/write/ioctl.</span> + +<span class="go"> Signed-off-by: John Doe <john.doe@mail.com></span> +</pre></div> +</div> +</div> +<div class="section" id="split-the-work-inside-the-team"> +<h2>4. Split the work inside the team<a class="headerlink" href="#split-the-work-inside-the-team" title="Permalink to this headline">¶</a></h2> +<p>Add <cite>TODOs</cite> with each team member tasks. Try to split the work evenly.</p> +<p>Before starting to code, make a plan. On top of your skeleton file, add TODOs with each member tasks. Agree on global +structures and the overall driver design. Then start coding.</p> +</div> +<div class="section" id="do-reviews"> +<h2>5. Do reviews<a class="headerlink" href="#do-reviews" title="Permalink to this headline">¶</a></h2> +<p>Create Pull Requests with your commits and go through review rounds with your team members. You can follow <cite>How to create a PR</cite> <a class="reference external" href="https://www.youtube.com/watch?v=YvoHJJWvn98">video</a>.</p> +</div> +<div class="section" id="merge-the-work"> +<h2>6. Merge the work<a class="headerlink" href="#merge-the-work" title="Permalink to this headline">¶</a></h2> +<p>The final work is the result of merging all the pull requests. Following the commit messages +one should clearly understand the progress of the code and how the work was managed inside the team.</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">f5118b873294 uart16550: Add uart16550_interrupt implementation</span> +<span class="go">2115503fc3e3 uart16550: Add uart16550_ioctl implementation</span> +<span class="go">b31a257fd8b8 uart16550: Add uart16550_write implementation</span> +<span class="go">ac1af6d88a25 uart16550: Add uart16550_read implementation</span> +<span class="go">9f680e8136bf uart16550: Add uart16550_open/release implementation</span> +<span class="go">3c92a02cc527 uart16550: Add skeleton for SO2 assignment #2</span> +</pre></div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lab12-kernel-profiling.html" class="btn btn-neutral float-left" title="SO2 Lab 12 - Kernel Profiling" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="assign0-kernel-api.html" class="btn btn-neutral float-right" title="Assignment 0 - Kernel API" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/assign0-kernel-api.html b/refs/pull/405/merge/so2/assign0-kernel-api.html new file mode 100644 index 00000000..268115fe --- /dev/null +++ b/refs/pull/405/merge/so2/assign0-kernel-api.html @@ -0,0 +1,307 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Assignment 0 - Kernel API — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Assignment 1 - Kprobe based tracer" href="assign1-kprobe-based-tracer.html" /> + <link rel="prev" title="Collaboration" href="assign-collaboration.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Assignment 0 - Kernel API</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#assignment-s-objectives">Assignment's Objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#statement">Statement</a></li> +<li class="toctree-l3"><a class="reference internal" href="#testing">Testing</a></li> +<li class="toctree-l3"><a class="reference internal" href="#quickstart">QuickStart</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#tips">Tips</a></li> +<li class="toctree-l4"><a class="reference internal" href="#penalties">Penalties</a></li> +<li class="toctree-l4"><a class="reference internal" href="#submitting-the-assigment">Submitting the assigment</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#resources">Resources</a></li> +<li class="toctree-l3"><a class="reference internal" href="#questions">Questions</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">Assignment 0 - Kernel API</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/assign0-kernel-api.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="assignment-0-kernel-api"> +<h1>Assignment 0 - Kernel API<a class="headerlink" href="#assignment-0-kernel-api" title="Permalink to this headline">¶</a></h1> +<ul class="simple"> +<li>Deadline: <strong class="command">Monday, 25 March 2024, 23:59</strong></li> +</ul> +<div class="section" id="assignment-s-objectives"> +<h2>Assignment's Objectives<a class="headerlink" href="#assignment-s-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>getting familiar with the qemu setup</li> +<li>loading/unloading kernel modules</li> +<li>getting familiar with the list API implemented in the kernel</li> +<li>have fun :)</li> +</ul> +</div> +<div class="section" id="statement"> +<h2>Statement<a class="headerlink" href="#statement" title="Permalink to this headline">¶</a></h2> +<p>Write a kernel module called <cite>list</cite> (the resulting file must be called <cite>list.ko</cite>) which stores data (strings) +in an internal list.</p> +<p>It is mandatory to use <a class="reference external" href="https://github.com/torvalds/linux/blob/master/include/linux/list.h">the list API</a> +implemented in the kernel. +For details you can take a look at <a class="reference external" href="https://linux-kernel-labs.github.io/refs/heads/master/so2/lab2-kernel-api.html">the laboratory 2</a>.</p> +<p>The module exports a directory named <strong class="command">list</strong> to procfs. The directory contains two files:</p> +<ul class="simple"> +<li><strong class="command">management</strong>: with write-only access; is the interface for transmitting commands to the kernel module</li> +<li><strong class="command">preview</strong>: with read-only access; is the interface through which the internal contents of the kernel list can be viewed.</li> +</ul> +<p><a class="reference external" href="https://github.com/linux-kernel-labs/linux/blob/master/tools/labs/templates/assignments/0-list/list.c">The code skeleton</a> implements the two procfs files. +You will need to create a list and implement support for <cite>adding</cite> and <cite>reading</cite> data. Follow the TODOs in the code for details.</p> +<p>To interact with the kernel list, you must write commands (using the <cite>echo</cite> command) in the <cite>/proc/list/management</cite> file:</p> +<ul class="simple"> +<li><cite>addf name</cite>: adds the <cite>name</cite> element to the top of the list</li> +<li><cite>adde name</cite>: adds the <cite>name</cite> element to the end of the list</li> +<li><cite>delf name</cite>: deletes the first appearance of the <cite>name</cite> item from the list</li> +<li><cite>dela name</cite>: deletes all occurrences of the <cite>name</cite> element in the list</li> +</ul> +<p>Viewing the contents of the list is done by viewing the contents of the <cite>/proc/list/preview</cite> file (use the` cat` command). +The format contains one element on each line.</p> +</div> +<div class="section" id="testing"> +<h2>Testing<a class="headerlink" href="#testing" title="Permalink to this headline">¶</a></h2> +<p>In order to simplify the assignment evaluation process, but also to reduce the mistakes of the submitted assignments, +the assignment evaluation will be done automatically with the help of a +<a class="reference external" href="https://github.com/linux-kernel-labs/linux/blob/master/tools/labs/templates/assignments/0-list/checker/_checker">test script</a> called <cite>_checker</cite>. +The test script assumes that the kernel module is called <cite>list.ko</cite>.</p> +</div> +<div class="section" id="quickstart"> +<h2>QuickStart<a class="headerlink" href="#quickstart" title="Permalink to this headline">¶</a></h2> +<p>It is mandatory to start the implementation of the assignment from the code skeleton found in the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/0-list/-/blob/master/src/list.c">list.c</a> file. +You should follow the instructions in the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/0-list/-/blob/master/README.md">README.md file</a> of the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/0-list">assignment's repo</a>.</p> +<div class="section" id="tips"> +<h3>Tips<a class="headerlink" href="#tips" title="Permalink to this headline">¶</a></h3> +<p>To increase your chances of getting the highest grade, read and follow the Linux kernel +coding style described in the <a class="reference external" href="https://elixir.bootlin.com/linux/v4.19.19/source/Documentation/process/coding-style.rst">Coding Style document</a>.</p> +<p>Also, use the following static analysis tools to verify the code:</p> +<ul class="simple"> +<li>checkpatch.pl</li> +</ul> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> linux/scripts/checkpatch.pl --no-tree --terse -f /path/to/your/list.c +</pre></div> +</div> +<ul class="simple"> +<li>sparse</li> +</ul> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> sudo apt-get install sparse +<span class="gp">$</span> <span class="nb">cd</span> linux +<span class="gp">$</span> make <span class="nv">C</span><span class="o">=</span><span class="m">2</span> /path/to/your/list.c +</pre></div> +</div> +<ul class="simple"> +<li>cppcheck</li> +</ul> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> sudo apt-get install cppcheck +<span class="gp">$</span> cppcheck /path/to/your/list.c +</pre></div> +</div> +</div> +<div class="section" id="penalties"> +<h3>Penalties<a class="headerlink" href="#penalties" title="Permalink to this headline">¶</a></h3> +<p>Information about assigments penalties can be found on the +<a class="reference external" href="https://ocw.cs.pub.ro/courses/so2/teme/general">General Directions page</a>.</p> +<p>In exceptional cases (the assigment passes the tests by not complying with the requirements) +and if the assigment does not pass all the tests, the grade will may decrease more than mentioned above.</p> +</div> +<div class="section" id="submitting-the-assigment"> +<h3>Submitting the assigment<a class="headerlink" href="#submitting-the-assigment" title="Permalink to this headline">¶</a></h3> +<p>The assignment will be graded automatically using the <a class="reference external" href="https://github.com/systems-cs-pub-ro/vmchecker-next/wiki/Student-Handbook">vmchecker-next</a> infrastructure. +The submission will be made on moodle on the <a class="reference external" href="https://curs.upb.ro/2022/course/view.php?id=5121">course's page</a> to the related assignment. +You will find the submission details in the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/0-list/-/blob/master/README.md">README.md file</a> of the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/0-list/-/blob/master">repo</a>.</p> +</div> +</div> +<div class="section" id="resources"> +<h2>Resources<a class="headerlink" href="#resources" title="Permalink to this headline">¶</a></h2> +<p>We recommend that you use gitlab to store your homework. Follow the directions in +<a class="reference external" href="https://gitlab.cs.pub.ro/so2/0-list/-/blob/master/README.md">README.md file</a>.</p> +</div> +<div class="section" id="questions"> +<h2>Questions<a class="headerlink" href="#questions" title="Permalink to this headline">¶</a></h2> +<p>For questions about the topic, you can consult the mailing <a class="reference external" href="http://cursuri.cs.pub.ro/pipermail/so2/">list archives</a> +or you can write a question on the dedicated Teams channel.</p> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="assign-collaboration.html" class="btn btn-neutral float-left" title="Collaboration" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="assign1-kprobe-based-tracer.html" class="btn btn-neutral float-right" title="Assignment 1 - Kprobe based tracer" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/assign1-kprobe-based-tracer.html b/refs/pull/405/merge/so2/assign1-kprobe-based-tracer.html new file mode 100644 index 00000000..df4bb3fa --- /dev/null +++ b/refs/pull/405/merge/so2/assign1-kprobe-based-tracer.html @@ -0,0 +1,375 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Assignment 1 - Kprobe based tracer — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Assignment 2 - Driver UART" href="assign2-driver-uart.html" /> + <link rel="prev" title="Assignment 0 - Kernel API" href="assign0-kernel-api.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Assignment 1 - Kprobe based tracer</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#assignment-s-objectives">Assignment's Objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#statement">Statement</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#implementation-details">Implementation details</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#testing">Testing</a></li> +<li class="toctree-l3"><a class="reference internal" href="#quickstart">QuickStart</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#tips">Tips</a></li> +<li class="toctree-l4"><a class="reference internal" href="#penalties">Penalties</a></li> +<li class="toctree-l4"><a class="reference internal" href="#submitting-the-assigment">Submitting the assigment</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#resources">Resources</a></li> +<li class="toctree-l3"><a class="reference internal" href="#questions">Questions</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">Assignment 1 - Kprobe based tracer</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/assign1-kprobe-based-tracer.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="assignment-1-kprobe-based-tracer"> +<h1>Assignment 1 - Kprobe based tracer<a class="headerlink" href="#assignment-1-kprobe-based-tracer" title="Permalink to this headline">¶</a></h1> +<ul class="simple"> +<li>Deadline: <strong class="command">Monday, 8 April 2024, 23:59</strong></li> +</ul> +<div class="section" id="assignment-s-objectives"> +<h2>Assignment's Objectives<a class="headerlink" href="#assignment-s-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>gaining knowledge related to the instrumentation of functions in the Linux kernel (<code class="docutils literal"><span class="pre">kretprobes</span></code> mechanism)</li> +<li>gaining knowledge regarding the <code class="docutils literal"><span class="pre">/proc</span></code> file system from the Linux kernel</li> +<li>get familiar with data structures specific to the Linux kernel (<code class="docutils literal"><span class="pre">hash</span> <span class="pre">table</span></code> and <code class="docutils literal"><span class="pre">list</span></code>)</li> +</ul> +</div> +<div class="section" id="statement"> +<h2>Statement<a class="headerlink" href="#statement" title="Permalink to this headline">¶</a></h2> +<p>Build a kernel operations surveillant.</p> +<p>With this surveillant, we aim to intercept:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">kmalloc</span></code> and <code class="docutils literal"><span class="pre">kfree</span></code> calls</li> +<li><code class="docutils literal"><span class="pre">schedule</span></code> calls</li> +<li><code class="docutils literal"><span class="pre">up</span></code> and <code class="docutils literal"><span class="pre">down_interruptible</span></code> calls</li> +<li><code class="docutils literal"><span class="pre">mutex_lock</span></code> and <code class="docutils literal"><span class="pre">mutex_unlock</span></code> calls</li> +</ul> +<p>The surveillant will hold, at the process level, the number of calls for each of the above functions. +For the <code class="docutils literal"><span class="pre">kmalloc</span></code> and <code class="docutils literal"><span class="pre">kfree</span></code> calls the total quantity of allocated and deallocated memory will be +shown.</p> +<p>The surveillant will be implemented as a kernel module with the name <code class="docutils literal"><span class="pre">tracer.ko</span></code>.</p> +<div class="section" id="implementation-details"> +<h3>Implementation details<a class="headerlink" href="#implementation-details" title="Permalink to this headline">¶</a></h3> +<p>The interception will be done by recording a sample (<code class="docutils literal"><span class="pre">kretprobe</span></code>) for each of the above functions. The +surveillant will retain a list/hashtable with the monitored processes and will account for +the above information for these processes.</p> +<p>For the control of the list/hashtable with the monitored processes, a char device called <code class="docutils literal"><span class="pre">/dev/tracer</span></code> +will be used, with major <cite>10</cite> and minor <cite>42</cite>. It will expose an <code class="docutils literal"><span class="pre">ioctl</span></code> interface with two arguments:</p> +<ul> +<li><p class="first">the first argument is the request to the monitoring subsystem:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">TRACER_ADD_PROCESS</span></code></li> +<li><code class="docutils literal"><span class="pre">TRACER_REMOVE_PROCESS</span></code></li> +</ul> +</div></blockquote> +</li> +<li><p class="first">the second argument is the PID of the process for which the monitoring request will be executed</p> +</li> +</ul> +<p>In order to create a char device with major <cite>10</cite> you will need to use the <a class="reference external" href="https://elixir.bootlin.com/linux/latest/source/include/linux/miscdevice.h">miscdevice</a> interface in the kernel. +Definitions of related macros can be found in the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/1-tracer/-/blob/master/src/tracer.h">tracer.h header</a>.</p> +<p>Since the <code class="docutils literal"><span class="pre">kmalloc</span></code> function is inline for instrumenting the allocated amount of memory, the <code class="docutils literal"><span class="pre">__kmalloc</span></code> +function will be inspected as follows:</p> +<ul class="simple"> +<li>a <code class="docutils literal"><span class="pre">kretprobe</span></code> will be used, which will retain the amount of memory allocated and the address of the allocated memory area.</li> +<li>the <code class="docutils literal"><span class="pre">.entry_handler</span></code> and <code class="docutils literal"><span class="pre">.handler</span></code> fields in the <code class="docutils literal"><span class="pre">kretprobe</span></code> structure will be used to retain information about the amount of memory allocated and the address from which the allocated memory starts.</li> +</ul> +<div class="highlight-C"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="k">struct</span> <span class="n">kretprobe</span> <span class="n">kmalloc_probe</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">entry_handler</span> <span class="o">=</span> <span class="n">kmalloc_probe_entry_handler</span><span class="p">,</span> <span class="cm">/* entry handler */</span> + <span class="p">.</span><span class="n">handler</span> <span class="o">=</span> <span class="n">kmalloc_probe_handler</span><span class="p">,</span> <span class="cm">/* return probe handler */</span> + <span class="p">.</span><span class="n">maxactive</span> <span class="o">=</span> <span class="mi">32</span><span class="p">,</span> +<span class="p">};</span> +</pre></div> +</div> +<p>Since the <code class="docutils literal"><span class="pre">kfree</span></code> function only receives the address of the memory area to be freed, in order to determine +the total amount of memory freed, we will need to determine its size based on the address of the area. +This is possible because there is an address-size association made when inspecting the <code class="docutils literal"><span class="pre">__kmalloc</span></code> function.</p> +<p>For the rest of the instrumentation functions it is enough to use a <code class="docutils literal"><span class="pre">kretprobe</span></code>.</p> +<div class="highlight-C"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="k">struct</span> <span class="n">kretprobe</span> <span class="n">up_probe</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">entry_handler</span> <span class="o">=</span> <span class="n">up_probe_handler</span><span class="p">,</span> + <span class="p">.</span><span class="n">maxactive</span> <span class="o">=</span> <span class="mi">32</span><span class="p">,</span> +<span class="p">};</span> +</pre></div> +</div> +<p>The virtual machine kernel has the <code class="docutils literal"><span class="pre">CONFIG_DEBUG_LOCK_ALLOC</span></code> option enabled where the <code class="docutils literal"><span class="pre">mutex_lock</span></code> symbol +is a macro that expands to <code class="docutils literal"><span class="pre">mutex_lock_nested</span></code>. Thus, in order to obtain information about the <code class="docutils literal"><span class="pre">mutex_lock</span></code> +function you will have to instrument the <code class="docutils literal"><span class="pre">mutex_lock_nested</span></code> function.</p> +<p>Processes that have been added to the list/hashtable and that end their execution will be removed +from the list/hashtable. Also, a process will be removed from the dispatch list/hashtable following +the <code class="docutils literal"><span class="pre">TRACER_REMOVE_PROCESS</span></code> operation.</p> +<p>The information retained by the surveillant will be displayed via the procfs file system, in the <code class="docutils literal"><span class="pre">/proc/tracer</span></code> file. +For each monitored process an entry is created in the <code class="docutils literal"><span class="pre">/proc/tracer</span></code> file having as first field the process PID. +The entry will be read-only, and a read operation on it will display the retained results. An example of +displaying the contents of the entry is:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span>cat /proc/tracer +<span class="go">PID kmalloc kfree kmalloc_mem kfree_mem sched up down lock unlock</span> +<span class="go">42 12 12 2048 2048 124 2 2 9 9</span> +<span class="go">1099 0 0 0 0 1984 0 0 0 0</span> +<span class="go">1244 0 0 0 0 1221 100 1023 1023 1002</span> +<span class="go">1337 123 99 125952 101376 193821 992 81921 7421 6392</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="testing"> +<h2>Testing<a class="headerlink" href="#testing" title="Permalink to this headline">¶</a></h2> +<p>In order to simplify the assignment evaluation process, but also to reduce the mistakes of the submitted assignments, +the assignment evaluation will be done automatically with the help of a +<a class="reference external" href="https://github.com/linux-kernel-labs/linux/blob/master/tools/labs/templates/assignments/1-tracer/checker/_checker">test script</a> called <cite>_checker</cite>. +The test script assumes that the kernel module is called <cite>tracer.ko</cite>.</p> +</div> +<div class="section" id="quickstart"> +<h2>QuickStart<a class="headerlink" href="#quickstart" title="Permalink to this headline">¶</a></h2> +<p>It is mandatory to start the implementation of the assignment from the code skeleton found in the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/1-tracer/-/tree/master/src">src</a> directory. +There is only one header in the skeleton called <a class="reference external" href="https://gitlab.cs.pub.ro/so2/1-tracer/-/blob/master/src/tracer.h">tracer.h</a>. +You will provide the rest of the implementation. You can add as many <cite>*.c`</cite> sources and additional <cite>*.h`</cite> headers. +You should also provide a Kbuild file that will compile the kernel module called <cite>tracer.ko</cite>. +Follow the instructions in the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/1-tracer/-/blob/master/README.md">README.md file</a> of the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/1-tracer">assignment's repo</a>.</p> +<div class="section" id="tips"> +<h3>Tips<a class="headerlink" href="#tips" title="Permalink to this headline">¶</a></h3> +<p>To increase your chances of getting the highest grade, read and follow the Linux kernel +coding style described in the <a class="reference external" href="https://elixir.bootlin.com/linux/v4.19.19/source/Documentation/process/coding-style.rst">Coding Style document</a>.</p> +<p>Also, use the following static analysis tools to verify the code:</p> +<ul class="simple"> +<li>checkpatch.pl</li> +</ul> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> linux/scripts/checkpatch.pl --no-tree --terse -f /path/to/your/tracer.c +</pre></div> +</div> +<ul class="simple"> +<li>sparse</li> +</ul> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> sudo apt-get install sparse +<span class="gp">$</span> <span class="nb">cd</span> linux +<span class="gp">$</span> make <span class="nv">C</span><span class="o">=</span><span class="m">2</span> /path/to/your/tracer.c +</pre></div> +</div> +<ul class="simple"> +<li>cppcheck</li> +</ul> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> sudo apt-get install cppcheck +<span class="gp">$</span> cppcheck /path/to/your/tracer.c +</pre></div> +</div> +</div> +<div class="section" id="penalties"> +<h3>Penalties<a class="headerlink" href="#penalties" title="Permalink to this headline">¶</a></h3> +<p>Information about assigments penalties can be found on the +<a class="reference external" href="https://ocw.cs.pub.ro/courses/so2/teme/general">General Directions page</a>. In addition, the following +elements will be taken into account:</p> +<ul class="simple"> +<li><em>-2</em>: missing of proper disposal of resources (<code class="docutils literal"><span class="pre">kretprobes</span></code>, entries in <code class="docutils literal"><span class="pre">/proc</span></code>)</li> +<li><em>-2</em>: data synchronization issues for data used by multiple executing instances (e.g. the list/hashtable)</li> +</ul> +<p>In exceptional cases (the assigment passes the tests but it is not complying with the requirements) +and if the assigment does not pass all the tests, the grade may decrease more than mentioned above.</p> +</div> +<div class="section" id="submitting-the-assigment"> +<h3>Submitting the assigment<a class="headerlink" href="#submitting-the-assigment" title="Permalink to this headline">¶</a></h3> +<p>The assignment will be graded automatically using the <a class="reference external" href="https://github.com/systems-cs-pub-ro/vmchecker-next/wiki/Student-Handbook">vmchecker-next</a> infrastructure. +The submission will be made on moodle on the <a class="reference external" href="https://curs.upb.ro/2022/course/view.php?id=5121">course's page</a> to the related assignment. +You will find the submission details in the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/1-tracer/-/blob/master/README.md">README.md file</a> of the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/1-tracer">repo</a>.</p> +</div> +</div> +<div class="section" id="resources"> +<h2>Resources<a class="headerlink" href="#resources" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li><a class="reference external" href="https://www.kernel.org/doc/Documentation/kprobes.txt">Documentation/kprobes.txt</a> - description of the <code class="docutils literal"><span class="pre">kprobes</span></code> subsystem from Linux kernel sources.</li> +<li><a class="reference external" href="https://elixir.bootlin.com/linux/latest/source/samples/kprobes">samples/kprobes/</a> - some examples of using <code class="docutils literal"><span class="pre">kprobes</span></code> from Linux kernel sources.</li> +</ul> +<p>We recommend that you use gitlab to store your homework. Follow the directions in +<a class="reference external" href="https://gitlab.cs.pub.ro/so2/1-tracer/-/blob/master/README.md">README</a>.</p> +</div> +<div class="section" id="questions"> +<h2>Questions<a class="headerlink" href="#questions" title="Permalink to this headline">¶</a></h2> +<p>For questions about the topic, you can consult the mailing <a class="reference external" href="http://cursuri.cs.pub.ro/pipermail/so2/">list archives</a> +or you can write a question on the dedicated Teams channel.</p> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="assign0-kernel-api.html" class="btn btn-neutral float-left" title="Assignment 0 - Kernel API" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="assign2-driver-uart.html" class="btn btn-neutral float-right" title="Assignment 2 - Driver UART" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/assign2-driver-uart.html b/refs/pull/405/merge/so2/assign2-driver-uart.html new file mode 100644 index 00000000..cc1a9317 --- /dev/null +++ b/refs/pull/405/merge/so2/assign2-driver-uart.html @@ -0,0 +1,354 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Assignment 2 - Driver UART — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Assignment 3 - Software RAID" href="assign3-software-raid.html" /> + <link rel="prev" title="Assignment 1 - Kprobe based tracer" href="assign1-kprobe-based-tracer.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Assignment 2 - Driver UART</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#assignment-s-objectives">Assignment's Objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#statement">Statement</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#buffers-scheme">Buffers Scheme</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#implementation-details">Implementation Details</a></li> +<li class="toctree-l3"><a class="reference internal" href="#testing">Testing</a></li> +<li class="toctree-l3"><a class="reference internal" href="#quickstart">QuickStart</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#tips">Tips</a></li> +<li class="toctree-l4"><a class="reference internal" href="#penalties">Penalties</a></li> +<li class="toctree-l4"><a class="reference internal" href="#submitting-the-assigment">Submitting the assigment</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#resources">Resources</a></li> +<li class="toctree-l3"><a class="reference internal" href="#questions">Questions</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">Assignment 2 - Driver UART</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/assign2-driver-uart.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="assignment-2-driver-uart"> +<h1>Assignment 2 - Driver UART<a class="headerlink" href="#assignment-2-driver-uart" title="Permalink to this headline">¶</a></h1> +<ul class="simple"> +<li>Deadline: <strong class="command">Monday, 22 April 2024, 23:59</strong></li> +<li>The assigment is individual</li> +</ul> +<div class="section" id="assignment-s-objectives"> +<h2>Assignment's Objectives<a class="headerlink" href="#assignment-s-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>consolidating the knowledge of device drivers</li> +<li>read hardware documentation and track the desired functionality in the documentation</li> +<li>work with interrupts; use of non-blocking functions in interrupt context</li> +<li>use of buffers; synchronization</li> +<li>kernel modules with parameters</li> +</ul> +</div> +<div class="section" id="statement"> +<h2>Statement<a class="headerlink" href="#statement" title="Permalink to this headline">¶</a></h2> +<p>Write a kernel module that implements a driver for the serial port (<cite>UART16550</cite>). +The device driver must support the two standard serial ports in a PC, <cite>COM1</cite> and <cite>COM2</cite> (<cite>0x3f8</cite> and <cite>0x2f8</cite>, +in fact the entire range of <cite>8</cite> addresses <cite>0x3f8-0x3ff</cite> and <cite>0x2f8-0x2ff</cite> specific to the two ports). +In addition to the standard routines (<cite>open</cite>, <cite>read</cite>, <cite>write</cite>, <cite>close</cite>), +the driver must also have support for changing communication parameters using an <cite>ioctl</cite> operation (<cite>UART16550_IOCTL_SET_LINE</cite>).</p> +<p>The driver must use interrupts for both reception and transmission to reduce latency and CPU usage time. +<cite>Read</cite> and <cite>write</cite> calls must also be blocking. <strong class="command">Assignments that do not meet these requirements will not be considered.</strong> +It is recommended that you use a buffer for the read routine and another buffer for the write routine for each serial port in the driver.</p> +<p>A blocking read call means that the read routine called from the user-space will be blocked until <strong class="command">at least</strong> one byte is read +(the read buffer in the kernel is empty and no data can be read). +A blocking write call means that the write routine called from the user-space will be blocked until <strong class="command">at least</strong> one byte is written +(the write buffer in the kernel is full and no data can be written).</p> +<div class="section" id="buffers-scheme"> +<h3>Buffers Scheme<a class="headerlink" href="#buffers-scheme" title="Permalink to this headline">¶</a></h3> +<img alt="../_images/buffers-scheme.png" src="../_images/buffers-scheme.png" /> +<p>Data transfer between the various buffers is a <a class="reference external" href="https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem">Producer-Consumer</a> problem. Example:</p> +<ul class="simple"> +<li>The process is the producer and the device is the consumer if it is written from the process to the device; the process will block until there is at least one free space in the consumer's buffer</li> +<li>The process is the consumer and the device is the producer if it is read from a process from the device; the process will block until there is at least one element in the producer's buffer.</li> +</ul> +</div> +</div> +<div class="section" id="implementation-details"> +<h2>Implementation Details<a class="headerlink" href="#implementation-details" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>the driver will be implemented as a kernel module named <strong class="command">uart16550.ko</strong></li> +<li>the driver will be accessed as a character device driver, with different functions depending on the parameters transmitted to the load module:<ul> +<li>the <cite>major</cite> parameter will specify the major with which the device must be registered</li> +<li>the <cite>option</cite> parameter will specify how it works:<ul> +<li>OPTION_BOTH: will also register COM1 and COM2, with the major given by the <cite>major</cite> parameter and the minors 0 (for COM1) and 1 (for COM2);</li> +<li>OPTION_COM1: will only register COM1, with the major <cite>major</cite> and minor 0;</li> +<li>OPTION_COM2: will only register COM2, with the major <cite>major</cite> and minor 1;</li> +</ul> +</li> +<li>to learn how to pass parameters in Linux, see <a class="reference external" href="https://tldp.org/LDP/lkmpg/2.6/html/x323.html">tldp</a></li> +<li>the default values are <cite>major=42</cite> and <cite>option=OPTION_BOTH</cite>.</li> +</ul> +</li> +<li>the interrupt number associated with COM1 is 4 (<cite>IRQ_COM1</cite>) and the interrupt number associated with COM2 is 3 (<cite>IRQ_COM2</cite>)</li> +<li><a class="reference external" href="https://gitlab.cs.pub.ro/so2/2-uart/-/blob/master/src/uart16550.h">the header</a> with the definitions needed for special operations;</li> +<li>a starting point in implementing read / write routines is the <a class="reference external" href="https://ocw.cs.pub.ro/courses/so2/laboratoare/lab04?&#sincronizare_-_cozi_de_asteptare">example</a> of uppercase / lowercase character device driver; the only difference is that you have to use two buffers, one for read and one for write;</li> +<li>you can use <a class="reference external" href="https://lwn.net/Articles/347619/">kfifo</a> for buffers;</li> +<li>you do not have to use deferred functions to read / write data from / to ports (you can do everything from interrupt context);</li> +<li>you will need to synchronize the read / write routines with the interrupt handling routine for the routines to be blocking; it is recommended to use <a class="reference external" href="https://ocw.cs.pub.ro/courses/so2/laboratoare/lab04?&#sincronizare_-_cozi_de_asteptare">synchronization with waiting queues</a></li> +<li>In order for the assigment to work, the <cite>default serial driver</cite> must be disabled:<ul> +<li><cite>cat /proc/ioports | grep serial</cite> will detect the presence of the default driver on the regions where COM1 and COM2 are defined</li> +<li>in order to deactivate it, the kernel must be recompiled, either by setting the serial driver as the module, or by deactivating it completely (this modification is already made on the virtual machine)<ul> +<li><cite>Device Drivers -> Character devices -> Serial driver -> 8250/16550 and compatible serial support.</cite></li> +</ul> +</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="testing"> +<h2>Testing<a class="headerlink" href="#testing" title="Permalink to this headline">¶</a></h2> +<p>In order to simplify the assignment evaluation process, but also to reduce the mistakes of the submitted assignments, +the assignment evaluation will be done automatically with the help of a +<a class="reference external" href="https://gitlab.cs.pub.ro/so2/2-uart/-/blob/master/checker/2-uart-checker/_checker">test script</a> called <cite>_checker</cite>. +The test script assumes that the kernel module is called <cite>uart16550.ko</cite>.</p> +</div> +<div class="section" id="quickstart"> +<h2>QuickStart<a class="headerlink" href="#quickstart" title="Permalink to this headline">¶</a></h2> +<p>It is mandatory to start the implementation of the assignment from the code skeleton found in the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/2-uart/-/tree/master/src">src</a> directory. +There is only one header in the skeleton called <a class="reference external" href="https://gitlab.cs.pub.ro/so2/2-uart/-/blob/master/src/uart16550.h">uart16550.h</a>. +You will provide the rest of the implementation. You can add as many <cite>*.c`</cite> sources and additional <cite>*.h`</cite> headers. +You should also provide a Kbuild file that will compile the kernel module called <cite>uart16550.ko</cite>. +Follow the instructions in the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/2-uart/-/blob/master/README.md">README.md file</a> of the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/2-uart">assignment's repo</a>.</p> +<div class="section" id="tips"> +<h3>Tips<a class="headerlink" href="#tips" title="Permalink to this headline">¶</a></h3> +<p>To increase your chances of getting the highest grade, read and follow the Linux kernel +coding style described in the <a class="reference external" href="https://elixir.bootlin.com/linux/v4.19.19/source/Documentation/process/coding-style.rst">Coding Style document</a>.</p> +<p>Also, use the following static analysis tools to verify the code:</p> +<ul class="simple"> +<li>checkpatch.pl</li> +</ul> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> linux/scripts/checkpatch.pl --no-tree --terse -f /path/to/your/list.c +</pre></div> +</div> +<ul class="simple"> +<li>sparse</li> +</ul> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> sudo apt-get install sparse +<span class="gp">$</span> <span class="nb">cd</span> linux +<span class="gp">$</span> make <span class="nv">C</span><span class="o">=</span><span class="m">2</span> /path/to/your/list.c +</pre></div> +</div> +<ul class="simple"> +<li>cppcheck</li> +</ul> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> sudo apt-get install cppcheck +<span class="gp">$</span> cppcheck /path/to/your/list.c +</pre></div> +</div> +</div> +<div class="section" id="penalties"> +<h3>Penalties<a class="headerlink" href="#penalties" title="Permalink to this headline">¶</a></h3> +<p>Information about assigments penalties can be found on the +<a class="reference external" href="https://ocw.cs.pub.ro/courses/so2/teme/general">General Directions page</a>.</p> +<p>In exceptional cases (the assigment passes the tests by not complying with the requirements) +and if the assigment does not pass all the tests, the grade will may decrease more than mentioned above.</p> +</div> +<div class="section" id="submitting-the-assigment"> +<h3>Submitting the assigment<a class="headerlink" href="#submitting-the-assigment" title="Permalink to this headline">¶</a></h3> +<p>The assignment will be graded automatically using the <a class="reference external" href="https://github.com/systems-cs-pub-ro/vmchecker-next/wiki/Student-Handbook">vmchecker-next</a> infrastructure. +The submission will be made on moodle on the <a class="reference external" href="https://curs.upb.ro/2022/course/view.php?id=5121">course's page</a> to the related assignment. +You will find the submission details in the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/2-uart/-/blob/master/README.md">README.md file</a> of the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/2-uart">repo</a>.</p> +</div> +</div> +<div class="section" id="resources"> +<h2>Resources<a class="headerlink" href="#resources" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>serial port documentation can be found on <a class="reference external" href="https://tldp.org/HOWTO/Serial-HOWTO-19.html">tldp</a></li> +<li><a class="reference external" href="http://www.byterunner.com/16550.html">table with registers</a></li> +<li><a class="reference external" href="https://pdf1.alldatasheet.com/datasheet-pdf/view/9301/NSC/PC16550D.html">datasheet 16550</a></li> +<li><a class="reference external" href="https://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming">alternative documentation</a></li> +</ul> +<p>We recommend that you use gitlab to store your homework. Follow the directions in +<a class="reference external" href="https://gitlab.cs.pub.ro/so2/2-uart/-/blob/master/README.md">README</a>.</p> +</div> +<div class="section" id="questions"> +<h2>Questions<a class="headerlink" href="#questions" title="Permalink to this headline">¶</a></h2> +<p>For questions about the topic, you can consult the mailing <a class="reference external" href="http://cursuri.cs.pub.ro/pipermail/so2/">list archives</a> +or you can write a question on the dedicated Teams channel.</p> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="assign1-kprobe-based-tracer.html" class="btn btn-neutral float-left" title="Assignment 1 - Kprobe based tracer" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="assign3-software-raid.html" class="btn btn-neutral float-right" title="Assignment 3 - Software RAID" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/assign3-software-raid.html b/refs/pull/405/merge/so2/assign3-software-raid.html new file mode 100644 index 00000000..f3773aae --- /dev/null +++ b/refs/pull/405/merge/so2/assign3-software-raid.html @@ -0,0 +1,366 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Assignment 3 - Software RAID — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Assignment 4 - SO2 Transport Protocol" href="assign4-transport-protocol.html" /> + <link rel="prev" title="Assignment 2 - Driver UART" href="assign2-driver-uart.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Assignment 3 - Software RAID</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#assignment-s-objectives">Assignment's Objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#statement">Statement</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#important-to-know">Important to know</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#implementation-details">Implementation Details</a></li> +<li class="toctree-l3"><a class="reference internal" href="#testing">Testing</a></li> +<li class="toctree-l3"><a class="reference internal" href="#quickstart">QuickStart</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#tips">Tips</a></li> +<li class="toctree-l4"><a class="reference internal" href="#penalties">Penalties</a></li> +<li class="toctree-l4"><a class="reference internal" href="#submitting-the-assigment">Submitting the assigment</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#resources">Resources</a></li> +<li class="toctree-l3"><a class="reference internal" href="#questions">Questions</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">Assignment 3 - Software RAID</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/assign3-software-raid.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="assignment-3-software-raid"> +<h1>Assignment 3 - Software RAID<a class="headerlink" href="#assignment-3-software-raid" title="Permalink to this headline">¶</a></h1> +<ul class="simple"> +<li>Deadline: <strong class="command">Thursday, 16 May 2024, 23:59</strong></li> +</ul> +<p>Implementing a software RAID module that uses a logical block device that will read and write data from two physical devices, +ensuring the consistency and synchronization of data from the two physical devices. The type of RAID implemented will be similar to a <cite>RAID 1</cite>.</p> +<div class="section" id="assignment-s-objectives"> +<h2>Assignment's Objectives<a class="headerlink" href="#assignment-s-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>in-depth understanding of how the I/O subsystem works.</li> +<li>acquire advanced skills working with <cite>bio</cite> structures.</li> +<li>work with the block / disk devices in the Linux kernel.</li> +<li>acquire skills to navigate and understand the code and API dedicated to the I/O subsystem in Linux.</li> +</ul> +</div> +<div class="section" id="statement"> +<h2>Statement<a class="headerlink" href="#statement" title="Permalink to this headline">¶</a></h2> +<p>Write a kernel module that implements the RAID software functionality. <a class="reference external" href="https://en.wikipedia.org/wiki/RAID#Software-based_RAID">Software RAID</a> provides an abstraction between +the logical device and the physical devices. The implementation will use <a class="reference external" href="https://en.wikipedia.org/wiki/RAID#Standard_levels">RAID scheme 1</a>.</p> +<p>The virtual machine has two hard disks that will represent the physical devices: <cite>/dev/vdb</cite> and <cite>/dev/vdc</cite>. The operating system +will provide a logical device (block type) that will interface the access from the user space. Writing requests to the logical device +will result in two writes, one for each hard disk. Hard disks are not partitioned. It will be considered that each hard disk has a +single partition that covers the entire disk.</p> +<p>Each partition will store a sector along with an associated checksum (CRC32) to ensure error recovery. At each reading, the related +information from both partitions is read. If a sector of the first partition has corrupt data (CRC value is wrong) then the sector +on the second partition will be read; at the same time the sector of the first partition will be corrected. Similar in the case of +a reading of a corrupt sector on the second partition. If a sector has incorrect CRC values on both partitions, an appropriate error +code will be returned.</p> +<div class="section" id="important-to-know"> +<h3>Important to know<a class="headerlink" href="#important-to-know" title="Permalink to this headline">¶</a></h3> +<p>To ensure error recovery, a CRC code is associated with each sector. CRC codes are stored by LOGICAL_DISK_SIZE byte of the partition +(macro defined in the assignment <a class="reference external" href="https://gitlab.cs.pub.ro/so2/3-raid/-/blob/master/src/ssr.h">header</a>). The disk structure will have the following layout:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">+-----------+-----------+-----------+ +---+---+---+</span> +<span class="go">| sector1 | sector2 | sector3 |.....|C1 |C2 |C3 |</span> +<span class="go">+-----------+-----------+-----------+ +---+---+---+</span> +</pre></div> +</div> +<p>where <code class="docutils literal"><span class="pre">C1</span></code>, <code class="docutils literal"><span class="pre">C2</span></code>, <code class="docutils literal"><span class="pre">C3</span></code> are the values CRC sectors <code class="docutils literal"><span class="pre">sector1</span></code>, <code class="docutils literal"><span class="pre">sector2</span></code>, <code class="docutils literal"><span class="pre">sector3</span></code>. The CRC area is found immediately after the <code class="docutils literal"><span class="pre">LOGICAL_DISK_SIZE</span></code> bytes of the partition.</p> +<p>As a seed for CRC use 0(zero).</p> +</div> +</div> +<div class="section" id="implementation-details"> +<h2>Implementation Details<a class="headerlink" href="#implementation-details" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>the kernel module will be named <code class="docutils literal"><span class="pre">ssr.ko</span></code></li> +<li>the logical device will be accessed as a block device with the major <code class="docutils literal"><span class="pre">SSR_MAJOR</span></code> and minor <code class="docutils literal"><span class="pre">SSR_FIRST_MINOR</span></code> under the name <code class="docutils literal"><span class="pre">/dev/ssr</span></code> (via the macro <code class="docutils literal"><span class="pre">LOGICAL_DISK_NAME</span></code>)</li> +<li>the virtual device (<code class="docutils literal"><span class="pre">LOGICAL_DISK_NAME</span></code> - <code class="docutils literal"><span class="pre">/dev/ssr</span></code>) will have the capacity of <code class="docutils literal"><span class="pre">LOGICAL_DISK_SECTORS</span></code> (use <code class="docutils literal"><span class="pre">set_capacity</span></code> with the <code class="docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> structure)</li> +<li>the two disks are represented by the devices <code class="docutils literal"><span class="pre">/dev/vdb</span></code>, respectively <code class="docutils literal"><span class="pre">/dev/vdc</span></code>, defined by means of macros <code class="docutils literal"><span class="pre">PHYSICAL_DISK1_NAME</span></code>, respectively <code class="docutils literal"><span class="pre">PHYSICAL_DISK2_NAME</span></code></li> +<li>to work with the <code class="docutils literal"><span class="pre">struct</span> <span class="pre">block</span> <span class="pre">_device</span></code> structure associated with a physical device, you can use the <code class="docutils literal"><span class="pre">blkdev_get_by_path</span></code> and <code class="docutils literal"><span class="pre">blkdev_put</span></code> functions</li> +<li>for the handling of requests from the user space, we recommend not to use a <code class="docutils literal"><span class="pre">request_queue</span></code>, but to do processing at <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> level +using the <code class="docutils literal"><span class="pre">submit_bio</span></code> field of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">block_device_operations</span></code></li> +<li>since data sectors are separated from CRC sectors you will have to build separate <code class="docutils literal"><span class="pre">bio</span></code> structures for data and CRC values</li> +<li>to allocate a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> for physical disks you can use <code class="xref c c-func docutils literal"><span class="pre">bio_alloc()</span></code>; to add data pages to bio use <code class="xref c c-func docutils literal"><span class="pre">alloc_page()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">bio_add_page()</span></code></li> +<li>to free up the space allocated for a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> you need to release the pages allocated to the bio (using the <code class="xref c c-func docutils literal"><span class="pre">__free_page()</span></code> macro ) and call +<code class="xref c c-func docutils literal"><span class="pre">bio_put()</span></code></li> +<li>when generating a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure, consider that its size must be multiple of the disk sector size (<code class="docutils literal"><span class="pre">KERNEL_SECTOR_SIZE</span></code>)</li> +<li>to send a request to a block device and wait for it to end, you can use the <code class="xref c c-func docutils literal"><span class="pre">submit_bio_wait()</span></code> function</li> +<li>use <code class="xref c c-func docutils literal"><span class="pre">bio_endio()</span></code> to signal the completion of processing a <code class="docutils literal"><span class="pre">bio</span></code> structure</li> +<li>for the CRC32 calculation you can use the <code class="xref c c-func docutils literal"><span class="pre">crc32()</span></code> macro provided by the kernel</li> +<li>useful macro definitions can be found in the assignment support <a class="reference external" href="https://gitlab.cs.pub.ro/so2/3-raid/-/blob/master/src/ssr.h">header</a></li> +<li>a single request processing function for block devices can be active at one time in a call stack (more details <a class="reference external" href="https://elixir.bootlin.com/linux/v5.10/source/block/blk-core.c#L1048">here</a>). +You will need to submit requests for physical devices in a kernel thread; we recommend using <code class="docutils literal"><span class="pre">workqueues</span></code>.</li> +<li>For a quick run, use a single bio to batch send the read/write request for CRC values for adjacent sectors. For example, +if you need to send requests for CRCs in sectors 0, 1, ..., 7, use a single bio, not 8 bios.</li> +<li>our recommendations are not mandatory (any solution that meets the requirements of the assignment is accepted)</li> +</ul> +</div> +<div class="section" id="testing"> +<h2>Testing<a class="headerlink" href="#testing" title="Permalink to this headline">¶</a></h2> +<p>In order to simplify the assignment evaluation process, but also to reduce the mistakes of the submitted assignments, +the assignment evaluation will be done automatically with the help of a +<a class="reference external" href="https://gitlab.cs.pub.ro/so2/3-raid/-/blob/master/checker/3-raid-checker/_checker">test script</a> called <cite>_checker</cite>. +The test script assumes that the kernel module is called <cite>ssr.ko</cite>.</p> +<p>If, as a result of the testing process, the sectors on both disks contain invalid data, resulting in +read errors that make the module impossible to use, you will need to redo the two disks in the +virtual machine using the commands:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> dd <span class="k">if</span><span class="o">=</span>/dev/zero <span class="nv">of</span><span class="o">=</span>/dev/vdb <span class="nv">bs</span><span class="o">=</span>1M +<span class="gp">$</span> dd <span class="k">if</span><span class="o">=</span>/dev/zero <span class="nv">of</span><span class="o">=</span>/dev/vdc <span class="nv">bs</span><span class="o">=</span>1M +</pre></div> +</div> +<p>You can also get the same result using the following command to start the virtual machine:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> rm disk<span class="o">{</span><span class="m">1</span>,2<span class="o">}</span>.img<span class="p">;</span> make console <span class="c1"># or rm disk{1,2}.img; make boot</span> +</pre></div> +</div> +</div> +<div class="section" id="quickstart"> +<h2>QuickStart<a class="headerlink" href="#quickstart" title="Permalink to this headline">¶</a></h2> +<p>It is mandatory to start the implementation of the assignment from the code skeleton found in the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/3-raid/-/tree/master/src">src</a> directory. +There is only one header in the skeleton called <a class="reference external" href="https://gitlab.cs.pub.ro/so2/3-raid/-/blob/master/src/ssr.h">ssr.h</a>. +You will provide the rest of the implementation. You can add as many <cite>*.c`</cite> sources and additional <cite>*.h`</cite> headers. +You should also provide a Kbuild file that will compile the kernel module called <cite>ssr.ko</cite>. +Follow the instructions in the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/3-raid/-/blob/master/README.md">README.md file</a> of the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/3-raid">assignment's repo</a>.</p> +<div class="section" id="tips"> +<h3>Tips<a class="headerlink" href="#tips" title="Permalink to this headline">¶</a></h3> +<p>To increase your chances of getting the highest grade, read and follow the Linux kernel +coding style described in the <a class="reference external" href="https://elixir.bootlin.com/linux/v4.19.19/source/Documentation/process/coding-style.rst">Coding Style document</a>.</p> +<p>Also, use the following static analysis tools to verify the code:</p> +<ul class="simple"> +<li>checkpatch.pl</li> +</ul> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> linux/scripts/checkpatch.pl --no-tree --terse -f /path/to/your/file.c +</pre></div> +</div> +<ul class="simple"> +<li>sparse</li> +</ul> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> sudo apt-get install sparse +<span class="gp">$</span> <span class="nb">cd</span> linux +<span class="gp">$</span> make <span class="nv">C</span><span class="o">=</span><span class="m">2</span> /path/to/your/file.c +</pre></div> +</div> +<ul class="simple"> +<li>cppcheck</li> +</ul> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> sudo apt-get install cppcheck +<span class="gp">$</span> cppcheck /path/to/your/file.c +</pre></div> +</div> +</div> +<div class="section" id="penalties"> +<h3>Penalties<a class="headerlink" href="#penalties" title="Permalink to this headline">¶</a></h3> +<p>Information about assigments penalties can be found on the +<a class="reference external" href="https://ocw.cs.pub.ro/courses/so2/teme/general">General Directions page</a>.</p> +<p>In exceptional cases (the assigment passes the tests by not complying with the requirements) +and if the assigment does not pass all the tests, the grade will may decrease more than mentioned above.</p> +</div> +<div class="section" id="submitting-the-assigment"> +<h3>Submitting the assigment<a class="headerlink" href="#submitting-the-assigment" title="Permalink to this headline">¶</a></h3> +<p>The assignment will be graded automatically using the <a class="reference external" href="https://github.com/systems-cs-pub-ro/vmchecker-next/wiki/Student-Handbook">vmchecker-next</a> infrastructure. +The submission will be made on moodle on the <a class="reference external" href="https://curs.upb.ro/2022/course/view.php?id=5121">course's page</a> to the related assignment. +You will find the submission details in the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/3-raid/-/blob/master/README.md">README.md file</a> of the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/3-raid">repo</a>.</p> +</div> +</div> +<div class="section" id="resources"> +<h2>Resources<a class="headerlink" href="#resources" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>implementation of the <a class="reference external" href="https://elixir.bootlin.com/linux/v5.10/source/drivers/md">RAID</a> software in the Linux kernel</li> +</ul> +<p>We recommend that you use gitlab to store your homework. Follow the directions in +<a class="reference external" href="https://gitlab.cs.pub.ro/so2/3-raid/-/blob/master/README.md">README</a>.</p> +</div> +<div class="section" id="questions"> +<h2>Questions<a class="headerlink" href="#questions" title="Permalink to this headline">¶</a></h2> +<p>For questions about the topic, you can consult the mailing <a class="reference external" href="http://cursuri.cs.pub.ro/pipermail/so2/">list archives</a> +or you can write a question on the dedicated Teams channel.</p> +<p>Before you ask a question, make sure that:</p> +<blockquote> +<div><ul class="simple"> +<li>you have read the statement of the assigment well</li> +<li>the question is not already presented on the <a class="reference external" href="https://ocw.cs.pub.ro/courses/so2/teme/tema2/faq">FAQ page</a></li> +<li>the answer cannot be found in the <a class="reference external" href="http://cursuri.cs.pub.ro/pipermail/so2/">mailing list archives</a></li> +</ul> +</div></blockquote> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="assign2-driver-uart.html" class="btn btn-neutral float-left" title="Assignment 2 - Driver UART" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="assign4-transport-protocol.html" class="btn btn-neutral float-right" title="Assignment 4 - SO2 Transport Protocol" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/assign4-transport-protocol.html b/refs/pull/405/merge/so2/assign4-transport-protocol.html new file mode 100644 index 00000000..da41dc61 --- /dev/null +++ b/refs/pull/405/merge/so2/assign4-transport-protocol.html @@ -0,0 +1,438 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Assignment 4 - SO2 Transport Protocol — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Assignment 7 - SO2 Virtual Machine Manager with KVM" href="assign7-kvm-vmm.html" /> + <link rel="prev" title="Assignment 3 - Software RAID" href="assign3-software-raid.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Assignment 4 - SO2 Transport Protocol</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#assignment-s-objectives">Assignment's Objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#statement">Statement</a></li> +<li class="toctree-l3"><a class="reference internal" href="#implementation-details">Implementation Details</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#sample-protocol-implementations">Sample Protocol Implementations</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#testing">Testing</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#tcpdump">tcpdump</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#quickstart">QuickStart</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#tips">Tips</a></li> +<li class="toctree-l4"><a class="reference internal" href="#penalties">Penalties</a></li> +<li class="toctree-l4"><a class="reference internal" href="#submitting-the-assigment">Submitting the assigment</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#resources">Resources</a></li> +<li class="toctree-l3"><a class="reference internal" href="#questions">Questions</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">Assignment 4 - SO2 Transport Protocol</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/assign4-transport-protocol.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="assignment-4-so2-transport-protocol"> +<h1>Assignment 4 - SO2 Transport Protocol<a class="headerlink" href="#assignment-4-so2-transport-protocol" title="Permalink to this headline">¶</a></h1> +<ul class="simple"> +<li>Deadline: <strong class="command">Monday, 29 May 2023, 23:00</strong></li> +<li>This assignment can be made in teams (max 2). Only one of them must submit the assignment, and the names of the student should be listed in a README file.</li> +</ul> +<p>Implement a simple datagram transport protocol - STP (<em>SO2 Transport Protocol</em>).</p> +<div class="section" id="assignment-s-objectives"> +<h2>Assignment's Objectives<a class="headerlink" href="#assignment-s-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>gaining knowledge about the operation of the networking subsystem in the Linux kernel</li> +<li>obtaining skills to work with the basic structures of the networking subsystem in Linux</li> +<li>deepening the notions related to communication and networking protocols by implementing a protocol in an existing protocol stack</li> +</ul> +</div> +<div class="section" id="statement"> +<h2>Statement<a class="headerlink" href="#statement" title="Permalink to this headline">¶</a></h2> +<p>Implement, in the Linux kernel, a protocol called STP (<em>SO2 Transport Protocol</em>), at network and transport level, that works using datagrams (it is not connection-oriented and does not use flow-control elements).</p> +<p>The STP protocol acts as a Transport layer protocol (port-based multiplexing) but operates at level 3 (Network) of <a class="reference external" href="http://en.wikipedia.org/wiki/OSI_model">the OSI stack</a>, above the Data Link level.</p> +<p>The STP header is defined by the <code class="docutils literal"><span class="pre">struct</span> <span class="pre">stp_header</span></code> structure:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">stp_header</span> <span class="p">{</span> + <span class="n">__be16</span> <span class="n">dst</span><span class="p">;</span> + <span class="n">__be16</span> <span class="n">src</span><span class="p">;</span> + <span class="n">__be16</span> <span class="n">len</span><span class="p">;</span> + <span class="n">__u8</span> <span class="n">flags</span><span class="p">;</span> + <span class="n">__u8</span> <span class="n">csum</span><span class="p">;</span> +<span class="p">};</span> +</pre></div> +</div> +<p>where:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">len</span></code> is the length of the packet in bytes (including the header);</li> +<li><code class="docutils literal"><span class="pre">dst</span></code> and <code class="docutils literal"><span class="pre">src</span></code> are the destination and source ports, respectively;</li> +<li><code class="docutils literal"><span class="pre">flags</span></code> contains various flags, currently unused (marked <em>reserved</em>);</li> +<li><code class="docutils literal"><span class="pre">csum</span></code> is the checksum of the entire package including the header; the checksum is calculated by exclusive OR (XOR) between all bytes.</li> +</ul> +</div></blockquote> +<p>Sockets using this protocol will use the <code class="docutils literal"><span class="pre">AF_STP</span></code> family.</p> +<p>The protocol must work directly over Ethernet. The ports used are between <code class="docutils literal"><span class="pre">1</span></code> and <code class="docutils literal"><span class="pre">65535</span></code>. Port <code class="docutils literal"><span class="pre">0</span></code> is not used.</p> +<p>The definition of STP-related structures and macros can be found in the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/4-stp/-/blob/master/src/stp.h">assignment support header</a>.</p> +</div> +<div class="section" id="implementation-details"> +<h2>Implementation Details<a class="headerlink" href="#implementation-details" title="Permalink to this headline">¶</a></h2> +<p>The kernel module will be named <strong>af_stp.ko</strong>.</p> +<p>You have to define a structure of type <a class="reference external" href="http://elixir.free-electrons.com/linux/v5.10/source/include/linux/net.h#L211">net_proto_family</a>, which provides the operation to create STP sockets. +Newly created sockets are not associated with any port or interface and cannot receive / send packets. +You must initialize the <a class="reference external" href="http://elixir.free-electrons.com/linux/v5.10/source/include/linux/net.h#L125">socket ops field</a> with the list of operations specific to the STP family. +This field refers to a structure <a class="reference external" href="http://elixir.free-electrons.com/linux/v5.10/source/include/linux/net.h#L139">proto_ops</a> which must include the following functions:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">release</span></code>: releases an STP socket</li> +<li><code class="docutils literal"><span class="pre">bind</span></code>: associates a socket with a port (possibly also an interface) on which packets will be received / sent:<ul> +<li>there may be bind sockets only on one port (not on an interface)</li> +<li>sockets associated with only one port will be able to receive packets sent to that port on all interfaces (analogous to UDP sockets associated with only one port); these sockets cannot send packets because the interface from which they can be sent via the standard sockets API cannot be specified</li> +<li>two sockets cannot be binded to the same port-interface combination:<ul> +<li>if there is a socket already binded with a port and an interface then a second socket cannot be binded to the same port and the same interface or without a specified interface</li> +<li>if there is a socket already binded to a port but without a specified interface then a second socket cannot be binded to the same port (with or without a specified interface)</li> +</ul> +</li> +<li>we recommend using a hash table for bind instead of other data structures (list, array); in the kernel there is a hash table implementation in the <a class="reference external" href="http://elixir.free-electrons.com/linux/v4.9.11/source/include/linux/hashtable.h">hashtable.h header</a></li> +</ul> +</li> +<li><code class="docutils literal"><span class="pre">connect</span></code>: associates a socket with a remote port and hardware address (MAC address) to which packets will be sent / received:<ul> +<li>this should allow <code class="docutils literal"><span class="pre">send</span></code> / <code class="docutils literal"><span class="pre">recv</span></code> operations on the socket instead of <code class="docutils literal"><span class="pre">sendmsg</span></code> / <code class="docutils literal"><span class="pre">recvmsg</span></code> or <code class="docutils literal"><span class="pre">sendto</span></code> / <code class="docutils literal"><span class="pre">recvfrom</span></code></li> +<li>once connected to a host, sockets will only accept packets from that host</li> +<li>once connected, the sockets can no longer be disconnected</li> +</ul> +</li> +<li><code class="docutils literal"><span class="pre">sendmsg</span></code>, <code class="docutils literal"><span class="pre">recvmsg</span></code>: send or receive a datagram on an STP socket:<ul> +<li>for the <em>receive</em> part, metainformation about the host that sent the packet can be stored in the <a class="reference external" href="http://elixir.free-electrons.com/linux/v5.10/source/include/linux/skbuff.h#L742">cb field in sk_buff</a></li> +</ul> +</li> +<li><code class="docutils literal"><span class="pre">poll</span></code>: the default function <code class="docutils literal"><span class="pre">datagram_poll</span></code> will have to be used</li> +<li>for the rest of the operations the predefined stubs in the kernel will have to be used (<code class="docutils literal"><span class="pre">sock_no_*</span></code>)</li> +</ul> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">proto_ops</span> <span class="n">stp_ops</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">family</span> <span class="o">=</span> <span class="n">PF_STP</span><span class="p">,</span> + <span class="p">.</span><span class="n">owner</span> <span class="o">=</span> <span class="n">THIS_MODULE</span><span class="p">,</span> + <span class="p">.</span><span class="n">release</span> <span class="o">=</span> <span class="n">stp_release</span><span class="p">,</span> + <span class="p">.</span><span class="n">bind</span> <span class="o">=</span> <span class="n">stp_bind</span><span class="p">,</span> + <span class="p">.</span><span class="n">connect</span> <span class="o">=</span> <span class="n">stp_connect</span><span class="p">,</span> + <span class="p">.</span><span class="n">socketpair</span> <span class="o">=</span> <span class="n">sock_no_socketpair</span><span class="p">,</span> + <span class="p">.</span><span class="n">accept</span> <span class="o">=</span> <span class="n">sock_no_accept</span><span class="p">,</span> + <span class="p">.</span><span class="n">getname</span> <span class="o">=</span> <span class="n">sock_no_getname</span><span class="p">,</span> + <span class="p">.</span><span class="n">poll</span> <span class="o">=</span> <span class="n">datagram_poll</span><span class="p">,</span> + <span class="p">.</span><span class="n">ioctl</span> <span class="o">=</span> <span class="n">sock_no_ioctl</span><span class="p">,</span> + <span class="p">.</span><span class="n">listen</span> <span class="o">=</span> <span class="n">sock_no_listen</span><span class="p">,</span> + <span class="p">.</span><span class="n">shutdown</span> <span class="o">=</span> <span class="n">sock_no_shutdown</span><span class="p">,</span> + <span class="p">.</span><span class="n">setsockopt</span> <span class="o">=</span> <span class="n">sock_no_setsockopt</span><span class="p">,</span> + <span class="p">.</span><span class="n">getsockopt</span> <span class="o">=</span> <span class="n">sock_no_getsockopt</span><span class="p">,</span> + <span class="p">.</span><span class="n">sendmsg</span> <span class="o">=</span> <span class="n">stp_sendmsg</span><span class="p">,</span> + <span class="p">.</span><span class="n">recvmsg</span> <span class="o">=</span> <span class="n">stp_recvmsg</span><span class="p">,</span> + <span class="p">.</span><span class="n">mmap</span> <span class="o">=</span> <span class="n">sock_no_mmap</span><span class="p">,</span> + <span class="p">.</span><span class="n">sendpage</span> <span class="o">=</span> <span class="n">sock_no_sendpage</span><span class="p">,</span> +<span class="p">};</span> +</pre></div> +</div> +<p>Socket operations use a type of address called <code class="docutils literal"><span class="pre">sockaddr_stp</span></code>, a type defined in the <a class="reference external" href="https://github.com/linux-kernel-labs/linux/blob/master/tools/labs/templates/assignments/4-stp/stp.h">assignment support header</a>. +For the <em>bind</em> operation, only the port and the index of the interface on which the socket is bind will be considered. +For the <em>receive</em> operation, only the <code class="docutils literal"><span class="pre">addr</span></code> and <code class="docutils literal"><span class="pre">port</span></code> fields in the structure will be filled in with the MAC address of the host that sent the packet and with the port from which it was sent. +Also, when sending a packet, the destination host will be obtained from the <code class="docutils literal"><span class="pre">addr</span></code> and <code class="docutils literal"><span class="pre">port</span></code> fields of this structure.</p> +<p>You need to register a structure <a class="reference external" href="http://elixir.free-electrons.com/linux/v5.10/source/include/linux/netdevice.h#L2501">packet_type</a>, using the call <a class="reference external" href="http://elixir.free-electrons.com/linux/v5.10/source/net/core/dev.c#L521">dev_add_pack</a> to be able to receive STP packets from the network layer.</p> +<p>The protocol will need to provide an interface through the <em>procfs</em> file system for statistics on sent / received packets. +The file must be named <code class="docutils literal"><span class="pre">/proc/net/stp_stats</span></code>, specified by the <code class="docutils literal"><span class="pre">STP_PROC_FULL_FILENAME</span></code> macro in <a class="reference external" href="https://gitlab.cs.pub.ro/so2/4-stp/-/blob/master/src/stp.h">assignment support header</a>. +The format must be of simple table type with <code class="docutils literal"><span class="pre">2</span></code> rows: on the first row the header of the table, and on the second row the statistics corresponding to the columns. +The columns of the table must be in order:</p> +<div class="code highlight-none"><div class="highlight"><pre><span></span>RxPkts HdrErr CsumErr NoSock NoBuffs TxPkts +</pre></div> +</div> +<p>where:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">RxPkts</span></code> - the number of packets received</li> +<li><code class="docutils literal"><span class="pre">HdrErr</span></code> - the number of packets received with header errors (packets too short or with source or destination 0 ports)</li> +<li><code class="docutils literal"><span class="pre">CsumErr</span></code> - the number of packets received with checksum errors</li> +<li><code class="docutils literal"><span class="pre">NoSock</span></code> - the number of received packets for which no destination socket was found</li> +<li><code class="docutils literal"><span class="pre">NoBuffs</span></code> - the number of received packets that could not be received because the socket queue was full</li> +<li><code class="docutils literal"><span class="pre">TxPkts</span></code> - the number of packets sent</li> +</ul> +<p>To create or delete the entry specified by <code class="docutils literal"><span class="pre">STP_PROC_FULL_FILENAME</span></code> we recommend using the functions <a class="reference external" href="http://elixir.free-electrons.com/linux/v5.10/source/include/linux/proc_fs.h#L108">proc_create</a> and <a class="reference external" href="http://elixir.free-electrons.com/linux/v5.10/source/fs/proc/generic.c#L772">proc_remove</a>.</p> +<div class="section" id="sample-protocol-implementations"> +<h3>Sample Protocol Implementations<a class="headerlink" href="#sample-protocol-implementations" title="Permalink to this headline">¶</a></h3> +<p>For examples of protocol implementation, we recommend the implementation of <a class="reference external" href="http://elixir.free-electrons.com/linux/v5.10/source/net/packet/af_packet.c">PF_PACKET</a> sockets and the various functions in <a class="reference external" href="http://elixir.free-electrons.com/linux/v5.10/source/net/ipv4/udp.c">UDP implementation</a> or <a class="reference external" href="http://elixir.free-electrons.com/linux/v5.10/source/net/ipv4/af_inet.c">IP implementation</a>.</p> +</div> +</div> +<div class="section" id="testing"> +<h2>Testing<a class="headerlink" href="#testing" title="Permalink to this headline">¶</a></h2> +<p>In order to simplify the assignment evaluation process, but also to reduce the mistakes of the submitted assignments, +the assignment evaluation will be done automatically with the help of a +<a class="reference external" href="https://gitlab.cs.pub.ro/so2/3-raid/-/blob/master/checker/4-stp-checker/_checker">test script</a> called <cite>_checker</cite>. +The test script assumes that the kernel module is called <cite>af_stp.ko</cite>.</p> +<div class="section" id="tcpdump"> +<h3>tcpdump<a class="headerlink" href="#tcpdump" title="Permalink to this headline">¶</a></h3> +<p>You can use the <code class="docutils literal"><span class="pre">tcpdump</span></code> utility to troubleshoot sent packets. +The tests use the loopback interface; to track sent packets you can use a command line of the form:</p> +<div class="code console highlight-none"><div class="highlight"><pre><span></span>tcpdump -i lo -XX +</pre></div> +</div> +<p>You can use a static version of <a class="reference external" href="http://elf.cs.pub.ro/so2/res/teme/tcpdump">tcpdump</a>. +To add to the <code class="docutils literal"><span class="pre">PATH</span></code> environment variable in the virtual machine, copy this file to <code class="docutils literal"><span class="pre">/linux/tools/labs/rootfs/bin</span></code>. +Create the directory if it does not exist. Remember to give the <code class="docutils literal"><span class="pre">tcpdump</span></code> file execution permissions:</p> +<div class="code console highlight-none"><div class="highlight"><pre><span></span># Connect to the docker using ./local.sh docker interactive +cd /linux/tools/labs/rootfs/bin +wget http://elf.cs.pub.ro/so2/res/teme/tcpdump +chmod +x tcpdump +</pre></div> +</div> +</div> +</div> +<div class="section" id="quickstart"> +<h2>QuickStart<a class="headerlink" href="#quickstart" title="Permalink to this headline">¶</a></h2> +<p>It is mandatory to start the implementation of the assignment from the code skeleton found in the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/4-stp/-/tree/master/src">src</a> directory. +There is only one header in the skeleton called <a class="reference external" href="https://gitlab.cs.pub.ro/so2/4-stp/-/blob/master/src/stp.h">stp.h</a>. +You will provide the rest of the implementation. You can add as many <cite>*.c`</cite> sources and additional <cite>*.h`</cite> headers. +You should also provide a Kbuild file that will compile the kernel module called <cite>af_stp.ko</cite>. +Follow the instructions in the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/4-stp/-/blob/master/README.md">README.md file</a> of the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/4-stp">assignment's repo</a>.</p> +<div class="section" id="tips"> +<h3>Tips<a class="headerlink" href="#tips" title="Permalink to this headline">¶</a></h3> +<p>To increase your chances of getting the highest grade, read and follow the Linux kernel coding style described in the <a class="reference external" href="https://elixir.bootlin.com/linux/v5.10/source/Documentation/process/coding-style.rst">Coding Style document</a>.</p> +<p>Also, use the following static analysis tools to verify the code:</p> +<ul> +<li><p class="first">checkpatch.pl</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> linux/scripts/checkpatch.pl --no-tree --terse -f /path/to/your/file.c +</pre></div> +</div> +</li> +<li><p class="first">sparse</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> sudo apt-get install sparse +<span class="gp">$</span> <span class="nb">cd</span> linux +<span class="gp">$</span> make <span class="nv">C</span><span class="o">=</span><span class="m">2</span> /path/to/your/file.c +</pre></div> +</div> +</li> +<li><p class="first">cppcheck</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> sudo apt-get install cppcheck +<span class="gp">$</span> cppcheck /path/to/your/file.c +</pre></div> +</div> +</li> +</ul> +</div> +<div class="section" id="penalties"> +<h3>Penalties<a class="headerlink" href="#penalties" title="Permalink to this headline">¶</a></h3> +<p>Information about assigments penalties can be found on the <a class="reference external" href="https://ocw.cs.pub.ro/courses/so2/teme/general">General Directions page</a>.</p> +<p>In exceptional cases (the assigment passes the tests by not complying with the requirements) and if the assigment does not pass all the tests, the grade will may decrease more than mentioned above.</p> +</div> +<div class="section" id="submitting-the-assigment"> +<h3>Submitting the assigment<a class="headerlink" href="#submitting-the-assigment" title="Permalink to this headline">¶</a></h3> +<p>The assignment will be graded automatically using the <a class="reference external" href="https://github.com/systems-cs-pub-ro/vmchecker-next/wiki/Student-Handbook">vmchecker-next</a> infrastructure. +The submission will be made on moodle on the <a class="reference external" href="https://curs.upb.ro/2022/course/view.php?id=5121">course's page</a> to the related assignment. +You will find the submission details in the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/4-stp/-/blob/master/README.md">README.md file</a> of the <a class="reference external" href="https://gitlab.cs.pub.ro/so2/4-stp">repo</a>.</p> +</div> +</div> +<div class="section" id="resources"> +<h2>Resources<a class="headerlink" href="#resources" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li><a class="reference external" href="https://linux-kernel-labs.github.io/refs/heads/master/so2/lec10-networking.html">Lecture 10 - Networking</a></li> +<li><a class="reference external" href="https://linux-kernel-labs.github.io/refs/heads/master/so2/lab10-networking.html">Lab 10 - Networking</a></li> +<li>Linux kernel sources<ul> +<li><a class="reference external" href="http://elixir.free-electrons.com/linux/v5.10/source/net/packet/af_packet.c">Implementing PF_PACKET sockets</a></li> +<li><a class="reference external" href="http://elixir.free-electrons.com/linux/v5.10/source/net/ipv4/udp.c">Implementation of the UDP protocol</a></li> +<li><a class="reference external" href="http://elixir.free-electrons.com/linux/v5.10/source/net/ipv4/af_inet.c">Implementation of the IP protocol</a></li> +</ul> +</li> +<li>Understanding Linux Network Internals<ul> +<li>chapters 8-13</li> +</ul> +</li> +<li><a class="reference external" href="https://gitlab.cs.pub.ro/so2/4-stp/-/blob/master/src/stp.h">assignment support header</a></li> +</ul> +<p>We recommend that you use gitlab to store your homework. Follow the directions in <a class="reference external" href="https://gitlab.cs.pub.ro/so2/4-stp/-/blob/master/README.md">README</a>.</p> +</div> +<div class="section" id="questions"> +<h2>Questions<a class="headerlink" href="#questions" title="Permalink to this headline">¶</a></h2> +<p>For questions about the topic, you can consult the mailing <a class="reference external" href="http://cursuri.cs.pub.ro/pipermail/so2/">list archives</a> +or you can write a question on the dedicated Teams channel.</p> +<p>Before you ask a question, make sure that:</p> +<blockquote> +<div><ul class="simple"> +<li>you have read the statement of the assigment well</li> +<li>the question is not already presented on the <a class="reference external" href="https://ocw.cs.pub.ro/courses/so2/teme/tema2/faq">FAQ page</a></li> +<li>the answer cannot be found in the <a class="reference external" href="http://cursuri.cs.pub.ro/pipermail/so2/">mailing list archives</a></li> +</ul> +</div></blockquote> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="assign3-software-raid.html" class="btn btn-neutral float-left" title="Assignment 3 - Software RAID" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="assign7-kvm-vmm.html" class="btn btn-neutral float-right" title="Assignment 7 - SO2 Virtual Machine Manager with KVM" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/assign5-pitix.html b/refs/pull/405/merge/so2/assign5-pitix.html new file mode 100644 index 00000000..471d5f5a --- /dev/null +++ b/refs/pull/405/merge/so2/assign5-pitix.html @@ -0,0 +1,354 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Assignment 5 - PITIX Filesystem — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Assignment 5 - PITIX Filesystem</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/assign5-pitix.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="assignment-5-pitix-filesystem"> +<h1>Assignment 5 - PITIX Filesystem<a class="headerlink" href="#assignment-5-pitix-filesystem" title="Permalink to this headline">¶</a></h1> +<p>Deadline: <strong class="command">Tuesday, 24 May 2022, 23:00</strong></p> +<div class="section" id="statement"> +<h2>Statement<a class="headerlink" href="#statement" title="Permalink to this headline">¶</a></h2> +<p>Write a kernel module to implement the <strong>PITIX</strong> file system, version 2. +This file system will only support files and directories. +Support operations for hard or symbolic links will not be implemented. +Also, support operations for special files (pipes, character devices, or blocks) will not be implemented. +Basically you need to implement the following:</p> +<blockquote> +<div><ul class="simple"> +<li>for directories: <code class="docutils literal"><span class="pre">lookup</span></code>, <code class="docutils literal"><span class="pre">unlink</span></code>, <code class="docutils literal"><span class="pre">mkdir</span></code>, <code class="docutils literal"><span class="pre">rmdir</span></code>, <code class="docutils literal"><span class="pre">iterate</span></code></li> +<li>for files: <code class="docutils literal"><span class="pre">create</span></code>, <code class="docutils literal"><span class="pre">truncate</span></code>, bitmap functions, see <a class="reference external" href="https://elixir.bootlin.com/linux/v4.15/source/fs/minix/inode.c#L375">minix_get_block</a>.</li> +</ul> +</div></blockquote> +<p>The rest of the functions either have generic kernel implementations, or you don't have to implement them.</p> +<p>The disk structure of the file system is:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">+--------------+-----------+-----------+------------+-----------------------+</span> +<span class="go">| | | | | |</span> +<span class="go">| superblock | imap | dmap | izone | dzone |</span> +<span class="go">+--------------+-----------+-----------+------------+-----------------------+</span> +<span class="go"> 4096 bytes 1 block 1 block 32 blocks 8*block_size blocks</span> +</pre></div> +</div> +<p>where:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">Superblock</span></code> is the superblock (<code class="docutils literal"><span class="pre">4096</span></code> bytes)</li> +<li><code class="docutils literal"><span class="pre">Imap</span></code> contains the bitmap of the blocks occupied by the inodes (<code class="docutils literal"><span class="pre">1</span></code> block)</li> +<li><code class="docutils literal"><span class="pre">Dmap</span></code> contains the bitmap of the blocks occupied by the data (<code class="docutils literal"><span class="pre">1</span></code> block)</li> +<li><code class="docutils literal"><span class="pre">Izone</span></code> contains inodes (<code class="docutils literal"><span class="pre">32</span></code> blocks)</li> +<li><code class="docutils literal"><span class="pre">Dzone</span></code> contains the data (the actual contents of the files) (<code class="docutils literal"><span class="pre">8</span> <span class="pre">*</span> <span class="pre">block_size</span></code> blocks)</li> +</ul> +<p>The superblock (<strong>on disk</strong>) is described by the following structure:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">pitix_super_block</span> <span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">magic</span><span class="p">;</span> + <span class="n">__u8</span> <span class="n">version</span><span class="p">;</span> + <span class="n">__u8</span> <span class="n">block_size_bits</span><span class="p">;</span> + <span class="n">__u8</span> <span class="n">imap_block</span><span class="p">;</span> + <span class="n">__u8</span> <span class="n">dmap_block</span><span class="p">;</span> + <span class="n">__u8</span> <span class="n">izone_block</span><span class="p">;</span> + <span class="n">__u8</span> <span class="n">dzone_block</span><span class="p">;</span> + <span class="n">__u16</span> <span class="n">bfree</span><span class="p">;</span> + <span class="n">__u16</span> <span class="n">ffree</span><span class="p">;</span> +<span class="p">};</span> +</pre></div> +</div> +<p>where:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">magic</span></code> must be initialized with <code class="docutils literal"><span class="pre">PITIX_MAGIC</span></code></li> +<li><code class="docutils literal"><span class="pre">version</span></code> must be initialized with <code class="docutils literal"><span class="pre">2</span></code> (<code class="docutils literal"><span class="pre">PITIX_VERSION</span></code>)</li> +<li><code class="docutils literal"><span class="pre">block_size_bits</span></code> is the block size of two; the block size can be <code class="docutils literal"><span class="pre">512</span></code>, <code class="docutils literal"><span class="pre">1024</span></code>, <code class="docutils literal"><span class="pre">2048</span></code>, or <code class="docutils literal"><span class="pre">4096</span></code></li> +<li><code class="docutils literal"><span class="pre">Imap_block</span></code> is the block number (relative to the device) to the bit vector used for the allocation / release sites inode</li> +<li><code class="docutils literal"><span class="pre">dmap_block</span></code> is the block number (relative to the device) for the bit vector used to allocate / release data blocks</li> +<li><code class="docutils literal"><span class="pre">izone_block</span></code> is the number of the first block (relative to the device) of the inode area</li> +<li><code class="docutils literal"><span class="pre">dzone_block</span></code> is the number of the first block (relative to the device) of the data area</li> +<li><code class="docutils literal"><span class="pre">bfree</span></code> is the number of free blocks (unallocated)</li> +<li><code class="docutils literal"><span class="pre">ffree</span></code> is the number of free (unallocated) inodes</li> +</ul> +<p>The inodes will be stored in the inode area and are described by the following structure:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">pitix_inode</span> <span class="p">{</span> + <span class="n">__u32</span> <span class="n">mode</span><span class="p">;</span> + <span class="kt">uid_t</span> <span class="n">uid</span><span class="p">;</span> + <span class="kt">gid_t</span> <span class="n">gid</span><span class="p">;</span> + <span class="n">__u32</span> <span class="n">size</span><span class="p">;</span> + <span class="n">__u32</span> <span class="n">time</span><span class="p">;</span> + <span class="n">__u16</span> <span class="n">direct_data_blocks</span> <span class="p">[</span><span class="n">INODE_DIRECT_DATA_BLOCKS</span><span class="p">];</span> + <span class="n">__u16</span> <span class="n">indirect_data_block</span><span class="p">;</span> +<span class="p">};</span> +</pre></div> +</div> +<p>where:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">mode</span></code> represents the access rights and inode type (file or directory) as represented in the kernel</li> +<li><code class="docutils literal"><span class="pre">uid</span></code> represents the UID as it is represented in the kernel</li> +<li><code class="docutils literal"><span class="pre">gid</span></code> represents the GID as it is represented in the kernel</li> +<li><code class="docutils literal"><span class="pre">size</span></code> is the size of the file / directory</li> +<li><code class="docutils literal"><span class="pre">time</span></code> represents the modification time as it is represented in the kernel</li> +<li><code class="docutils literal"><span class="pre">direct_data_blocks</span></code> is a vector (size <code class="docutils literal"><span class="pre">INODE_DIRECT_DATA_BLOCKS</span></code> ) that contains indexes of direct data blocks</li> +<li><code class="docutils literal"><span class="pre">indirect_data_block</span></code> is the index of a data block that contains the indexes of indirect data blocks</li> +</ul> +<p>The index of a data block (direct or indirect) indicates the number of that data block relative to the data area (<code class="docutils literal"><span class="pre">Dzone</span></code>). +The size of an index is <code class="docutils literal"><span class="pre">2</span></code> bytes.</p> +<p>As can be seen from its structure, the inode uses a simple routing scheme for data blocks. +Blocks in the range <code class="docutils literal"><span class="pre">[0,</span> <span class="pre">INODE_DIRECT_DATA_BLOCKS)</span></code> are blocks of direct data and are referenced by elements of the vector <code class="docutils literal"><span class="pre">direct_data_blocks</span></code> and blocks in the range <code class="docutils literal"><span class="pre">[INODE_DIRECT_DATA_BLOCKS,</span> <span class="pre">INODE_DIRECT_DATA_BL)</span></code> are indirect data blocks and are referred to by indices within the data block indicated by <code class="docutils literal"><span class="pre">indirect_data_block</span></code>.</p> +<p>The data block indicated by <code class="docutils literal"><span class="pre">indirect_data_block</span></code> must be allocated when we have to refer to a first block of indirect data and must be released when there are no more blocks of indirect data.</p> +<p>Unused indexes must be set to <code class="docutils literal"><span class="pre">0</span></code>. +The first block, the one with index <code class="docutils literal"><span class="pre">0</span></code>, is always allocated when formatting. This block cannot be used and, consequently, the value <code class="docutils literal"><span class="pre">0</span></code>:</p> +<ul class="simple"> +<li>in an element of the vector, <code class="docutils literal"><span class="pre">direct_data_blocks</span></code> means free slot (that element does not refer to a block of data directly)</li> +<li><code class="docutils literal"><span class="pre">indirect_data_block</span></code> means that no data block is allocated to keep track of indirect data blocks (when no indirect data blocks are needed)</li> +<li>an index within the data block referred to as <code class="docutils literal"><span class="pre">indirect_data_block</span></code> means free slot (that index does not refer to an indirect data block)</li> +</ul> +<p>It is guaranteed that the number of bytes occupied by an inode on the disk is a divisor of the block size.</p> +<p>Directories have associated a single block of data (referred to as <code class="docutils literal"><span class="pre">direct_data_block</span> <span class="pre">[0]</span></code>) in which directory entries will be stored. These are described by the following structure:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">pitix_dir_entry</span> <span class="p">{</span> + <span class="n">__u32</span> <span class="n">ino</span><span class="p">;</span> + <span class="kt">char</span> <span class="n">name</span> <span class="p">[</span><span class="n">PITIX_NAME_LEN</span><span class="p">];</span> +<span class="p">};</span> +</pre></div> +</div> +<p>where</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">inoi</span></code> is the inode number of the file or directory; this number is an index in the inode area</li> +<li><code class="docutils literal"><span class="pre">name</span></code> is the name of the file or directory; maximum name length is <code class="docutils literal"><span class="pre">16</span></code> bytes (<code class="docutils literal"><span class="pre">PITIX_NAME_LEN</span></code>); if the name length is less than 16 bytes, then the name will end with the ASCII character that has the code <code class="docutils literal"><span class="pre">0</span></code> (same as for strings)</li> +</ul> +<p>The root directory will be assigned inode <code class="docutils literal"><span class="pre">0</span></code> and data block <code class="docutils literal"><span class="pre">0</span></code>.</p> +<p>For simplicity, at <code class="docutils literal"><span class="pre">mkdir</span></code> it is not necessary to create the entries <code class="docutils literal"><span class="pre">.</span></code> (<em>dot</em>) and <code class="docutils literal"><span class="pre">..</span></code> (<em>dot dot</em>) in the new directory; the checker uses this assumption.</p> +<p>All numeric values are stored on disk in byte-order CPU.</p> +<p>In the <a href="#system-message-1"><span class="problematic" id="problematic-1">`assignment header <https://github.com/linux-kernel-labs/linux/blob/master/tools/labs/templates/assignments/5-pitix/pitix.h`__</span></a> you will find the structures described above together with useful macros and statements of the main functions to be implemented.</p> +<p>The kernel module will be named <code class="docutils literal"><span class="pre">pitix.ko</span></code>.</p> +</div> +<div class="section" id="testing"> +<h2>Testing<a class="headerlink" href="#testing" title="Permalink to this headline">¶</a></h2> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Enable <code class="docutils literal"><span class="pre">Loop</span> <span class="pre">Devices</span></code> support using <code class="docutils literal"><span class="pre">make</span> <span class="pre">menuconfig</span></code>. <code class="docutils literal"><span class="pre">Device</span> <span class="pre">drivers</span> <span class="pre">-></span> <span class="pre">Block</span> <span class="pre">devices</span> <span class="pre">-></span> <span class="pre">Loopback</span> <span class="pre">device</span> <span class="pre">support</span></code></p> +</div> +<p>In order to simplify the assignment evaluation process, but also to reduce the mistakes of the submitted assignments, the assignment evaluation will be done automatically with with the help of public tests that are in the new infrastructure.</p> +<p>For local testing, use the following commands:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> git clone https://github.com/linux-kernel-labs/linux.git +<span class="gp">$</span> <span class="nb">cd</span> linux/tools/labs +<span class="gp">$</span> <span class="nv">LABS</span><span class="o">=</span>assignments/5-pitix make skels +<span class="gp">$</span> <span class="c1">#the development of the assignment will be written in the 5-pitix directory</span> +<span class="gp">$</span> make build +<span class="gp">$</span> make copy +<span class="gp">$</span> make boot +</pre></div> +</div> +<p>Instructions for using the test suite can be found in the <code class="docutils literal"><span class="pre">README</span></code> file.</p> +<div class="section" id="tips"> +<h3>Tips<a class="headerlink" href="#tips" title="Permalink to this headline">¶</a></h3> +<p>To increase your chances of getting the highest grade, read and follow the Linux kernel coding style described in the <a class="reference external" href="https://elixir.bootlin.com/linux/v4.19.19/source/Documentation/process/coding-style.rst">Coding Style document</a>.</p> +<p>Also, use the following static analysis tools to verify the code:</p> +<ul class="simple"> +<li>checkpatch.pl</li> +</ul> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> linux/scripts/checkpatch.pl --no-tree --terse -f /path/to/your/file.c +</pre></div> +</div> +<ul class="simple"> +<li>sparse</li> +</ul> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> sudo apt-get install sparse +<span class="gp">$</span> <span class="nb">cd</span> linux +<span class="gp">$</span> make <span class="nv">C</span><span class="o">=</span><span class="m">2</span> /path/to/your/file.c +</pre></div> +</div> +<ul class="simple"> +<li>cppcheck</li> +</ul> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> sudo apt-get install cppcheck +<span class="gp">$</span> cppcheck /path/to/your/file.c +</pre></div> +</div> +</div> +<div class="section" id="penalties"> +<h3>Penalties<a class="headerlink" href="#penalties" title="Permalink to this headline">¶</a></h3> +<p>As a more difficult assignment, it is worth 2 points.</p> +<p>Information about assigments penalties can be found on the +<a class="reference external" href="https://ocw.cs.pub.ro/courses/so2/teme/general">General Directions page</a>.</p> +<p>In exceptional cases (the assigment passes the tests by not complying with the requirements) +and if the assigment does not pass all the tests, the grade will may decrease more than mentioned above.</p> +</div> +<div class="section" id="submitting-the-assigment"> +<h3>Submitting the assigment<a class="headerlink" href="#submitting-the-assigment" title="Permalink to this headline">¶</a></h3> +<p>The assignment archive will be submitted to vmchecker, according to the rules on the +<a class="reference external" href="https://ocw.cs.pub.ro/courses/so2/reguli-notare#reguli_de_trimitere_a_temelor">rules page</a>.</p> +<p>In the vmchecker interface choose the <code class="docutils literal"><span class="pre">Google</span> <span class="pre">Challenge</span> <span class="pre">-</span> <span class="pre">Sistem</span> <span class="pre">de</span> <span class="pre">fișiere</span></code> option for this assignment.</p> +</div> +</div> +<div class="section" id="resources"> +<h2>Resources<a class="headerlink" href="#resources" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li><a class="reference external" href="https://github.com/linux-kernel-labs/linux/blob/master/tools/labs/templates/assignments/5-pitix/pitix.h">assignment header</a></li> +<li><a class="reference external" href="https://linux-kernel-labs.github.io/refs/heads/master/so2/lab8-filesystems-part1.html">Lab 08: File system drivers (Part 1)</a></li> +<li><a class="reference external" href="https://linux-kernel-labs.github.io/refs/heads/master/so2/lab9-filesystems-part2.html">Lab 09: File system drivers (Part 2)</a></li> +<li><a class="reference external" href="https://elixir.bootlin.com/linux/v4.15/source/fs/minix">Minix filesystem source code</a></li> +</ul> +<p>We recommend that you use GitLab to store your homework. Follow the directions in +<a class="reference external" href="https://github.com/systems-cs-pub-ro/so2-assignments/blob/master/README.md">README</a> +and on the dedicated <a class="reference external" href="https://ocw.cs.pub.ro/courses/so2/teme/folosire-gitlab">Git wiki page</a>.</p> +<p>The resources for the assignment can also be found in the <a class="reference external" href="https://github.com/systems-cs-pub-ro/so2-assignments">so2-assignments</a> repo on GitHub. +The repo contains a <a class="reference external" href="https://github.com/systems-cs-pub-ro/so2-assignments/blob/master/so2-create-repo.sh">Bash script</a> +that helps you create a private repository on the faculty <a class="reference external" href="https://gitlab.cs.pub.ro/users/sign_in">GitLab</a> instance. +Follow the tips from the <a class="reference external" href="https://github.com/systems-cs-pub-ro/so2-assignments/blob/master/README.md">README</a> and +on the dedicated <a class="reference external" href="https://ocw.cs.pub.ro/courses/so2/teme/folosire-gitlab">Wiki page</a>.</p> +</div> +<div class="section" id="questions"> +<h2>Questions<a class="headerlink" href="#questions" title="Permalink to this headline">¶</a></h2> +<p>For questions about the assigment, you can consult the mailing <a class="reference external" href="http://cursuri.cs.pub.ro/pipermail/so2/">list archives</a> +or send an e-mail (you must be <a class="reference external" href="http://cursuri.cs.pub.ro/cgi-bin/mailman/listinfo/so2">registered</a>). +Please follow and follow <a class="reference external" href="https://ocw.cs.pub.ro/courses/so2/resurse/lista-discutii#mailing-list-guidelines">the tips for use of the list</a>.</p> +<p>Before you ask a question, make sure that:</p> +<ul class="simple"> +<li>you have read the statement of the assigment well</li> +<li>the question is not already presented on the <a class="reference external" href="https://ocw.cs.pub.ro/courses/so2/teme/tema2/faq">FAQ page</a></li> +<li>the answer cannot be found in the <a class="reference external" href="http://cursuri.cs.pub.ro/pipermail/so2/">mailing list archives</a></li> +</ul> +</div> +</div> + + + </div> + </div> + <footer> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/assign7-kvm-vmm.html b/refs/pull/405/merge/so2/assign7-kvm-vmm.html new file mode 100644 index 00000000..bdbf5db7 --- /dev/null +++ b/refs/pull/405/merge/so2/assign7-kvm-vmm.html @@ -0,0 +1,508 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Assignment 7 - SO2 Virtual Machine Manager with KVM — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Introduction" href="../lectures/intro.html" /> + <link rel="prev" title="Assignment 4 - SO2 Transport Protocol" href="assign4-transport-protocol.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Assignment 7 - SO2 Virtual Machine Manager with KVM</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#i-virtual-machine-manager">I. Virtual Machine Manager</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#initialize-the-vmm">1. Initialize the VMM</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#running-the-vm">Running the VM</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#setup-real-mode">Setup real mode</a></li> +<li class="toctree-l4"><a class="reference internal" href="#setup-long-mode">Setup long mode</a></li> +<li class="toctree-l4"><a class="reference internal" href="#running">Running</a></li> +<li class="toctree-l4"><a class="reference internal" href="#guest-code">Guest code</a></li> +<li class="toctree-l4"><a class="reference internal" href="#controller-queues">Controller queues</a></li> +<li class="toctree-l4"><a class="reference internal" href="#device-structures">Device structures</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#using-the-skeleton">Using the skeleton</a></li> +<li class="toctree-l3"><a class="reference internal" href="#debugging">Debugging</a></li> +<li class="toctree-l3"><a class="reference internal" href="#tasks">Tasks</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#submitting-the-assigment">Submitting the assigment</a></li> +<li class="toctree-l4"><a class="reference internal" href="#tips">Tips</a></li> +<li class="toctree-l4"><a class="reference internal" href="#penalties">Penalties</a></li> +<li class="toctree-l4"><a class="reference internal" href="#tldr">TLDR</a></li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">Assignment 7 - SO2 Virtual Machine Manager with KVM</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/assign7-kvm-vmm.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="assignment-7-so2-virtual-machine-manager-with-kvm"> +<h1>Assignment 7 - SO2 Virtual Machine Manager with KVM<a class="headerlink" href="#assignment-7-so2-virtual-machine-manager-with-kvm" title="Permalink to this headline">¶</a></h1> +<ul class="simple"> +<li>Deadline: <strong class="command">Tuesday, 29 May 2023, 23:00</strong></li> +<li>This assignment can be made in teams (max 2). Only one of them must submit the assignment, and the names of the student should be listed in a README file.</li> +</ul> +<p>In this assignment we will work on a simple Virtual Machine Manager (VMM). We will be using the KVM API +from the Linux kernel.</p> +<p>The assignment has two components: the VM code and the VMM code. We will be using a very simple protocol +to enable the communication between the two components. The protocol is called SIMVIRTIO.</p> +<div class="section" id="i-virtual-machine-manager"> +<h2>I. Virtual Machine Manager<a class="headerlink" href="#i-virtual-machine-manager" title="Permalink to this headline">¶</a></h2> +<p>In general, to build a VMM from scratch we will have to implement three main functionalities: initialize the VMM, initialize the virtual CPU and run the guest code. We will split the implementation of the VMM in these three phases.</p> +<div class="section" id="initialize-the-vmm"> +<h3>1. Initialize the VMM<a class="headerlink" href="#initialize-the-vmm" title="Permalink to this headline">¶</a></h3> +<p>A VM will be represented in general by three elements, a file descriptor used to interact with the KVM API, a file descriptor per VM used to configure it (e.g. set its memory) and a pointer to the VM's memory. We provide you with the following structure to start from when working with a VM.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">typedef</span> <span class="k">struct</span> <span class="n">vm</span> <span class="p">{</span> + <span class="kt">int</span> <span class="n">sys_fd</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">fd</span><span class="p">;</span> + <span class="kt">char</span> <span class="o">*</span><span class="n">mem</span><span class="p">;</span> +<span class="p">}</span> <span class="n">virtual_machine</span><span class="p">;</span> +</pre></div> +</div> +<p>The first step in initializing the KVM VM is to interract with the [KVM_API](<a class="reference external" href="https://www.kernel.org/doc/html/latest/virt/kvm/api.html">https://www.kernel.org/doc/html/latest/virt/kvm/api.html</a>]. The KVM API is exposed via <code class="docutils literal"><span class="pre">/dev/kvm</span></code>. We will be using ioctl calls to call the API.</p> +<p>The snippet below shows how one can call <code class="docutils literal"><span class="pre">KVM_GET_API_VERSION</span></code> to get the KVM API Version</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="n">kvm_fd</span> <span class="o">=</span> <span class="n">open</span><span class="p">(</span><span class="s">"/dev/kvm"</span><span class="p">,</span> <span class="n">O_RDWR</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="n">kvm_fd</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="n">perror</span><span class="p">(</span><span class="s">"open /dev/kvm"</span><span class="p">);</span> + <span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> +<span class="p">}</span> + +<span class="kt">int</span> <span class="n">api_ver</span> <span class="o">=</span> <span class="n">ioctl</span><span class="p">(</span><span class="n">kvm_fd</span><span class="p">,</span> <span class="n">KVM_GET_API_VERSION</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="n">api_ver</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="n">perror</span><span class="p">(</span><span class="s">"KVM_GET_API_VERSION"</span><span class="p">);</span> + <span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Let us now go briefly through how a VMM initializes a VM. This is only the bare bones, a VMM may do lots of other things during VM initialization.</p> +<ol class="arabic simple"> +<li>We first use KVM_GET_API_VERSION to check that we are running the expected version of KVM, <code class="docutils literal"><span class="pre">KVM_API_VERSION</span></code>.</li> +<li>We now create the VM using <code class="docutils literal"><span class="pre">KVM_CREATE_VM</span></code>. Note that calling <code class="docutils literal"><span class="pre">KVM_CREATE_VM</span></code> returns a file descriptor. We will be using this file descriptor for the next phases of the setup.</li> +<li>(Optional) On Intel based CPUs we will have to call <code class="docutils literal"><span class="pre">KVM_SET_TSS_ADDR</span></code> with address <code class="docutils literal"><span class="pre">0xfffbd000</span></code></li> +<li>Next, we allocate the memory for the VM, we will be using <code class="docutils literal"><span class="pre">mmap</span></code> for this with <code class="docutils literal"><span class="pre">PROT_WRITE</span></code>, <code class="docutils literal"><span class="pre">MAP_PRIVATE</span></code>, <code class="docutils literal"><span class="pre">MAP_ANONYMOUS</span></code> and <code class="docutils literal"><span class="pre">MAP_NORESERVE</span></code>. We recommend allocating 0x100000 bytes for the VM.</li> +<li>We flag the memory as <code class="docutils literal"><span class="pre">MADV_MERGEABLE</span></code> using <code class="docutils literal"><span class="pre">madvise</span></code></li> +<li>Finally, we use <code class="docutils literal"><span class="pre">KVM_SET_USER_MEMORY_REGION</span></code> to assign the memory to the VM.</li> +</ol> +<p><strong>Make sure you understand what file descriptor to use and when, we use the KVM fd when calling KVM_CREATE_VM, but when interacting with the vm such as calling KVM_SET_USER_MEMORY_REGION we use the VMs +file descriptor</strong></p> +<p>TLDR: API used for VM initialization:</p> +<ul class="simple"> +<li>KVM_GET_API_VERSION</li> +<li>KVM_CREATE_VM</li> +<li>KVM_SET_TSS_ADDR</li> +<li>KVM_SET_USER_MEMORY_REGION.</li> +</ul> +<div class="section" id="initialize-a-virtual-cpu"> +<h4>2. Initialize a virtual CPU<a class="headerlink" href="#initialize-a-virtual-cpu" title="Permalink to this headline">¶</a></h4> +<p>We need a Virtual CPU (VCPU) to store registers.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">typedef</span> <span class="k">struct</span> <span class="n">vcpu</span> <span class="p">{</span> + <span class="kt">int</span> <span class="n">fd</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">kvm_run</span> <span class="o">*</span><span class="n">kvm_run</span><span class="p">;</span> +<span class="p">}</span> <span class="n">virtual_cpu</span><span class="p">;</span> +</pre></div> +</div> +<p>To create a virtual CPU we will do the following: +1. Call <code class="docutils literal"><span class="pre">KVM_CREATE_VCPU</span></code> to create the virtual CPU. This call returns a file descriptor. +2. Use <code class="docutils literal"><span class="pre">KVM_GET_VCPU_MMAP_SIZE</span></code> to get the size of the shared memory +3. Allocated the necessary VCPU mem size with <code class="docutils literal"><span class="pre">mmap</span></code>. We will be passing the VCPU file descriptor to the <code class="docutils literal"><span class="pre">mmap</span></code> call. We can store the result in <code class="docutils literal"><span class="pre">kvm_run</span></code>.</p> +<p>TLDR: API used for VM</p> +<ul class="simple"> +<li>KVM_CREATE_VCPU</li> +<li>KVM_GET_VCPU_MMAP_SIZE</li> +</ul> +<p><strong>We recommend using 2MB pages to simplify the translation process</strong></p> +</div> +</div> +</div> +<div class="section" id="running-the-vm"> +<h2>Running the VM<a class="headerlink" href="#running-the-vm" title="Permalink to this headline">¶</a></h2> +<div class="section" id="setup-real-mode"> +<h3>Setup real mode<a class="headerlink" href="#setup-real-mode" title="Permalink to this headline">¶</a></h3> +<p>At first, the CPU will start in Protected mode. To do run any meaningful code, we will switch the CPU to [Real mode](<a class="reference external" href="https://wiki.osdev.org/Real_Mode">https://wiki.osdev.org/Real_Mode</a>). To do this we will +need to configure several CPU registers.</p> +<ol class="arabic simple"> +<li>First, we will use <code class="docutils literal"><span class="pre">KVM_GET_SREGS</span></code> to get the registers. We use <code class="docutils literal"><span class="pre">struct</span> <span class="pre">kvm_regs</span></code> for this task.</li> +<li>We will need to set <code class="docutils literal"><span class="pre">cs.selector</span></code> and <code class="docutils literal"><span class="pre">cs.base</span></code> to 0. We will use <code class="docutils literal"><span class="pre">KVM_SET_SREGS</span></code> to set the registers.</li> +<li>Next we will clear all <code class="docutils literal"><span class="pre">FLAGS</span></code> bits via the <code class="docutils literal"><span class="pre">rflags</span></code> register, this means setting <code class="docutils literal"><span class="pre">rflags</span></code> to 2 since bit 1 must always be to 1. We alo set the <code class="docutils literal"><span class="pre">RIP</span></code> register to 0.</li> +</ol> +</div> +<div class="section" id="setup-long-mode"> +<h3>Setup long mode<a class="headerlink" href="#setup-long-mode" title="Permalink to this headline">¶</a></h3> +<p>Read mode is all right for very simple guests, such as the one found in the folder <cite>guest_16_bits</cite>. But, +most programs nowdays need 64 bits addresses, and such we will need to switch to long mode. The following article from OSDev presents all the necessary information about [Setting Up Long Mode](<a class="reference external" href="https://wiki.osdev.org/Setting_Up_Long_Mode">https://wiki.osdev.org/Setting_Up_Long_Mode</a>).</p> +<p>In <code class="docutils literal"><span class="pre">vcpu.h</span></code>, you may found helpful macros such as CR0_PE, CR0_MP, CR0_ET, etc.</p> +<p>Since we will running a more complex program, we will also create a small stack for our program +<code class="docutils literal"><span class="pre">regs.rsp</span> <span class="pre">=</span> <span class="pre">1</span> <span class="pre"><<</span> <span class="pre">20;</span></code>. Don't forget to set the RIP and RFLAGS registers.</p> +</div> +<div class="section" id="running"> +<h3>Running<a class="headerlink" href="#running" title="Permalink to this headline">¶</a></h3> +<p>After we setup our VCPU in real or long mode we can finally start running code on the VM.</p> +<ol class="arabic simple"> +<li>We copy to the vm memory the guest code, <cite>memcpy(vm->mem, guest_code, guest_code_size)</cite> The guest code will be available in two variables which will be discussed below.</li> +<li>In a infinite loop we run the following:</li> +</ol> +<blockquote> +<div><ul class="simple"> +<li>We call <code class="docutils literal"><span class="pre">KVM_RUN</span></code> on the VCPU file descriptor to run the VPCU</li> +<li>Through the shared memory of the VCPU we check the <code class="docutils literal"><span class="pre">exit_reason</span></code> parameter to see if the guest has made any requests:</li> +<li>We will handle the following VMEXITs: <cite>KVM_EXIT_MMIO</cite>, <cite>KVM_EXIT_IO</cite> and <code class="docutils literal"><span class="pre">KVM_EXIT_HLT</span></code>. <code class="docutils literal"><span class="pre">KVM_EXIT_MMIO</span></code> is triggered when the VM writes to a MMIO address. <code class="docutils literal"><span class="pre">KVM_EXIT_IO</span></code> is called when the VM calls <code class="docutils literal"><span class="pre">inb</span></code> or <code class="docutils literal"><span class="pre">outb</span></code>. <code class="docutils literal"><span class="pre">KVM_EXIT_HLT</span></code> is called when the user does a <code class="docutils literal"><span class="pre">hlt</span></code> instruction.</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="guest-code"> +<h3>Guest code<a class="headerlink" href="#guest-code" title="Permalink to this headline">¶</a></h3> +<p>The VM that is running is also called guest. We will be using the guest to test our implementation.</p> +<ol class="arabic simple"> +<li>To test the implementation before implementing SIMVIRTIO. The guest will write at address 400 and the RAX register the value 42.</li> +<li>To test a more complicated implementation,we will extend the previous program to also write "Hello, world!n" on port <cite>0xE9</cite> using the <cite>outb</cite> instruction.</li> +<li>To test the implementation of <cite>SIMVIRTIO</cite>, we will</li> +</ol> +<p>How do we get the guest code? The guest code is available at the following static pointers guest16, guest16_end-guest16. The linker script is populating them.</p> +<p>## SIMVIRTIO: +From the communication between the guest and the VMM we will implement a very simple protocol called <code class="docutils literal"><span class="pre">SIMVIRTIO</span></code>. It's a simplified version of the real protocol used in the real world called virtio.</p> +<p>Configuration space:</p> +<table border="1" class="docutils"> +<colgroup> +<col width="13%" /> +<col width="15%" /> +<col width="15%" /> +<col width="15%" /> +<col width="17%" /> +<col width="12%" /> +<col width="12%" /> +</colgroup> +<thead valign="bottom"> +<tr class="row-odd"><th class="head">u32</th> +<th class="head">u16</th> +<th class="head">u8</th> +<th class="head">u8</th> +<th class="head">u8</th> +<th class="head">u8</th> +<th class="head">u8</th> +</tr> +</thead> +<tbody valign="top"> +<tr class="row-even"><td>magic value +R</td> +<td>max queue len +R</td> +<td>device status +R</td> +<td>driver status +R/W</td> +<td>queue selector +R/W</td> +<td>Q0(TX) CTL +R/W</td> +<td>Q1(RX) CTL +R/w</td> +</tr> +</tbody> +</table> +</div> +<div class="section" id="controller-queues"> +<h3>Controller queues<a class="headerlink" href="#controller-queues" title="Permalink to this headline">¶</a></h3> +<p>We provide you with the following structures and methods for the <code class="docutils literal"><span class="pre">SIMVIRTIO</span></code> implementation.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">typedef</span> <span class="kt">uint8_t</span> <span class="n">q_elem_t</span><span class="p">;</span> +<span class="k">typedef</span> <span class="k">struct</span> <span class="n">queue_control</span> <span class="p">{</span> + <span class="c1">// Ptr to current available head/producer index in 'buffer'.</span> + <span class="kt">unsigned</span> <span class="n">head</span><span class="p">;</span> + <span class="c1">// Ptr to last index in 'buffer' used by consumer.</span> + <span class="kt">unsigned</span> <span class="n">tail</span><span class="p">;</span> +<span class="p">}</span> <span class="n">queue_control_t</span><span class="p">;</span> +<span class="k">typedef</span> <span class="k">struct</span> <span class="n">simqueue</span> <span class="p">{</span> + <span class="c1">// MMIO queue control.</span> + <span class="k">volatile</span> <span class="n">queue_control_t</span> <span class="o">*</span><span class="n">q_ctrl</span><span class="p">;</span> + <span class="c1">// Size of the queue buffer/data.</span> + <span class="kt">unsigned</span> <span class="n">maxlen</span><span class="p">;</span> + <span class="c1">// Queue data buffer.</span> + <span class="n">q_elem_t</span> <span class="o">*</span><span class="n">buffer</span><span class="p">;</span> +<span class="p">}</span> <span class="n">simqueue_t</span><span class="p">;</span> +<span class="kt">int</span> <span class="nf">circ_bbuf_push</span><span class="p">(</span><span class="n">simqueue_t</span> <span class="o">*</span><span class="n">q</span><span class="p">,</span> <span class="n">q_elem_t</span> <span class="n">data</span><span class="p">)</span> +<span class="p">{</span> +<span class="p">}</span> +<span class="kt">int</span> <span class="nf">circ_bbuf_pop</span><span class="p">(</span><span class="n">simqueue_t</span> <span class="o">*</span><span class="n">q</span><span class="p">,</span> <span class="n">q_elem_t</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span> +<span class="p">{</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="device-structures"> +<h3>Device structures<a class="headerlink" href="#device-structures" title="Permalink to this headline">¶</a></h3> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define MAGIC_VALUE 0x74726976</span> +<span class="cp">#define DEVICE_RESET 0x0</span> +<span class="cp">#define DEVICE_CONFIG 0x2</span> +<span class="cp">#define DEVICE_READY 0x4</span> +<span class="cp">#define DRIVER_ACK 0x0</span> +<span class="cp">#define DRIVER 0x2</span> +<span class="cp">#define DRIVER_OK 0x4</span> +<span class="cp">#define DRIVER_RESET 0x8000</span> +<span class="k">typedef</span> <span class="k">struct</span> <span class="n">device</span> <span class="p">{</span> + <span class="kt">uint32_t</span> <span class="n">magic</span><span class="p">;</span> + <span class="kt">uint8_t</span> <span class="n">device_status</span><span class="p">;</span> + <span class="kt">uint8_t</span> <span class="n">driver_status</span><span class="p">;</span> + <span class="kt">uint8_t</span> <span class="n">max_queue_len</span><span class="p">;</span> +<span class="p">}</span> <span class="n">device_t</span><span class="p">;</span> +<span class="k">typedef</span> <span class="k">struct</span> <span class="n">device_table</span> <span class="p">{</span> + <span class="kt">uint16_t</span> <span class="n">count</span><span class="p">;</span> + <span class="kt">uint64_t</span> <span class="n">device_addresses</span><span class="p">[</span><span class="mi">10</span><span class="p">];</span> + <span class="p">}</span> <span class="n">device_table_t</span><span class="p">;</span> +</pre></div> +</div> +<p>We will be implementing the following handles: +* MMIO (read/write) VMEXIT +* PIO (read/write) VMEXIT</p> +</div> +</div> +<div class="section" id="using-the-skeleton"> +<h2>Using the skeleton<a class="headerlink" href="#using-the-skeleton" title="Permalink to this headline">¶</a></h2> +</div> +<div class="section" id="debugging"> +<h2>Debugging<a class="headerlink" href="#debugging" title="Permalink to this headline">¶</a></h2> +</div> +<div class="section" id="tasks"> +<h2>Tasks<a class="headerlink" href="#tasks" title="Permalink to this headline">¶</a></h2> +<ol class="arabic simple"> +<li>30p Implement a simple VMM that runs the code from <cite>guest_16_bits</cite>. We will be running the VCPU in read mode for this task</li> +<li>20p Extend the previous implementation to run the VCPU in real mode. We will be running the <cite>guest_32_bits</cite> example</li> +<li>30p Implement the <cite>SIMVIRTIO</cite> protocol.</li> +<li>10p Implement pooling as opposed to VMEXIT. We will use the macro <cite>USE_POOLING</cite> to switch this option on and off.</li> +<li>10p Add profiling code. Measure the number of VMEXITs triggered by the VMM.</li> +</ol> +<div class="section" id="submitting-the-assigment"> +<h3>Submitting the assigment<a class="headerlink" href="#submitting-the-assigment" title="Permalink to this headline">¶</a></h3> +<p>The assignment archive will be submitted on <strong>Moodle</strong>, according to the rules on the <a class="reference external" href="https://ocw.cs.pub.ro/courses/so2/reguli-notare#reguli_de_trimitere_a_temelor">rules page</a>.</p> +</div> +<div class="section" id="tips"> +<h3>Tips<a class="headerlink" href="#tips" title="Permalink to this headline">¶</a></h3> +<p>To increase your chances of getting the highest grade, read and follow the Linux kernel coding style described in the <a class="reference external" href="https://elixir.bootlin.com/linux/v4.19.19/source/Documentation/process/coding-style.rst">Coding Style document</a>.</p> +<p>Also, use the following static analysis tools to verify the code:</p> +<ul> +<li><p class="first">checkpatch.pl</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> linux/scripts/checkpatch.pl --no-tree --terse -f /path/to/your/file.c +</pre></div> +</div> +</li> +<li><p class="first">sparse</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> sudo apt-get install sparse +<span class="gp">$</span> <span class="nb">cd</span> linux +<span class="gp">$</span> make <span class="nv">C</span><span class="o">=</span><span class="m">2</span> /path/to/your/file.c +</pre></div> +</div> +</li> +<li><p class="first">cppcheck</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> sudo apt-get install cppcheck +<span class="gp">$</span> cppcheck /path/to/your/file.c +</pre></div> +</div> +</li> +</ul> +</div> +<div class="section" id="penalties"> +<h3>Penalties<a class="headerlink" href="#penalties" title="Permalink to this headline">¶</a></h3> +<p>Information about assigments penalties can be found on the <a class="reference external" href="https://ocw.cs.pub.ro/courses/so2/teme/general">General Directions page</a>.</p> +<p>In exceptional cases (the assigment passes the tests by not complying with the requirements) and if the assigment does not pass all the tests, the grade will may decrease more than mentioned above.</p> +<p>## References +We recommend you the following readings before starting to work on the homework: +* [KVM host in a few lines of code](<a class="reference external" href="https://zserge.com/posts/kvm/">https://zserge.com/posts/kvm/</a>)</p> +</div> +<div class="section" id="tldr"> +<h3>TLDR<a class="headerlink" href="#tldr" title="Permalink to this headline">¶</a></h3> +<ol class="arabic simple"> +<li>The VMM creates and initializes a virtual machine and a virtual CPU</li> +<li>We switch to real mode and check run the simple guest code from <cite>guest_16_bits</cite></li> +<li>We switch to long mode and run the more complex guest from <cite>guest_32_bits</cite></li> +<li>We implement the SIMVIRTIO protocol. We will describe how it behaves in the following subtasks.</li> +<li>The guest writes in the TX queue (queue 0) the ascii code for <cite>R</cite> which will result in a <cite>VMEXIT</cite></li> +</ol> +<p>6. the VMM will handle the VMEXIT caused by the previous write in the queue. When the guests receiver the +<cite>R</cite> letter it will initiate the reser procedure of the device and set the device status to <cite>DEVICE_RESET</cite> +7. After the reset handling, the guest must set the status of the device to <cite>DRIVER_ACK</cite>. After this, the guest will write to the TX queue the letter <cite>C</cite> +8. In the VMM we will initialize the config process when letter <cite>C</cite> is received.It will set the device status to <cite>DEVICE_CONFIG</cite> and add a new entry in the device_table +9. After the configuration process is finished, the guest will set the driver status to <cite>DRIVER_OK</cite> +10. Nex, the VMM will set the device status to <cite>DEVICE_READY</cite> +11. The guest will write in the TX queue "Ana are mere" and will execute a halt +12. The VMM will print to the STDOUT the message received and execute the halt request +13. Finally, the VMM will verify that at address 0x400 and in register RAX is stored the value 42</p> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="assign4-transport-protocol.html" class="btn btn-neutral float-left" title="Assignment 4 - SO2 Transport Protocol" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../lectures/intro.html" class="btn btn-neutral float-right" title="Introduction" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/grading.html b/refs/pull/405/merge/so2/grading.html new file mode 100644 index 00000000..953de357 --- /dev/null +++ b/refs/pull/405/merge/so2/grading.html @@ -0,0 +1,447 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 - General Rules and Grading — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lecture 01 - Course overview and Linux kernel introduction" href="lec1-intro.html" /> + <link rel="prev" title="Operating Systems 2" href="index.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 - General Rules and Grading</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#general-rules">General Rules</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#laboratory">1. Laboratory</a></li> +<li class="toctree-l4"><a class="reference internal" href="#final-deadline-for-submitting-assignments">2. Final deadline for submitting assignments</a></li> +<li class="toctree-l4"><a class="reference internal" href="#assignment-presentations">3. Assignment Presentations</a></li> +<li class="toctree-l4"><a class="reference internal" href="#rules-on-assignments">4. Rules on Assignments</a></li> +<li class="toctree-l4"><a class="reference internal" href="#penalties-for-plagiarized-assignments">5. Penalties for Plagiarized Assignments</a></li> +<li class="toctree-l4"><a class="reference internal" href="#retake-grade-increase">6. Retake/Grade Increase</a></li> +<li class="toctree-l4"><a class="reference internal" href="#class-redo">7. Class Redo</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#grading">Grading</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#lectures-3-points">1. Lectures (3 points)</a></li> +<li class="toctree-l4"><a class="reference internal" href="#laboratory-2-points">2. Laboratory (2 points)</a></li> +<li class="toctree-l4"><a class="reference internal" href="#assignments-5-points-extra">3. Assignments (5 points + Extra)</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 - General Rules and Grading</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/grading.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-general-rules-and-grading"> +<h1>SO2 - General Rules and Grading<a class="headerlink" href="#so2-general-rules-and-grading" title="Permalink to this headline">¶</a></h1> +<div class="section" id="general-rules"> +<h2>General Rules<a class="headerlink" href="#general-rules" title="Permalink to this headline">¶</a></h2> +<div class="section" id="laboratory"> +<h3>1. Laboratory<a class="headerlink" href="#laboratory" title="Permalink to this headline">¶</a></h3> +<p>There is no formal rule for dividing students; everyone can participate in any laboratory as long as the following rules are respected. +Priority for participation is given to students from the respective group (34xC3 or optional). +The limit of students in a laboratory is 14 people. +Starting from the third week, the participation list in the laboratory is "frozen". +Students who have a retake can participate in any laboratory as long as there are available spots. +Like other students, the participation list is "frozen" starting from the third week. +The division is done on the laboratory hours division page. +You can make up for a maximum of 2 laboratories (you can attend another subgroup) (in those laboratories where there are available spots). +Laboratories cannot be made up retroactively. You cannot make up a laboratory from the previous week within the same laboratory week. +Laboratory activities take place only in the laboratory room. +We encourage you to go through the brief and laboratory exercises at home. +You can solve exercises at home, but you will have to start from scratch in the laboratory.</p> +</div> +<div class="section" id="final-deadline-for-submitting-assignments"> +<h3>2. Final deadline for submitting assignments<a class="headerlink" href="#final-deadline-for-submitting-assignments" title="Permalink to this headline">¶</a></h3> +<p>The final deadline for submitting SO2 assignments is <strong>Wednesday, May 29, 2024, 23:59.</strong>. +Beyond this date, assignments cannot be submitted anymore. +Please ensure timely submission of assignments with complete information to be graded. +We will not accept assignments submitted after this date or assignments not submitted on vmchecker-next. +For the testing part, assignments will receive the score indicated from testing on vmchecker-next; tests failed due to reasons unrelated to vmchecker-next will not be graded. +Assignments cannot be submitted for the special June 2023 exam session. +Assignments can be resubmitted after TODO for the September 2024 exam session. +The deadline for submitting assignments for the Fall 2024 session is TODO.</p> +</div> +<div class="section" id="assignment-presentations"> +<h3>3. Assignment Presentations<a class="headerlink" href="#assignment-presentations" title="Permalink to this headline">¶</a></h3> +<p>The SO2 team reserves the right to request presentations for some homework assignments. +A presentation involves a discussion with at least two assistants about the completion of the assignment, the solution used, and any encountered issues. +The purpose of the assignment presentation sessions is to clarify any uncertainties regarding the completion of the assignment and to verify its correctness. +Individuals who will present an assignment will be contacted at least 24 hours in advance by the laboratory assistant. +Most likely, a 15-minute slot before/after the SO2 class or at the end of the SO2 laboratory session will be used.</p> +</div> +<div class="section" id="rules-on-assignments"> +<h3>4. Rules on Assignments<a class="headerlink" href="#rules-on-assignments" title="Permalink to this headline">¶</a></h3> +<p>The assignments for Operating Systems 2 are individual, except when explicitly stated that an assignment can be solved in a team. +This is because the primary objective of the assignments is for you to acquire or deepen your practical skills. +If the level of collaboration is too high or if you seek solutions online, this objective will not be achieved. +Each assignment is to be completed by a student without consulting the source code of their peers.</p> +<p>We understand that teamwork is important, but we do not have the environment to carry out team projects in the Operating Systems 2 course. +If you encounter any problems in completing an assignment, use the discussion list or ask the laboratory assistants or course instructors. +Our role is to help you solve them. +Feel free to rely on the SO2 team.</p> +<p>You can discuss among yourselves within the bounds of common sense; that is, you should not dictate a solution to someone, but you can offer a general idea. +If you are the one being asked and providing explanations, please consider redirecting to the discussion list and the SO2 team. +It is not allowed to request the solution to an assignment on a site like StackExchange, Rent a Coder, ChatGPT etc. +You can ask more generic questions, but do not request the solution to the assignment.</p> +<p>You can freely use code from the laboratory, skeletons provided by us. +You can use external resources (GitHub, open-source code, or others) as long as they do not represent obvious solutions to the assignments, publicly available with or without intention. +See also the next paragraph.</p> +<p>It is not allowed to publish assignment solutions (even after the end of the course). +If you find assignment solutions on GitHub or elsewhere, report them to the discussion list or privately to the laboratory assistant or course instructor. +We reiterate that if you need clarification that you would address to older colleagues or other forums, StackExchange, or other sources, use the discussion list and the SO2 team. +It is the safest and most honest way to solve problems.</p> +<p>It is not allowed to transfer files between yourselves. +In general, we recommend not to screen-share with another colleague, whether for inspiration or to help them with their assignment. +Avoid testing an assignment on a colleague's system. +There may be exceptions; you can help someone troubleshoot, but please ensure that it does not transition from "let's solve this problem together" to "let me solve your assignment for you". +However, we recommend using the discussion list or the SO2 team to ask questions.</p> +</div> +<div class="section" id="penalties-for-plagiarized-assignments"> +<h3>5. Penalties for Plagiarized Assignments<a class="headerlink" href="#penalties-for-plagiarized-assignments" title="Permalink to this headline">¶</a></h3> +<p>In general, we consider punitive measures as a last resort. +As long as the assignment is completed individually, without problematic source code contribution from external sources, then it is not a plagiarized assignment.</p> +<p>The notion of a plagiarized assignment refers to, without limitation, situations such as:</p> +<blockquote> +<div><ul class="simple"> +<li>Two assignments that are similar enough to draw this conclusion;</li> +<li>Using source code from the internet that is an obvious solution to the assignment;</li> +<li>Using pieces of code from another colleague;</li> +<li>Accessing another colleague's code during the assignment;</li> +<li>Modifying an existing assignment;</li> +<li>Following another colleague's code;</li> +<li>Direct assistance in completing the assignment (someone else wrote or dictated the code);</li> +<li>Someone else wrote the assignment (voluntarily, for payment, or other benefits).</li> +<li>If two assignments are considered plagiarized, both the source and destination will be penalized equally, without discussions about who plagiarized from whom and whose fault it is.</li> +</ul> +</div></blockquote> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p class="last">Plagiarizing an assignment results in the elimination of points for the assignments completed up to that session. +Any assignment submitted until that session receives a score of 0 and cannot be resubmitted during the current academic year. +If there were instances of plagiarized assignments during the semester, it will be possible to obtain points in the summer, for the September session, from assignments <strong>not yet</strong> submitted. +We reiterate that our goal is not and will not be penalization for plagiarism. +We consider cheating to be dishonest behavior that will be punished if it occurs. +However, our goal is to prevent cheating; for this purpose, we offer support and resources from the team in all its forms (discussion list, face-to-face discussions with the SO2 team). +Please use them with confidence; we believe that an honest approach to completing assignments will also result in a gain of knowledge and skills for you.</p> +</div> +</div> +<div class="section" id="retake-grade-increase"> +<h3>6. Retake/Grade Increase<a class="headerlink" href="#retake-grade-increase" title="Permalink to this headline">¶</a></h3> +<p>In the retake/grade increase session in September, only assignments can be submitted, only the final exam can be retaken, or both. +You can continue to submit assignments with the deadlines from the semester, meaning you can achieve a maximum grade of 7 for each assignment. +Assignments are submitted using the vmchecker-next interface. +If you did not have plagiarized assignments during the semester, you can (re)submit any assignments. +If there were instances of plagiarized assignments during the semester, you can submit only assignments not yet submitted during the semester. +The submission deadline is TODO</p> +<p>If you do not wish to retake the final exam, you can choose not to participate in the exam. +Grades will be recorded in the official catalog, according to the SO2 catalog.</p> +<p>In the special retake/grade increase session in June, only the final exam can be retaken, and no homework assignments can be submitted.</p> +<p>The exam in the retake session will consist of 11 equally weighted topics (for a total of 3 points - one topic is a bonus). Passing the exam is conditional on obtaining 1 point out of the 3 points assigned to the course. In practice, this means correctly solving 3 out of the 11 topics in the exam.</p> +<p>In the case of retaking the final exam, the higher grade will be retained (between the semester grade and the grade from the retake session).</p> +<p>You can participate in only one exam during a session.</p> +</div> +<div class="section" id="class-redo"> +<h3>7. Class Redo<a class="headerlink" href="#class-redo" title="Permalink to this headline">¶</a></h3> +<p>If you prefer, you can keep the score from the previous academic year for the entire semester's activity (labs, assignments, course work), and only retake the final exam. +You cannot keep the score for individual components of the semester (only assignments or only course work).</p> +<p>If you want to keep the score from the previous academic year for the entire semester's activity, you must announce this at the begining of the semester. +Otherwise, the score from the previous academic year's semester will be reset according to the default mode.</p> +<p>By default, the score for the academic year will be reset on October 1. +If you do not graduate from the course during the current academic year, you will need to retake it completely during the next academic year.</p> +</div> +</div> +<div class="section" id="grading"> +<h2>Grading<a class="headerlink" href="#grading" title="Permalink to this headline">¶</a></h2> +<p>You must achieve at least 4.5 points out of 10 to pass.</p> +<div class="section" id="lectures-3-points"> +<h3>1. Lectures (3 points)<a class="headerlink" href="#lectures-3-points" title="Permalink to this headline">¶</a></h3> +<ul class="simple"> +<li>Completion of the course is conditioned by obtaining 30% (3 out of 10) of the course score.</li> +<li>The lecture score will be obtained from 11 lecture quizzes to be completed before each class (one quiz is a bonus).</li> +<li><dl class="first docutils"> +<dt>Each course assignment contains a set of 4 questions from the material covered in the previous class (one question is a bonus).</dt> +<dd><ul class="first last"> +<li>There will be no final exam.</li> +<li>Each question is scored with 0 or 1.</li> +<li>A question is scored only if it is fully and correctly answered.</li> +<li>A question answered incompletely or one answered completely but with incorrect specifications or errors will not be scored.</li> +<li>Course assignments cannot be redone.</li> +<li>Each assignment lasts 3 minutes.</li> +<li>The score is obtained from the formula min(sum_of_assignment_scores / 10 * 4/3, 10).</li> +<li>The assignments are closed book.</li> +</ul> +</dd> +</dl> +</li> +<li><dl class="first docutils"> +<dt>For those who cannot attend the course assignments or wish to improve their course score, an assignment will be given at the end of the semester (during the last class) covering all the course material.</dt> +<dd><ul class="first last"> +<li>The end-of-semester assignment (last class) consists of 11 questions for the 3 course points and lasts 60 minutes.</li> +<li>The end-of-semester assignment is open-book. You are allowed to use class notes, books, slides, laptops, or tablets without internet access.</li> +<li>Access with mobile phones is not permitted. Phones must be turned off/silent/deactivated during the exam.</li> +<li>You may download course materials, labs, or other resources for offline use.</li> +</ul> +</dd> +</dl> +</li> +</ul> +</div> +<div class="section" id="laboratory-2-points"> +<h3>2. Laboratory (2 points)<a class="headerlink" href="#laboratory-2-points" title="Permalink to this headline">¶</a></h3> +<ul class="simple"> +<li>The laboratories are held in EG106, EG306, and PR706.</li> +<li>Completion of the laboratory exercises leads to obtaining 10 or 11 points allocated for the laboratory.</li> +<li>The final grade for the laboratory is calculated using the formula (sum(l1:l12) / 12).</li> +</ul> +</div> +<div class="section" id="assignments-5-points-extra"> +<h3>3. Assignments (5 points + Extra)<a class="headerlink" href="#assignments-5-points-extra" title="Permalink to this headline">¶</a></h3> +<ul class="simple"> +<li><dl class="first docutils"> +<dt>There are 4 Assignments:</dt> +<dd><ul class="first last"> +<li>Assignment 0 - "Kernel API" - 0.5 points</li> +<li>Assignment 1 - "Kprobe based tracer" - 1.5 points</li> +<li>Assignment 2 - "Driver UART" 1.5 points</li> +<li>Assignment 3 - "Software RAID" - 1.5 points</li> +</ul> +</dd> +</dl> +</li> +<li><dl class="first docutils"> +<dt>Extra activities:</dt> +<dd><ul class="first last"> +<li>SO2 transport protocol - 2 points</li> +<li>SO2 Virtual Machine Manager with KVM - 2 points</li> +</ul> +</dd> +</dl> +</li> +<li><dl class="first docutils"> +<dt>In case the total score for assignments + "Extra" activities exceeds 5 points, the following procedure will be followed:</dt> +<dd><ul class="first last"> +<li>5 points are considered as part of the total score.</li> +<li>The difference between the total score and 5 points will be proportionally adjusted relative to the grade obtained in the lecture.</li> +</ul> +</dd> +</dl> +</li> +</ul> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">S</span> <span class="o">=</span> <span class="n">A0</span> <span class="o">+</span> <span class="n">A1</span> <span class="o">+</span> <span class="n">A2</span> <span class="o">+</span> <span class="n">A3</span> <span class="o">+</span> <span class="n">Extra</span><span class="p">;</span> +<span class="k">if</span> <span class="p">(</span><span class="n">S</span> <span class="o"><=</span> <span class="mi">5</span><span class="p">)</span> + <span class="n">assignment_grade</span> <span class="o">=</span> <span class="n">S</span><span class="p">;</span> +<span class="k">else</span> + <span class="n">assignment_grade</span> <span class="o">=</span> <span class="mi">5</span> <span class="o">+</span> <span class="p">(</span><span class="n">S</span> <span class="o">-</span> <span class="mi">5</span><span class="p">)</span> <span class="o">*</span> <span class="n">course_grade</span> <span class="o">/</span> <span class="mi">3</span><span class="p">;</span> <span class="c1">// 0 <= course_grade <=3</span> +</pre></div> +</div> +<ul class="simple"> +<li><dl class="first docutils"> +<dt>The verification and scoring of assignments:</dt> +<dd><ul class="first last"> +<li>Assignments are tested against plagiarism.</li> +<li>Assignments will be automatically verified using the <a class="reference external" href="https://github.com/systems-cs-pub-ro/vmchecker-next/wiki/Student-Handbook">vmchecker-next</a> infrastructure integrated with moodle.</li> +<li>The verification tests are public.</li> +<li>Students who upload their assignments on Moodle must wait for the checker's feedback in the feedback section of the assignment upload page.</li> +<li>The grade listed in the feedback section will be the final grade for the assigment.</li> +<li>There may be exceptional situations where this rule is not considered (for example, if the assignment is implemented solely to pass the tests and does not meet the assignment requirements).</li> +<li>The verification system deducts points (automatically) for certain situations (segmentation faults, unhandled exceptions, compilation errors, or warnings) regardless of the test results.</li> +<li>Deductions are specified in the instructions list and in the assignment statement.</li> +<li>Deductions are subtracted from the assignment grade (maximum of 10) not from the assignment score.</li> +</ul> +</dd> +</dl> +</li> +<li><dl class="first docutils"> +<dt>Late assignments</dt> +<dd><ul class="first last"> +<li>Each assignment has a deadline of 2 weeks from the publication date. (exception! Assignment 0)</li> +<li>After the deadline, 0.25 points per day (out of 10, the maximum grade for each assignment) will be deducted for 12 days (up to a maximum grade of 7).</li> +<li>The deduction is from the grade (maximum 10), not from the score. An assignment incurs deductions of 0.25 points per day from the maximum grade (10), regardless of its score.</li> +<li>For example, if for assignment 3 (scored with 1.5 points) the delay is 4 days, you will receive a deduction of 4 * 0.25 = 1 point from the grade, resulting in a maximum grade of 9, equivalent to a maximum score of 1.35 points.</li> +<li>After 12 days, no further deductions will be made; a maximum grade of 7 can be obtained for an assignment submitted 13 days after the deadline expiration, or 50 days, or more, including during the retake session.</li> +</ul> +</dd> +</dl> +</li> +</ul> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="index.html" class="btn btn-neutral float-left" title="Operating Systems 2" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lec1-intro.html" class="btn btn-neutral float-right" title="SO2 Lecture 01 - Course overview and Linux kernel introduction" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/index.html b/refs/pull/405/merge/so2/index.html new file mode 100644 index 00000000..00c2d690 --- /dev/null +++ b/refs/pull/405/merge/so2/index.html @@ -0,0 +1,247 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Operating Systems 2 — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 - General Rules and Grading" href="grading.html" /> + <link rel="prev" title="Linux Kernel Teaching" href="../index.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Operating Systems 2</a><ul> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">Operating Systems 2</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/index.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="operating-systems-2"> +<h1>Operating Systems 2<a class="headerlink" href="#operating-systems-2" title="Permalink to this headline">¶</a></h1> +<div class="toctree-wrapper compound"> +<p class="caption"><span class="caption-text">Good To Know</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +</ul> +</div> +<div class="toctree-wrapper compound"> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +</ul> +</div> +<div class="toctree-wrapper compound"> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +</ul> +</div> +<div class="toctree-wrapper compound"> +<p class="caption"><span class="caption-text">Assignments</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l1"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l1"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l1"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l1"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l1"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../index.html" class="btn btn-neutral float-left" title="Linux Kernel Teaching" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="grading.html" class="btn btn-neutral float-right" title="SO2 - General Rules and Grading" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lab1-intro.html b/refs/pull/405/merge/so2/lab1-intro.html new file mode 100644 index 00000000..5972d832 --- /dev/null +++ b/refs/pull/405/merge/so2/lab1-intro.html @@ -0,0 +1,1683 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lab 01 - Introduction — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lab 02 - Kernel API" href="lab2-kernel-api.html" /> + <link rel="prev" title="SO2 Lecture 12 - Virtualization" href="lec12-virtualization.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lab 01 - Introduction</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#about-this-laboratory">About this laboratory</a></li> +<li class="toctree-l3"><a class="reference internal" href="#references">References</a></li> +<li class="toctree-l3"><a class="reference internal" href="#documentation">Documentation</a></li> +<li class="toctree-l3"><a class="reference internal" href="#kernel-modules-overview">Kernel Modules Overview</a></li> +<li class="toctree-l3"><a class="reference internal" href="#an-example-of-a-kernel-module">An example of a kernel module</a></li> +<li class="toctree-l3"><a class="reference internal" href="#compiling-kernel-modules">Compiling kernel modules</a></li> +<li class="toctree-l3"><a class="reference internal" href="#loading-unloading-a-kernel-module">Loading/unloading a kernel module</a></li> +<li class="toctree-l3"><a class="reference internal" href="#kernel-module-debugging">Kernel Module Debugging</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#objdump">objdump</a></li> +<li class="toctree-l4"><a class="reference internal" href="#addr2line">addr2line</a></li> +<li class="toctree-l4"><a class="reference internal" href="#minicom">minicom</a></li> +<li class="toctree-l4"><a class="reference internal" href="#netconsole">netconsole</a></li> +<li class="toctree-l4"><a class="reference internal" href="#printk-debugging">Printk debugging</a></li> +<li class="toctree-l4"><a class="reference internal" href="#dynamic-debugging">Dynamic debugging</a></li> +<li class="toctree-l4"><a class="reference internal" href="#kdb-kernel-debugger">KDB: Kernel debugger</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#remarks">Remarks</a></li> +<li class="toctree-l4"><a class="reference internal" href="#kernel-module">1. Kernel module</a></li> +<li class="toctree-l4"><a class="reference internal" href="#printk">2. Printk</a></li> +<li class="toctree-l4"><a class="reference internal" href="#error">3. Error</a></li> +<li class="toctree-l4"><a class="reference internal" href="#sub-modules">4. Sub-modules</a></li> +<li class="toctree-l4"><a class="reference internal" href="#kernel-oops-1">5. Kernel oops</a></li> +<li class="toctree-l4"><a class="reference internal" href="#module-parameters">6. Module parameters</a></li> +<li class="toctree-l4"><a class="reference internal" href="#proc-info-1">7. Proc info</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#good-to-know-1">Good to know</a></li> +<li class="toctree-l3"><a class="reference internal" href="#source-code-navigation">Source code navigation</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#cscope">cscope</a></li> +<li class="toctree-l4"><a class="reference internal" href="#clangd">clangd</a></li> +<li class="toctree-l4"><a class="reference internal" href="#kscope">Kscope</a></li> +<li class="toctree-l4"><a class="reference internal" href="#lxr-cross-reference">LXR Cross-Reference</a></li> +<li class="toctree-l4"><a class="reference internal" href="#sourceweb">SourceWeb</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#kernel-debugging">Kernel Debugging</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#gdb-linux">gdb (Linux)</a></li> +<li class="toctree-l4"><a class="reference internal" href="#getting-a-stack-trace">Getting a stack trace</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lab 01 - Introduction</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lab1-intro.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lab-01-introduction"> +<h1>SO2 Lab 01 - Introduction<a class="headerlink" href="#so2-lab-01-introduction" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>presenting the rules and objectives of the Operating Systems 2 lab</li> +<li>introducing the lab documentation</li> +<li>introducing the Linux kernel and related resources</li> +<li>creating simple modules</li> +<li>describing the process of kernel module compilation</li> +<li>presenting how a module can be used with a kernel</li> +<li>simple kernel debugging methods</li> +</ul> +</div> +<div class="section" id="about-this-laboratory"> +<h2>About this laboratory<a class="headerlink" href="#about-this-laboratory" title="Permalink to this headline">¶</a></h2> +<p>The Operating Systems 2 lab is a kernel programming and driver development lab. +The objectives of the laboratory are:</p> +<ul class="simple"> +<li>deepening the notions presented in the course</li> +<li>presentation of kernel programming interfaces (kernel API)</li> +<li>gaining documenting, development and debugging skills on a freestanding +environment</li> +<li>acquiring knowledge and skills for drivers development</li> +</ul> +<p>A laboratory will present a set of concepts, applications and commands +specific to a given problem. The lab will start with a presentation +(each lab will have a set of slides) (15 minutes) and the remaining +time will be allocated to the lab exercises (80 minutes).</p> +<p>For best laboratory performance, we recommend that you read the related slides. +To fully understand a laboratory, we recommend going through the lab support. For +in-depth study, use the supporting documentation.</p> +</div> +<div class="section" id="references"> +<h2>References<a class="headerlink" href="#references" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>Linux<ul> +<li><a class="reference external" href="http://www.amazon.com/Linux-Kernel-Development-Robert-Love/dp/0672329468/">Linux Kernel Development, 3rd +Edition</a></li> +<li><a class="reference external" href="http://free-electrons.com/doc/books/ldd3.pdf">Linux Device Drivers, 3rd +Edition</a></li> +<li><a class="reference external" href="http://www.amazon.com/Essential-Device-Drivers-Sreekrishnan-Venkateswaran/dp/0132396556">Essential Linux Device +Drivers</a></li> +</ul> +</li> +<li>General<ul> +<li><a class="reference external" href="http://cursuri.cs.pub.ro/cgi-bin/mailman/listinfo/pso">mailing list</a> +(<a class="reference external" href="http://blog.gmane.org/gmane.education.region.romania.operating-systems-design">searching the mailing list</a>)</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="documentation"> +<h2>Documentation<a class="headerlink" href="#documentation" title="Permalink to this headline">¶</a></h2> +<p>Kernel development is a difficult process, compared to user space +programming. The API is different and the complexity of the subsystems +in kernel requires additional preparation. The associated documentation +is heterogeneous, sometimes requiring the inspection of multiple sources +to have a more complete understanding of a certain aspect.</p> +<p>The main advantages of the Linux kernel are the access to sources and +the open development system. Because of this, the Internet offers a +larger number of documentation for the kernel.</p> +<p>A few links related to the Linux kernel are shown bellow:</p> +<ul class="simple"> +<li><a class="reference external" href="http://kernelnewbies.org">KernelNewbies</a></li> +<li><a class="reference external" href="http://kernelnewbies.org/KernelHacking">KernelNewbies - Kernel Hacking</a></li> +<li><a class="reference external" href="http://www.tldp.org/HOWTO/KernelAnalysis-HOWTO.html">Kernel Analysis - HOWTO</a></li> +<li><a class="reference external" href="http://web.archive.org/web/20090228191439/http://www.linuxhq.com/lkprogram.html">Linux Kernel Programming</a></li> +<li><a class="reference external" href="http://en.wikibooks.org/wiki/Linux_kernel">Linux kernel - Wikibooks</a></li> +</ul> +<p>The links are not comprehensive. Using <a class="reference external" href="http://www.google.com">The Internet</a> and +<a class="reference external" href="http://lxr.free-electrons.com/">kernel source code</a> is essential.</p> +</div> +<div class="section" id="kernel-modules-overview"> +<h2>Kernel Modules Overview<a class="headerlink" href="#kernel-modules-overview" title="Permalink to this headline">¶</a></h2> +<p>A monolithic kernel, though faster than a microkernel, has the disadvantage of +lack of modularity and extensibility. On modern monolithic kernels, this has +been solved by using kernel modules. A kernel module (or loadable kernel mode) +is an object file that contains code that can extend the kernel functionality +at runtime (it is loaded as needed); When a kernel module is no longer needed, +it can be unloaded. Most of the device drivers are used in the form of kernel +modules.</p> +<p>For the development of Linux device drivers, it is recommended to download the +kernel sources, configure and compile them and then install the compiled version +on the test /development tool machine.</p> +</div> +<div class="section" id="an-example-of-a-kernel-module"> +<h2>An example of a kernel module<a class="headerlink" href="#an-example-of-a-kernel-module" title="Permalink to this headline">¶</a></h2> +<p>Below is a very simple example of a kernel module. When loading into the kernel, +it will generate the message <code class="code docutils literal"><span class="pre">"Hi"</span></code>. When unloading the kernel module, the +<code class="code docutils literal"><span class="pre">"Bye"</span></code> message will be generated.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/kernel.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/init.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/module.h></span><span class="cp"></span> + +<span class="n">MODULE_DESCRIPTION</span><span class="p">(</span><span class="s">"My kernel module"</span><span class="p">);</span> +<span class="n">MODULE_AUTHOR</span><span class="p">(</span><span class="s">"Me"</span><span class="p">);</span> +<span class="n">MODULE_LICENSE</span><span class="p">(</span><span class="s">"GPL"</span><span class="p">);</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">dummy_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_debug</span><span class="p">(</span><span class="s">"Hi</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">dummy_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_debug</span><span class="p">(</span><span class="s">"Bye</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> +<span class="p">}</span> + +<span class="n">module_init</span><span class="p">(</span><span class="n">dummy_init</span><span class="p">);</span> +<span class="n">module_exit</span><span class="p">(</span><span class="n">dummy_exit</span><span class="p">);</span> +</pre></div> +</div> +<p>The generated messages will not be displayed on the console but will be saved +in a specially reserved memory area for this, from where they will be extracted +by the logging daemon (syslog). To display kernel messages, you can use the +<strong class="command">dmesg</strong> command or inspect the logs:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># cat /var/log/syslog | tail -2</span> +Feb <span class="m">20</span> <span class="m">13</span>:57:38 asgard kernel: Hi +Feb <span class="m">20</span> <span class="m">13</span>:57:43 asgard kernel: Bye + +<span class="c1"># dmesg | tail -2</span> +Hi +Bye +</pre></div> +</div> +</div> +<div class="section" id="compiling-kernel-modules"> +<h2>Compiling kernel modules<a class="headerlink" href="#compiling-kernel-modules" title="Permalink to this headline">¶</a></h2> +<p>Compiling a kernel module differs from compiling an user program. First, other +headers should be used. Also, the module should not be linked to libraries. +And, last but not least, the module must be compiled with the same options as +the kernel in which we load the module. For these reasons, there is a standard +compilation method (<code class="code docutils literal"><span class="pre">kbuild</span></code>). This method requires the use of two files: +a <code class="file docutils literal"><span class="pre">Makefile</span></code> and a <code class="file docutils literal"><span class="pre">Kbuild</span></code> file.</p> +<p>Below is an example of a <code class="file docutils literal"><span class="pre">Makefile</span></code>:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nv">KDIR</span> <span class="o">=</span> /lib/modules/<span class="sb">`</span>uname -r<span class="sb">`</span>/build + +kbuild: + make -C <span class="k">$(</span>KDIR<span class="k">)</span> <span class="nv">M</span><span class="o">=</span><span class="sb">`</span><span class="nb">pwd</span><span class="sb">`</span> + +clean: + make -C <span class="k">$(</span>KDIR<span class="k">)</span> <span class="nv">M</span><span class="o">=</span><span class="sb">`</span><span class="nb">pwd</span><span class="sb">`</span> clean +</pre></div> +</div> +<p>And the example of a <code class="file docutils literal"><span class="pre">Kbuild</span></code> file used to compile a module:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nv">EXTRA_CFLAGS</span> <span class="o">=</span> -Wall -g + +obj-m <span class="o">=</span> modul.o +</pre></div> +</div> +<p>As you can see, calling <strong class="command">make</strong> on the <code class="file docutils literal"><span class="pre">Makefile</span></code> file in the +example shown will result in the <strong class="command">make</strong> invocation in the kernel +source directory (<code class="docutils literal"><span class="pre">/lib/modules/`uname</span> <span class="pre">-r`/build</span></code>) and referring to the +current directory (<code class="docutils literal"><span class="pre">M</span> <span class="pre">=</span> <span class="pre">`pwd`</span></code>). This process ultimately leads to reading +the <code class="file docutils literal"><span class="pre">Kbuild</span></code> file from the current directory and compiling the module +as instructed in this file.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>For labs we will configure different <strong class="command">KDIR</strong>, according to +the virtual machine specifications:</p> +<div class="last highlight-bash"><div class="highlight"><pre><span></span><span class="nv">KDIR</span> <span class="o">=</span> /home/student/src/linux +<span class="o">[</span>...<span class="o">]</span> +</pre></div> +</div> +</div> +<p>A <code class="file docutils literal"><span class="pre">Kbuild</span></code> file contains one or more directives for compiling a kernel +module. The easiest example of such a directive is <code class="docutils literal"><span class="pre">obj-m</span> <span class="pre">=</span> +<span class="pre">module.o</span></code>. Following this directive, a kernel module (<code class="code docutils literal"><span class="pre">ko</span></code> - kernel +object) will be created, starting from the <code class="docutils literal"><span class="pre">module.o</span></code> file. <code class="docutils literal"><span class="pre">module.o</span></code> will +be created starting from <code class="docutils literal"><span class="pre">module.c</span></code> or <code class="docutils literal"><span class="pre">module.S</span></code>. All of these files can +be found in the <code class="file docutils literal"><span class="pre">Kbuild</span></code>'s directory.</p> +<p>An example of a <code class="file docutils literal"><span class="pre">Kbuild</span></code> file that uses several sub-modules is shown +below:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nv">EXTRA_CFLAGS</span> <span class="o">=</span> -Wall -g + +obj-m <span class="o">=</span> supermodule.o +supermodule-y <span class="o">=</span> module-a.o module-b.o +</pre></div> +</div> +<p>For the example above, the steps to compile are:</p> +<blockquote> +<div><ul class="simple"> +<li>compile the <code class="file docutils literal"><span class="pre">module-a.c</span></code> and <code class="file docutils literal"><span class="pre">module-b.c</span></code> sources, +resulting in module-a.o and module-b.o objects</li> +<li><code class="file docutils literal"><span class="pre">module-a.o</span></code> and <code class="file docutils literal"><span class="pre">module-b.o</span></code> will then be linked +in <code class="file docutils literal"><span class="pre">supermodule.o</span></code></li> +<li>from <code class="file docutils literal"><span class="pre">supermodule.o</span></code> will be created <code class="file docutils literal"><span class="pre">supermodule.ko</span></code> +module</li> +</ul> +</div></blockquote> +<p>The suffix of targets in <code class="file docutils literal"><span class="pre">Kbuild</span></code> determines how they are used, as +follows:</p> +<blockquote> +<div><ul class="simple"> +<li>M (modules) is a target for loadable kernel modules</li> +<li>Y (yes) represents a target for object files to be compiled and then +linked to a module (<code class="docutils literal"><span class="pre">$(mode_name)-y</span></code>) or within the kernel (<code class="docutils literal"><span class="pre">obj-y</span></code>)</li> +<li>any other target suffix will be ignored by <code class="file docutils literal"><span class="pre">Kbuild</span></code> and will not be +compiled</li> +</ul> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">These suffixes are used to easily configure the kernel by running the +<strong class="command">make menuconfig</strong> command or directly editing the +<code class="file docutils literal"><span class="pre">.config</span></code> file. This file sets a series of variables that are +used to determine which features are added to the kernel at build +time. For example, when adding BTRFS support with <strong class="command">make +menuconfig</strong>, add the line <code class="code docutils literal"><span class="pre">CONFIG_BTRFS_FS</span> <span class="pre">=</span> <span class="pre">y</span></code> to the +<code class="file docutils literal"><span class="pre">.config</span></code> file. The BTRFS kbuild contains the line +<code class="docutils literal"><span class="pre">obj-$(CONFIG_BTRFS_FS):=</span> <span class="pre">btrfs.o</span></code>, which becomes <code class="docutils literal"><span class="pre">obj-y:=</span> +<span class="pre">btrfs.o</span></code>. This will compile the <code class="file docutils literal"><span class="pre">btrfs.o</span></code> object and will be +linked to the kernel. Before the variable was set, the line became +<code class="docutils literal"><span class="pre">obj:=btrfs.o</span></code> and so it was ignored, and the kernel was build +without BTRFS support.</p> +</div> +<p>For more details, see the <code class="file docutils literal"><span class="pre">Documentation/kbuild/makefiles.txt</span></code> and +<code class="file docutils literal"><span class="pre">Documentation/kbuild/modules.txt</span></code> files within the kernel sources.</p> +</div> +<div class="section" id="loading-unloading-a-kernel-module"> +<h2>Loading/unloading a kernel module<a class="headerlink" href="#loading-unloading-a-kernel-module" title="Permalink to this headline">¶</a></h2> +<p>To load a kernel module, use the <strong class="command">insmod</strong> utility. This utility +receives as a parameter the path to the <code class="file docutils literal"><span class="pre">*.ko</span></code> file in which the module +was compiled and linked. Unloading the module from the kernel is done using +the <strong class="command">rmmod</strong> command, which receives the module name as a parameter.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ insmod module.ko +$ rmmod module.ko +</pre></div> +</div> +<p>When loading the kernel module, the routine specified as a parameter of the +<code class="docutils literal"><span class="pre">module_init</span></code> macro will be executed. Similarly, when the module is unloaded +the routine specified as a parameter of the <code class="docutils literal"><span class="pre">module_exit</span></code> will be executed.</p> +<p>A complete example of compiling and loading/unloading a kernel module is +presented below:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>faust:~/lab-01/modul-lin# ls +Kbuild Makefile modul.c + +faust:~/lab-01/modul-lin# make +make -C /lib/modules/<span class="sb">`</span>uname -r<span class="sb">`</span>/build <span class="nv">M</span><span class="o">=</span><span class="sb">`</span><span class="nb">pwd</span><span class="sb">`</span> +make<span class="o">[</span><span class="m">1</span><span class="o">]</span>: Entering directory <span class="sb">`</span>/usr/src/linux-2.6.28.4<span class="s1">'</span> +<span class="s1"> LD /root/lab-01/modul-lin/built-in.o</span> +<span class="s1"> CC [M] /root/lab-01/modul-lin/modul.o</span> +<span class="s1"> Building modules, stage 2.</span> +<span class="s1"> MODPOST 1 modules</span> +<span class="s1"> CC /root/lab-01/modul-lin/modul.mod.o</span> +<span class="s1"> LD [M] /root/lab-01/modul-lin/modul.ko</span> +<span class="s1">make[1]: Leaving directory `/usr/src/linux-2.6.28.4'</span> + +faust:~/lab-01/modul-lin# ls +built-in.o Kbuild Makefile modul.c Module.markers +modules.order Module.symvers modul.ko modul.mod.c +modul.mod.o modul.o + +faust:~/lab-01/modul-lin# insmod modul.ko + +faust:~/lab-01/modul-lin# dmesg <span class="p">|</span> tail -1 +Hi + +faust:~/lab-01/modul-lin# rmmod modul + +faust:~/lab-01/modul-lin# dmesg <span class="p">|</span> tail -2 +Hi +Bye +</pre></div> +</div> +<p>Information about modules loaded into the kernel can be found using the +<strong class="command">lsmod</strong> command or by inspecting the <code class="file docutils literal"><span class="pre">/proc/modules</span></code>, +<code class="file docutils literal"><span class="pre">/sys/module</span></code> directories.</p> +</div> +<div class="section" id="kernel-module-debugging"> +<h2>Kernel Module Debugging<a class="headerlink" href="#kernel-module-debugging" title="Permalink to this headline">¶</a></h2> +<p>Troubleshooting a kernel module is much more complicated than debugging a +regular program. First, a mistake in a kernel module can lead to blocking the +entire system. Troubleshooting is therefore much slowed down. To avoid reboot, +it is recommended to use a virtual machine (qemu, virtualbox, vmware).</p> +<p>When a module containing bugs is inserted into the kernel, it will eventually +generate a <a class="reference external" href="https://en.wikipedia.org/wiki/Linux_kernel_oops">kernel oops</a>. +A kernel oops is an invalid operation detected by the kernel and can only +be generated by the kernel. For a stable kernel version, it almost certainly +means that the module contains a bug. After the oops appears, the kernel will +continue to work.</p> +<p>Very important to the appearance of a kernel oops is saving the generated +message. As noted above, messages generated by the kernel are saved in logs and +can be displayed with the <strong class="command">dmesg</strong> command. To make sure that no kernel +message is lost, it is recommended to insert/test the kernel directly from the +console, or periodically check the kernel messages. Noteworthy is that an oops +can occur because of a programming error, but also a because of hardware error.</p> +<p>If a fatal error occurs, after which the system can not return to a stable +state, a <a class="reference external" href="https://en.wikipedia.org/wiki/Linux_kernel_panic">kernel panic</a> is +generated.</p> +<p>Look at the kernel module below that contains a bug that generates an oops:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/*</span> +<span class="cm"> * Oops generating kernel module</span> +<span class="cm"> */</span> + +<span class="cp">#include</span> <span class="cpf"><linux/kernel.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/module.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/init.h></span><span class="cp"></span> + +<span class="n">MODULE_DESCRIPTION</span> <span class="p">(</span><span class="s">"Oops"</span><span class="p">);</span> +<span class="n">MODULE_LICENSE</span> <span class="p">(</span><span class="s">"GPL"</span><span class="p">);</span> +<span class="n">MODULE_AUTHOR</span> <span class="p">(</span><span class="s">"PSO"</span><span class="p">);</span> + +<span class="cp">#define OP_READ 0</span> +<span class="cp">#define OP_WRITE 1</span> +<span class="cp">#define OP_OOPS OP_WRITE</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_oops_init</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="o">*</span><span class="n">a</span><span class="p">;</span> + + <span class="n">a</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span> <span class="o">*</span><span class="p">)</span> <span class="mh">0x00001234</span><span class="p">;</span> +<span class="cp">#if OP_OOPS == OP_WRITE</span> + <span class="o">*</span><span class="n">a</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span> +<span class="cp">#elif OP_OOPS == OP_READ</span> + <span class="n">printk</span> <span class="p">(</span><span class="n">KERN_ALERT</span> <span class="s">"value = %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="o">*</span><span class="n">a</span><span class="p">);</span> +<span class="cp">#else</span> +<span class="cp">#error "Unknown op for oops!"</span> +<span class="cp">#endif</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">my_oops_exit</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> +<span class="p">}</span> + +<span class="n">module_init</span> <span class="p">(</span><span class="n">my_oops_init</span><span class="p">);</span> +<span class="n">module_exit</span> <span class="p">(</span><span class="n">my_oops_exit</span><span class="p">);</span> +</pre></div> +</div> +<p>Inserting this module into the kernel will generate an oops:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>faust:~/lab-01/modul-oops# insmod oops.ko +<span class="o">[</span>...<span class="o">]</span> + +faust:~/lab-01/modul-oops# dmesg <span class="p">|</span> tail -32 +BUG: unable to handle kernel paging request at <span class="m">00001234</span> +IP: <span class="o">[</span><c89d4005><span class="o">]</span> my_oops_init+0x5/0x20 <span class="o">[</span>oops<span class="o">]</span> + *de <span class="o">=</span> <span class="m">00000000</span> +Oops: <span class="m">0002</span> <span class="o">[</span><span class="c1">#1] PREEMPT DEBUG_PAGEALLOC</span> +last sysfs file: /sys/devices/virtual/net/lo/operstate +Modules linked in: oops<span class="o">(</span>+<span class="o">)</span> netconsole ide_cd_mod pcnet32 crc32 cdrom <span class="o">[</span>last unloaded: modul<span class="o">]</span> + +Pid: <span class="m">4157</span>, comm: insmod Not tainted <span class="o">(</span><span class="m">2</span>.6.28.4 <span class="c1">#2) VMware Virtual Platform</span> +EIP: <span class="m">0060</span>:<span class="o">[</span><c89d4005><span class="o">]</span> EFLAGS: <span class="m">00010246</span> CPU: <span class="m">0</span> +EIP is at my_oops_init+0x5/0x20 <span class="o">[</span>oops<span class="o">]</span> +EAX: <span class="m">00000000</span> EBX: fffffffc ECX: c89d4300 EDX: <span class="m">00000001</span> +ESI: c89d4000 EDI: <span class="m">00000000</span> EBP: c5799e24 ESP: c5799e24 + DS: 007b ES: 007b FS: <span class="m">0000</span> GS: <span class="m">0033</span> SS: <span class="m">0068</span> +Process insmod <span class="o">(</span>pid: <span class="m">4157</span>, <span class="nv">ti</span><span class="o">=</span>c5799000 <span class="nv">task</span><span class="o">=</span>c665c780 task.ti<span class="o">=</span>c5799000<span class="o">)</span> +Stack: + c5799f8c c010102d c72b51d8 0000000c c5799e58 c01708e4 <span class="m">00000124</span> <span class="m">00000000</span> + c89d4300 c5799e58 c724f448 <span class="m">00000001</span> c89d4300 c5799e60 c0170981 c5799f8c + c014b698 <span class="m">00000000</span> <span class="m">00000000</span> c5799f78 c5799f20 <span class="m">00000500</span> c665cb00 c89d4300 +Call Trace: + <span class="o">[</span><c010102d><span class="o">]</span> ? _stext+0x2d/0x170 + <span class="o">[</span><c01708e4><span class="o">]</span> ? __vunmap+0xa4/0xf0 + <span class="o">[</span><c0170981><span class="o">]</span> ? vfree+0x21/0x30 + <span class="o">[</span><c014b698><span class="o">]</span> ? load_module+0x19b8/0x1a40 + <span class="o">[</span><c035e965><span class="o">]</span> ? __mutex_unlock_slowpath+0xd5/0x140 + <span class="o">[</span><c0140da6><span class="o">]</span> ? trace_hardirqs_on_caller+0x106/0x150 + <span class="o">[</span><c014b7aa><span class="o">]</span> ? sys_init_module+0x8a/0x1b0 + <span class="o">[</span><c0140da6><span class="o">]</span> ? trace_hardirqs_on_caller+0x106/0x150 + <span class="o">[</span><c0240a08><span class="o">]</span> ? trace_hardirqs_on_thunk+0xc/0x10 + <span class="o">[</span><c0103407><span class="o">]</span> ? sysenter_do_call+0x12/0x43 +Code: <c7> <span class="m">05</span> <span class="m">34</span> <span class="m">12</span> <span class="m">00</span> <span class="m">00</span> <span class="m">03</span> <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> 5d c3 eb 0d <span class="m">90</span> <span class="m">90</span> <span class="m">90</span> <span class="m">90</span> <span class="m">90</span> <span class="m">90</span> <span class="m">90</span> <span class="m">90</span> +EIP: <span class="o">[</span><c89d4005><span class="o">]</span> my_oops_init+0x5/0x20 <span class="o">[</span>oops<span class="o">]</span> SS:ESP <span class="m">0068</span>:c5799e24 +---<span class="o">[</span> end trace 2981ce73ae801363 <span class="o">]</span>--- +</pre></div> +</div> +<p>Although relatively cryptic, the message provided by the kernel to the +appearance of an oops provides valuable information about the error. First line:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>BUG: unable to handle kernel paging request at <span class="m">00001234</span> +EIP: <span class="o">[</span><c89d4005><span class="o">]</span> my_oops_init + 0x5 / 0x20 <span class="o">[</span>oops<span class="o">]</span> +</pre></div> +</div> +<p>Tells us the cause and the address of the instruction that generated the error. +In our case this is an invalid access to memory.</p> +<p>Next line</p> +<blockquote> +<div><code class="docutils literal"><span class="pre">Oops:</span> <span class="pre">0002</span> <span class="pre">[#</span> <span class="pre">1]</span> <span class="pre">PREEMPT</span> <span class="pre">DEBUG_PAGEALLOC</span></code></div></blockquote> +<p>Tells us that it's the first oops (#1). This is important in the context that +an oops can lead to other oopses. Usually only the first oops is relevant. +Furthermore, the oops code (<code class="docutils literal"><span class="pre">0002</span></code>) provides information about the error type +(see <code class="file docutils literal"><span class="pre">arch/x86/include/asm/trap_pf.h</span></code>):</p> +<blockquote> +<div><ul class="simple"> +<li>Bit 0 == 0 means no page found, 1 means protection fault</li> +<li>Bit 1 == 0 means read, 1 means write</li> +<li>Bit 2 == 0 means kernel, 1 means user mode</li> +</ul> +</div></blockquote> +<p>In this case, we have a write access that generated the oops (bit 1 is 1).</p> +<p>Below is a dump of the registers. It decodes the instruction pointer (<code class="docutils literal"><span class="pre">EIP</span></code>) +value and notes that the bug appeared in the <code class="code docutils literal"><span class="pre">my_oops_init</span></code> function with +a 5-byte offset (<code class="docutils literal"><span class="pre">EIP:</span> <span class="pre">[<c89d4005>]</span> <span class="pre">my_oops_init+0x5</span></code>). The message also +shows the stack content and a backtrace of calls until then.</p> +<p>If an invalid read call is generated (<code class="docutils literal"><span class="pre">#define</span> <span class="pre">OP_OOPS</span> <span class="pre">OP_READ</span></code>), the message +will be the same, but the oops code will differ, which would now be <code class="docutils literal"><span class="pre">0000</span></code>:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>faust:~/lab-01/modul-oops# dmesg <span class="p">|</span> tail -33 +BUG: unable to handle kernel paging request at <span class="m">00001234</span> +IP: <span class="o">[</span><c89c3016><span class="o">]</span> my_oops_init+0x6/0x20 <span class="o">[</span>oops<span class="o">]</span> + *de <span class="o">=</span> <span class="m">00000000</span> +Oops: <span class="m">0000</span> <span class="o">[</span><span class="c1">#1] PREEMPT DEBUG_PAGEALLOC</span> +last sysfs file: /sys/devices/virtual/net/lo/operstate +Modules linked in: oops<span class="o">(</span>+<span class="o">)</span> netconsole pcnet32 crc32 ide_cd_mod cdrom + +Pid: <span class="m">2754</span>, comm: insmod Not tainted <span class="o">(</span><span class="m">2</span>.6.28.4 <span class="c1">#2) VMware Virtual Platform</span> +EIP: <span class="m">0060</span>:<span class="o">[</span><c89c3016><span class="o">]</span> EFLAGS: <span class="m">00010292</span> CPU: <span class="m">0</span> +EIP is at my_oops_init+0x6/0x20 <span class="o">[</span>oops<span class="o">]</span> +EAX: <span class="m">00000000</span> EBX: fffffffc ECX: c89c3380 EDX: <span class="m">00000001</span> +ESI: c89c3010 EDI: <span class="m">00000000</span> EBP: c57cbe24 ESP: c57cbe1c + DS: 007b ES: 007b FS: <span class="m">0000</span> GS: <span class="m">0033</span> SS: <span class="m">0068</span> +Process insmod <span class="o">(</span>pid: <span class="m">2754</span>, <span class="nv">ti</span><span class="o">=</span>c57cb000 <span class="nv">task</span><span class="o">=</span>c66ec780 task.ti<span class="o">=</span>c57cb000<span class="o">)</span> +Stack: + c57cbe34 <span class="m">00000282</span> c57cbf8c c010102d c57b9280 0000000c c57cbe58 c01708e4 + <span class="m">00000124</span> <span class="m">00000000</span> c89c3380 c57cbe58 c5db1d38 <span class="m">00000001</span> c89c3380 c57cbe60 + c0170981 c57cbf8c c014b698 <span class="m">00000000</span> <span class="m">00000000</span> c57cbf78 c57cbf20 <span class="m">00000580</span> +Call Trace: + <span class="o">[</span><c010102d><span class="o">]</span> ? _stext+0x2d/0x170 + <span class="o">[</span><c01708e4><span class="o">]</span> ? __vunmap+0xa4/0xf0 + <span class="o">[</span><c0170981><span class="o">]</span> ? vfree+0x21/0x30 + <span class="o">[</span><c014b698><span class="o">]</span> ? load_module+0x19b8/0x1a40 + <span class="o">[</span><c035d083><span class="o">]</span> ? printk+0x0/0x1a + <span class="o">[</span><c035e965><span class="o">]</span> ? __mutex_unlock_slowpath+0xd5/0x140 + <span class="o">[</span><c0140da6><span class="o">]</span> ? trace_hardirqs_on_caller+0x106/0x150 + <span class="o">[</span><c014b7aa><span class="o">]</span> ? sys_init_module+0x8a/0x1b0 + <span class="o">[</span><c0140da6><span class="o">]</span> ? trace_hardirqs_on_caller+0x106/0x150 + <span class="o">[</span><c0240a08><span class="o">]</span> ? trace_hardirqs_on_thunk+0xc/0x10 + <span class="o">[</span><c0103407><span class="o">]</span> ? sysenter_do_call+0x12/0x43 +Code: <a1> <span class="m">34</span> <span class="m">12</span> <span class="m">00</span> <span class="m">00</span> c7 <span class="m">04</span> <span class="m">24</span> <span class="m">54</span> <span class="m">30</span> 9c c8 <span class="m">89</span> <span class="m">44</span> <span class="m">24</span> <span class="m">04</span> e8 <span class="m">58</span> a0 <span class="m">99</span> f7 <span class="m">31</span> +EIP: <span class="o">[</span><c89c3016><span class="o">]</span> my_oops_init+0x6/0x20 <span class="o">[</span>oops<span class="o">]</span> SS:ESP <span class="m">0068</span>:c57cbe1c +---<span class="o">[</span> end trace 45eeb3d6ea8ff1ed <span class="o">]</span>--- +</pre></div> +</div> +<div class="section" id="objdump"> +<h3>objdump<a class="headerlink" href="#objdump" title="Permalink to this headline">¶</a></h3> +<p>Detailed information about the instruction that generated the oops can be found +using the <strong class="command">objdump</strong> utility. Useful options to use are <strong class="command">-d</strong> +to disassemble the code and <strong class="command">-S</strong> for interleaving C code in assembly +language code. For efficient decoding, however, we need the address where the +kernel module was loaded. This can be found in <code class="file docutils literal"><span class="pre">/proc/modules</span></code>.</p> +<p>Here's an example of using <strong class="command">objdump</strong> on the above module to identify +the instruction that generated the oops:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>faust:~/lab-01/modul-oops# cat /proc/modules +oops <span class="m">1280</span> <span class="m">1</span> - Loading 0xc89d4000 +netconsole <span class="m">8352</span> <span class="m">0</span> - Live 0xc89ad000 +pcnet32 <span class="m">33412</span> <span class="m">0</span> - Live 0xc895a000 +ide_cd_mod <span class="m">34952</span> <span class="m">0</span> - Live 0xc8903000 +crc32 <span class="m">4224</span> <span class="m">1</span> pcnet32, Live 0xc888a000 +cdrom <span class="m">34848</span> <span class="m">1</span> ide_cd_mod, Live 0xc886d000 + +faust:~/lab-01/modul-oops# objdump -dS --adjust-vma<span class="o">=</span>0xc89d4000 oops.ko + +oops.ko: file format elf32-i386 + + +Disassembly of section .text: + +c89d4000 <init_module>: +<span class="c1">#define OP_READ 0</span> +<span class="c1">#define OP_WRITE 1</span> +<span class="c1">#define OP_OOPS OP_WRITE</span> + +static int my_oops_init <span class="o">(</span>void<span class="o">)</span> +<span class="o">{</span> +c89d4000: <span class="m">55</span> push %ebp +<span class="c1">#else</span> +<span class="c1">#error "Unknown op for oops!"</span> +<span class="c1">#endif</span> + + <span class="k">return</span> <span class="m">0</span><span class="p">;</span> +<span class="o">}</span> +c89d4001: <span class="m">31</span> c0 xor %eax,%eax +<span class="c1">#define OP_READ 0</span> +<span class="c1">#define OP_WRITE 1</span> +<span class="c1">#define OP_OOPS OP_WRITE</span> + +static int my_oops_init <span class="o">(</span>void<span class="o">)</span> +<span class="o">{</span> +c89d4003: <span class="m">89</span> e5 mov %esp,%ebp + int *a<span class="p">;</span> + + <span class="nv">a</span> <span class="o">=</span> <span class="o">(</span>int *<span class="o">)</span> 0x00001234<span class="p">;</span> +<span class="c1">#if OP_OOPS == OP_WRITE</span> + *a <span class="o">=</span> <span class="m">3</span><span class="p">;</span> +c89d4005: c7 <span class="m">05</span> <span class="m">34</span> <span class="m">12</span> <span class="m">00</span> <span class="m">00</span> <span class="m">03</span> movl <span class="nv">$0</span>x3,0x1234 +c89d400c: <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> +<span class="c1">#else</span> +<span class="c1">#error "Unknown op for oops!"</span> +<span class="c1">#endif</span> + + <span class="k">return</span> <span class="m">0</span><span class="p">;</span> +<span class="o">}</span> +c89d400f: 5d pop %ebp +c89d4010: c3 ret +c89d4011: eb 0d jmp c89c3020 <cleanup_module> +c89d4013: <span class="m">90</span> nop +c89d4014: <span class="m">90</span> nop +c89d4015: <span class="m">90</span> nop +c89d4016: <span class="m">90</span> nop +c89d4017: <span class="m">90</span> nop +c89d4018: <span class="m">90</span> nop +c89d4019: <span class="m">90</span> nop +c89d401a: <span class="m">90</span> nop +c89d401b: <span class="m">90</span> nop +c89d401c: <span class="m">90</span> nop +c89d401d: <span class="m">90</span> nop +c89d401e: <span class="m">90</span> nop +c89d401f: <span class="m">90</span> nop + +c89d4020 <cleanup_module>: + +static void my_oops_exit <span class="o">(</span>void<span class="o">)</span> +<span class="o">{</span> +c89d4020: <span class="m">55</span> push %ebp +c89d4021: <span class="m">89</span> e5 mov %esp,%ebp +<span class="o">}</span> +c89d4023: 5d pop %ebp +c89d4024: c3 ret +c89d4025: <span class="m">90</span> nop +c89d4026: <span class="m">90</span> nop +c89d4027: <span class="m">90</span> nop +</pre></div> +</div> +<p>Note that the instruction that generated the oops (<code class="docutils literal"><span class="pre">c89d4005</span></code> identified +earlier) is:</p> +<blockquote> +<div><code class="docutils literal"><span class="pre">C89d4005:</span> <span class="pre">c7</span> <span class="pre">05</span> <span class="pre">34</span> <span class="pre">12</span> <span class="pre">00</span> <span class="pre">00</span> <span class="pre">03</span> <span class="pre">movl</span> <span class="pre">$</span> <span class="pre">0x3,0x1234</span></code></div></blockquote> +<p>That is exactly what was expected - storing value 3 at 0x0001234.</p> +<p>The <code class="file docutils literal"><span class="pre">/proc/modules</span></code> is used to find the address where a kernel module is +loaded. The <strong class="command">--adjust-vma</strong> option allows you to display instructions +relative to <code class="docutils literal"><span class="pre">0xc89d4000</span></code>. The <strong class="command">-l</strong> option displays the number of +each line in the source code interleaved with the assembly language code.</p> +</div> +<div class="section" id="addr2line"> +<h3>addr2line<a class="headerlink" href="#addr2line" title="Permalink to this headline">¶</a></h3> +<p>A more simplistic way to find the code that generated an oops is to use the +<strong class="command">addr2line</strong> utility:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>faust:~/lab-01/modul-oops# addr2line -e oops.o 0x5 +/root/lab-01/modul-oops/oops.c:23 +</pre></div> +</div> +<p>Where <code class="docutils literal"><span class="pre">0x5</span></code> is the value of the program counter (<code class="docutils literal"><span class="pre">EIP</span> <span class="pre">=</span> <span class="pre">c89d4005</span></code>) that +generated the oops, minus the base address of the module (<code class="docutils literal"><span class="pre">0xc89d4000</span></code>) +according to <code class="file docutils literal"><span class="pre">/proc/modules</span></code></p> +</div> +<div class="section" id="minicom"> +<h3>minicom<a class="headerlink" href="#minicom" title="Permalink to this headline">¶</a></h3> +<p><strong class="command">Minicom</strong> (or other equivalent utilities, eg <strong class="command">picocom</strong>, +<strong class="command">screen</strong>) is a utility that can be used to connect and interact with a +serial port. The serial port is the basic method for analyzing kernel messages +or interacting with an embedded system in the development phase. There are two +more common ways to connect:</p> +<ul class="simple"> +<li>a serial port where the device we are going to use is <code class="file docutils literal"><span class="pre">/dev/ttyS0</span></code></li> +<li>a serial USB port (FTDI) in which case the device we are going to use is +<code class="file docutils literal"><span class="pre">/dev/ttyUSB</span></code>.</li> +</ul> +<p>For the virtual machine used in the lab, the device that we need to use is +displayed after the virtual machine starts:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>char device redirected to /dev/pts/20 <span class="o">(</span>label virtiocon0<span class="o">)</span> +</pre></div> +</div> +<p>Minicom use:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1">#for connecting via COM1 and using a speed of 115,200 characters per second</span> +minicom -b <span class="m">115200</span> -D /dev/ttyS0 + +<span class="c1">#For USB serial port connection</span> +minicom -D /dev/ttyUSB0 + +<span class="c1">#To connect to the serial port of the virtual machine</span> +minicom -D /dev/pts/20 +</pre></div> +</div> +</div> +<div class="section" id="netconsole"> +<h3>netconsole<a class="headerlink" href="#netconsole" title="Permalink to this headline">¶</a></h3> +<p><strong class="command">Netconsole</strong> is a utility that allows logging of kernel debugging +messages over the network. This is useful when the disk logging system does not +work or when serial ports are not available or when the terminal does not +respond to commands. <strong class="command">Netconsole</strong> comes in the form of a kernel +module.</p> +<p>To work, it needs the following parameters:</p> +<blockquote> +<div><ul class="simple"> +<li>port, IP address, and the source interface name of the debug station</li> +<li>port, MAC address, and IP address of the machine to which the debug +messages will be sent</li> +</ul> +</div></blockquote> +<p>These parameters can be configured when the module is inserted into the kernel, +or even while the module is inserted if it has been compiled with the +<code class="docutils literal"><span class="pre">CONFIG_NETCONSOLE_DYNAMIC</span></code> option.</p> +<p>An example configuration when inserting <strong class="command">netconsole</strong> kernel module is +as follows:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>alice:~# modprobe netconsole <span class="nv">netconsole</span><span class="o">=</span><span class="m">6666</span>@192.168.191.130/eth0,6000@192.168.191.1/00:50:56:c0:00:08 +</pre></div> +</div> +<p>Thus, the debug messages on the station that has the address +<code class="docutils literal"><span class="pre">192.168.191.130</span></code> will be sent to the <code class="docutils literal"><span class="pre">eth0</span></code> interface, having source port +<code class="docutils literal"><span class="pre">6666</span></code>. The messages will be sent to <code class="docutils literal"><span class="pre">192.168.191.1</span></code> with the MAC address +<code class="docutils literal"><span class="pre">00:50:56:c0:00:08</span></code>, on port <code class="docutils literal"><span class="pre">6000</span></code>.</p> +<p>Messages can be played on the destination station using <strong class="command">netcat</strong>:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>bob:~ <span class="c1"># nc -l -p 6000 -u</span> +</pre></div> +</div> +<p>Alternatively, the destination station can configure <strong class="command">syslogd</strong> to +intercept these messages. More information can be found in +<code class="file docutils literal"><span class="pre">Documentation/networking/netconsole.txt</span></code>.</p> +</div> +<div class="section" id="printk-debugging"> +<h3>Printk debugging<a class="headerlink" href="#printk-debugging" title="Permalink to this headline">¶</a></h3> +<p><code class="docutils literal"><span class="pre">The</span> <span class="pre">two</span> <span class="pre">oldest</span> <span class="pre">and</span> <span class="pre">most</span> <span class="pre">useful</span> <span class="pre">debugging</span> <span class="pre">aids</span> <span class="pre">are</span> <span class="pre">Your</span> <span class="pre">Brain</span> <span class="pre">and</span> <span class="pre">Printf</span></code>.</p> +<p>For debugging, a primitive way is often used, but it is quite effective: +<code class="code docutils literal"><span class="pre">printk</span></code> debugging. Although a debugger can also be used, it is generally +not very useful: simple bugs (uninitialized variables, memory management +problems, etc.) can be easily localized by control messages and the +kernel-decoded oop message.</p> +<p>For more complex bugs, even a debugger can not help us too much unless the +operating system structure is very well understood. When debugging a kernel +module, there are a lot of unknowns in the equation: multiple contexts (we have +multiple processes and threads running at a time), interruptions, virtual +memory, etc.</p> +<p>You can use <code class="code docutils literal"><span class="pre">printk</span></code> to display kernel messages to user space. It is +similar to <code class="code docutils literal"><span class="pre">printf</span></code>'s functionality; the only difference is that the +transmitted message can be prefixed with a string of <code class="code docutils literal"><span class="pre">"<n>"</span></code>, where +<code class="code docutils literal"><span class="pre">n</span></code> indicates the error level (loglevel) and has values between <code class="docutils literal"><span class="pre">0</span></code> and +<code class="docutils literal"><span class="pre">7</span></code>. Instead of <code class="code docutils literal"><span class="pre">"<n>"</span></code>, the levels can also be coded by symbolic +constants:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">KERN_EMERG</span> <span class="o">-</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">0</span> +<span class="n">KERN_ALERT</span> <span class="o">-</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">1</span> +<span class="n">KERN_CRIT</span> <span class="o">-</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">2</span> +<span class="n">KERN_ERR</span> <span class="o">-</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">3</span> +<span class="n">KERN_WARNING</span> <span class="o">-</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">4</span> +<span class="n">KERN_NOTICE</span> <span class="o">-</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">5</span> +<span class="n">KERN_INFO</span> <span class="o">-</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">6</span> +<span class="n">KERN_DEBUG</span> <span class="o">-</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">7</span> +</pre></div> +</div> +<p>The definitions of all log levels are found in <code class="file docutils literal"><span class="pre">linux/kern_levels.h</span></code>. +Basically, these log levels are used by the system to route messages sent to +various outputs: console, log files in <code class="file docutils literal"><span class="pre">/var/log</span></code> etc.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>To display <code class="code docutils literal"><span class="pre">printk</span></code> messages in user space, the <code class="code docutils literal"><span class="pre">printk</span></code> +log level must be of higher priority than <cite>console_loglevel</cite> +variable. The default console log level can be configured from +<code class="file docutils literal"><span class="pre">/proc/sys/kernel/printk</span></code>.</p> +<p>For instance, the command:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nb">echo</span> <span class="m">8</span> > /proc/sys/kernel/printk +</pre></div> +</div> +<p class="last">will enable all the kernel log messages to be displayed in the +console. That is, the logging level has to be strictly less than the +<code class="code docutils literal"><span class="pre">console_loglevel</span></code> variable. For example, if the +<code class="code docutils literal"><span class="pre">console_loglevel</span></code> has a value of <code class="docutils literal"><span class="pre">5</span></code> (specific to +<code class="code docutils literal"><span class="pre">KERN_NOTICE</span></code>), only messages with loglevel stricter than <code class="docutils literal"><span class="pre">5</span></code> +(i.e <code class="code docutils literal"><span class="pre">KERN_EMERG</span></code>, <code class="code docutils literal"><span class="pre">KERN_ALERT</span></code>, <code class="code docutils literal"><span class="pre">KERN_CRIT</span></code>, +<code class="code docutils literal"><span class="pre">KERN_ERR</span></code>, <code class="code docutils literal"><span class="pre">KERN_WARNING</span></code>) will be shown.</p> +</div> +<p>Console-redirected messages can be useful for quickly viewing the effect of +executing the kernel code, but they are no longer so useful if the kernel +encounters an irreparable error and the system freezes. In this case, the logs +of the system must be consulted, as they keep the information between system +restarts. These are found in <code class="file docutils literal"><span class="pre">/var/log</span></code> and are text files, populated by +<code class="code docutils literal"><span class="pre">syslogd</span></code> and <code class="code docutils literal"><span class="pre">klogd</span></code> during the kernel run. <code class="code docutils literal"><span class="pre">syslogd</span></code> and +<code class="code docutils literal"><span class="pre">klogd</span></code> take the information from the virtual file system mounted in +<code class="file docutils literal"><span class="pre">/proc</span></code>. In principle, with <code class="code docutils literal"><span class="pre">syslogd</span></code> and <code class="code docutils literal"><span class="pre">klogd</span></code> turned on, +all messages coming from the kernel will go to <code class="file docutils literal"><span class="pre">/var/log/kern.log</span></code>.</p> +<p>A simpler version for debugging is using the <code class="file docutils literal"><span class="pre">/var/log/debug</span></code> file. It +is populated only with the <code class="code docutils literal"><span class="pre">printk</span></code> messages from the kernel with the +<code class="code docutils literal"><span class="pre">KERN_DEBUG</span></code> log level.</p> +<p>Given that a production kernel (similar to the one we're probably running with) +contains only release code, our module is among the few that send messages +prefixed with KERN_DEBUG . In this way, we can easily navigate through the +<code class="file docutils literal"><span class="pre">/var/log/debug</span></code> information by finding the messages corresponding to a +debugging session for our module.</p> +<p>Such an example would be the following:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># Clear the debug file of previous information (or possibly a backup)</span> +$ <span class="nb">echo</span> <span class="s2">"New debug session"</span> > /var/log/debug +<span class="c1"># Run the tests</span> +<span class="c1"># If there is no critical error causing a panic kernel, check the output</span> +<span class="c1"># if a critical error occurs and the machine only responds to a restart,</span> + restart the system and check /var/log/debug. +</pre></div> +</div> +<p>The format of the messages must obviously contain all the information of +interest in order to detect the error, but inserting in the code <code class="code docutils literal"><span class="pre">printk</span></code> +to provide detailed information can be as time-consuming as writing the code to +solve the problem. This is usually a trade-off between the completeness of the +debugging messages displayed using <code class="code docutils literal"><span class="pre">printk</span></code> and the time it takes to +insert these messages into the text.</p> +<p>A very simple way, less time-consuming for inserting <code class="code docutils literal"><span class="pre">printk</span></code> and +providing the possibility to analyze the flow of instructions for tests is the +use of the predefined constants <code class="code docutils literal"><span class="pre">__FILE__</span></code>, <code class="code docutils literal"><span class="pre">__LINE__</span></code> and +<code class="code docutils literal"><span class="pre">__func__</span></code>:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">__FILE__</span></code> is replaced by the compiler with the name of the source file +it is currently being compiled.</li> +<li><code class="docutils literal"><span class="pre">__LINE__</span></code> is replaced by the compiler with the line number on which the +current instruction is found in the current source file.</li> +<li><code class="docutils literal"><span class="pre">__func__</span></code> /<code class="docutils literal"><span class="pre">__FUNCTION__</span></code> is replaced by the compiler with the name +of the function in which the current instruction is found.</li> +</ul> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last"><code class="code docutils literal"><span class="pre">__FILE__</span></code> and <code class="code docutils literal"><span class="pre">__LINE__</span></code> are part of the ANSI C specifications: +<code class="code docutils literal"><span class="pre">__func__</span></code> is part of specification C99; <code class="code docutils literal"><span class="pre">__FUNCTION__</span></code> is a GNU +<code class="code docutils literal"><span class="pre">C</span></code> extension and is not portable; However, since we write code for the +<code class="code docutils literal"><span class="pre">Linux</span></code> kernel, we can use it without any problems.</p> +</div> +<p>The following macro definition can be used in this case:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define PRINT_DEBUG \</span> +<span class="cp"> printk (KERN_DEBUG "[% s]: FUNC:% s: LINE:% d \ n", __FILE__,</span> + <span class="n">__FUNCTION__</span><span class="p">,</span> <span class="n">__LINE__</span><span class="p">)</span> +</pre></div> +</div> +<p>Then, at each point where we want to see if it is "reached" in execution, +insert PRINT_DEBUG; This is a simple and quick way, and can yield by carefully +analyzing the output.</p> +<p>The <strong class="command">dmesg</strong> command is used to view the messages printed with +<code class="code docutils literal"><span class="pre">printk</span></code> but not appearing on the console.</p> +<p>To delete all previous messages from a log file, run:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>cat /dev/null > /var/log/debug +</pre></div> +</div> +<p>To delete messages displayed by the <strong class="command">dmesg</strong> command, run:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>dmesg -c +</pre></div> +</div> +</div> +<div class="section" id="dynamic-debugging"> +<h3>Dynamic debugging<a class="headerlink" href="#dynamic-debugging" title="Permalink to this headline">¶</a></h3> +<p>Dynamic <a class="reference external" href="https://www.kernel.org/doc/html/v4.15/admin-guide/dynamic-debug-howto.html">dyndbg</a> +debugging enables dynamic debugging activation/deactivation. +Unlike <code class="code docutils literal"><span class="pre">printk</span></code>, it offers more advanced <code class="code docutils literal"><span class="pre">printk</span></code> options for the +messages we want to display; it is very useful for complex modules or +troubleshooting subsystems. +This significantly reduces the amount of messages displayed, leaving only +those relevant for the debug context. To enable <code class="docutils literal"><span class="pre">dyndbg</span></code>, the kernel must be +compiled with the <code class="docutils literal"><span class="pre">CONFIG_DYNAMIC_DEBUG</span></code> option. Once configured, +<code class="code docutils literal"><span class="pre">pr_debug()</span></code>, <code class="code docutils literal"><span class="pre">dev_dbg()</span></code> and <code class="code docutils literal"><span class="pre">print_hex_dump_debug()</span></code>, +<code class="code docutils literal"><span class="pre">print_hex_dump_bytes()</span></code> can be dynamically enabled per call.</p> +<p>The <code class="file docutils literal"><span class="pre">/sys/kernel/debug/dynamic_debug/control</span></code> file from the debugfs (where +<code class="file docutils literal"><span class="pre">/sys/kernel/debug</span></code> is the path to which debugfs was mounted) is used to +filter messages or to view existing filters.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">mount</span> <span class="o">-</span><span class="n">t</span> <span class="n">debugfs</span> <span class="n">none</span> <span class="o">/</span><span class="n">debug</span> +</pre></div> +</div> +<p><a class="reference external" href="http://opensourceforu.com/2010/10/debugging-linux-kernel-with-debugfs/">Debugfs</a> +is a simple file system, used as a kernel-space interface and +user-space interface to configure different debug options. Any debug utility +can create and use its own files /folders in debugfs.</p> +<p>For example, to display existing filters in <code class="docutils literal"><span class="pre">dyndbg</span></code>, you will use:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>cat /debug/dynamic_debug/control +</pre></div> +</div> +<p>And to enable the debug message from line <code class="docutils literal"><span class="pre">1603</span></code> in the <code class="file docutils literal"><span class="pre">svcsock.c</span></code> file:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nb">echo</span> <span class="s1">'file svcsock.c line 1603 +p'</span> > /debug/dynamic_debug/control +</pre></div> +</div> +<p>The <code class="file docutils literal"><span class="pre">/debug/dynamic_debug/control</span></code> file is not a regular file. It shows +the <code class="docutils literal"><span class="pre">dyndbg</span></code> settings on the filters. Writing in it with an echo will change +these settings (it will not actually make a write). Be aware that the file +contains settings for <code class="docutils literal"><span class="pre">dyndbg</span></code> debugging messages. Do not log in this file.</p> +<div class="section" id="dyndbg-options"> +<h4>Dyndbg Options<a class="headerlink" href="#dyndbg-options" title="Permalink to this headline">¶</a></h4> +<ul> +<li><p class="first"><code class="docutils literal"><span class="pre">func</span></code> - just the debug messages from the functions that have the same +name as the one defined in the filter.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nb">echo</span> <span class="s1">'func svc_tcp_accept +p'</span> > /debug/dynamic_debug/control +</pre></div> +</div> +</li> +<li><p class="first"><code class="docutils literal"><span class="pre">file</span></code> - the name of the file(s) for which we want to display the debug +messages. It can be just the source name, but also the absolute path or +kernel-tree path.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>file svcsock.c +file kernel/freezer.c +file /usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c +</pre></div> +</div> +</li> +<li><p class="first"><code class="docutils literal"><span class="pre">module</span></code> - module name.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>module sunrpc +</pre></div> +</div> +</li> +<li><p class="first"><code class="docutils literal"><span class="pre">format</span></code> - only messages whose display format contains the specified string.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>format <span class="s2">"nfsd: SETATTR"</span> +</pre></div> +</div> +</li> +<li><p class="first"><code class="docutils literal"><span class="pre">line</span></code> - the line or lines for which we want to enable debug calls.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># Triggers debug messages between lines 1603 and 1605 in the svcsock.c file</span> +$ <span class="nb">echo</span> <span class="s1">'file svcsock.c line 1603-1605 +p'</span> > /sys/kernel/debug/dynamic_debug/control +<span class="c1"># Enables debug messages from the beginning of the file to line 1605</span> +$ <span class="nb">echo</span> <span class="s1">'file svcsock.c line -1605 +p'</span> > /sys/kernel/debug/dynamic_debug/control +</pre></div> +</div> +</li> +</ul> +<p>In addition to the above options, a series of flags can be added, removed, or set +with operators <code class="docutils literal"><span class="pre">+</span></code>, <code class="docutils literal"><span class="pre">-</span></code> or <code class="docutils literal"><span class="pre">=</span></code>:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">p</span></code> activates the pr_debug() .</li> +<li><code class="docutils literal"><span class="pre">f</span></code> includes the name of the function in the printed message.</li> +<li><code class="docutils literal"><span class="pre">l</span></code> includes the line number in the printed message.</li> +<li><code class="docutils literal"><span class="pre">m</span></code> includes the module name in the printed message.</li> +<li><code class="docutils literal"><span class="pre">t</span></code> includes the thread id if it is not called from interrupt context</li> +<li><code class="docutils literal"><span class="pre">_</span></code> no flag is set.</li> +</ul> +</div></blockquote> +</div> +</div> +<div class="section" id="kdb-kernel-debugger"> +<h3>KDB: Kernel debugger<a class="headerlink" href="#kdb-kernel-debugger" title="Permalink to this headline">¶</a></h3> +<p>The kernel debugger has proven to be very useful to facilitate the development and +debugging process. One of its main advantages is the possibility to perform live debugging. +This allows us to monitor, in real time, the accesses to memory or even modify the memory +while debugging. +The debugger has been integrated in the mainline kernel starting with version 2.6.26-rci. +KDB is not a <em>source debugger</em>, but for a complete analysis it can be used in parallel with +gdb and symbol files -- see <a class="reference internal" href="#gdb-intro"><span class="std std-ref">the GDB debugging section</span></a></p> +<p>To use KDB, you have the following options:</p> +<blockquote> +<div><ul class="simple"> +<li>non-usb keyboard + VGA text console</li> +<li>serial port console</li> +<li>USB EHCI debug port</li> +</ul> +</div></blockquote> +<p>For the lab, we will use a serial interface connected to the host. +The following command will activate GDB over the serial port:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nb">echo</span> hvc0 > /sys/module/kgdboc/parameters/kgdboc +</pre></div> +</div> +<p>KDB is a <em>stop mode debugger</em>, which means that, while it is active, all the other processes +are stopped. The kernel can be <em>forced</em> to enter KDB during execution using the following +<a class="reference external" href="http://en.wikipedia.org/wiki/Magic_SysRq_key">SysRq</a> command</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nb">echo</span> g > /proc/sysrq-trigger +</pre></div> +</div> +<p>or by using the key combination <code class="docutils literal"><span class="pre">Ctrl+O</span> <span class="pre">g</span></code> in a terminal connected to the serial port +(for example using <strong class="command">minicom</strong>).</p> +<p>KDB has various commands to control and define the context of the debugged system:</p> +<blockquote> +<div><ul class="simple"> +<li>lsmod, ps, kill, dmesg, env, bt (backtrace)</li> +<li>dump trace logs</li> +<li>hardware breakpoints</li> +<li>modifying memory</li> +</ul> +</div></blockquote> +<p>For a better description of the available commands you can use the <code class="docutils literal"><span class="pre">help</span></code> command in +the KDB shell. +In the next example, you can notice a simple KDB usage example which sets a hardware +breakpoint to monitor the changes of the <code class="docutils literal"><span class="pre">mVar</span></code> variable.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># trigger KDB</span> +<span class="nb">echo</span> g > /proc/sysrq-trigger +<span class="c1"># or if we are connected to the serial port issue</span> +Ctrl-O g +<span class="c1"># breakpoint on write access to the mVar variable</span> +kdb> bph mVar dataw +<span class="c1"># return from KDB</span> +kdb> go +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">If you want to learn how to easily browse through the Linux source code +and how to debug kernel code, read the <a class="reference external" href="#good-to-know">Good to know</a> +section.</p> +</div> +</div> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="section" id="remarks"> +<h3>Remarks<a class="headerlink" href="#remarks" title="Permalink to this headline">¶</a></h3> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<ul class="last simple"> +<li>Usually, the steps used to develop a kernel module are the +following:<ul> +<li>editing the module source code (on the physical machine);</li> +<li>module compilation (on the physical machine);</li> +<li>generation of the minimal image for the virtual machine; +this image contains the kernel, your module, busybox and +eventually test programs;</li> +<li>starting the virtual machine using QEMU;</li> +<li>running the tests in the virtual machine.</li> +</ul> +</li> +<li>When using cscope, use <code class="file docutils literal"><span class="pre">~/src/linux</span></code>. +If there is no <code class="file docutils literal"><span class="pre">cscope.out</span></code> file, you can generate it using +the command <strong class="command">make ARCH=x86 cscope</strong>.</li> +<li>You can find more details about the virtual machine at +<a class="reference internal" href="../info/vm.html#vm-link"><span class="std std-ref">Recommended Setup</span></a>.</li> +</ul> +</div> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p class="last">Before solving an exercice, <strong>carefully</strong> read all its bullets.</p> +</div> +<div class="admonition important" id="exercises-summary"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is kernel_modules. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/kernel_modules/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +</div> +<div class="section" id="kernel-module"> +<h3>1. Kernel module<a class="headerlink" href="#kernel-module" title="Permalink to this headline">¶</a></h3> +<p>To work with the kernel modules, we will follow the steps described +<a class="reference internal" href="#exercises-summary"><span class="std std-ref">above</span></a>.</p> +<dl class="docutils"> +<dt>Generate the skeleton for the task named <strong>1-2-test-mod</strong> then build the module,</dt> +<dd>by running the following command in <code class="file docutils literal"><span class="pre">tools/labs</span></code>.</dd> +</dl> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nv">LABS</span><span class="o">=</span>kernel_modules make skels +$ make build +</pre></div> +</div> +<p>These command will build all the modules in the current +lab skeleton.</p> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p class="last">Until after solving exercise 3, you will get a compilation error for +<code class="docutils literal"><span class="pre">3-error-mod</span></code>. To avoid this issue, remove the directory +<code class="file docutils literal"><span class="pre">skels/kernel_modules/3-error-mod/</span></code> and remove the corresponding +line from <code class="docutils literal"><span class="pre">skels/Kbuild</span></code>.</p> +</div> +<p>Start the VM using <strong class="command">make console</strong>, and perform the following tasks:</p> +<ul class="simple"> +<li>load the kernel module.</li> +<li>list the kernel modules and check if current module is present</li> +<li>unload the kernel module</li> +<li>view the messages displayed at loading/unloading the kernel module using +<strong class="command">dmesg</strong> command</li> +</ul> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Read <a class="reference internal" href="#loading-unloading-a-kernel-module">Loading/unloading a kernel module</a> section. When unloading +a kernel module, you can specify only the module name +(without extension).</p> +</div> +</div> +<div class="section" id="printk"> +<h3>2. Printk<a class="headerlink" href="#printk" title="Permalink to this headline">¶</a></h3> +<p>Watch the virtual machine console. Why were the messages displayed directly +to the virtual machine console?</p> +<p>Configure the system such that the messages are not displayed directly +on the serial console, and they can only be inspected using <code class="docutils literal"><span class="pre">dmesg</span></code>.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">One option is to set the console log level by writting +the desired level to <code class="docutils literal"><span class="pre">/proc/sys/kernel/printk</span></code>. +Use a value smaller than the level used for the prints in +the source code of the module.</p> +</div> +<p>Load/unload the module again. +The messages should not be printed to the virtual machine console, +but they should be visible when running <code class="docutils literal"><span class="pre">dmesg</span></code>.</p> +</div> +<div class="section" id="error"> +<h3>3. Error<a class="headerlink" href="#error" title="Permalink to this headline">¶</a></h3> +<p>Generate the skeleton for the task named <strong>3-error-mod</strong>. Compile the +sources and get the corresponding kernel module.</p> +<p>Why have compilation +errors occurred? <strong>Hint:</strong> How does this module differ from the previous module?</p> +<p>Modify the module to solve the cause of those errors, then compile and test +the module.</p> +</div> +<div class="section" id="sub-modules"> +<h3>4. Sub-modules<a class="headerlink" href="#sub-modules" title="Permalink to this headline">¶</a></h3> +<p>Inspect the C source files <code class="docutils literal"><span class="pre">mod1.c</span></code> and <code class="docutils literal"><span class="pre">mod2.c</span></code> in <code class="file docutils literal"><span class="pre">4-multi-mod/</span></code>. +Module 2 contains only the definition of a function used by module 1.</p> +<p>Change the <code class="file docutils literal"><span class="pre">Kbuild</span></code> file to create the <code class="docutils literal"><span class="pre">multi_mod.ko</span></code> module from the +two C source files.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Read the <a class="reference internal" href="#compiling-kernel-modules">Compiling kernel modules</a> section of the lab.</p> +</div> +<p>Compile, copy, boot the VM, load and unload the kernel module. Make sure messages +are properly displayed on the console.</p> +</div> +<div class="section" id="kernel-oops-1"> +<h3>5. Kernel oops<a class="headerlink" href="#kernel-oops-1" title="Permalink to this headline">¶</a></h3> +<p>Enter the directory for the task <strong>5-oops-mod</strong> and inspect the +C source file. Notice where the problem will occur. Add the compilation flag +<code class="docutils literal"><span class="pre">-g</span></code> in the Kbuild file.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Read <a class="reference internal" href="#compiling-kernel-modules">Compiling kernel modules</a> section of the lab.</p> +</div> +<p>Compile the corresponding module and load it into the kernel. Identify the memory +address at which the oops appeared.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Read <a href="#system-message-1"><span class="problematic" id="problematic-1">`Debugging`_</span></a> section of the lab. To identify the +address, follow the oops message and extract the value of +the instructions pointer (<code class="docutils literal"><span class="pre">EIP</span></code>) register.</p> +</div> +<p>Determine which instruction has triggered the oops.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use the <code class="file docutils literal"><span class="pre">proc/modules</span></code> information to get the load address of +the kernel module. Use, on the physical machine, objdump +and/or addr2line . Objdump needs debugging support for +compilation! Read the lab's <a class="reference internal" href="#objdump">objdump</a> and <a class="reference internal" href="#addr2line">addr2line</a> +sections.</p> +</div> +<p>Try to unload the kernel module. Notice that the operation does not +work because there are references from the kernel module within the +kernel since the oops; Until the release of those references (which is +almost impossible in the case of an oops), the module can not be +unloaded.</p> +</div> +<div class="section" id="module-parameters"> +<h3>6. Module parameters<a class="headerlink" href="#module-parameters" title="Permalink to this headline">¶</a></h3> +<p>Enter the directory for the task <strong>6-cmd-mod</strong> and inspect the C +<code class="docutils literal"><span class="pre">cmd_mod.c</span></code> source file. Compile and copy the associated module and +load the kernel module to see the printk message. Then unload the +module from the kernel.</p> +<p>Without modifying the sources, load the kernel module so that the +message shown is <code class="docutils literal"><span class="pre">Early</span> <span class="pre">bird</span> <span class="pre">gets</span> <span class="pre">tired</span></code>.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">The str variable can be changed by passing a parameter to +the module. Find more information <a class="reference external" href="http://tldp.org/LDP/lkmpg/2.6/html/x323.html">here</a>.</p> +</div> +<span class="target" id="proc-info"></span></div> +<div class="section" id="proc-info-1"> +<h3>7. Proc info<a class="headerlink" href="#proc-info-1" title="Permalink to this headline">¶</a></h3> +<p>Check the skeleton for the task named <strong>7-list-proc</strong>. Add code to +display the Process ID (<code class="docutils literal"><span class="pre">PID</span></code>) and the executable name for the current +process.</p> +<p>Follow the commands marked with <code class="docutils literal"><span class="pre">TODO</span></code>. +The information must be displayed both when loading and unloading the +module.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<ul class="last simple"> +<li>In the Linux kernel, a process is described by the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>. Use <a class="reference external" href="http://elixir.free-electrons.com/linux/latest/source">LXR</a> or <code class="docutils literal"><span class="pre">cscope</span></code> to find the +definition of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>.</li> +<li>To find the structure field that contains the name of the +executable, look for the "executable" comment.</li> +<li>The pointer to the structure of the current process +running at a given time in the kernel is given by the +<code class="xref c c-macro docutils literal"><span class="pre">current</span></code> variable (of the type +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct*</span></code>).</li> +</ul> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">To use <code class="xref c c-macro docutils literal"><span class="pre">current</span></code> you'll need to include the header +in which the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code> is defined, i.e +<code class="docutils literal"><span class="pre">linux/sched.h</span></code>.</p> +</div> +<p>Compile, copy, boot the VM and load the module. Unload the kernel module.</p> +<p>Repeat the loading/unloading operation. Note that the PIDs of the +displayed processes differ. This is because a process is created +from the executable <code class="file docutils literal"><span class="pre">/sbin/insmod</span></code> when the module is loaded and +when the module is unloaded a process is created from the executable +<code class="file docutils literal"><span class="pre">/sbin/rmmod</span></code>.</p> +</div> +</div> +<div class="section" id="good-to-know-1"> +<span id="good-to-know"></span><h2>Good to know<a class="headerlink" href="#good-to-know-1" title="Permalink to this headline">¶</a></h2> +<p>The following sections contain useful information for getitng used to the Linux +kernel code and debugging techniques.</p> +</div> +<div class="section" id="source-code-navigation"> +<h2>Source code navigation<a class="headerlink" href="#source-code-navigation" title="Permalink to this headline">¶</a></h2> +<div class="section" id="cscope"> +<span id="cscope-intro"></span><h3>cscope<a class="headerlink" href="#cscope" title="Permalink to this headline">¶</a></h3> +<p><a class="reference external" href="http://cscope.sourceforge.net/">Cscope</a> is a tool for +efficient navigation of C sources. To use it, a cscope database must +be generated from the existing sources. In a Linux tree, the command +<strong class="command">make ARCH=x86 cscope</strong> is sufficient. Specification of the +architecture through the ARCH variable is optional but recommended; +otherwise, some architecture dependent functions will appear multiple +times in the database.</p> +<p>You can build the cscope database with the command <strong class="command">make +ARCH=x86 COMPILED_SOURCE=1 cscope</strong>. This way, the cscope database will +only contain symbols that have already been used in the compile +process before, thus resulting in better performance when searching +for symbols.</p> +<p>Cscope can also be used as stand-alone, but it is more useful when +combined with an editor. To use cscope with <strong class="command">vim</strong>, it is necessary to +install both packages and add the following lines to the file +<code class="file docutils literal"><span class="pre">.vimrc</span></code> (the machine in the lab already has the settings):</p> +<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="k">if</span> has<span class="p">(</span><span class="s2">"cscope"</span><span class="p">)</span> +<span class="c"> " Look for a 'cscope.out' file starting from the current directory,</span> +<span class="c"> " going up to the root directory.</span> + <span class="k">let</span> s:dirs <span class="p">=</span> split<span class="p">(</span>getcwd<span class="p">(),</span> <span class="s2">"/"</span><span class="p">)</span> + <span class="k">while</span> s:dirs <span class="p">!=</span> [] + <span class="k">let</span> s:<span class="nb">path</span> <span class="p">=</span> <span class="s2">"/"</span> . <span class="k">join</span><span class="p">(</span>s:dirs<span class="p">,</span> <span class="s2">"/"</span><span class="p">)</span> + <span class="k">if</span> <span class="p">(</span>filereadable<span class="p">(</span>s:<span class="nb">path</span> . <span class="s2">"/cscope.out"</span><span class="p">))</span> + execute <span class="s2">"cs add "</span> . s:<span class="nb">path</span> . <span class="s2">"/cscope.out "</span> . s:<span class="nb">path</span> . <span class="s2">" -v"</span> + <span class="k">break</span> + <span class="k">endif</span> + <span class="k">let</span> s:dirs <span class="p">=</span> s:dirs[:<span class="m">-2</span>] + <span class="k">endwhile</span> + + <span class="k">set</span> <span class="nb">csto</span><span class="p">=</span><span class="m">0</span> <span class="c">" Use cscope first, then ctags</span> + <span class="k">set</span> <span class="nb">cst</span> <span class="c">" Only search cscope</span> + <span class="k">set</span> <span class="nb">csverb</span> <span class="c">" Make cs verbose</span> + + nmap `<span class="p"><</span>C<span class="p">-</span>\<span class="p">></span>`s :<span class="k">cs</span> find s `<span class="p"><</span>C<span class="p">-</span>R<span class="p">></span>`<span class="p">=</span>expand<span class="p">(</span><span class="s2">"`<cword>`"</span><span class="p">)</span>`<span class="p"><</span>CR<span class="p">></span>``<span class="p"><</span>CR<span class="p">></span>` + nmap `<span class="p"><</span>C<span class="p">-</span>\<span class="p">></span>`<span class="k">g</span> :<span class="k">cs</span> find <span class="k">g</span> `<span class="p"><</span>C<span class="p">-</span>R<span class="p">></span>`<span class="p">=</span>expand<span class="p">(</span><span class="s2">"`<cword>`"</span><span class="p">)</span>`<span class="p"><</span>CR<span class="p">></span>``<span class="p"><</span>CR<span class="p">></span>` + nmap `<span class="p"><</span>C<span class="p">-</span>\<span class="p">></span>`<span class="k">c</span> :<span class="k">cs</span> find <span class="k">c</span> `<span class="p"><</span>C<span class="p">-</span>R<span class="p">></span>`<span class="p">=</span>expand<span class="p">(</span><span class="s2">"`<cword>`"</span><span class="p">)</span>`<span class="p"><</span>CR<span class="p">></span>``<span class="p"><</span>CR<span class="p">></span>` + nmap `<span class="p"><</span>C<span class="p">-</span>\<span class="p">></span>`<span class="k">t</span> :<span class="k">cs</span> find <span class="k">t</span> `<span class="p"><</span>C<span class="p">-</span>R<span class="p">></span>`<span class="p">=</span>expand<span class="p">(</span><span class="s2">"`<cword>`"</span><span class="p">)</span>`<span class="p"><</span>CR<span class="p">></span>``<span class="p"><</span>CR<span class="p">></span>` + nmap `<span class="p"><</span>C<span class="p">-</span>\<span class="p">></span>`<span class="k">e</span> :<span class="k">cs</span> find <span class="k">e</span> `<span class="p"><</span>C<span class="p">-</span>R<span class="p">></span>`<span class="p">=</span>expand<span class="p">(</span><span class="s2">"`<cword>`"</span><span class="p">)</span>`<span class="p"><</span>CR<span class="p">></span>``<span class="p"><</span>CR<span class="p">></span>` + nmap `<span class="p"><</span>C<span class="p">-</span>\<span class="p">></span>`<span class="k">f</span> :<span class="k">cs</span> find <span class="k">f</span> `<span class="p"><</span>C<span class="p">-</span>R<span class="p">></span>`<span class="p">=</span>expand<span class="p">(</span><span class="s2">"`<cfile>`"</span><span class="p">)</span>`<span class="p"><</span>CR<span class="p">></span>``<span class="p"><</span>CR<span class="p">></span>` + nmap `<span class="p"><</span>C<span class="p">-</span>\<span class="p">></span>`<span class="k">i</span> :<span class="k">cs</span> find <span class="k">i</span> ^`<span class="p"><</span>C<span class="p">-</span>R<span class="p">></span>`<span class="p">=</span>expand<span class="p">(</span><span class="s2">"`<cfile>`"</span><span class="p">)</span>`<span class="p"><</span>CR<span class="p">></span>`$`<span class="p"><</span>CR<span class="p">></span>` + nmap `<span class="p"><</span>C<span class="p">-</span>\<span class="p">></span>`<span class="k">d</span> :<span class="k">cs</span> find <span class="k">d</span> `<span class="p"><</span>C<span class="p">-</span>R<span class="p">></span>`<span class="p">=</span>expand<span class="p">(</span><span class="s2">"`<cword>`"</span><span class="p">)</span>`<span class="p"><</span>CR<span class="p">></span>``<span class="p"><</span>CR<span class="p">></span>` + nmap <span class="p"><</span>F6<span class="p">></span> :cnext <span class="p"><</span>CR<span class="p">></span> + nmap <span class="p"><</span>F5<span class="p">></span> :cprev <span class="p"><</span>CR<span class="p">></span> + +<span class="c"> " Open a quickfix window for the following queries.</span> + <span class="k">set</span> <span class="nb">cscopequickfix</span><span class="p">=</span>s<span class="p">-,</span><span class="k">c</span><span class="p">-,</span><span class="k">d</span><span class="p">-,</span><span class="k">i</span><span class="p">-,</span><span class="k">t</span><span class="p">-,</span><span class="k">e</span><span class="p">-,</span><span class="k">g</span><span class="p">-</span> +<span class="k">endif</span> +</pre></div> +</div> +<p>The script searches for a file called <code class="file docutils literal"><span class="pre">cscope.out</span></code> in the current directory, or +in parent directories. If <strong class="command">vim</strong> finds this file, you can use the shortcut <code class="code docutils literal"><span class="pre">Ctrl</span> <span class="pre">+]</span></code> +or <code class="code docutils literal"><span class="pre">Ctrl+\</span> <span class="pre">g</span></code> (the combination control-\ followed by g) to jump directly to +the definition of the word under the cursor (function, variable, structure, etc.). +Similarly, you can use <code class="code docutils literal"><span class="pre">Ctrl+\</span> <span class="pre">s</span></code> to go where the word under the cursor is used.</p> +<p>You can take a cscope-enabled <code class="file docutils literal"><span class="pre">.vimrc</span></code> file (also contains other goodies) from +<a class="reference external" href="https://github.com/ddvlad/cfg/blob/master/_vimrc">https://github.com/ddvlad/cfg/blob/master/_vimrc</a>. +The following guidelines are based on this file, but also show basic <strong class="command">vim</strong> commands +that have the same effect.</p> +<p>If there are more than one results (usually there are) you can move between them +using <code class="code docutils literal"><span class="pre">F6</span></code> and <code class="code docutils literal"><span class="pre">F5</span></code> (<code class="code docutils literal"><span class="pre">:ccnext</span></code> and <code class="code docutils literal"><span class="pre">:cprev</span></code>). +You can also open a new panel showing the results using <code class="code docutils literal"><span class="pre">:copen</span></code>. To close +the panel, use the <code class="code docutils literal"><span class="pre">:cclose</span></code> command.</p> +<p>To return to the previous location, use <code class="code docutils literal"><span class="pre">Ctrl+o</span></code> (o, not zero). +The command can be used multiple times and works even if cscope changed the +file you are currently editing.</p> +<p>To go to a symbol definition directly when <strong class="command">vim</strong> starts, use <code class="code docutils literal"><span class="pre">vim</span> <span class="pre">-t</span> <span class="pre"><symbol_name></span></code> +(for example <code class="code docutils literal"><span class="pre">vim</span> <span class="pre">-t</span> <span class="pre">task_struct</span></code>). Otherwise, if you started <strong class="command">vim</strong> and want +to search for a symbol by name, use <code class="code docutils literal"><span class="pre">cs</span> <span class="pre">find</span> <span class="pre">g</span> <span class="pre"><symbol_name></span></code> (for example +<code class="code docutils literal"><span class="pre">cs</span> <span class="pre">find</span> <span class="pre">g</span> <span class="pre">task_struct</span></code>).</p> +<p>If you found more than one results and opened a panel showing all the matches +(using <code class="code docutils literal"><span class="pre">:copen</span></code>) and you want to find a symbol of type structure, +it is recommended to search in the results panel (using <code class="code docutils literal"><span class="pre">/</span></code> -- slash) +the character <code class="code docutils literal"><span class="pre">{</span></code> (opening brace).</p> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>You can get a summary of all the <strong class="command">cscope</strong> commands using <strong class="command">:cs help</strong>.</p> +<p class="last">For more info, use the <strong class="command">vim</strong> built-in help command: <strong class="command">:h cscope</strong> or <strong class="command">:h copen</strong>.</p> +</div> +<p>If you use <strong class="command">emacs</strong>, install the <code class="code docutils literal"><span class="pre">xcscope-el</span></code> package and +add the following lines in <code class="file docutils literal"><span class="pre">~/.emacs</span></code>.</p> +<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="p">(</span>require ‘xcscope<span class="p">)</span> +<span class="p">(</span><span class="k">cscope</span><span class="p">-</span>setup<span class="p">)</span> +</pre></div> +</div> +<p>These commands will activate cscope for the C and C++ modes automatically. +<code class="code docutils literal"><span class="pre">C-s</span> <span class="pre">s</span></code> is the key bindings prefix and <code class="code docutils literal"><span class="pre">C-s</span> <span class="pre">s</span> <span class="pre">s</span></code> is used to +search for a symbol (if you call it when the cursor is over a word, +it will use that). For more details, check <cite>https://github.com/dkogan/xcscope.el</cite></p> +</div> +<div class="section" id="clangd"> +<h3>clangd<a class="headerlink" href="#clangd" title="Permalink to this headline">¶</a></h3> +<p><a class="reference external" href="https://clangd.llvm.org/">Clangd</a> is a language server that provides tools +for navigating C and C++ code. +<a class="reference external" href="https://microsoft.github.io/language-server-protocol/">Language Server Protocol</a> +facilitates features like go-to-definition, find-references, hover, completion, etc., +using semantic whole project analysis.</p> +<p>Clangd requires a compilation database to understand the kernel source code. +It can be generated with:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>make defconfig +make +scripts/clang-tools/gen_compile_commands.py +</pre></div> +</div> +<p>LSP clients:</p> +<ul class="simple"> +<li>Vim/Neovim (<a class="reference external" href="https://github.com/neoclide/coc.nvim">coc.nvim</a>, <a class="reference external" href="https://github.com/neovim/nvim-lspconfig">nvim-lsp</a>, <a class="reference external" href="https://github.com/natebosch/vim-lsc">vim-lsc</a>, <a class="reference external" href="https://github.com/prabirshrestha/vim-lsp">vim-lsp</a>)</li> +<li>Emacs (<a class="reference external" href="https://github.com/emacs-lsp/lsp-mode">lsp-mode</a>)</li> +<li>VSCode (<a class="reference external" href="https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd">clangd extension</a>)</li> +</ul> +</div> +<div class="section" id="kscope"> +<h3>Kscope<a class="headerlink" href="#kscope" title="Permalink to this headline">¶</a></h3> +<p>For a simpler interface, <a class="reference external" href="http://sourceforge.net/projects/kscope/">Kscope</a> +is a cscope frontend which uses QT. It is lightweight, very fast and very +easy to use. It allows searching using regular expressions, call graphs, etc. +Kscope is no longer mantained.</p> +<p>There is also a <a class="reference external" href="https///opendesktop.org/content/show.php/Kscope4?content=156987">port</a> +of version 1.6 for Qt4 and KDE 4 which keeps the integration of the text +editor Kate and is easier to use than the last version on SourceForge.</p> +</div> +<div class="section" id="lxr-cross-reference"> +<h3>LXR Cross-Reference<a class="headerlink" href="#lxr-cross-reference" title="Permalink to this headline">¶</a></h3> +<p>LXR (LXR Cross-Reference) is a tool that allows indexing and +referencing the symbols in the source code of a program using +a web interface. The web interface shows links to +locations in files where a symbol is defined or used. Development website +for LXR is <a class="reference external" href="http://sourceforge.net/projects/lxr">http://sourceforge.net/projects/lxr</a>. Similar tools +are <a class="reference external" href="http://oracle.github.io/opengrok/">OpenGrok</a> and +<a class="reference external" href="http://en.wikipedia.org/wiki/Gonzui">Gonzui</a>.</p> +<p>Although LXR was originally intended for the Linux kernel sources, it is +also used in the sources of <a class="reference external" href="http://lxr.mozilla.org/">Mozilla</a>, +<a class="reference external" href="http://apache.wirebrain.de/lxr/">Apache HTTP Server</a> and +<a class="reference external" href="http://lxr.linux.no/freebsd/source">FreeBSD</a>.</p> +<p>There are a number of sites that use LXR for cross-referencing the +the sources of the Linux kernel, the main site being <a class="reference external" href="http://lxr.linux.no/linux/">the original site of +development</a> which does not work anymore. You can +use <a class="reference external" href="https://elixir.bootlin.com/">https://elixir.bootlin.com/</a>.</p> +<p>LXR allows searching for an identifier (symbol), after a free text +or after a file name. The main feature and, at the same +time, the main advantage provided is the ease of finding the declaration +of any global identifier. This way, it facilitates quick access to function +declarations, variables, macro definitions and the code can be easily +navigated. Also, the fact that it can detect what code areas are affected +when a variable or function is changed is a real advantage in the development +and debugging phase.</p> +</div> +<div class="section" id="sourceweb"> +<h3>SourceWeb<a class="headerlink" href="#sourceweb" title="Permalink to this headline">¶</a></h3> +<p><a class="reference external" href="http://rprichard.github.io/sourceweb/">SourceWeb</a> is a source code indexer +for C and C++. It uses the +<a class="reference external" href="http://clang.llvm.org/docs/IntroductionToTheClangAST.html">framework</a> +provided by the Clang compiler to index the code.</p> +<p>The main difference between cscope and SourceWeb is the fact that SourceWeb +is, in a way, a compiler pass. SourceWeb doesn't index all the code, but +only the code that was efectively compiled by the compiler. This way, some +problems are eliminated, such as ambiguities about which variant of a function +defined in multiple places is used. This also means that the indexing takes +more time, because the compiled files must pass one more time through +the indexer to generate the references.</p> +<p>Usage example:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>make oldconfig +sw-btrace make -j4 +sw-btrace-to-compile-db +sw-clang-indexer --index-project +sourceweb index +</pre></div> +</div> +<p><code class="file docutils literal"><span class="pre">sw-btrace</span></code> is a script that adds the <code class="file docutils literal"><span class="pre">libsw-btrace.so</span></code> +library to <code class="code docutils literal"><span class="pre">LD_PRELOAD</span></code>. This way, the library is loaded by +every process started by <code class="code docutils literal"><span class="pre">make</span></code> (basically, the compiler), +registers the commands used to start the processes and generates +a filed called <code class="file docutils literal"><span class="pre">btrace.log</span></code>. This file is then used by +<code class="code docutils literal"><span class="pre">sw-btrace-to-compile-db</span></code> which converts it to a format defined +by clang: <a class="reference external" href="http://clang.llvm.org/docs/JSONCompilationDatabase.html">JSON Compilation Database</a>. +This JSON Compilation Database resulted from the above steps is then +used by the indexer, which makes one more pass through the compiled +source files and generates the index used by the GUI.</p> +<p>Word of advice: don't index the sources you are working with, but use +a copy, because SourceWeb doesn't have, at this moment, the capability +to regenerate the index for a single file and you will have to regenerate +the complete index.</p> +</div> +</div> +<div class="section" id="kernel-debugging"> +<h2>Kernel Debugging<a class="headerlink" href="#kernel-debugging" title="Permalink to this headline">¶</a></h2> +<p>Debugging a kernel is a much more difficult process than the debugging +of a program, because there is no support from the operating system. +This is why this process is usually done using two computers, connected +on serial interfaces.</p> +<div class="section" id="gdb-linux"> +<span id="gdb-intro"></span><h3>gdb (Linux)<a class="headerlink" href="#gdb-linux" title="Permalink to this headline">¶</a></h3> +<p>A simpler debug method on Linux, but with many disadvantages, +is local debugging, using <a class="reference external" href="http://www.gnu.org/software/gdb/">gdb</a>, +the uncompressed kernel image (<code class="file docutils literal"><span class="pre">vmlinux</span></code>) and <code class="file docutils literal"><span class="pre">/proc/kcore</span></code> +(the real-time kernel image). This method is usually used to inspect +the kernel and detect certain inconsistencies while it runs. The +method is useful especially if the kernel was compiled using the +<code class="code docutils literal"><span class="pre">-g</span></code> option, which keeps debug information. Some well-known +debug techniques can't be used by this method, such as breakpoints +of data modification.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>Because <code class="file docutils literal"><span class="pre">/proc</span></code> is a virtual filesystem, <code class="file docutils literal"><span class="pre">/proc/kcore</span></code> +does not physically exist on the disk. It is generated on-the-fly +by the kernel when a program tries to access <code class="file docutils literal"><span class="pre">proc/kcore</span></code>.</p> +<p>It is used for debugging purposes.</p> +<p>From <strong class="command">man proc</strong>, we have:</p> +<div class="last highlight-none"><div class="highlight"><pre><span></span>/proc/kcore +This file represents the physical memory of the system and is stored in the ELF core file format. With this pseudo-file, and +an unstripped kernel (/usr/src/linux/vmlinux) binary, GDB can be used to examine the current state of any kernel data struc‐ +tures. +</pre></div> +</div> +</div> +<p>The uncompressed kernel image offers information about the data structures +and symbols it contains.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>student@eg106$ <span class="nb">cd</span> ~/src/linux +student@eg106$ file vmlinux +vmlinux: ELF <span class="m">32</span>-bit LSB executable, Intel <span class="m">80386</span>, ... +student@eg106$ nm vmlinux <span class="p">|</span> grep sys_call_table +c02e535c R sys_call_table +student@eg106$ cat System.map <span class="p">|</span> grep sys_call_table +c02e535c R sys_call_table +</pre></div> +</div> +<p>The <strong class="command">nm</strong> utility is used to show the symbols in an object or +executable file. In our case, <code class="file docutils literal"><span class="pre">vmlinux</span></code> is an ELF file. Alternately, +we can use the file <code class="file docutils literal"><span class="pre">System.map</span></code> to view information about the +symbols in kernel.</p> +<p>Then we use <strong class="command">gdb</strong> to inspect the symbols using the uncompressed +kernel image. A simple <strong class="command">gdb</strong> session is the following:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>student@eg106$ <span class="nb">cd</span> ~/src/linux +stduent@eg106$ gdb --quiet vmlinux +Using host libthread_db library <span class="s2">"/lib/tls/libthread_db.so.1"</span>. +<span class="o">(</span>gdb<span class="o">)</span> x/x 0xc02e535c +0xc02e535c <span class="sb">`</span><sys_call_table><span class="sb">`</span>: 0xc011bc58 +<span class="o">(</span>gdb<span class="o">)</span> x/16 0xc02e535c +0xc02e535c <span class="sb">`</span><sys_call_table><span class="sb">`</span>: 0xc011bc58 0xc011482a 0xc01013d3 0xc014363d +0xc02e536c <span class="sb">`</span><sys_call_table+16><span class="sb">`</span>: 0xc014369f 0xc0142d4e 0xc0142de5 0xc011548b +0xc02e537c <span class="sb">`</span><sys_call_table+32><span class="sb">`</span>: 0xc0142d7d 0xc01507a1 0xc015042c 0xc0101431 +0xc02e538c <span class="sb">`</span><sys_call_table+48><span class="sb">`</span>: 0xc014249e 0xc0115c6c 0xc014fee7 0xc0142725 +<span class="o">(</span>gdb<span class="o">)</span> x/x sys_call_table +0xc011bc58 <span class="sb">`</span><sys_restart_syscall><span class="sb">`</span>: 0xffe000ba +<span class="o">(</span>gdb<span class="o">)</span> x/x <span class="p">&</span>sys_call_table +0xc02e535c <span class="sb">`</span><sys_call_table><span class="sb">`</span>: 0xc011bc58 +<span class="o">(</span>gdb<span class="o">)</span> x/16 <span class="p">&</span>sys_call_table +0xc02e535c <span class="sb">`</span><sys_call_table><span class="sb">`</span>: 0xc011bc58 0xc011482a 0xc01013d3 0xc014363d +0xc02e536c <span class="sb">`</span><sys_call_table+16><span class="sb">`</span>: 0xc014369f 0xc0142d4e 0xc0142de5 0xc011548b +0xc02e537c <span class="sb">`</span><sys_call_table+32><span class="sb">`</span>: 0xc0142d7d 0xc01507a1 0xc015042c 0xc0101431 +0xc02e538c <span class="sb">`</span><sys_call_table+48><span class="sb">`</span>: 0xc014249e 0xc0115c6c 0xc014fee7 0xc0142725 +<span class="o">(</span>gdb<span class="o">)</span> x/x sys_fork +0xc01013d3 <span class="sb">`</span><sys_fork><span class="sb">`</span>: 0x3824548b +<span class="o">(</span>gdb<span class="o">)</span> disass sys_fork +Dump of assembler code <span class="k">for</span> <span class="k">function</span> sys_fork: +0xc01013d3 <span class="sb">`</span><sys_fork+0><span class="sb">`</span>: mov 0x38<span class="o">(</span>%esp<span class="o">)</span>,%edx +0xc01013d7 <span class="sb">`</span><sys_fork+4><span class="sb">`</span>: mov <span class="nv">$0</span>x11,%eax +0xc01013dc <span class="sb">`</span><sys_fork+9><span class="sb">`</span>: push <span class="nv">$0</span>x0 +0xc01013de <span class="sb">`</span><sys_fork+11><span class="sb">`</span>: push <span class="nv">$0</span>x0 +0xc01013e0 <span class="sb">`</span><sys_fork+13><span class="sb">`</span>: push <span class="nv">$0</span>x0 +0xc01013e2 <span class="sb">`</span><sys_fork+15><span class="sb">`</span>: lea 0x10<span class="o">(</span>%esp<span class="o">)</span>,%ecx +0xc01013e6 <span class="sb">`</span><sys_fork+19><span class="sb">`</span>: call 0xc0111aab <span class="sb">`</span><do_fork><span class="sb">`</span> +0xc01013eb <span class="sb">`</span><sys_fork+24><span class="sb">`</span>: add <span class="nv">$0</span>xc,%esp +0xc01013ee <span class="sb">`</span><sys_fork+27><span class="sb">`</span>: ret +End of assembler dump. +</pre></div> +</div> +<p>It can be noticed that the uncompressed kernel image was used as an argument +for <strong class="command">gdb</strong>. The image can be found in the root of the kernel sources +after compilation.</p> +<p>A few commands used for debugging using <strong class="command">gdb</strong> are:</p> +<ul class="simple"> +<li><strong class="command">x</strong> (examine) - Used to show the contents of the memory area +whose address is specified as an argument to the command (this address +can be the value of a physical address, a symbol or the address of a +symbol). It can take as arguments (preceded by <code class="code docutils literal"><span class="pre">/</span></code>): the format +to display the data in (<code class="code docutils literal"><span class="pre">x</span></code> for hexadecimal, <code class="code docutils literal"><span class="pre">d</span></code> for +decimal, etc.), how many memory units to display and the size of a +memory unit.</li> +<li><strong class="command">disassemble</strong> - Used to disassemble a function.</li> +<li><strong class="command">p</strong> (print) - Used to evaluate and show the value of an +expression. The format to show the data in can be specified as +an argument (<code class="code docutils literal"><span class="pre">/x</span></code> for hexadecimal, <code class="code docutils literal"><span class="pre">/d</span></code> for decimal, etc.).</li> +</ul> +<p>The analysis of the kernel image is a method of static analysis. If we +want to perform dynamic analysis (analyzing how the kernel runs, not +only its static image) we can use <code class="file docutils literal"><span class="pre">/proc/kcore</span></code>; this is a dynamic +image (in memory) of the kernel.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>student@eg106$ gdb ~/src/linux/vmlinux /proc/kcore +Core was generated by `root=/dev/hda3 ro'. +#0 0x00000000 in ?? () +(gdb) p sys_call_table +$1 = -1072579496 +(gdb) p /x sys_call_table +$2 = 0xc011bc58 +(gdb) p /x &sys_call_table +$3 = 0xc02e535c +(gdb) x/16 &sys_call_table +0xc02e535c `<sys_call_table>`: 0xc011bc58 0xc011482a 0xc01013d3 0xc014363d +0xc02e536c `<sys_call_table+16>`: 0xc014369f 0xc0142d4e 0xc0142de5 0xc011548b +0xc02e537c `<sys_call_table+32>`: 0xc0142d7d 0xc01507a1 0xc015042c 0xc0101431 +0xc02e538c `<sys_call_table+48>`: 0xc014249e 0xc0115c6c 0xc014fee7 0xc0142725 +</pre></div> +</div> +<p>Using the dynamic image of the kernel is useful for detecting <a class="reference external" href="http://en.wikipedia.org/wiki/Rootkit">rootkits</a>.</p> +<ul class="simple"> +<li><a class="reference external" href="http://linuxdriver.co.il/ldd3/linuxdrive3-CHP-4-SECT-6.html">Linux Device Drivers 3rd Edition - Debuggers and Related Tools</a></li> +<li><a class="reference external" href="http://www.securityfocus.com/infocus/1811">Detecting Rootkits and Kernel-level Compromises in Linux</a></li> +<li><a class="reference external" href="http://user-mode-linux.sf.net/">User-Mode Linux</a></li> +</ul> +</div> +<div class="section" id="getting-a-stack-trace"> +<h3>Getting a stack trace<a class="headerlink" href="#getting-a-stack-trace" title="Permalink to this headline">¶</a></h3> +<p>Sometimes, you will want information about the trace the execution +reaches a certain point. You can determine this information using +<strong class="command">cscope</strong> or LXR, but some function are called from many +execution paths, which makes this method difficult.</p> +<p>In these situations, it is useful to get a stack trace, which can be +simply done using the function <code class="code docutils literal"><span class="pre">dump_stack()</span></code>.</p> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lec12-virtualization.html" class="btn btn-neutral float-left" title="SO2 Lecture 12 - Virtualization" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lab2-kernel-api.html" class="btn btn-neutral float-right" title="SO2 Lab 02 - Kernel API" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lab10-networking.html b/refs/pull/405/merge/so2/lab10-networking.html new file mode 100644 index 00000000..3de3e5af --- /dev/null +++ b/refs/pull/405/merge/so2/lab10-networking.html @@ -0,0 +1,1418 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lab 10 - Networking — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lab 11 - Kernel Development on ARM" href="lab11-arm-kernel-development.html" /> + <link rel="prev" title="SO2 Lab 09 - File system drivers (Part 2)" href="lab9-filesystems-part2.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lab 10 - Networking</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#overview">Overview</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#networking-in-user-space">Networking in user space</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#linux-networking">Linux networking</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#the-struct-socket-structure">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="#the-struct-sock-structure">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">sock</span></code> structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="#the-struct-sk-buff-structure">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">sk_buff</span></code> structure</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#conversions-1">Conversions</a></li> +<li class="toctree-l3"><a class="reference internal" href="#netfilter-1">netfilter</a></li> +<li class="toctree-l3"><a class="reference internal" href="#netcat">netcat</a></li> +<li class="toctree-l3"><a class="reference internal" href="#further-reading">Further reading</a></li> +<li class="toctree-l3"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#displaying-packets-in-kernel-space">1. Displaying packets in kernel space</a></li> +<li class="toctree-l4"><a class="reference internal" href="#filtering-by-destination-address">2. Filtering by destination address</a></li> +<li class="toctree-l4"><a class="reference internal" href="#listening-on-a-tcp-socket">3. Listening on a TCP socket</a></li> +<li class="toctree-l4"><a class="reference internal" href="#accepting-connections-in-kernel-space">4. Accepting connections in kernel space</a></li> +<li class="toctree-l4"><a class="reference internal" href="#udp-socket-sender">5. UDP socket sender</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lab 10 - Networking</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lab10-networking.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lab-10-networking"> +<h1>SO2 Lab 10 - Networking<a class="headerlink" href="#so2-lab-10-networking" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<blockquote> +<div><ul class="simple"> +<li>Understanding the Linux kernel networking architecture</li> +<li>Acquiring practical IP packet management skills using a packet filter or +firewall</li> +<li>Familiarize yourself with how to use sockets at the Linux kernel level</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="overview"> +<h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline">¶</a></h2> +<p>The development of the Internet has led to an exponential increase in network +applications and, as a consequence, to increasing the speed and productivity +requirements of an operating system's networking subsystem. The networking +subsystem is not an essential component of an operating system kernel (the Linux +kernel can be compiled without networking support). It is, however, quite +unlikely for a computing system (or even an embedded device) to have a +non-networked operating system due to the need for connectivity. Modern operating +systems use the <a class="reference external" href="https://en.wikipedia.org/wiki/Internet_protocol_suite">TCP/IP stack</a>. Their kernel +implements protocols up to the transport layer, while application layer protocols +are typically implemented in user space (HTTP, FTP, SSH, etc.).</p> +<div class="section" id="networking-in-user-space"> +<h3>Networking in user space<a class="headerlink" href="#networking-in-user-space" title="Permalink to this headline">¶</a></h3> +<p>In user space the abstraction of network communication is the socket. The +socket abstracts a communication channel and is the kernel-based TCP/IP stack +interaction interface. An IP socket is associated with an IP address, the +transport layer protocol used (TCP, UDP etc) and a port. Common function calls +that use sockets are: creation (<code class="docutils literal"><span class="pre">socket</span></code>), initialization +(<code class="docutils literal"><span class="pre">bind</span></code>), connecting (<code class="docutils literal"><span class="pre">connect</span></code>), waiting for a connection +(<code class="docutils literal"><span class="pre">listen</span></code>, <code class="docutils literal"><span class="pre">accept</span></code>), closing a socket (<code class="docutils literal"><span class="pre">close</span></code>).</p> +<p>Network communication is accomplished via <code class="docutils literal"><span class="pre">read</span></code>/<code class="docutils literal"><span class="pre">write</span></code> or <code class="docutils literal"><span class="pre">recv</span></code>/<code class="docutils literal"><span class="pre">send</span></code> calls +for TCP sockets and <code class="docutils literal"><span class="pre">recvfrom</span></code>/<code class="docutils literal"><span class="pre">sendto</span></code> for UDP sockets. Transmission and +reception operations are transparent to the application, leaving encapsulation +and transmission over network at the kernel's discretion. However, it is +possible to implement the TCP/IP stack in user space using raw sockets (the +<code class="docutils literal"><span class="pre">PF_PACKET</span></code> option when creating a socket), or implementing an application +layer protocol in kernel (<a class="reference external" href="http://en.wikipedia.org/wiki/TUX_web_server">TUX web server</a>).</p> +<p>For more details about user space programming using sockets, see <a class="reference external" href="https://www.beej.us/guide/bgnet/">Beej's Guide to +Network Programming Using Internet +Sockets</a>.</p> +</div> +</div> +<div class="section" id="linux-networking"> +<h2>Linux networking<a class="headerlink" href="#linux-networking" title="Permalink to this headline">¶</a></h2> +<p>The Linux kernel provides three basic structures for working with network +packets: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code>, <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sock</span></code> and <code class="xref c c-type docutils literal"><span class="pre">struct</span> +<span class="pre">sk_buff</span></code>.</p> +<p>The first two are abstractions of a socket:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> is an abstraction very close to user space, ie <a class="reference external" href="http://en.wikipedia.org/wiki/Berkeley_sockets">BSD +sockets</a> used to program +network applications;</li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sock</span></code> or <em>INET socket</em> in Linux terminology is the network +representation of a socket.</li> +</ul> +</div></blockquote> +<p>The two structures are related: the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> contains an INET +socket field, and the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sock</span></code> has a BSD socket that holds it.</p> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sk_buff</span></code> structure is the representation of a network packet +and its status. The structure is created when a kernel packet is received, +either from the user space or from the network interface.</p> +<div class="section" id="the-struct-socket-structure"> +<h3>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> structure<a class="headerlink" href="#the-struct-socket-structure" title="Permalink to this headline">¶</a></h3> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> structure is the kernel representation of a BSD +socket, the operations that can be executed on it are similar to those offered +by the kernel (through system calls). Common operations with sockets +(creation, initialization/bind, closing, etc.) result in specific system +calls; they work with the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> structure.</p> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> operations are described in <code class="file docutils literal"><span class="pre">net/socket.c</span></code> and +are independent of the protocol type. The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> structure is thus +a generic interface over particular network operations implementations. +Typically, the names of these operations begin with the <code class="docutils literal"><span class="pre">sock_</span></code> prefix.</p> +<div class="section" id="operations-on-the-socket-structure"> +<span id="socketstructops"></span><h4>Operations on the socket structure<a class="headerlink" href="#operations-on-the-socket-structure" title="Permalink to this headline">¶</a></h4> +<p>Socket operations are:</p> +<div class="section" id="creation"> +<h5>Creation<a class="headerlink" href="#creation" title="Permalink to this headline">¶</a></h5> +<p>Creation is similar to calling the <code class="xref c c-func docutils literal"><span class="pre">socket()</span></code> function in user space, but the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> created will be stored in the <code class="docutils literal"><span class="pre">res</span></code> parameter:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">int</span> <span class="pre">sock_create(int</span> <span class="pre">family,</span> <span class="pre">int</span> <span class="pre">type,</span> <span class="pre">int</span> <span class="pre">protocol,</span> <span class="pre">struct</span> <span class="pre">socket</span> <span class="pre">**res)</span></code> +creates a socket after the <code class="xref c c-func docutils literal"><span class="pre">socket()</span></code> system call;</li> +<li><code class="docutils literal"><span class="pre">int</span> <span class="pre">sock_create_kern(struct</span> <span class="pre">net</span> <span class="pre">*net,</span> <span class="pre">int</span> <span class="pre">family,</span> <span class="pre">int</span> <span class="pre">type,</span> <span class="pre">int</span> <span class="pre">protocol,</span> +<span class="pre">struct</span> <span class="pre">socket</span> <span class="pre">**res)</span></code> creates a kernel socket;</li> +<li><code class="docutils literal"><span class="pre">int</span> <span class="pre">sock_create_lite(int</span> <span class="pre">family,</span> <span class="pre">int</span> <span class="pre">type,</span> <span class="pre">int</span> <span class="pre">protocol,</span> <span class="pre">struct</span> <span class="pre">socket</span> <span class="pre">**res)</span></code> +creates a kernel socket without parameter sanity checks.</li> +</ul> +</div></blockquote> +<p>The parameters of these calls are as follows:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">net</span></code>, where it is present, used as reference to the network namespace used; +we will usually initialize it with <code class="docutils literal"><span class="pre">init_net</span></code>;</li> +<li><code class="docutils literal"><span class="pre">family</span></code> represents the family of protocols used in the transfer of +information; they usually begin with the <code class="docutils literal"><span class="pre">PF_</span></code> (Protocol Family) string; +the constants representing the family of protocols used are found in +<code class="file docutils literal"><span class="pre">linux/socket.h</span></code>, of which the most commonly used is <code class="docutils literal"><span class="pre">PF_INET</span></code>, for +TCP/IP protocols;</li> +<li><code class="docutils literal"><span class="pre">type</span></code> is the type of socket; the constants used for this parameter are +found in <code class="file docutils literal"><span class="pre">linux/net.h</span></code>, of which the most used are <code class="docutils literal"><span class="pre">SOCK_STREAM</span></code> for +a connection based source-to-destination communication and <code class="docutils literal"><span class="pre">SOCK_DGRAM</span></code> +for connectionless communication;</li> +<li><code class="docutils literal"><span class="pre">protocol</span></code> represents the protocol used and is closely related to the +<code class="docutils literal"><span class="pre">type</span></code> parameter; the constants used for this parameter are found in +<code class="file docutils literal"><span class="pre">linux/in.h</span></code>, of which the most used are <code class="docutils literal"><span class="pre">IPPROTO_TCP</span></code> for TCP and +<code class="docutils literal"><span class="pre">IPPROTO_UDP</span></code> for UDP.</li> +</ul> +</div></blockquote> +<p>To create a TCP socket in kernel space, you must call:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">;</span> +<span class="kt">int</span> <span class="n">err</span><span class="p">;</span> + +<span class="n">err</span> <span class="o">=</span> <span class="n">sock_create_kern</span><span class="p">(</span><span class="o">&</span><span class="n">init_net</span><span class="p">,</span> <span class="n">PF_INET</span><span class="p">,</span> <span class="n">SOCK_STREAM</span><span class="p">,</span> <span class="n">IPPROTO_TCP</span><span class="p">,</span> <span class="o">&</span><span class="n">sock</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> +<span class="p">}</span> +</pre></div> +</div> +<p>and for creating UDP sockets:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">;</span> +<span class="kt">int</span> <span class="n">err</span><span class="p">;</span> + +<span class="n">err</span> <span class="o">=</span> <span class="n">sock_create_kern</span><span class="p">(</span><span class="o">&</span><span class="n">init_net</span><span class="p">,</span> <span class="n">PF_INET</span><span class="p">,</span> <span class="n">SOCK_DGRAM</span><span class="p">,</span> <span class="n">IPPROTO_UDP</span><span class="p">,</span> <span class="o">&</span><span class="n">sock</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> +<span class="p">}</span> +</pre></div> +</div> +<p>A usage sample is part of the <code class="xref c c-func docutils literal"><span class="pre">sys_socket()</span></code> system call handler:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">SYSCALL_DEFINE3</span><span class="p">(</span><span class="n">socket</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span> <span class="n">family</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span> <span class="n">type</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span> <span class="n">protocol</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">retval</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">flags</span><span class="p">;</span> + + <span class="cm">/* Check the SOCK_* constants for consistency. */</span> + <span class="n">BUILD_BUG_ON</span><span class="p">(</span><span class="n">SOCK_CLOEXEC</span> <span class="o">!=</span> <span class="n">O_CLOEXEC</span><span class="p">);</span> + <span class="n">BUILD_BUG_ON</span><span class="p">((</span><span class="n">SOCK_MAX</span> <span class="o">|</span> <span class="n">SOCK_TYPE_MASK</span><span class="p">)</span> <span class="o">!=</span> <span class="n">SOCK_TYPE_MASK</span><span class="p">);</span> + <span class="n">BUILD_BUG_ON</span><span class="p">(</span><span class="n">SOCK_CLOEXEC</span> <span class="o">&</span> <span class="n">SOCK_TYPE_MASK</span><span class="p">);</span> + <span class="n">BUILD_BUG_ON</span><span class="p">(</span><span class="n">SOCK_NONBLOCK</span> <span class="o">&</span> <span class="n">SOCK_TYPE_MASK</span><span class="p">);</span> + + <span class="n">flags</span> <span class="o">=</span> <span class="n">type</span> <span class="o">&</span> <span class="o">~</span><span class="n">SOCK_TYPE_MASK</span><span class="p">;</span> + <span class="k">if</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&</span> <span class="o">~</span><span class="p">(</span><span class="n">SOCK_CLOEXEC</span> <span class="o">|</span> <span class="n">SOCK_NONBLOCK</span><span class="p">))</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EINVAL</span><span class="p">;</span> + <span class="n">type</span> <span class="o">&=</span> <span class="n">SOCK_TYPE_MASK</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">SOCK_NONBLOCK</span> <span class="o">!=</span> <span class="n">O_NONBLOCK</span> <span class="o">&&</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&</span> <span class="n">SOCK_NONBLOCK</span><span class="p">))</span> + <span class="n">flags</span> <span class="o">=</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&</span> <span class="o">~</span><span class="n">SOCK_NONBLOCK</span><span class="p">)</span> <span class="o">|</span> <span class="n">O_NONBLOCK</span><span class="p">;</span> + + <span class="n">retval</span> <span class="o">=</span> <span class="n">sock_create</span><span class="p">(</span><span class="n">family</span><span class="p">,</span> <span class="n">type</span><span class="p">,</span> <span class="n">protocol</span><span class="p">,</span> <span class="o">&</span><span class="n">sock</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">retval</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">goto</span> <span class="n">out</span><span class="p">;</span> + + <span class="k">return</span> <span class="nf">sock_map_fd</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="n">flags</span> <span class="o">&</span> <span class="p">(</span><span class="n">O_CLOEXEC</span> <span class="o">|</span> <span class="n">O_NONBLOCK</span><span class="p">));</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="closing"> +<h5>Closing<a class="headerlink" href="#closing" title="Permalink to this headline">¶</a></h5> +<p>Close connection (for sockets using connection) and release associated +resources:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">void</span> <span class="pre">sock_release(struct</span> <span class="pre">socket</span> <span class="pre">*sock)</span></code> calls the <code class="docutils literal"><span class="pre">release</span></code> function in +the <code class="docutils literal"><span class="pre">ops</span></code> field of the socket structure:</li> +</ul> +</div></blockquote> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">sock_release</span><span class="p">(</span><span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">sock</span><span class="o">-></span><span class="n">ops</span><span class="p">)</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">owner</span> <span class="o">=</span> <span class="n">sock</span><span class="o">-></span><span class="n">ops</span><span class="o">-></span><span class="n">owner</span><span class="p">;</span> + + <span class="n">sock</span><span class="o">-></span><span class="n">ops</span><span class="o">-></span><span class="n">release</span><span class="p">(</span><span class="n">sock</span><span class="p">);</span> + <span class="n">sock</span><span class="o">-></span><span class="n">ops</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="n">module_put</span><span class="p">(</span><span class="n">owner</span><span class="p">);</span> + <span class="p">}</span> + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="sending-receiving-messages"> +<h5>Sending/receiving messages<a class="headerlink" href="#sending-receiving-messages" title="Permalink to this headline">¶</a></h5> +<p>The messages are sent/received using the following functions:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">int</span> <span class="pre">sock_recvmsg(struct</span> <span class="pre">socket</span> <span class="pre">*sock,</span> <span class="pre">struct</span> <span class="pre">msghdr</span> <span class="pre">*msg,</span> <span class="pre">int</span> <span class="pre">flags);</span></code></li> +<li><code class="docutils literal"><span class="pre">int</span> <span class="pre">kernel_recvmsg(struct</span> <span class="pre">socket</span> <span class="pre">*sock,</span> <span class="pre">struct</span> <span class="pre">msghdr</span> <span class="pre">*msg,</span> <span class="pre">struct</span> <span class="pre">kvec</span> <span class="pre">*vec,</span> <span class="pre">size_t</span> <span class="pre">num,</span> <span class="pre">size_t</span> <span class="pre">size,</span> <span class="pre">int</span> <span class="pre">flags);</span></code></li> +<li><code class="docutils literal"><span class="pre">int</span> <span class="pre">sock_sendmsg(struct</span> <span class="pre">socket</span> <span class="pre">*sock,</span> <span class="pre">struct</span> <span class="pre">msghdr</span> <span class="pre">*msg);</span></code></li> +<li><code class="docutils literal"><span class="pre">int</span> <span class="pre">kernel_sendmsg(struct</span> <span class="pre">socket</span> <span class="pre">*sock,</span> <span class="pre">struct</span> <span class="pre">msghdr</span> <span class="pre">*msg,</span> <span class="pre">struct</span> <span class="pre">kvec</span> <span class="pre">*vec,</span> <span class="pre">size_t</span> <span class="pre">num,</span> <span class="pre">size_t</span> <span class="pre">size);</span></code></li> +</ul> +</div></blockquote> +<p>The message sending/receiving functions will then call the <code class="docutils literal"><span class="pre">sendmsg</span></code>/ +<code class="docutils literal"><span class="pre">recvmsg</span></code> function in the <code class="docutils literal"><span class="pre">ops</span></code> field of the socket. Functions +containing <code class="docutils literal"><span class="pre">kernel_</span></code> as a prefix are used when the socket is used in the +kernel.</p> +<p>The parameters are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">msg</span></code>, a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">msghdr</span></code> structure, containing the message to be +sent/received. Among the important components of this structure are <code class="docutils literal"><span class="pre">msg_name</span></code> +and <code class="docutils literal"><span class="pre">msg_namelen</span></code>, which, for UDP sockets, must be filled in with the address +to which the message is sent (<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sockaddr_in</span></code>);</li> +<li><code class="docutils literal"><span class="pre">vec</span></code>, a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">kvec</span></code> structure, containing a pointer to the buffer +containing its data and size; as can be seen, it has a similar structure to the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">iovec</span></code> structure (the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">iovec</span></code> structure +corresponds to the user space data, and the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">kvec</span></code> structure +corresponds to kernel space data).</li> +</ul> +</div></blockquote> +<p>A usage example can be seen in the <code class="xref c c-func docutils literal"><span class="pre">sys_sendto()</span></code> system call handler:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">SYSCALL_DEFINE6</span><span class="p">(</span><span class="n">sendto</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span> <span class="n">fd</span><span class="p">,</span> <span class="kt">void</span> <span class="n">__user</span> <span class="o">*</span><span class="p">,</span> <span class="n">buff</span><span class="p">,</span> <span class="kt">size_t</span><span class="p">,</span> <span class="n">len</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">,</span> <span class="n">flags</span><span class="p">,</span> <span class="k">struct</span> <span class="n">sockaddr</span> <span class="n">__user</span> <span class="o">*</span><span class="p">,</span> <span class="n">addr</span><span class="p">,</span> + <span class="kt">int</span><span class="p">,</span> <span class="n">addr_len</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">sockaddr_storage</span> <span class="n">address</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">err</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">msghdr</span> <span class="n">msg</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">iovec</span> <span class="n">iov</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">fput_needed</span><span class="p">;</span> + + <span class="n">err</span> <span class="o">=</span> <span class="n">import_single_range</span><span class="p">(</span><span class="n">WRITE</span><span class="p">,</span> <span class="n">buff</span><span class="p">,</span> <span class="n">len</span><span class="p">,</span> <span class="o">&</span><span class="n">iov</span><span class="p">,</span> <span class="o">&</span><span class="n">msg</span><span class="p">.</span><span class="n">msg_iter</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">unlikely</span><span class="p">(</span><span class="n">err</span><span class="p">))</span> + <span class="k">return</span> <span class="n">err</span><span class="p">;</span> + <span class="n">sock</span> <span class="o">=</span> <span class="n">sockfd_lookup_light</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="o">&</span><span class="n">err</span><span class="p">,</span> <span class="o">&</span><span class="n">fput_needed</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">sock</span><span class="p">)</span> + <span class="k">goto</span> <span class="n">out</span><span class="p">;</span> + + <span class="n">msg</span><span class="p">.</span><span class="n">msg_name</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="n">msg</span><span class="p">.</span><span class="n">msg_control</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="n">msg</span><span class="p">.</span><span class="n">msg_controllen</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="n">msg</span><span class="p">.</span><span class="n">msg_namelen</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="k">if</span> <span class="p">(</span><span class="n">addr</span><span class="p">)</span> <span class="p">{</span> + <span class="n">err</span> <span class="o">=</span> <span class="n">move_addr_to_kernel</span><span class="p">(</span><span class="n">addr</span><span class="p">,</span> <span class="n">addr_len</span><span class="p">,</span> <span class="o">&</span><span class="n">address</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">goto</span> <span class="n">out_put</span><span class="p">;</span> + <span class="n">msg</span><span class="p">.</span><span class="n">msg_name</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="p">)</span><span class="o">&</span><span class="n">address</span><span class="p">;</span> + <span class="n">msg</span><span class="p">.</span><span class="n">msg_namelen</span> <span class="o">=</span> <span class="n">addr_len</span><span class="p">;</span> + <span class="p">}</span> + <span class="k">if</span> <span class="p">(</span><span class="n">sock</span><span class="o">-></span><span class="n">file</span><span class="o">-></span><span class="n">f_flags</span> <span class="o">&</span> <span class="n">O_NONBLOCK</span><span class="p">)</span> + <span class="n">flags</span> <span class="o">|=</span> <span class="n">MSG_DONTWAIT</span><span class="p">;</span> + <span class="n">msg</span><span class="p">.</span><span class="n">msg_flags</span> <span class="o">=</span> <span class="n">flags</span><span class="p">;</span> + <span class="n">err</span> <span class="o">=</span> <span class="n">sock_sendmsg</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="o">&</span><span class="n">msg</span><span class="p">);</span> + +<span class="nl">out_put</span><span class="p">:</span> + <span class="n">fput_light</span><span class="p">(</span><span class="n">sock</span><span class="o">-></span><span class="n">file</span><span class="p">,</span> <span class="n">fput_needed</span><span class="p">);</span> +<span class="nl">out</span><span class="p">:</span> + <span class="k">return</span> <span class="n">err</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="the-struct-socket-fields"> +<h4>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> fields<a class="headerlink" href="#the-struct-socket-fields" title="Permalink to this headline">¶</a></h4> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/**</span> +<span class="cm"> * struct socket - general BSD socket</span> +<span class="cm"> * @state: socket state (%SS_CONNECTED, etc)</span> +<span class="cm"> * @type: socket type (%SOCK_STREAM, etc)</span> +<span class="cm"> * @flags: socket flags (%SOCK_NOSPACE, etc)</span> +<span class="cm"> * @ops: protocol specific socket operations</span> +<span class="cm"> * @file: File back pointer for gc</span> +<span class="cm"> * @sk: internal networking protocol agnostic socket representation</span> +<span class="cm"> * @wq: wait queue for several uses</span> +<span class="cm"> */</span> +<span class="k">struct</span> <span class="n">socket</span> <span class="p">{</span> + <span class="n">socket_state</span> <span class="n">state</span><span class="p">;</span> + + <span class="kt">short</span> <span class="n">type</span><span class="p">;</span> + + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + + <span class="k">struct</span> <span class="n">socket_wq</span> <span class="n">__rcu</span> <span class="o">*</span><span class="n">wq</span><span class="p">;</span> + + <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">;</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">proto_ops</span> <span class="o">*</span><span class="n">ops</span><span class="p">;</span> +<span class="p">};</span> +</pre></div> +</div> +<p>The noteworthy fields are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">ops</span></code> - the structure that stores pointers to protocol-specific functions;</li> +<li><code class="docutils literal"><span class="pre">sk</span></code> - The <code class="docutils literal"><span class="pre">INET</span> <span class="pre">socket</span></code> associated with it.</li> +</ul> +</div></blockquote> +<div class="section" id="the-struct-proto-ops-structure"> +<h5>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">proto_ops</span></code> structure<a class="headerlink" href="#the-struct-proto-ops-structure" title="Permalink to this headline">¶</a></h5> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">proto_ops</span></code> structure contains the implementations of the specific +operations implemented (TCP, UDP, etc.); these functions will be called from +generic functions through <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> (<code class="xref c c-func docutils literal"><span class="pre">sock_release()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">sock_sendmsg()</span></code>, etc.)</p> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">proto_ops</span></code> structure therefore contains a number of function +pointers for specific protocol implementations:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">proto_ops</span> <span class="p">{</span> + <span class="kt">int</span> <span class="n">family</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">owner</span><span class="p">;</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">release</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">bind</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="n">myaddr</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">sockaddr_len</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">connect</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="n">vaddr</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">sockaddr_len</span><span class="p">,</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">socketpair</span><span class="p">)(</span><span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock1</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock2</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">accept</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">newsock</span><span class="p">,</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">kern</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">getname</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="n">addr</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">peer</span><span class="p">);</span> + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The initialization of the <code class="docutils literal"><span class="pre">ops</span></code> field from <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">socket</span></code> is done in +the <code class="xref c c-func docutils literal"><span class="pre">__sock_create()</span></code> function, by calling the <code class="xref c c-func docutils literal"><span class="pre">create()</span></code> function, +specific to each protocol; an equivalent call is the implementation of the +<code class="xref c c-func docutils literal"><span class="pre">__sock_create()</span></code> function:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="c1">//...</span> + <span class="n">err</span> <span class="o">=</span> <span class="n">pf</span><span class="o">-></span><span class="n">create</span><span class="p">(</span><span class="n">net</span><span class="p">,</span> <span class="n">sock</span><span class="p">,</span> <span class="n">protocol</span><span class="p">,</span> <span class="n">kern</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">goto</span> <span class="n">out_module_put</span><span class="p">;</span> +<span class="c1">//...</span> +</pre></div> +</div> +<p>This will instantiate the function pointers with calls specific to the protocol +type associated with the socket. The <code class="xref c c-func docutils literal"><span class="pre">sock_register()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">sock_unregister()</span></code> calls are used to fill the <code class="docutils literal"><span class="pre">net_families</span></code> vector.</p> +<p>For the rest of the socket operations (other than creating, closing, and +sending/receiving a message as described above in the <a class="reference internal" href="#operations-on-the-socket-structure">Operations on the socket +structure</a> section), the functions sent via pointers in this structure will be +called. For example, for <code class="docutils literal"><span class="pre">bind</span></code>, which associates a socket with a socket on +the local machine, we will have the following code sequence:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define MY_PORT 60000</span> + +<span class="k">struct</span> <span class="n">sockaddr_in</span> <span class="n">addr</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">sin_family</span> <span class="o">=</span> <span class="n">AF_INET</span><span class="p">,</span> + <span class="p">.</span><span class="n">sin_port</span> <span class="o">=</span> <span class="n">htons</span> <span class="p">(</span><span class="n">MY_PORT</span><span class="p">),</span> + <span class="p">.</span><span class="n">sin_addr</span> <span class="o">=</span> <span class="p">{</span> <span class="n">htonl</span> <span class="p">(</span><span class="n">INADDR_LOOPBACK</span><span class="p">)</span> <span class="p">}</span> +<span class="p">};</span> + +<span class="c1">//...</span> + <span class="n">err</span> <span class="o">=</span> <span class="n">sock</span><span class="o">-></span><span class="n">ops</span><span class="o">-></span><span class="n">bind</span> <span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="p">)</span> <span class="o">&</span><span class="n">addr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">addr</span><span class="p">));</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> + <span class="p">}</span> +<span class="c1">//...</span> +</pre></div> +</div> +<p>As you can see, for transmitting the address and port information that +will be associated with the socket, a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sockaddr_in</span></code> is filled.</p> +</div> +</div> +</div> +<div class="section" id="the-struct-sock-structure"> +<h3>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sock</span></code> structure<a class="headerlink" href="#the-struct-sock-structure" title="Permalink to this headline">¶</a></h3> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sock</span></code> describes an <code class="docutils literal"><span class="pre">INET</span></code> socket. Such a structure is +associated with a user space socket and implicitly with a <code class="xref c c-type docutils literal"><span class="pre">struct</span> +<span class="pre">socket</span></code> structure. The structure is used to store information about the status +of a connection. The structure's fields and associated operations usually begin +with the <code class="docutils literal"><span class="pre">sk_</span></code> string. Some fields are listed below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">sock</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="nl">sk_padding</span> <span class="p">:</span> <span class="mi">1</span><span class="p">,</span> + <span class="nl">sk_no_check_tx</span> <span class="p">:</span> <span class="mi">1</span><span class="p">,</span> + <span class="nl">sk_no_check_rx</span> <span class="p">:</span> <span class="mi">1</span><span class="p">,</span> + <span class="nl">sk_userlocks</span> <span class="p">:</span> <span class="mi">4</span><span class="p">,</span> + <span class="nl">sk_protocol</span> <span class="p">:</span> <span class="mi">8</span><span class="p">,</span> + <span class="nl">sk_type</span> <span class="p">:</span> <span class="mi">16</span><span class="p">;</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sk_socket</span><span class="p">;</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">sk_send_head</span><span class="p">;</span> + <span class="c1">//...</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">sk_state_change</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">sk_data_ready</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">sk_write_space</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">sk_error_report</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">sk_backlog_rcv</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">sk_destruct</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">);</span> +<span class="p">};</span> +</pre></div> +</div> +<p></p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">sk_protocol</span></code> is the type of protocol used by the socket;</li> +<li><code class="docutils literal"><span class="pre">sk_type</span></code> is the socket type (<code class="docutils literal"><span class="pre">SOCK_STREAM</span></code>, <code class="docutils literal"><span class="pre">SOCK_DGRAM</span></code>, etc.);</li> +<li><code class="docutils literal"><span class="pre">sk_socket</span></code> is the BSD socket that holds it;</li> +<li><code class="docutils literal"><span class="pre">sk_send_head</span></code> is the list of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sk_buff</span></code> structures for +transmission;</li> +<li>the function pointers at the end are callbacks for different situations.</li> +</ul> +</div></blockquote> +<p>Initializing the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sock</span></code> and attaching it to a BSD socket is done +using the callback created from <code class="docutils literal"><span class="pre">net_families</span></code> (called +<code class="xref c c-func docutils literal"><span class="pre">__sock_create()</span></code>). Here's how to initialize the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sock</span></code> +structure for the IP protocol, in the <code class="xref c c-func docutils literal"><span class="pre">inet_create()</span></code> function:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/*</span> +<span class="cm"> * Create an inet socket.</span> +<span class="cm"> */</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">inet_create</span><span class="p">(</span><span class="k">struct</span> <span class="n">net</span> <span class="o">*</span><span class="n">net</span><span class="p">,</span> <span class="k">struct</span> <span class="n">socket</span> <span class="o">*</span><span class="n">sock</span><span class="p">,</span> <span class="kt">int</span> <span class="n">protocol</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">kern</span><span class="p">)</span> +<span class="p">{</span> + + <span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">;</span> + + <span class="c1">//...</span> + <span class="n">err</span> <span class="o">=</span> <span class="o">-</span><span class="n">ENOBUFS</span><span class="p">;</span> + <span class="n">sk</span> <span class="o">=</span> <span class="n">sk_alloc</span><span class="p">(</span><span class="n">net</span><span class="p">,</span> <span class="n">PF_INET</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">,</span> <span class="n">answer_prot</span><span class="p">,</span> <span class="n">kern</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">sk</span><span class="p">)</span> + <span class="k">goto</span> <span class="n">out</span><span class="p">;</span> + + <span class="n">err</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="k">if</span> <span class="p">(</span><span class="n">INET_PROTOSW_REUSE</span> <span class="o">&</span> <span class="n">answer_flags</span><span class="p">)</span> + <span class="n">sk</span><span class="o">-></span><span class="n">sk_reuse</span> <span class="o">=</span> <span class="n">SK_CAN_REUSE</span><span class="p">;</span> + + + <span class="c1">//...</span> + <span class="n">sock_init_data</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="n">sk</span><span class="p">);</span> + + <span class="n">sk</span><span class="o">-></span><span class="n">sk_destruct</span> <span class="o">=</span> <span class="n">inet_sock_destruct</span><span class="p">;</span> + <span class="n">sk</span><span class="o">-></span><span class="n">sk_protocol</span> <span class="o">=</span> <span class="n">protocol</span><span class="p">;</span> + <span class="n">sk</span><span class="o">-></span><span class="n">sk_backlog_rcv</span> <span class="o">=</span> <span class="n">sk</span><span class="o">-></span><span class="n">sk_prot</span><span class="o">-></span><span class="n">backlog_rcv</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="the-struct-sk-buff-structure"> +<span id="structskbuff"></span><h3>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sk_buff</span></code> structure<a class="headerlink" href="#the-struct-sk-buff-structure" title="Permalink to this headline">¶</a></h3> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sk_buff</span></code> (socket buffer) describes a network packet. The +structure fields contain information about both the header and packet contents, +the protocols used, the network device used, and pointers to the other +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sk_buff</span></code>. A summary description of the content of the structure +is presented below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="p">{</span> + <span class="k">union</span> <span class="p">{</span> + <span class="k">struct</span> <span class="p">{</span> + <span class="cm">/* These two members must be first. */</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">prev</span><span class="p">;</span> + + <span class="k">union</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">net_device</span> <span class="o">*</span><span class="n">dev</span><span class="p">;</span> + <span class="cm">/* Some protocols might use this space to store information,</span> +<span class="cm"> * while device pointer would be NULL.</span> +<span class="cm"> * UDP receive path is one user.</span> +<span class="cm"> */</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">dev_scratch</span><span class="p">;</span> + <span class="p">};</span> + <span class="p">};</span> + + <span class="k">struct</span> <span class="n">rb_node</span> <span class="n">rbnode</span><span class="p">;</span> <span class="cm">/* used in netem & tcp stack */</span> + <span class="p">};</span> + <span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">;</span> + + <span class="k">union</span> <span class="p">{</span> + <span class="n">ktime_t</span> <span class="n">tstamp</span><span class="p">;</span> + <span class="n">u64</span> <span class="n">skb_mstamp</span><span class="p">;</span> + <span class="p">};</span> + + <span class="cm">/*</span> +<span class="cm"> * This is the control buffer. It is free to use for every</span> +<span class="cm"> * layer. Please put your private variables there. If you</span> +<span class="cm"> * want to keep them across layers you have to do a skb_clone()</span> +<span class="cm"> * first. This is owned by whoever has the skb queued ATM.</span> +<span class="cm"> */</span> + <span class="kt">char</span> <span class="n">cb</span><span class="p">[</span><span class="mi">48</span><span class="p">]</span> <span class="n">__aligned</span><span class="p">(</span><span class="mi">8</span><span class="p">);</span> + + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">_skb_refdst</span><span class="p">;</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">destructor</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + <span class="k">union</span> <span class="p">{</span> + <span class="k">struct</span> <span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">_skb_refdst</span><span class="p">;</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">destructor</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + <span class="p">};</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="n">tcp_tsorted_anchor</span><span class="p">;</span> + <span class="p">};</span> + <span class="cm">/* ... */</span> + + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">,</span> + <span class="n">data_len</span><span class="p">;</span> + <span class="n">__u16</span> <span class="n">mac_len</span><span class="p">,</span> + <span class="n">hdr_len</span><span class="p">;</span> + + <span class="cm">/* ... */</span> + + <span class="n">__be16</span> <span class="n">protocol</span><span class="p">;</span> + <span class="n">__u16</span> <span class="n">transport_header</span><span class="p">;</span> + <span class="n">__u16</span> <span class="n">network_header</span><span class="p">;</span> + <span class="n">__u16</span> <span class="n">mac_header</span><span class="p">;</span> + + <span class="cm">/* private: */</span> + <span class="n">__u32</span> <span class="n">headers_end</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> + <span class="cm">/* public: */</span> + + <span class="cm">/* These elements must be at the end, see alloc_skb() for details. */</span> + <span class="n">sk_buff_data_t</span> <span class="n">tail</span><span class="p">;</span> + <span class="n">sk_buff_data_t</span> <span class="n">end</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">head</span><span class="p">,</span> + <span class="o">*</span><span class="n">data</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">truesize</span><span class="p">;</span> + <span class="n">refcount_t</span> <span class="n">users</span><span class="p">;</span> +<span class="p">};</span> +</pre></div> +</div> +<p>where:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">next</span></code> and <code class="docutils literal"><span class="pre">prev</span></code> are pointers to the next, and previous element in the +buffer list;</li> +<li><code class="docutils literal"><span class="pre">dev</span></code> is the device which sends or receives the buffer;</li> +<li><code class="docutils literal"><span class="pre">sk</span></code> is the socket associated with the buffer;</li> +<li><code class="docutils literal"><span class="pre">destructor</span></code> is the callback that deallocates the buffer;</li> +<li><code class="docutils literal"><span class="pre">transport_header</span></code>, <code class="docutils literal"><span class="pre">network_header</span></code>, and <code class="docutils literal"><span class="pre">mac_header</span></code> are offsets +between the beginning of the packet and the beginning of the various headers +in the packets. They are internally maintained by the various processing +layers through which the packet passes. To get pointers to the headers, use +one of the following functions: <code class="xref c c-func docutils literal"><span class="pre">tcp_hdr()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">udp_hdr()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">ip_hdr()</span></code>, etc. In principle, each protocol provides a function to +get a reference to the header of that protocol within a received packet. +Keep in mind that the <code class="docutils literal"><span class="pre">network_header</span></code> field is not set until the packet +reaches the network layer and the <code class="docutils literal"><span class="pre">transport_header</span></code> field is not set +until the packet reaches the transport layer.</li> +</ul> +</div></blockquote> +<p>The structure of an <a class="reference external" href="https://en.wikipedia.org/wiki/IPv4#Header">IP header</a> +(<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">iphdr</span></code>) has the following fields:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">iphdr</span> <span class="p">{</span> +<span class="cp">#if defined(__LITTLE_ENDIAN_BITFIELD)</span> + <span class="n">__u8</span> <span class="nl">ihl</span><span class="p">:</span><span class="mi">4</span><span class="p">,</span> + <span class="nl">version</span><span class="p">:</span><span class="mi">4</span><span class="p">;</span> +<span class="cp">#elif defined (__BIG_ENDIAN_BITFIELD)</span> + <span class="n">__u8</span> <span class="nl">version</span><span class="p">:</span><span class="mi">4</span><span class="p">,</span> + <span class="nl">ihl</span><span class="p">:</span><span class="mi">4</span><span class="p">;</span> +<span class="cp">#else</span> +<span class="cp">#error "Please fix <asm/byteorder.h>"</span> +<span class="cp">#endif</span> + <span class="n">__u8</span> <span class="n">tos</span><span class="p">;</span> + <span class="n">__be16</span> <span class="n">tot_len</span><span class="p">;</span> + <span class="n">__be16</span> <span class="n">id</span><span class="p">;</span> + <span class="n">__be16</span> <span class="n">frag_off</span><span class="p">;</span> + <span class="n">__u8</span> <span class="n">ttl</span><span class="p">;</span> + <span class="n">__u8</span> <span class="n">protocol</span><span class="p">;</span> + <span class="n">__sum16</span> <span class="n">check</span><span class="p">;</span> + <span class="n">__be32</span> <span class="n">saddr</span><span class="p">;</span> + <span class="n">__be32</span> <span class="n">daddr</span><span class="p">;</span> + <span class="cm">/*The options start here. */</span> +<span class="p">};</span> +</pre></div> +</div> +<p>where:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">protocol</span></code> is the transport layer protocol used;</li> +<li><code class="docutils literal"><span class="pre">saddr</span></code> is the source IP address;</li> +<li><code class="docutils literal"><span class="pre">daddr</span></code> is the destination IP address.</li> +</ul> +</div></blockquote> +<p>The structure of a <a class="reference external" href="https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_segment_structure">TCP header</a> +(<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">tcphdr</span></code>) has the following fields:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">tcphdr</span> <span class="p">{</span> + <span class="n">__be16</span> <span class="n">source</span><span class="p">;</span> + <span class="n">__be16</span> <span class="n">dest</span><span class="p">;</span> + <span class="n">__be32</span> <span class="n">seq</span><span class="p">;</span> + <span class="n">__be32</span> <span class="n">ack_seq</span><span class="p">;</span> +<span class="cp">#if defined(__LITTLE_ENDIAN_BITFIELD)</span> + <span class="n">__u16</span> <span class="nl">res1</span><span class="p">:</span><span class="mi">4</span><span class="p">,</span> + <span class="nl">doff</span><span class="p">:</span><span class="mi">4</span><span class="p">,</span> + <span class="nl">fin</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">syn</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">rst</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">psh</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">ack</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">urg</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">ece</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">cwr</span><span class="p">:</span><span class="mi">1</span><span class="p">;</span> +<span class="cp">#elif defined(__BIG_ENDIAN_BITFIELD)</span> + <span class="n">__u16</span> <span class="nl">doff</span><span class="p">:</span><span class="mi">4</span><span class="p">,</span> + <span class="nl">res1</span><span class="p">:</span><span class="mi">4</span><span class="p">,</span> + <span class="nl">cwr</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">ece</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">urg</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">ack</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">psh</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">rst</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">syn</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> + <span class="nl">fin</span><span class="p">:</span><span class="mi">1</span><span class="p">;</span> +<span class="cp">#else</span> +<span class="cp">#error "Adjust your <asm/byteorder.h> defines"</span> +<span class="cp">#endif</span> + <span class="n">__be16</span> <span class="n">window</span><span class="p">;</span> + <span class="n">__sum16</span> <span class="n">check</span><span class="p">;</span> + <span class="n">__be16</span> <span class="n">urg_ptr</span><span class="p">;</span> +<span class="p">};</span> +</pre></div> +</div> +<p>where:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">source</span></code> is the source port;</li> +<li><code class="docutils literal"><span class="pre">dest</span></code> is the destination port;</li> +<li><code class="docutils literal"><span class="pre">syn</span></code>, <code class="docutils literal"><span class="pre">ack</span></code>, <code class="docutils literal"><span class="pre">fin</span></code> are the TCP flags used; for a more detailed view, +see this <a class="reference external" href="http://www.eventhelix.com/Realtimemantra/Networking/Tcp.pdf">diagram</a>.</li> +</ul> +</div></blockquote> +<p>The structure of a <a class="reference external" href="https://en.wikipedia.org/wiki/User_Datagram_Protocol#Packet_structure">UDP header</a> +(<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">udphdr</span></code>) has the following fields:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">udphdr</span> <span class="p">{</span> + <span class="n">__be16</span> <span class="n">source</span><span class="p">;</span> + <span class="n">__be16</span> <span class="n">dest</span><span class="p">;</span> + <span class="n">__be16</span> <span class="n">len</span><span class="p">;</span> + <span class="n">__sum16</span> <span class="n">check</span><span class="p">;</span> +<span class="p">};</span> +</pre></div> +</div> +<p>where:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">source</span></code> is the source port;</li> +<li><code class="docutils literal"><span class="pre">dest</span></code> is the destination port.</li> +</ul> +</div></blockquote> +<p>An example of accessing the information present in the headers of a network +packet is as follows:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">;</span> + +<span class="k">struct</span> <span class="n">iphdr</span> <span class="o">*</span><span class="n">iph</span> <span class="o">=</span> <span class="n">ip_hdr</span><span class="p">(</span><span class="n">skb</span><span class="p">);</span> <span class="cm">/* IP header */</span> +<span class="cm">/* iph->saddr - source IP address */</span> +<span class="cm">/* iph->daddr - destination IP address */</span> +<span class="k">if</span> <span class="p">(</span><span class="n">iph</span><span class="o">-></span><span class="n">protocol</span> <span class="o">==</span> <span class="n">IPPROTO_TCP</span><span class="p">)</span> <span class="p">{</span> <span class="cm">/* TCP protocol */</span> + <span class="k">struct</span> <span class="n">tcphdr</span> <span class="o">*</span><span class="n">tcph</span> <span class="o">=</span> <span class="n">tcp_hdr</span><span class="p">(</span><span class="n">skb</span><span class="p">);</span> <span class="cm">/* TCP header */</span> + <span class="cm">/* tcph->source - source TCP port */</span> + <span class="cm">/* tcph->dest - destination TCP port */</span> +<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">iph</span><span class="o">-></span><span class="n">protocol</span> <span class="o">==</span> <span class="n">IPPROTO_UDP</span><span class="p">)</span> <span class="p">{</span> <span class="cm">/* UDP protocol */</span> + <span class="k">struct</span> <span class="n">udphdr</span> <span class="o">*</span><span class="n">udph</span> <span class="o">=</span> <span class="n">udp_hdr</span><span class="p">(</span><span class="n">skb</span><span class="p">);</span> <span class="cm">/* UDP header */</span> + <span class="cm">/* udph->source - source UDP port */</span> + <span class="cm">/* udph->dest - destination UDP port */</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="conversions-1"> +<span id="conversions"></span><h2>Conversions<a class="headerlink" href="#conversions-1" title="Permalink to this headline">¶</a></h2> +<p>In different systems, there are several ways of ordering bytes in a word +(<a class="reference external" href="http://en.wikipedia.org/wiki/Endianness">Endianness</a>), including: <a class="reference external" href="http://en.wikipedia.org/wiki/Endianness#Big-endian">Big +Endian</a> (the most +significant byte first) and <a class="reference external" href="http://en.wikipedia.org/wiki/Endianness#Little-endian">Little +Endian</a> (the least +significant byte first). Since a network interconnects systems with different +platforms, the Internet has imposed a standard sequence for the storage of +numerical data, called <a class="reference external" href="http://en.wikipedia.org/wiki/Endianness#Endianness_in_networking">network byte-order</a>. In +contrast, the byte sequence for the representation of numerical data on the host +computer is called host byte-order. Data received/sent from/to the network is in +the network byte-order format and should be converted between this format and +the host byte-order.</p> +<p>For converting we use the following macros:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">u16</span> <span class="pre">htons(u16</span> <span class="pre">x)</span></code> converts a 16 bit integer from host byte-order to +network byte-order (host to network short);</li> +<li><code class="docutils literal"><span class="pre">u32</span> <span class="pre">htonl(u32</span> <span class="pre">x)</span></code> converts a 32 bit integer from host byte-order to +network byte-order (host to network long);</li> +<li><code class="docutils literal"><span class="pre">u16</span> <span class="pre">ntohs(u16</span> <span class="pre">x)</span></code> converts a 16 bit integer from network byte-order to +host byte-order (network to host short);</li> +<li><code class="docutils literal"><span class="pre">u32</span> <span class="pre">ntohl(u32</span> <span class="pre">x)</span></code> converts a 32 bit integer from network byte-order to +host byte-order (network to host long).</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="netfilter-1"> +<span id="netfilter"></span><h2>netfilter<a class="headerlink" href="#netfilter-1" title="Permalink to this headline">¶</a></h2> +<p>Netfilter is the name of the kernel interface for capturing network packets for +modifying/analyzing them (for filtering, NAT, etc.). <a class="reference external" href="http://www.netfilter.org/">The netfilter</a> interface is used in user space by <a class="reference external" href="http://www.frozentux.net/documents/iptables-tutorial/">iptables</a>.</p> +<p>In the Linux kernel, packet capture using netfilter is done by attaching hooks. +Hooks can be specified in different locations in the path followed by a kernel +network packet, as needed. An organization chart with the route followed by a +package and the possible areas for a hook can be found <a class="reference external" href="http://linux-ip.net/nf/nfk-traversal.png">here</a>.</p> +<p>The header included when using netfilter is <code class="file docutils literal"><span class="pre">linux/netfilter.h</span></code>.</p> +<p>A hook is defined through the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">nf_hook_ops</span></code> structure:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">nf_hook_ops</span> <span class="p">{</span> + <span class="cm">/* User fills in from here down. */</span> + <span class="n">nf_hookfn</span> <span class="o">*</span><span class="n">hook</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">net_device</span> <span class="o">*</span><span class="n">dev</span><span class="p">;</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">priv</span><span class="p">;</span> + <span class="n">u_int8_t</span> <span class="n">pf</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">hooknum</span><span class="p">;</span> + <span class="cm">/* Hooks are ordered in ascending priority. */</span> + <span class="kt">int</span> <span class="n">priority</span><span class="p">;</span> +<span class="p">};</span> +</pre></div> +</div> +<p>where:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">pf</span></code> is the package type (<code class="docutils literal"><span class="pre">PF_INET</span></code>, etc.);</li> +<li><dl class="first docutils"> +<dt><code class="docutils literal"><span class="pre">priority</span></code> is the priority; priorities are defined in</dt> +<dd><code class="file docutils literal"><span class="pre">uapi/linux/netfilter_ipv4.h</span></code> as follows:</dd> +</dl> +</li> +</ul> +</div></blockquote> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">enum</span> <span class="n">nf_ip_hook_priorities</span> <span class="p">{</span> + <span class="n">NF_IP_PRI_FIRST</span> <span class="o">=</span> <span class="n">INT_MIN</span><span class="p">,</span> + <span class="n">NF_IP_PRI_CONNTRACK_DEFRAG</span> <span class="o">=</span> <span class="o">-</span><span class="mi">400</span><span class="p">,</span> + <span class="n">NF_IP_PRI_RAW</span> <span class="o">=</span> <span class="o">-</span><span class="mi">300</span><span class="p">,</span> + <span class="n">NF_IP_PRI_SELINUX_FIRST</span> <span class="o">=</span> <span class="o">-</span><span class="mi">225</span><span class="p">,</span> + <span class="n">NF_IP_PRI_CONNTRACK</span> <span class="o">=</span> <span class="o">-</span><span class="mi">200</span><span class="p">,</span> + <span class="n">NF_IP_PRI_MANGLE</span> <span class="o">=</span> <span class="o">-</span><span class="mi">150</span><span class="p">,</span> + <span class="n">NF_IP_PRI_NAT_DST</span> <span class="o">=</span> <span class="o">-</span><span class="mi">100</span><span class="p">,</span> + <span class="n">NF_IP_PRI_FILTER</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> + <span class="n">NF_IP_PRI_SECURITY</span> <span class="o">=</span> <span class="mi">50</span><span class="p">,</span> + <span class="n">NF_IP_PRI_NAT_SRC</span> <span class="o">=</span> <span class="mi">100</span><span class="p">,</span> + <span class="n">NF_IP_PRI_SELINUX_LAST</span> <span class="o">=</span> <span class="mi">225</span><span class="p">,</span> + <span class="n">NF_IP_PRI_CONNTRACK_HELPER</span> <span class="o">=</span> <span class="mi">300</span><span class="p">,</span> + <span class="n">NF_IP_PRI_CONNTRACK_CONFIRM</span> <span class="o">=</span> <span class="n">INT_MAX</span><span class="p">,</span> + <span class="n">NF_IP_PRI_LAST</span> <span class="o">=</span> <span class="n">INT_MAX</span><span class="p">,</span> +<span class="p">};</span> +</pre></div> +</div> +<p></p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">dev</span></code> is the device (network interface) on which the capture is +intended;</li> +<li><code class="docutils literal"><span class="pre">hooknum</span></code> is the type of hook used. When a packet is captured, the +processing mode is defined by the <code class="docutils literal"><span class="pre">hooknum</span></code> and <code class="docutils literal"><span class="pre">hook</span></code> fields. For IP, +hook types are defined in <code class="file docutils literal"><span class="pre">linux/netfilter.h</span></code>:</li> +</ul> +</div></blockquote> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">enum</span> <span class="n">nf_inet_hooks</span> <span class="p">{</span> + <span class="n">NF_INET_PRE_ROUTING</span><span class="p">,</span> + <span class="n">NF_INET_LOCAL_IN</span><span class="p">,</span> + <span class="n">NF_INET_FORWARD</span><span class="p">,</span> + <span class="n">NF_INET_LOCAL_OUT</span><span class="p">,</span> + <span class="n">NF_INET_POST_ROUTING</span><span class="p">,</span> + <span class="n">NF_INET_NUMHOOKS</span> +<span class="p">};</span> +</pre></div> +</div> +<p></p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">hook</span></code> is the handler called when capturing a network packet (packet sent +as a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sk_buff</span></code> structure). The <code class="docutils literal"><span class="pre">private</span></code> field is private information +handed to the handler. The capture handler prototype is defined by the +<code class="xref c c-type docutils literal"><span class="pre">nf_hookfn</span></code> type:</li> +</ul> +</div></blockquote> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">nf_hook_state</span> <span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">hook</span><span class="p">;</span> + <span class="n">u_int8_t</span> <span class="n">pf</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">net_device</span> <span class="o">*</span><span class="n">in</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">net_device</span> <span class="o">*</span><span class="n">out</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">net</span> <span class="o">*</span><span class="n">net</span><span class="p">;</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">okfn</span><span class="p">)(</span><span class="k">struct</span> <span class="n">net</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="p">);</span> +<span class="p">};</span> + +<span class="k">typedef</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="nf">nf_hookfn</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">priv</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">nf_hook_state</span> <span class="o">*</span><span class="n">state</span><span class="p">);</span> +</pre></div> +</div> +<p>For the <code class="xref c c-func docutils literal"><span class="pre">nf_hookfn()</span></code> capture function, the <code class="docutils literal"><span class="pre">priv</span></code> parameter is the +private information with which the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">nf_hook_ops</span></code> was +initialized. <code class="docutils literal"><span class="pre">skb</span></code> is the pointer to the captured network packet. Based on +<code class="docutils literal"><span class="pre">skb</span></code> information, packet filtering decisions are made. The function's +<code class="docutils literal"><span class="pre">state</span></code> parameter is the status information related to the packet capture, +including the input interface, the output interface, the priority, the hook +number. Priority and hook number are useful for allowing the same function to +be called by several hooks.</p> +<p>A capture handler can return one of the constants <code class="docutils literal"><span class="pre">NF_*</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* Responses from hook functions. */</span> +<span class="cp">#define NF_DROP 0</span> +<span class="cp">#define NF_ACCEPT 1</span> +<span class="cp">#define NF_STOLEN 2</span> +<span class="cp">#define NF_QUEUE 3</span> +<span class="cp">#define NF_REPEAT 4</span> +<span class="cp">#define NF_STOP 5</span> +<span class="cp">#define NF_MAX_VERDICT NF_STOP</span> +</pre></div> +</div> +<p><code class="docutils literal"><span class="pre">NF_DROP</span></code> is used to filter (ignore) a packet, and <code class="docutils literal"><span class="pre">NF_ACCEPT</span></code> is used to +accept a packet and forward it.</p> +<p>Registering/unregistering a hook is done using the functions defined in +<code class="file docutils literal"><span class="pre">linux/netfilter.h</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* Function to register/unregister hook points. */</span> +<span class="kt">int</span> <span class="nf">nf_register_net_hook</span><span class="p">(</span><span class="k">struct</span> <span class="n">net</span> <span class="o">*</span><span class="n">net</span><span class="p">,</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">nf_hook_ops</span> <span class="o">*</span><span class="n">ops</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">nf_unregister_net_hook</span><span class="p">(</span><span class="k">struct</span> <span class="n">net</span> <span class="o">*</span><span class="n">net</span><span class="p">,</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">nf_hook_ops</span> <span class="o">*</span><span class="n">ops</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">nf_register_net_hooks</span><span class="p">(</span><span class="k">struct</span> <span class="n">net</span> <span class="o">*</span><span class="n">net</span><span class="p">,</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">nf_hook_ops</span> <span class="o">*</span><span class="n">reg</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">n</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">nf_unregister_net_hooks</span><span class="p">(</span><span class="k">struct</span> <span class="n">net</span> <span class="o">*</span><span class="n">net</span><span class="p">,</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">nf_hook_ops</span> <span class="o">*</span><span class="n">reg</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">n</span><span class="p">);</span> +</pre></div> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p>Prior to version 3.11-rc2 of the Linux kernel, +there are some restrictions related to the use of header extraction functions +from a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sk_buff</span></code> structure set as a parameter in a netfilter +hook. While the IP header can be obtained each time using <code class="xref c c-func docutils literal"><span class="pre">ip_hdr()</span></code>, +the TCP and UDP headers can be obtained with <code class="xref c c-func docutils literal"><span class="pre">tcp_hdr()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">udp_hdr()</span></code> only for packages that come from inside the system rather +than the ones that are received from outside the system. In the latter case, +you must manually calculate the header offset in the package:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="c1">// For TCP packets (iph->protocol == IPPROTO_TCP)</span> +<span class="n">tcph</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">tcphdr</span><span class="o">*</span><span class="p">)((</span><span class="n">__u32</span><span class="o">*</span><span class="p">)</span><span class="n">iph</span> <span class="o">+</span> <span class="n">iph</span><span class="o">-></span><span class="n">ihl</span><span class="p">);</span> +<span class="c1">// For UDP packets (iph->protocol == IPPROTO_UDP)</span> +<span class="n">udph</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">udphdr</span><span class="o">*</span><span class="p">)((</span><span class="n">__u32</span><span class="o">*</span><span class="p">)</span><span class="n">iph</span> <span class="o">+</span> <span class="n">iph</span><span class="o">-></span><span class="n">ihl</span><span class="p">);</span> +</pre></div> +</div> +<p class="last">This code works in all filtering situations, so it's recommended to use it +instead of header access functions.</p> +</div> +<p>A usage example for a netfilter hook is shown below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/netfilter.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/netfilter_ipv4.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/net.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/in.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/skbuff.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/ip.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/tcp.h></span><span class="cp"></span> + +<span class="k">static</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="nf">my_nf_hookfn</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">priv</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">nf_hook_state</span> <span class="o">*</span><span class="n">state</span><span class="p">)</span> +<span class="p">{</span> + <span class="cm">/* process packet */</span> + <span class="c1">//...</span> + + <span class="k">return</span> <span class="n">NF_ACCEPT</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">nf_hook_ops</span> <span class="n">my_nfho</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">hook</span> <span class="o">=</span> <span class="n">my_nf_hookfn</span><span class="p">,</span> + <span class="p">.</span><span class="n">hooknum</span> <span class="o">=</span> <span class="n">NF_INET_LOCAL_OUT</span><span class="p">,</span> + <span class="p">.</span><span class="n">pf</span> <span class="o">=</span> <span class="n">PF_INET</span><span class="p">,</span> + <span class="p">.</span><span class="n">priority</span> <span class="o">=</span> <span class="n">NF_IP_PRI_FIRST</span> +<span class="p">};</span> + +<span class="kt">int</span> <span class="n">__init</span> <span class="nf">my_hook_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="n">nf_register_net_hook</span><span class="p">(</span><span class="o">&</span><span class="n">init_net</span><span class="p">,</span> <span class="o">&</span><span class="n">my_nfho</span><span class="p">);</span> +<span class="p">}</span> + +<span class="kt">void</span> <span class="n">__exit</span> <span class="nf">my_hook_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">nf_unregister_net_hook</span><span class="p">(</span><span class="o">&</span><span class="n">init_net</span><span class="p">,</span> <span class="o">&</span><span class="n">my_nfho</span><span class="p">);</span> +<span class="p">}</span> + +<span class="n">module_init</span><span class="p">(</span><span class="n">my_hook_init</span><span class="p">);</span> +<span class="n">module_exit</span><span class="p">(</span><span class="n">my_hook_exit</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="netcat"> +<h2>netcat<a class="headerlink" href="#netcat" title="Permalink to this headline">¶</a></h2> +<p>When developing applications that include networking code, one of the most +used tools is netcat. Also nicknamed "Swiss-army knife for TCP / IP". It allows:</p> +<blockquote> +<div><ul class="simple"> +<li>Initiating TCP connections;</li> +<li>Waiting for a TCP connection;</li> +<li>Sending and receiving UDP packets;</li> +<li>Displaying traffic in hexdump format;</li> +<li>Run a program after establishing a connection (eg, a shell);</li> +<li>Set special options in sent packages.</li> +</ul> +</div></blockquote> +<p>Initiating TCP connections:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">nc hostname port</span> +</pre></div> +</div> +<p>Listening to a TCP port:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">nc -l -p port</span> +</pre></div> +</div> +<p>Sending and receiving UDP packets is done adding the <code class="docutils literal"><span class="pre">-u</span></code> command line option.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The command is <strong class="command">nc</strong>; often <strong class="command">netcat</strong> is an alias for this +command. There are other implementations of the netcat command, some of which +have slightly different parameters than the classic implementation. Run +<strong class="command">man nc</strong> or <strong class="command">nc -h</strong> to check how to use it.</p> +</div> +<p>For more information on netcat, check the following <a class="reference external" href="https://www.win.tue.nl/~aeb/linux/hh/netcat_tutorial.pdf">tutorial</a>.</p> +</div> +<div class="section" id="further-reading"> +<h2>Further reading<a class="headerlink" href="#further-reading" title="Permalink to this headline">¶</a></h2> +<ol class="arabic simple"> +<li>Understanding Linux Network Internals</li> +<li><a class="reference external" href="http://www.cs.unh.edu/cnrg/gherrin/">Linux IP networking</a></li> +<li><a class="reference external" href="http://www.stllinux.org/meeting_notes/2001/0719/myTUX/">The TUX Web Server</a></li> +<li><a class="reference external" href="https://www.beej.us/guide/bgnet/">Beej's Guide to Network Programming Using Internet Sockets</a></li> +<li><a class="reference external" href="http://www.linuxjournal.com/article/7660">Kernel Korner - Network Programming in the Kernel</a></li> +<li><a class="reference external" href="http://phrack.org/issues/61/13.html">Hacking the Linux Kernel Network Stack</a></li> +<li><a class="reference external" href="http://www.netfilter.org/">The netfilter.org project</a></li> +<li><a class="reference external" href="https://www.digitalocean.com/community/tutorials/a-deep-dive-into-iptables-and-netfilter-architecture">A Deep Dive Into Iptables and Netfilter Architecture</a></li> +<li><a class="reference external" href="http://www.linuxfoundation.org/en/Net:Main_Page">Linux Foundation Networking Page</a></li> +</ol> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is networking. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/networking/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p class="last">You need to make sure that the <code class="docutils literal"><span class="pre">netfilter</span></code> support is active in kernel. It +is enabled via <code class="docutils literal"><span class="pre">CONFIG_NETFILTER</span></code>. To activate it, run <strong class="command">make menuconfig</strong> in +the <code class="file docutils literal"><span class="pre">linux</span></code> directory and check the <code class="docutils literal"><span class="pre">Network</span> <span class="pre">packet</span> <span class="pre">filtering</span> <span class="pre">framework</span> +<span class="pre">(Netfilter)</span></code> option in <code class="docutils literal"><span class="pre">Networking</span> <span class="pre">support</span> <span class="pre">-></span> <span class="pre">Networking</span> <span class="pre">options</span></code>. If it +was not enabled, enable it (as builtin, not external module - it must be +marked with <code class="docutils literal"><span class="pre">*</span></code>).</p> +</div> +<div class="section" id="displaying-packets-in-kernel-space"> +<h3>1. Displaying packets in kernel space<a class="headerlink" href="#displaying-packets-in-kernel-space" title="Permalink to this headline">¶</a></h3> +<p>Write a kernel module that displays the source address and port for TCP packets +that initiate an outbound connection. Start from the code in +<code class="file docutils literal"><span class="pre">1-2-netfilter</span></code> and fill in the areas marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">1</span></code>, taking into +account the comments below.</p> +<p>You will need to register a netfilter hook of type <code class="docutils literal"><span class="pre">NF_INET_LOCAL_OUT</span></code> as explained +in the <a class="reference internal" href="#netfilter">netfilter</a> section.</p> +<p><a class="reference internal" href="#the-struct-sk-buff-structure">The struct sk_buff structure</a> lets you access the packet headers using +specific functions. The <code class="xref c c-func docutils literal"><span class="pre">ip_hdr()</span></code> function returns the IP header as a +pointer to a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">iphdr</span></code> structure. The <code class="xref c c-func docutils literal"><span class="pre">tcp_hdr()</span></code> function +returns the TCP header as a pointer to a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">tcphdr</span></code> structure.</p> +<p>The <a class="reference external" href="http://www.eventhelix.com/Realtimemantra/Networking/Tcp.pdf">diagram</a> explains how to make a TCP connection. The connection initiation +packet has the <code class="docutils literal"><span class="pre">SYN</span></code> flag set in the TCP header and the <code class="docutils literal"><span class="pre">ACK</span></code> flag cleared.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>To display the source IP address, use the <code class="docutils literal"><span class="pre">%pI4</span></code> format of the printk +function. Details can be found in the <a class="reference external" href="https://www.kernel.org/doc/Documentation/printk-formats.txt">kernel documentation</a> (<code class="docutils literal"><span class="pre">IPv4</span> +<span class="pre">addresses</span></code> section). The following is an example code snippet that uses +<code class="docutils literal"><span class="pre">%pI4</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">printk</span><span class="p">(</span><span class="s">"IP address is %pI4</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="o">&</span><span class="n">iph</span><span class="o">-></span><span class="n">saddr</span><span class="p">);</span> +</pre></div> +</div> +<p class="last">When using the <code class="docutils literal"><span class="pre">%pI4</span></code> format, the argument to printk is a pointer. Hence the +construction <code class="docutils literal"><span class="pre">&iph->saddr</span></code> (with operator & - ampersand) instead of +<code class="docutils literal"><span class="pre">iph->saddr</span></code>.</p> +</div> +<p>The source TCP port is, in the TCP header, in the <a class="reference external" href="http://en.wikipedia.org/wiki/Endianness#Endianness_in_networking">network byte-order</a> format. +Read through the <a class="reference internal" href="#conversions"><span class="std std-ref">Conversions</span></a> section. Use <code class="xref c c-func docutils literal"><span class="pre">ntohs()</span></code> to convert.</p> +<p>For testing, use the <code class="file docutils literal"><span class="pre">1-2-netfilter/user/test-1.sh</span></code> file. The test creates +a connection to the localhost, a connection that will be intercepted and +displayed by the kernel module. The script is copied on the virtual machine by +the <strong class="command">make copy</strong> command only if it is marked as executable. The script +uses the statically compiled <strong class="command">netcat</strong> tool stored in +<code class="file docutils literal"><span class="pre">skels/networking/netcat</span></code>; this program must have execution +permissions.</p> +<p>After running the checker the output should be similar to the one bellow:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp"># ./test-1.sh</span> +<span class="p">[</span> <span class="mf">229.783512</span><span class="p">]</span> <span class="n">TCP</span> <span class="n">connection</span> <span class="n">initiated</span> <span class="n">from</span> <span class="mf">127.0.0.1</span><span class="o">:</span><span class="mi">44716</span> +<span class="n">Should</span> <span class="n">show</span> <span class="n">up</span> <span class="n">in</span> <span class="n">filter</span><span class="p">.</span> +<span class="n">Check</span> <span class="n">dmesg</span> <span class="n">output</span><span class="p">.</span> +</pre></div> +</div> +</div> +<div class="section" id="filtering-by-destination-address"> +<h3>2. Filtering by destination address<a class="headerlink" href="#filtering-by-destination-address" title="Permalink to this headline">¶</a></h3> +<p>Extend the module from exercise 1 so that you can specify a destination address +by means of a <code class="docutils literal"><span class="pre">MY_IOCTL_FILTER_ADDRESS</span></code> ioctl call. You'll only show packages +containing the specified destination address. To solve this task, fill in the +areas marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">2</span></code> and follow the specifications below.</p> +<p>To implement the ioctl routine, you must fill out the <code class="docutils literal"><span class="pre">my_ioctl</span></code> function. +Review the section in <a class="reference internal" href="lab3-device-drivers.html#ioctl"><span class="std std-ref">ioctl</span></a>. The address sent from user space is in +<a class="reference external" href="http://en.wikipedia.org/wiki/Endianness#Endianness_in_networking">network byte-order</a>, so there will be <strong>NO need</strong> for conversion.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The IP address sent via <code class="docutils literal"><span class="pre">ioctl</span></code> is sent by address, not by value. The +address must be stored in the <code class="docutils literal"><span class="pre">ioctl_set_addr</span></code> variable. For copying use +<code class="xref c c-func docutils literal"><span class="pre">copy_from_user()</span></code>.</p> +</div> +<p>To compare the addresses, fill out the <code class="docutils literal"><span class="pre">test_daddr</span></code> function. Addresses in +network byte-order will be used without having to convert addresses (if they +are equal from left to right they will be equal if reversed too).</p> +<p>The <code class="docutils literal"><span class="pre">test_daddr</span></code> function must be called from the netfilter hook to display +the connection initialization packets for which the destination address is the +one sent through the ioctl routine. The connection initiation packet has the +<code class="docutils literal"><span class="pre">SYN</span></code> flag set in the TCP header and the <code class="docutils literal"><span class="pre">ACK</span></code> flag cleared. You have to +check two things:</p> +<blockquote> +<div><ul class="simple"> +<li>the TCP flags;</li> +<li>the destination address of the packet (using <code class="docutils literal"><span class="pre">test_addr</span></code>).</li> +</ul> +</div></blockquote> +<p>For testing, use the <code class="file docutils literal"><span class="pre">1-2-netfilter/user/test-2.sh</span></code> script. This script +needs to compile the <code class="file docutils literal"><span class="pre">1-2-netfilter/user/test.c</span></code> file in the test +executable. Compilation is done automatically on the physical system when +running the <strong class="command">make build</strong> command. The test script is copied to the +virtual machine only if it is marked as executable. The script uses the +statically compiled <strong class="command">netcat</strong> tool in <code class="file docutils literal"><span class="pre">skels/networking/netcat</span></code>; +this executable must have execution permissions.</p> +<p>After running the checker the output should be similar to the one bellow:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ./test-2.sh +<span class="go">[ 797.673535] TCP connection initiated from 127.0.0.1:44721</span> +<span class="go">Should show up in filter.</span> +<span class="go">Should NOT show up in filter.</span> +<span class="go">Check dmesg output.</span> +</pre></div> +</div> +<p>The test ask for packet filtering first for the <code class="docutils literal"><span class="pre">127.0.0.1</span></code> IP address and +then for the <code class="docutils literal"><span class="pre">127.0.0.2</span></code> IP address. The first connection initiation packet +(to <code class="docutils literal"><span class="pre">127.0.0.1</span></code>) is intercepted and displayed by the filter, while the second +(to <code class="docutils literal"><span class="pre">127.0.0.2</span></code>) is not intercepted.</p> +</div> +<div class="section" id="listening-on-a-tcp-socket"> +<h3>3. Listening on a TCP socket<a class="headerlink" href="#listening-on-a-tcp-socket" title="Permalink to this headline">¶</a></h3> +<p>Write a kernel module that creates a TCP socket that listens to connections on +port <code class="docutils literal"><span class="pre">60000</span></code> on the loopback interface (in <code class="docutils literal"><span class="pre">init_module</span></code>). Start from the +code in <code class="file docutils literal"><span class="pre">3-4-tcp-sock</span></code> fill in the areas marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">1</span></code> taking +into account the observations below.</p> +<p>Read the <a class="reference internal" href="#operations-on-the-socket-structure">Operations on the socket structure</a> and <a class="reference internal" href="#the-struct-proto-ops-structure">The struct proto_ops +structure</a> sections.</p> +<p>The <code class="docutils literal"><span class="pre">sock</span></code> socket is a <code class="docutils literal"><span class="pre">server</span> <span class="pre">socket</span></code> and must be put in the listening +state. That is, the <code class="docutils literal"><span class="pre">bind</span></code> and <code class="docutils literal"><span class="pre">listen</span></code> operations must be applied to the +socket. For the <code class="docutils literal"><span class="pre">bind</span></code> and <code class="docutils literal"><span class="pre">listen</span></code> equivalent, in kernel space you will +need to call <code class="docutils literal"><span class="pre">sock->ops->...;</span></code> examples of such functions you can call are +<code class="docutils literal"><span class="pre">sock->ops->bind</span></code>, <code class="docutils literal"><span class="pre">sock->ops->listen</span></code> etc.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>For example, call <code class="docutils literal"><span class="pre">sock->ops->bind</span></code>, or <code class="docutils literal"><span class="pre">sock->ops->listen</span></code> functions, see +how they are called in the <code class="xref c c-func docutils literal"><span class="pre">sys_bind()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">sys_listen()</span></code> system +call handlers.</p> +<p class="last">Look for the system call handlers in the <code class="docutils literal"><span class="pre">net/socket.c</span></code> file in the Linux +kernel source code tree.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">For the second argument of the <code class="docutils literal"><span class="pre">listen</span></code> (backlog) call, use the +<code class="docutils literal"><span class="pre">LISTEN_BACKLOG</span></code>.</p> +</div> +<p>Remember to release the socket in the module's exit function and in the area +marked with error labels; use <code class="xref c c-func docutils literal"><span class="pre">sock_release()</span></code>.</p> +<p>For testing, run the <strong class="command">3-4-tcp_sock/test-3.sh</strong> script. The script is +copied on the virtual machine by <strong class="command">make copy</strong> only if it is marked as +executable.</p> +<p>After running the test, a TCP socket will be displayed by listening to +connections on port <code class="docutils literal"><span class="pre">60000</span></code>.</p> +</div> +<div class="section" id="accepting-connections-in-kernel-space"> +<h3>4. Accepting connections in kernel space<a class="headerlink" href="#accepting-connections-in-kernel-space" title="Permalink to this headline">¶</a></h3> +<p>Expand the module from the previous exercise to allow an external connection (no +need to send any message, only accept new connections). Fill in the areas marked +with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">2</span></code>.</p> +<p>Read the <a class="reference internal" href="#operations-on-the-socket-structure">Operations on the socket structure</a> and <a class="reference internal" href="#the-struct-proto-ops-structure">The struct proto_ops +structure</a> sections.</p> +<p>For the kernel space <code class="docutils literal"><span class="pre">accept</span></code> equivalent, see the system call handler for +<code class="xref c c-func docutils literal"><span class="pre">sys_accept4()</span></code>. Follow the <a class="reference external" href="https://elixir.bootlin.com/linux/v4.17/source/drivers/staging/lustre/lnet/lnet/lib-socket.c#L511">lnet_sock_accept</a> +implementation, and how the <code class="docutils literal"><span class="pre">sock->ops->accept</span></code> call is used. Use <code class="docutils literal"><span class="pre">0</span></code> as +the value for the second to last argument (<code class="docutils literal"><span class="pre">flags</span></code>), and <code class="docutils literal"><span class="pre">true</span></code> for the +last argument (<code class="docutils literal"><span class="pre">kern</span></code>).</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Look for the system call handlers in the <code class="docutils literal"><span class="pre">net/socket.c</span></code> file in the Linux +kernel source code tree.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The new socket (<code class="docutils literal"><span class="pre">new_sock</span></code>) must be created with the +<code class="xref c c-func docutils literal"><span class="pre">sock_create_lite()</span></code> function and then its operations must be configured +using</p> +<div class="last highlight-console"><div class="highlight"><pre><span></span><span class="go">newsock->ops = sock->ops;</span> +</pre></div> +</div> +</div> +<p>Print the address and port of the destination socket. To find the peer name of a +socket (its address), refer to the <code class="xref c c-func docutils literal"><span class="pre">sys_getpeername()</span></code> system call handler.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The first argument for the <code class="docutils literal"><span class="pre">sock->ops->getname</span></code> function will be the +connection socket, ie <code class="docutils literal"><span class="pre">new_sock</span></code>, the one initialized with by the <code class="docutils literal"><span class="pre">accept</span></code> +call.</p> +<p>The last argument of the <code class="docutils literal"><span class="pre">sock->ops->getname</span></code> function will be <code class="docutils literal"><span class="pre">1</span></code>, +meaning that we want to know about the endpoint or the peer (<em>remote end</em> or +<em>peer</em>).</p> +<p class="last">Display the peer address (indicated by the <code class="docutils literal"><span class="pre">raddr</span></code> variable) using the +<code class="docutils literal"><span class="pre">print_sock_address</span></code> macro defined in the file.</p> +</div> +<p>Release the newly created socket (after accepting the connection) in the module +exit function and after the error label. After adding the <code class="docutils literal"><span class="pre">accept</span></code> code to the +module initialization function, the <strong class="command">insmod</strong> operation will lock until +a connection is established. You can unlock using <strong class="command">netcat</strong> on that +port. Consequently, the test script from the previous exercise will not work.</p> +<p>For testing, run the <code class="file docutils literal"><span class="pre">3-4-tcp_sock/test-4.sh</span></code> script. The script is copied on +the virtual machine by <strong class="command">make copy</strong> only if it is marked as executable.</p> +<p>Nothing special will be displayed (in the kernel buffer). The success of the +test will be defined by the connection establishment. Then use <code class="docutils literal"><span class="pre">Ctrl+c</span></code> to +stop the test script, and then you can remove the kernel module.</p> +</div> +<div class="section" id="udp-socket-sender"> +<h3>5. UDP socket sender<a class="headerlink" href="#udp-socket-sender" title="Permalink to this headline">¶</a></h3> +<p>Write a kernel module that creates a UDP socket and sends the message from the +<code class="docutils literal"><span class="pre">MY_TEST_MESSAGE</span></code> macro on the socket to the loopback address on port +<code class="docutils literal"><span class="pre">60001</span></code>.</p> +<p>Start from the code in <code class="file docutils literal"><span class="pre">5-udp-sock</span></code>.</p> +<p>Read the <a class="reference internal" href="#operations-on-the-socket-structure">Operations on the socket structure</a> and <a class="reference internal" href="#the-struct-proto-ops-structure">The struct proto_ops +structure</a> sections.</p> +<p>To see how to send messages in the kernel space, see the <code class="xref c c-func docutils literal"><span class="pre">sys_send()</span></code> +system call handler or <a class="reference internal" href="#sending-receiving-messages">Sending/receiving messages</a>.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>The <code class="docutils literal"><span class="pre">msg_name</span></code> field of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">msghdr</span></code> structure must be +initialized to the destination address (pointer to <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">sockaddr</span></code>) +and the <code class="docutils literal"><span class="pre">msg_namelen</span></code> field to the address size.</p> +<p>Initialize the <code class="docutils literal"><span class="pre">msg_flags</span></code> field of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">msghdr</span></code> structure +to <code class="docutils literal"><span class="pre">0</span></code>.</p> +<p class="last">Initialize the <code class="docutils literal"><span class="pre">msg_control</span></code> and <code class="docutils literal"><span class="pre">msg_controllen</span></code> fields of the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">msghdr</span></code> structure to <code class="docutils literal"><span class="pre">NULL</span></code> and <code class="docutils literal"><span class="pre">0</span></code> respectively.</p> +</div> +<p>For sending the message use <code class="xref c c-func docutils literal"><span class="pre">kernel_sendmsg()</span></code>.</p> +<p>The message transmission parameters are retrieved from the kernel space. Cast +the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">iovec</span></code> structure pointer to a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">kvec</span></code> pointer +in the <code class="xref c c-func docutils literal"><span class="pre">kernel_sendmsg()</span></code> call.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">The last two parameters of <code class="xref c c-func docutils literal"><span class="pre">kernel_sendmsg()</span></code> are <code class="docutils literal"><span class="pre">1</span></code> (number of I/O +vectors) and <code class="docutils literal"><span class="pre">len</span></code> (message size).</p> +</div> +<p>For testing, use the <code class="file docutils literal"><span class="pre">test-5.sh</span></code> file. The script is copied on the virtual +machine by the <strong class="command">make copy</strong> command only if it is marked as executable. +The script uses the statically compiled <code class="docutils literal"><span class="pre">netcat</span></code> tool stored in +<code class="file docutils literal"><span class="pre">skels/networking/netcat</span></code>; this executable must have execution +permissions.</p> +<p>For a correct implementation, running the <code class="file docutils literal"><span class="pre">test-5.sh</span></code> script will cause +the <code class="docutils literal"><span class="pre">kernelsocket</span></code> message to be displayed like in the output below:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">/root # ./test-5.sh</span> +<span class="go">+ pid=1059</span> +<span class="go">+ sleep 1</span> +<span class="go">+ nc -l -u -p 60001</span> +<span class="go">+ insmod udp_sock.ko</span> +<span class="go">kernelsocket</span> +<span class="go">+ rmmod udp_sock</span> +<span class="go">+ kill 1059</span> +</pre></div> +</div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lab9-filesystems-part2.html" class="btn btn-neutral float-left" title="SO2 Lab 09 - File system drivers (Part 2)" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lab11-arm-kernel-development.html" class="btn btn-neutral float-right" title="SO2 Lab 11 - Kernel Development on ARM" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lab11-arm-kernel-development.html b/refs/pull/405/merge/so2/lab11-arm-kernel-development.html new file mode 100644 index 00000000..da649963 --- /dev/null +++ b/refs/pull/405/merge/so2/lab11-arm-kernel-development.html @@ -0,0 +1,621 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lab 11 - Kernel Development on ARM — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lab 12 - Kernel Profiling" href="lab12-kernel-profiling.html" /> + <link rel="prev" title="SO2 Lab 10 - Networking" href="lab10-networking.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lab 11 - Kernel Development on ARM</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#system-on-a-chip">System on a Chip</a></li> +<li class="toctree-l3"><a class="reference internal" href="#board-support-package">Board Support package</a></li> +<li class="toctree-l3"><a class="reference internal" href="#toolchain">Toolchain</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#compiling-the-linux-kernel-on-arm">Compiling the Linux kernel on ARM</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#linux-kernel-image">Linux kernel image</a></li> +<li class="toctree-l3"><a class="reference internal" href="#rootfs">Rootfs</a></li> +<li class="toctree-l3"><a class="reference internal" href="#device-tree">Device tree</a></li> +<li class="toctree-l3"><a class="reference internal" href="#qemu">Qemu</a></li> +<li class="toctree-l3"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#intro">0. Intro</a></li> +<li class="toctree-l4"><a class="reference internal" href="#boot">1. Boot</a></li> +<li class="toctree-l4"><a class="reference internal" href="#cpu-information">2. CPU information</a></li> +<li class="toctree-l4"><a class="reference internal" href="#i-o-memory">3. I/O memory</a></li> +<li class="toctree-l4"><a class="reference internal" href="#hello-world">4. Hello World</a></li> +<li class="toctree-l4"><a class="reference internal" href="#simple-device">5. Simple device</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lab 11 - Kernel Development on ARM</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lab11-arm-kernel-development.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lab-11-kernel-development-on-arm"> +<h1>SO2 Lab 11 - Kernel Development on ARM<a class="headerlink" href="#so2-lab-11-kernel-development-on-arm" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>get a feeling of what System on a Chip (SoC) means</li> +<li>get familiar with embedded world using ARM as a supported architecture</li> +<li>understand what a Board Support Package means (BSP)</li> +<li>compile and boot an ARM kernel with Qemu using i.MX6UL platform as an example</li> +<li>get familiar with hardware description using Device Trees</li> +</ul> +</div> +<div class="section" id="system-on-a-chip"> +<h2>System on a Chip<a class="headerlink" href="#system-on-a-chip" title="Permalink to this headline">¶</a></h2> +<p>A System on a Chip (<strong>SoC</strong>) is an integrated circuit (<strong>IC</strong>) that integrates an entire system onto it. The components +that can be usually found on an SoC include a central processing unit (<strong>CPU</strong>), memory, input/output ports, storage devices +together with more sophisticated modules like audio digital interfaces, neural processing units (<strong>NPU</strong>) or graphical +processing units (<strong>GPU</strong>).</p> +<dl class="docutils"> +<dt>SoCs can be used in various applications most common are:</dt> +<dd><ul class="first last simple"> +<li>consumer electronics (TV sets, mobile phones, video game consoles)</li> +<li>industrial computers (medical imaging, etc)</li> +<li>automotive</li> +<li>home appliances</li> +</ul> +</dd> +</dl> +<p>The leading architecture for SoCs is <strong>ARM</strong>. Worth mentioning here is that there are also x86-based SoCs platforms. Another thing +we need to keep an eye on is <strong>RISC-V</strong> an open standard instruction set architecture.</p> +<p>A simplified view of an <strong>ARM</strong> platform is shown in the image below:</p> +<img alt="../_images/schematic1.png" class="align-center" src="../_images/schematic1.png" /> +<p>We will refer as a reference platform at NXP's <a class="reference external" href="imx6ul">i.MX6UL</a> platform, but in general all SoC's contain the following building blocks:</p> +<blockquote> +<div><blockquote> +<div><ul class="simple"> +<li>one or more CPU cores</li> +<li>a system bus</li> +<li>clock and reset module<ul> +<li>PLL</li> +<li>OSC</li> +<li>reset controller</li> +</ul> +</li> +</ul> +</div></blockquote> +<ul class="simple"> +<li>interrupt controller</li> +<li>timers</li> +<li>memory controller</li> +<li>peripheral controllers<ul> +<li><a class="reference external" href="https://en.wikipedia.org/wiki/I%C2%B2C">I2C</a></li> +<li><a class="reference external" href="https://en.wikipedia.org/wiki/Serial_Peripheral_Interface">SPI</a></li> +<li><a class="reference external" href="https://en.wikipedia.org/wiki/General-purpose_input/output">GPIO</a></li> +<li><a class="reference external" href="https://en.wikipedia.org/wiki/Network_interface_controller">Ethernet</a> (for network)</li> +<li><a class="reference external" href="https://en.wikipedia.org/wiki/MultiMediaCard">uSDHC</a> (for storage)</li> +<li>USB</li> +<li><a class="reference external" href="https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter">UART</a></li> +<li><a class="reference external" href="https://en.wikipedia.org/wiki/I%C2%B2S">I2S</a> (for sound)</li> +<li>eLCDIF (for LCD Panel)</li> +</ul> +</li> +</ul> +</div></blockquote> +<p>Here is the complete block diagram for i.MX6UL platform:</p> +<a class="reference internal image-reference" href="https://www.nxp.com/assets/images/en/block-diagrams/IMX6UL-BD.jpg"><img alt="IMX6UL-BD" class="align-center" src="https://www.nxp.com/assets/images/en/block-diagrams/IMX6UL-BD.jpg" style="width: 60%;" /></a> +<p>i.MX6UL Evaluation Kit board looks like this:</p> +<a class="reference internal image-reference" href="https://www.compulab.com/wp-content/gallery/sbc-imx6ul/compulab_sbc-imx6ul_single-board-computer.jpg"><img alt="imx6ul-evk" class="align-center" src="https://www.compulab.com/wp-content/gallery/sbc-imx6ul/compulab_sbc-imx6ul_single-board-computer.jpg" style="width: 60%;" /></a> +<p>Other popular SoC boards:</p> +<blockquote> +<div><ul class="simple"> +<li><a class="reference external" href="https://en.wikipedia.org/wiki/Raspberry_Pi">Broadcom Raspberry Pi</a></li> +<li><a class="reference external" href="https://en.wikipedia.org/wiki/BeagleBoard">Texas Instruments Beagle board</a></li> +<li><a class="reference external" href="https://wiki.odroid.com/odroid-xu4/odroid-xu4">Odroid Xu4</a></li> +<li><a class="reference external" href="https://developer.nvidia.com/embedded/jetson-nano-developer-kit">Nvidia Jetson Nano</a></li> +</ul> +</div></blockquote> +</div> +<div class="section" id="board-support-package"> +<h2>Board Support package<a class="headerlink" href="#board-support-package" title="Permalink to this headline">¶</a></h2> +<p>A board support package (<strong>BSP</strong>) is the minimal set of software packages that allow to demonstrate the capabilities of a certain hardware platform. This includes:</p> +<blockquote> +<div><ul class="simple"> +<li>toolchain</li> +<li>bootloader</li> +<li>Linux kernel image, device tree files and drivers</li> +<li>root filesystem</li> +</ul> +</div></blockquote> +<p>Semiconductor manufacturers usually provide a <strong>BSP</strong> together with an evaluation board. BSP is typically bundled using <a class="reference external" href="https://www.yoctoproject.org/">Yocto</a></p> +</div> +<div class="section" id="toolchain"> +<h2>Toolchain<a class="headerlink" href="#toolchain" title="Permalink to this headline">¶</a></h2> +<p>Because our development machines are mostly x86-based we need a cross compiler that can produce executable +code for ARM platform.</p> +<p>We can build our own cross compiler from scratch using <a class="reference external" href="https://crosstool-ng.github.io/">https://crosstool-ng.github.io/</a> or we can install one</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf <span class="c1"># for arm32</span> +$ sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu <span class="c1"># for arm64</span> +</pre></div> +</div> +<p>There are several of toolchain binaries depending on the configuration:</p> +<blockquote> +<div><ul class="simple"> +<li>With "arm-eabi-gcc" you have the Linux system C library which will make calls into the kernel IOCTLs, e.g. for allocating memory pages to the process.</li> +<li>With "arm-eabi-none-gcc" you are running on platform which doesn't have an operating system at all - so the C library is different to cope with that.</li> +</ul> +</div></blockquote> +<div class="section" id="compiling-the-linux-kernel-on-arm"> +<h3>Compiling the Linux kernel on ARM<a class="headerlink" href="#compiling-the-linux-kernel-on-arm" title="Permalink to this headline">¶</a></h3> +<p>Compile the kernel for 32bit ARM boards:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># select defconfig based on your platform</span> +$ <span class="nv">ARCH</span><span class="o">=</span>arm <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabihf- make imx_v6_v7_defconfig +<span class="c1"># compile the kernel</span> +$ <span class="nv">ARCH</span><span class="o">=</span>arm <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabihf- make -j8 +</pre></div> +</div> +<p>Compile the kernel for 64bit ARM boards:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># for 64bit ARM there is a single config for all supported boards</span> +$ <span class="nv">ARCH</span><span class="o">=</span>arm <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabihf- make defconfig +<span class="c1"># compile the kernel</span> +$ <span class="nv">ARCH</span><span class="o">=</span>arm64 <span class="nv">CROSS_COMPILE</span><span class="o">=</span>aarch64-linux-gnu- make -j8 +</pre></div> +</div> +</div> +</div> +<div class="section" id="linux-kernel-image"> +<h2>Linux kernel image<a class="headerlink" href="#linux-kernel-image" title="Permalink to this headline">¶</a></h2> +<p>The kernel image binary is named <code class="docutils literal"><span class="pre">vmlinux</span></code> and it can be found in the root of the kernel tree. Compressed image used for booting can be found under:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">arch/arm/boot/Image</span></code>, for arm32</li> +<li><code class="docutils literal"><span class="pre">arch/arm64/boot/Image</span></code>, for arm64</li> +</ul> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ file vmlinux + vmlinux: ELF <span class="m">32</span>-bit LSB executable, ARM, EABI5 version <span class="m">1</span> <span class="o">(</span>SYSV<span class="o">)</span>, statically linked, not stripped + +$ file vmlinux + vmlinux: ELF <span class="m">64</span>-bit LSB shared object, ARM aarch64, version <span class="m">1</span> <span class="o">(</span>SYSV<span class="o">)</span>, statically linked, not stripped +</pre></div> +</div> +</div> +<div class="section" id="rootfs"> +<h2>Rootfs<a class="headerlink" href="#rootfs" title="Permalink to this headline">¶</a></h2> +<p>The root filesystem (<code class="docutils literal"><span class="pre">rootfs</span></code>) is the filesystem mounted at the top of files hierarchy (<code class="docutils literal"><span class="pre">/</span></code>). It should contain at least +the critical files allowing the system to boot to a shell.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>root@so2$ tree -d -L <span class="m">2</span> +├── bin +├── boot +├── dev +├── etc +├── home +│ └── root +├── lib +│ └── udev +├── mnt +├── proc +├── sbin +│ └── init +├── sys +├── usr +│ ├── bin +│ ├── include +│ ├── lib +└── var +</pre></div> +</div> +<p>As for <code class="docutils literal"><span class="pre">x86</span></code> we will make use of Yocto rootfs images. In order to download an <code class="docutils literal"><span class="pre">ext4</span></code> rootfs image for <code class="docutils literal"><span class="pre">arm32</span></code> one needs to run:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nb">cd</span> tools/labs/ +$ <span class="nv">ARCH</span><span class="o">=</span>arm make core-image-minimal-qemuarm.ext4 +</pre></div> +</div> +</div> +<div class="section" id="device-tree"> +<h2>Device tree<a class="headerlink" href="#device-tree" title="Permalink to this headline">¶</a></h2> +<p>Device tree (<strong>DT</strong>) is a tree structure used to describe the hardware devices in a system. Each node in the tree describes a device hence it is called <strong>device node</strong>. DT was introduced +to provide a way to discover non-discoverable hardware (e.g a device on an I2C bus). This information was previously stored inside the source code for the Linux kernel. This meant that +each time we needed to modify a node for a device the kernel needed to be recompiled. This no longer holds true as device tree and kernel image are separate binaries now.</p> +<p>Device trees are stored inside device tree sources (<em>.dts</em>) and compiled into device tree blobs (<em>.dtb</em>).</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># compile dtbs</span> +$ make dtbs + +<span class="c1"># location for DT sources on arm32</span> +$ ls arch/arm/boot/dts/ + imx6ul-14x14-evk.dtb imx6ull-14x14-evk.dtb bcm2835-rpi-a-plus.dts + +<span class="c1"># location for DT source on arm64</span> +$ ls arch/arm64/boot/dts/<vendor> + imx8mm-evk.dts imx8mp-evk.dts +</pre></div> +</div> +<p>The following image is a represantation of a simple device tree, describing board type, cpu and memory.</p> +<img alt="../_images/dts_node1.png" class="align-center" src="../_images/dts_node1.png" /> +<p>Notice that a device tree node can be defined using <code class="docutils literal"><span class="pre">label:</span> <span class="pre">name@address</span></code>:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">label</span></code>, is an identifier used to reference the node from other places</li> +<li><code class="docutils literal"><span class="pre">name</span></code>, node identifier</li> +<li><code class="docutils literal"><span class="pre">address</span></code>, used to differentiate nodes with the same name.</li> +</ul> +</div></blockquote> +<p>A node might contain several properties arranged in the <code class="docutils literal"><span class="pre">name</span> <span class="pre">=</span> <span class="pre">value</span></code> format. The name is a string +and the value can be bytes, strings, array of strings.</p> +<p>Here is an example:</p> +<div class="code c highlight-none"><div class="highlight"><pre><span></span>/ { + node@0 { + empty-property; + string-property = "string value"; + string-list-property = "string value 1", "string value 2"; + int-list-property = <value1 value2>; + + child-node@0 { + child-empty-property; + child-string-property = "string value"; + child-node-reference = <&child-node1>; + }; + + child-node1: child-node@1 { + child-empty-property; + child-string-property = "string value"; + }; + }; +}; +</pre></div> +</div> +</div> +<div class="section" id="qemu"> +<h2>Qemu<a class="headerlink" href="#qemu" title="Permalink to this headline">¶</a></h2> +<p>We will use <code class="docutils literal"><span class="pre">qemu-system-arm</span></code> to boot 32bit ARM platforms. Although, this can be installed from official distro repos, for example:</p> +<div class="code bash highlight-none"><div class="highlight"><pre><span></span>sudo apt-get install -y qemu-system-arm +</pre></div> +</div> +<p>We strongly recommend using latest version of <code class="docutils literal"><span class="pre">qemu-system-arm</span></code> build from sources:</p> +<div class="code bash highlight-none"><div class="highlight"><pre><span></span>$ git clone https://gitlab.com/qemu-project/qemu.git +$ ./configure --target-list=arm-softmmu --disable-docs +$ make -j8 +$ ./build/qemu-system-arm +</pre></div> +</div> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is arm_kernel_development. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/arm_kernel_development/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>The rules for working with the virtual machine for <code class="docutils literal"><span class="pre">ARM</span></code> are modified as follows</p> +<div class="last highlight-shell"><div class="highlight"><pre><span></span><span class="c1"># modules build</span> +tools/labs $ <span class="nv">ARCH</span><span class="o">=</span>arm <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabihf- make build +<span class="c1"># modules copy</span> +tools/labs $ <span class="nv">ARCH</span><span class="o">=</span>arm make copy +<span class="c1"># kernel build</span> +$ <span class="nv">ARCH</span><span class="o">=</span>arm <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabihf- make -j8 +</pre></div> +</div> +</div> +<div class="section" id="intro"> +<h3>0. Intro<a class="headerlink" href="#intro" title="Permalink to this headline">¶</a></h3> +<p>Inspect the following locations in the Linux kernel code and identify platforms and vendors using +ARM architecture:</p> +<blockquote> +<div><ul class="simple"> +<li>32-bit: <code class="docutils literal"><span class="pre">arch/arm/boot/dts</span></code></li> +<li>64-bit: <code class="docutils literal"><span class="pre">arch/arm64/boot/dts</span></code></li> +</ul> +</div></blockquote> +<p>Use <code class="docutils literal"><span class="pre">qemu</span></code> and look at the supported platforms:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>../qemu/build/arm-softmmu/qemu-system-arm -M ? +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">We used our own compiled version of <code class="docutils literal"><span class="pre">Qemu</span></code> for <code class="docutils literal"><span class="pre">arm32</span></code>. See <a class="reference internal" href="#qemu">Qemu</a> section for more details.</p> +</div> +</div> +<div class="section" id="boot"> +<h3>1. Boot<a class="headerlink" href="#boot" title="Permalink to this headline">¶</a></h3> +<p>Use <code class="docutils literal"><span class="pre">qemu</span></code> to boot <code class="docutils literal"><span class="pre">i.MX6UL</span></code> platform. In order to boot, we first need to compile the kernel. +Review <a class="reference internal" href="#compiling-the-linux-kernel-on-arm">Compiling the Linux kernel on ARM</a> section.</p> +<p>Successful compilation will result in the following binaries:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">arch/arm/boot/Image</span></code>, kernel image compiled for ARM</li> +<li><code class="docutils literal"><span class="pre">arch/arm/boot/dts/imx6ul-14x14-evk.dtb</span></code>, device tree blob for <code class="docutils literal"><span class="pre">i.MX6UL</span></code> board</li> +</ul> +</div></blockquote> +<p>Review <a class="reference internal" href="#rootfs">Rootfs</a> section and download <code class="docutils literal"><span class="pre">core-image-minimal-qemuarm.ext4</span></code> rootfs. +Run <code class="docutils literal"><span class="pre">qemu</span></code> using then following command:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>../qemu/build/arm-softmmu/qemu-system-arm -M mcimx6ul-evk -cpu cortex-a7 -m 512M <span class="se">\</span> + -kernel arch/arm/boot/zImage -nographic -dtb arch/arm/boot/dts/imx6ul-14x14-evk.dtb <span class="se">\</span> + -append <span class="s2">"root=/dev/mmcblk0 rw console=ttymxc0 loglevel=8 earlycon printk"</span> -sd tools/labs/core-image-minimal-qemuarm.ext4 +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">LCDIF and ASRC devices are not well supported with <code class="docutils literal"><span class="pre">Qemu</span></code>. Remove them from compilation.</p> +</div> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nv">ARCH</span><span class="o">=</span>arm <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabihf- make menuconfig +<span class="c1"># set FSL_ASRC=n and DRM_MXSFB=n</span> +$ <span class="nv">ARCH</span><span class="o">=</span>arm <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabihf- make -j8 +</pre></div> +</div> +<p>Once the kernel is booted check kernel version and cpu info:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ cat /proc/cpuinfo +$ cat /proc/version +</pre></div> +</div> +</div> +<div class="section" id="cpu-information"> +<h3>2. CPU information<a class="headerlink" href="#cpu-information" title="Permalink to this headline">¶</a></h3> +<p>Inspect the CPU configuration for <code class="docutils literal"><span class="pre">NXP</span> <span class="pre">i.MX6UL</span></code> board. Start with <code class="docutils literal"><span class="pre">arch/arm/boot/dts/imx6ul-14x14-evk.dts</span></code>.</p> +<blockquote> +<div><ul class="simple"> +<li>find <code class="docutils literal"><span class="pre">cpu@0</span></code> device tree node and look for <code class="docutils literal"><span class="pre">operating-points</span></code> property.</li> +<li>read the maximum and minimum operating frequency the processor can run</li> +</ul> +<blockquote> +<div><div class="code bash highlight-none"><div class="highlight"><pre><span></span>$ cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq +$ cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq +</pre></div> +</div> +</div></blockquote> +</div></blockquote> +</div> +<div class="section" id="i-o-memory"> +<h3>3. I/O memory<a class="headerlink" href="#i-o-memory" title="Permalink to this headline">¶</a></h3> +<p>Inspect I/O space configuration for <code class="docutils literal"><span class="pre">NXP</span> <span class="pre">i.MX6UL</span></code> board. Start with <code class="docutils literal"><span class="pre">arch/arm/boot/dts/imx6ul-14x14-evk.dts</span></code> and identify each device mentioned below.</p> +<div class="code bash highlight-none"><div class="highlight"><pre><span></span>$ cat /proc/iomem + 00900000-0091ffff : 900000.sram sram@900000 + 0209c000-0209ffff : 209c000.gpio gpio@209c000 + 021a0000-021a3fff : 21a0000.i2c i2c@21a0000 + 80000000-9fffffff : System RAM +</pre></div> +</div> +<p>Identify device tree nodes corresponding to:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">System</span> <span class="pre">RAM</span></code>, look for <code class="docutils literal"><span class="pre">memory@80000000</span></code> node in <code class="docutils literal"><span class="pre">arch/arm/boot/dts/imx6ul-14x14-evk.dtsi</span></code>. What's the size of the System RAM?</li> +<li><code class="docutils literal"><span class="pre">GPIO1</span></code>, look for <code class="docutils literal"><span class="pre">gpio@209c000</span></code> node in <code class="docutils literal"><span class="pre">arch/arm/boot/dts/imx6ul.dtsi</span></code>. What's the size of the I/O space for this device?</li> +<li><code class="docutils literal"><span class="pre">I2C1</span></code>, look for <code class="docutils literal"><span class="pre">i2c@21a0000</span></code> node in <code class="docutils literal"><span class="pre">arch/arm/boot/dts/imx6ul.dtsi</span></code>. What's the size of the I/O spaces for this device?</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="hello-world"> +<h3>4. Hello World<a class="headerlink" href="#hello-world" title="Permalink to this headline">¶</a></h3> +<p>Implement a simple kernel module that prints a message at load/unload time. Compile it and load it on <code class="docutils literal"><span class="pre">i.MX6UL</span></code> emulated platform.</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span><span class="c1"># modules build</span> +tools/labs $ <span class="nv">ARCH</span><span class="o">=</span>arm <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabihf- make build +<span class="c1"># modules copy</span> +tools/labs $ <span class="nv">ARCH</span><span class="o">=</span>arm make copy +<span class="c1"># kernel build</span> +$ <span class="nv">ARCH</span><span class="o">=</span>arm <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabihf- make -j8 +</pre></div> +</div> +</div> +<div class="section" id="simple-device"> +<h3>5. Simple device<a class="headerlink" href="#simple-device" title="Permalink to this headline">¶</a></h3> +<p>Implement a driver for a simple platform device. Find <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">1</span></code> and notice how <code class="docutils literal"><span class="pre">simple_driver</span></code> is declared and register as a platform driver. +Follow <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">2</span></code> and add the <code class="docutils literal"><span class="pre">so2,simple-device-v1</span></code> and <code class="docutils literal"><span class="pre">so2,simple-device-v2</span></code> compatible strings in the simple_device_ids array.</p> +<p>Create two device tree nodes in <code class="docutils literal"><span class="pre">arch/arm/boot/dts/imx6ul.dtsi</span></code> under <code class="docutils literal"><span class="pre">soc</span></code> node with compatible strings <code class="docutils literal"><span class="pre">so2,simple-device-v1</span></code> and +<code class="docutils literal"><span class="pre">so2,simple-device-v2</span></code> respectively. Then notice the behavior when loading <code class="docutils literal"><span class="pre">simple_driver</span></code> module.</p> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lab10-networking.html" class="btn btn-neutral float-left" title="SO2 Lab 10 - Networking" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lab12-kernel-profiling.html" class="btn btn-neutral float-right" title="SO2 Lab 12 - Kernel Profiling" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lab12-kernel-profiling.html b/refs/pull/405/merge/so2/lab12-kernel-profiling.html new file mode 100644 index 00000000..ee02cd06 --- /dev/null +++ b/refs/pull/405/merge/so2/lab12-kernel-profiling.html @@ -0,0 +1,680 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lab 12 - Kernel Profiling — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Collaboration" href="assign-collaboration.html" /> + <link rel="prev" title="SO2 Lab 11 - Kernel Development on ARM" href="lab11-arm-kernel-development.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lab 12 - Kernel Profiling</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lab-objectives">Lab Objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#overview">Overview</a></li> +<li class="toctree-l3"><a class="reference internal" href="#profiling-tools">Profiling Tools</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#perf">perf</a></li> +<li class="toctree-l4"><a class="reference internal" href="#ps">ps</a></li> +<li class="toctree-l4"><a class="reference internal" href="#time">time</a></li> +<li class="toctree-l4"><a class="reference internal" href="#top">top</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#profiling-methodology">Profiling Methodology</a></li> +<li class="toctree-l3"><a class="reference internal" href="#exercises">Exercises</a></li> +<li class="toctree-l3"><a class="reference internal" href="#demo-profiling-i-o-problems">0. Demo: Profiling I/O Problems</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#investigating-reduced-responsiveness">1. Investigating Reduced Responsiveness</a></li> +<li class="toctree-l4"><a class="reference internal" href="#launching-new-threads">2. Launching New Threads</a></li> +<li class="toctree-l4"><a class="reference internal" href="#tuning-cp">3. Tuning <code class="docutils literal"><span class="pre">cp</span></code></a></li> +<li class="toctree-l4"><a class="reference internal" href="#i-o-latency">4. I/O Latency</a></li> +<li class="toctree-l4"><a class="reference internal" href="#bad-elf">5. Bad ELF</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lab 12 - Kernel Profiling</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lab12-kernel-profiling.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lab-12-kernel-profiling"> +<h1>SO2 Lab 12 - Kernel Profiling<a class="headerlink" href="#so2-lab-12-kernel-profiling" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab Objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<blockquote> +<div><ul class="simple"> +<li>Familiarize yourself with the basics of Linux kernel profiling</li> +<li>Understanding basic profiling tools</li> +<li>Learning profiling methodologies and good practices</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="overview"> +<h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline">¶</a></h2> +<p>Up until now we have studied how the different components of the Linux kernel +work, and how to write drivers that interface with them in order to provide +support for devices or protocols. This has helped us understand how the Linux +kernel works, but most people will not get to write kernel drivers.</p> +<p>Nonetheless, the skills learned will help us to write applications that better +integrate with the whole operating system. In order to do this, one has to have +a good view of both the user space and the kernel space.</p> +<p>This session aims to merge the work we have done up until now in the kernel +space with real world use cases where we do not write kernel space code, but we +look through the kernel using profiling tools, in order to debug issues that +we're having when writing regular, low-level, applications.</p> +<p>Another focus of this session will be learning a general methodology for +debugging software issues, and we will approach some tools that give us insight +from the kernel on the way our application runs.</p> +</div> +<div class="section" id="profiling-tools"> +<h2>Profiling Tools<a class="headerlink" href="#profiling-tools" title="Permalink to this headline">¶</a></h2> +<p>The main tool that we will focus our attention on is <code class="docutils literal"><span class="pre">perf</span></code>, which offers +support for tracing applications, and also inspecting general aspects of the +system. We will also be using debugging tools that most people have used in +their day to day life, such as <code class="docutils literal"><span class="pre">htop</span></code>, <code class="docutils literal"><span class="pre">ps</span></code>, <code class="docutils literal"><span class="pre">lsof</span></code> and others.</p> +<div class="section" id="perf"> +<h3>perf<a class="headerlink" href="#perf" title="Permalink to this headline">¶</a></h3> +<p><code class="docutils literal"><span class="pre">perf</span></code> is a tool that instruments the CPU using +tracepoints, kprobes and uprobes. This tool allows us to take a look at what +functions are being called at a given point. This allows us to take a peak at +where the kernel is pending the most time, print out call stacks of functions, +and in general log what the CPU is running.</p> +<p><code class="docutils literal"><span class="pre">perf</span></code> integrates modules such as: +* static tracing +* dynamic tracing +* resource monitoring</p> +<p>The tracing interface that is offered by perf can be used by itself, using the +<code class="docutils literal"><span class="pre">perf</span></code> command together with its subcommands.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~# ./skels/kernel_profiling/perf + + usage: perf [--version] [--help] [OPTIONS] COMMAND [ARGS] + + The most commonly used perf commands are: + annotate Read perf.data (created by perf record) and display annotated code + archive Create archive with object files with build-ids found in perf.data file + bench General framework for benchmark suites + buildid-cache Manage build-id cache. + buildid-list List the buildids in a perf.data file + c2c Shared Data C2C/HITM Analyzer. + config Get and set variables in a configuration file. + data Data file related processing + diff Read perf.data files and display the differential profile + evlist List the event names in a perf.data file + ftrace simple wrapper for kernel's ftrace functionality + inject Filter to augment the events stream with additional information + kallsyms Searches running kernel for symbols + kmem Tool to trace/measure kernel memory properties + kvm Tool to trace/measure kvm guest os + list List all symbolic event types + lock Analyze lock events + mem Profile memory accesses + record Run a command and record its profile into perf.data + report Read perf.data (created by perf record) and display the profile + sched Tool to trace/measure scheduler properties (latencies) + script Read perf.data (created by perf record) and display trace output + stat Run a command and gather performance counter statistics + test Runs sanity tests. + timechart Tool to visualize total system behavior during a workload + top System profiling tool. + version display the version of perf binary + probe Define new dynamic tracepoints + + See 'perf help COMMAND' for more information on a specific command. +</pre></div> +</div> +<p>In the output above we can see all of perf's subcommands together with a +description of their functionality, the most significant of which are:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">stat</span></code> - displays statistics such as the number of context switches and page +faults;</li> +<li><code class="docutils literal"><span class="pre">top</span></code> - an interactive interface where we can inspect the most frequent +function calls and their caller. This interface allows us direct feedback +while profiling;</li> +<li><code class="docutils literal"><span class="pre">list</span></code> - lists the static trace point that we can instrument inside the +kernel. These are useful when trying to get an insight from inside the kernel;</li> +<li><code class="docutils literal"><span class="pre">probe</span></code> - add a dynamic trace point that instruments a function call in +order to be recorded by perf;</li> +<li><code class="docutils literal"><span class="pre">record</span></code> - records function calls and stack traces based on tracing points +defined by the user; It can also record specific function calls and their +stack traces. The record is saved in a file, named <code class="docutils literal"><span class="pre">perf.data</span></code> by default;</li> +<li><code class="docutils literal"><span class="pre">report</span></code> - displays the information saved in a perf recording.</li> +</ul> +<p>Another way to use perf's interface is through scripts that wrap over perf that +offer a higher level way of looking at events or data, without needing to know +the intricacies of the command. An example of this is the <code class="docutils literal"><span class="pre">iosnoop.sh</span></code> script, +which displays what I/O transfers are taking place.</p> +</div> +<div class="section" id="ps"> +<h3>ps<a class="headerlink" href="#ps" title="Permalink to this headline">¶</a></h3> +<p><code class="docutils literal"><span class="pre">ps</span></code> is the Linux tool that allows us to monitor the processes that are +running at a given time on the machine, including the kernel threads. This is a +simple and easy to use way of checking at a glance what processes are running on +the CPU, and what is their CPU and memory usage.</p> +<p>In order to list all the processes running, we use to <code class="docutils literal"><span class="pre">ps</span> <span class="pre">aux</span></code> command in the +following way:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span>TODO +root@qemux86:~/skels/kernel_profiling/0-demo# cd + root@qemux86:~# ps aux + USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND + root 1 0.0 0.5 2004 1256 ? Ss 12:06 0:12 init [5] + root 2 0.0 0.0 0 0 ? S 12:06 0:00 [kthreadd] + [...] + root 350 4.5 4.4 11132 10688 hvc0 T 12:07 17:21 ./io-app + root 1358 0.0 0.0 0 0 ? I 14:30 0:00 [kworker/u2:1-e + root 2293 0.1 1.5 5516 3704 ? Ss 18:18 0:00 sshd: root@pts/ + root 2295 0.0 1.3 3968 3232 pts/0 Ss+ 18:19 0:00 -sh + root 2307 0.0 0.0 0 0 ? I 18:19 0:00 [kworker/u2:2-e + root 2350 0.0 0.7 3032 1792 hvc0 R+ 18:26 0:00 ps aux + root 2392 2.6 0.0 0 0 ? D 18:31 0:00 test-script +</pre></div> +</div> +<p>One information of note is that the 7th column represents the that of the +process, <code class="docutils literal"><span class="pre">S</span></code> meaning suspended, <code class="docutils literal"><span class="pre">D</span></code> suspended due to I/O, and <code class="docutils literal"><span class="pre">R</span></code> meaning +running.</p> +</div> +<div class="section" id="time"> +<h3>time<a class="headerlink" href="#time" title="Permalink to this headline">¶</a></h3> +<p>The <code class="docutils literal"><span class="pre">time</span></code> command allows us to inspect the amount of time spent by a +process in I/O, running the application code, or running code in kernel space. +This can be useful in order to find out whether an application's issue comes +from running too much in kernel space, so it has some overhead when it does +system calls, or the issue is in the user code.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span>root@qemux86:~# time dd if=/dev/urandom of=./test-file bs=1K count=10 +10+0 records in +10+0 records out +10240 bytes (10 kB, 10 KiB) copied, 0.00299749 s, 3.4 MB/s + +real 0m0.020s +user 0m0.001s +sys 0m0.015s +</pre></div> +</div> +<p>In the output above we timed the generation of a file using <code class="docutils literal"><span class="pre">dd</span></code>. The result +of the timing is displayed at the bottom of output. The values outputted by the +tool are the following:</p> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">real</span></code> - the amount of time has passed from the start of the application to +its finishing;</li> +<li><code class="docutils literal"><span class="pre">user</span></code> - time spent running the <code class="docutils literal"><span class="pre">dd</span></code> code;</li> +<li><code class="docutils literal"><span class="pre">sys</span></code> - time spent running kernel code on behalf of the process.</li> +</ul> +<p>We see that the sum of the <code class="docutils literal"><span class="pre">user</span></code> and <code class="docutils literal"><span class="pre">sys</span></code> values doesn't add up to the +<code class="docutils literal"><span class="pre">real</span></code> value. This happens either when the application runs on multiple cores, +in which case the sum might be higher, or the application sleeps, in which case +the sum is lower.</p> +</div> +<div class="section" id="top"> +<h3>top<a class="headerlink" href="#top" title="Permalink to this headline">¶</a></h3> +<p><code class="docutils literal"><span class="pre">top</span></code> is an application that is found on most systems which lists in real time +the applications that are running on the system. <code class="docutils literal"><span class="pre">top</span></code> runs interactively, and +it auto-refreshes its output, as opposed to <code class="docutils literal"><span class="pre">ps</span></code>. We use this tool when we +want a high level of continuous monitoring.</p> +</div> +</div> +<div class="section" id="profiling-methodology"> +<h2>Profiling Methodology<a class="headerlink" href="#profiling-methodology" title="Permalink to this headline">¶</a></h2> +<p>When doing profiling, our goal is to identify the cause of a problem. Usually +this problem is observed by someone when their application doesn't work as +expected. When we say that an application did not work as expected, this can +mean different things for different people. For example, one person might +complain that the application has a slowdown, while another might say that the +application runs on the CPU, but it doesn't output anything.</p> +<p>The first step in any problem solving context is to understand the default +behaviour of the application we're trying to debug, and to make sure that it is +now not running in the expected parameters.</p> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is kernel_profiling. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/kernel_profiling/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">This session will require us to use the <code class="docutils literal"><span class="pre">perf</span></code> tracing tool. When running +natively on our systems, we have to install the +<code class="docutils literal"><span class="pre">linux-tools-<version>-generic</span></code> package using a package manager in order +to run it. Because in our visual machine we don't have access to a package +manager, we will be downloading the <code class="docutils literal"><span class="pre">perf</span></code> binary from <a class="reference external" href="http://swarm.cs.pub.ro/~sweisz/perf">this</a> link. Download the application in +the <code class="docutils literal"><span class="pre">skels/kernel_profiling</span></code> directory, and grant in execution +permissions.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p class="last">When running <code class="docutils literal"><span class="pre">perf</span></code>, make sure that you're running the downloaded version, +not the version in the <code class="docutils literal"><span class="pre">PATH</span></code> variable.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">When going through this session's exercises, we will have to run command in +parallel. In order to do this, we will have to connect to the virtual machine +using SSH. We recommend using the <code class="docutils literal"><span class="pre">core-image-sato-sdk-qemu</span></code> image, since it +has the tools that we need. To run the virtual machine using the +<code class="docutils literal"><span class="pre">core-image-sato-sdk-qemu</span></code> file system, uncomment line 16 in the +<code class="docutils literal"><span class="pre">qemu/Makefile</span></code> file.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">If you wish to run the <code class="docutils literal"><span class="pre">perf-tools</span></code> based scripts that we have included in +the repository, such as <code class="docutils literal"><span class="pre">iosnoop.sh</span></code>, you will have to grant it execution +privilleges, in order to be copied to the virtual machine file system.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>In order to improve the course of SO2, its components and the way it is +conducted, your opinions are very useful to us. Please fill the feedback form +on <a class="reference external" href="https://curs.upb.ro/2022/mod/feedbackadm/view.php?id=15292">curs.upb.ro platform</a>.</p> +<p>The form is anonymous and is active between May 22 and June 2, 2023. The +results will be visible to the SO2 team after all the grades have been +marked.</p> +<p>We invite you to evaluate the activity of the SO2 team and specify its +strengths and weaknesses and your suggestions for improving the subject. +Your feedback is very important to us to increase the quality of the subject +in the coming years.</p> +<p>We are particularly interested in:</p> +<blockquote class="last"> +<div><ul class="simple"> +<li>What did you not like and what do you think did not go well?</li> +<li>Why didn't you like it and why do you think it didn't go well?</li> +<li>What should we do to make things better?</li> +</ul> +</div></blockquote> +</div> +</div> +<div class="section" id="demo-profiling-i-o-problems"> +<h2>0. Demo: Profiling I/O Problems<a class="headerlink" href="#demo-profiling-i-o-problems" title="Permalink to this headline">¶</a></h2> +<p>When working with I/O, we have to keep in mind that it is one of the slowest +systems in the operating system, compared to memory, which is an order of +magnitude faster, and scheduling, which deals with what is currently running on +the CPU.</p> +<p>Because of this, I/O operations have do be thought out, because you might starve +you application by saturating the system with requests. Another issue that you +might face is that the I/O's slow speed might affect your application's +responsiveness, if it waits for the I/O operations to finish.</p> +<p>Let's take a look at an application and debug its issues.</p> +<p>We are going to run the <code class="docutils literal"><span class="pre">io-app</span></code> application, from the <code class="docutils literal"><span class="pre">0-demo</span></code> directory.</p> +<p>In order to inspect what is running on the CPU, and look at the stack of the +process, we can use the <code class="docutils literal"><span class="pre">perf</span> <span class="pre">record</span></code> subcommand in the following way:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~# ./perf record -a -g +Couldn't synthesize bpf events. +^C[ perf record: Woken up 7 times to write data ] +[ perf record: Captured and wrote 1.724 MB perf.data (8376 samples) ] +</pre></div> +</div> +<p>perf will record values indefinitely, but we can close it using the <code class="docutils literal"><span class="pre">Ctrl+c</span></code> +hotkey. We used the <code class="docutils literal"><span class="pre">-a</span></code> option in order to probe all CPUs, and <code class="docutils literal"><span class="pre">-g</span></code> option, +which record the whole call stack.</p> +<p>To visualize the recorded information, we will use the <code class="docutils literal"><span class="pre">perf</span> <span class="pre">report</span></code> command, +which will bring up a pager which will display the most frequent function calls +that were found on the CPU, and their call stack.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~# ./perf report --header -F overhead,comm,parent +<span class="c1"># Total Lost Samples: 0</span> +<span class="c1">#</span> +<span class="c1"># Samples: 8K of event 'cpu-clock:pppH'</span> +<span class="c1"># Event count (approx.): 2094000000</span> +<span class="c1">#</span> +<span class="c1"># Overhead Command Parent symbol</span> +<span class="c1"># ........ ............... .............</span> +<span class="c1">#</span> + <span class="m">58</span>.63% io-app <span class="o">[</span>other<span class="o">]</span> + <span class="p">|</span> + --58.62%--__libc_start_main + main + __kernel_vsyscall + <span class="p">|</span> + --58.61%--__irqentry_text_end + do_SYSENTER_32 + do_fast_syscall_32 + __noinstr_text_start + __ia32_sys_write + ksys_write + vfs_write + <span class="p">|</span> + --58.60%--ext4_file_write_iter + ext4_buffered_write_iter +<span class="o">[</span>...<span class="o">]</span> +</pre></div> +</div> +<p>We have used the <code class="docutils literal"><span class="pre">--header</span></code> in order to print the table header, and <code class="docutils literal"><span class="pre">-F</span> +<span class="pre">overhead,comm,parent</span></code>, in order to print the percentage of time where the call +stack, the command and the caller.</p> +<p>We can see that the <code class="docutils literal"><span class="pre">io-app</span></code> command is doing some writes in the file system, +and this contributes to much of the load on the system.</p> +<p>Armed with this information, we know that there are many I/O calls being done by +the application. In order to look at the size of these requests, we can use the +<code class="docutils literal"><span class="pre">iosnoop.sh</span></code> script in order to see how big these requests are.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~/skels/kernel_profiling# ./iosnoop.sh <span class="m">1</span> +Tracing block I/O. Ctrl-C to end. +COMM PID TYPE DEV BLOCK BYTES LATms +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">4800512</span> <span class="m">1310720</span> <span class="m">2</span>.10 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">4803072</span> <span class="m">1310720</span> <span class="m">2</span>.04 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">4805632</span> <span class="m">1310720</span> <span class="m">2</span>.03 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">4808192</span> <span class="m">1310720</span> <span class="m">2</span>.43 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">4810752</span> <span class="m">1310720</span> <span class="m">3</span>.48 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">4813312</span> <span class="m">1310720</span> <span class="m">3</span>.46 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">4815872</span> <span class="m">524288</span> <span class="m">1</span>.03 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">5029888</span> <span class="m">1310720</span> <span class="m">5</span>.82 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">5032448</span> <span class="m">786432</span> <span class="m">5</span>.80 +jbd2/vda-43 <span class="m">43</span> WS <span class="m">254</span>,0 <span class="m">2702392</span> <span class="m">8192</span> <span class="m">0</span>.22 +kworker/0:1H <span class="m">34</span> WS <span class="m">254</span>,0 <span class="m">2702408</span> <span class="m">4096</span> <span class="m">0</span>.40 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">4800512</span> <span class="m">1310720</span> <span class="m">2</span>.60 +io-app <span class="m">889</span> WS <span class="m">254</span>,0 <span class="m">4803072</span> <span class="m">1310720</span> <span class="m">2</span>.58 +<span class="o">[</span>...<span class="o">]</span> +</pre></div> +</div> +<p>From this output we see that the <code class="docutils literal"><span class="pre">io-app</span></code> is reading in a loop from the fact +that the first block <code class="docutils literal"><span class="pre">4800512</span></code> is repeating, and that it is doing big reads, +since it is reading one megabyte fer request. This constant looping adds the +load to the system that we're experiencing.</p> +<div class="section" id="investigating-reduced-responsiveness"> +<h3>1. Investigating Reduced Responsiveness<a class="headerlink" href="#investigating-reduced-responsiveness" title="Permalink to this headline">¶</a></h3> +<p>The <code class="docutils literal"><span class="pre">io.ko</span></code> module, located in the <code class="docutils literal"><span class="pre">kernel_profiling/1-io</span></code> directory, +decreases the system's responsiveness when inserted. We see that the command +line stutters when typing commands, but when running top, we see that the +system's load is not high, and there aren't any processes that are hogging +resources.</p> +<p>Find out what the <code class="docutils literal"><span class="pre">io.ko</span></code> module is doing and why is it leading to the +stuttering effect that we experience.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Trace all the functions being called and check where the CPU is +spending most of its time. In order to do this, you can run either <code class="docutils literal"><span class="pre">perf</span> +<span class="pre">record</span></code> and <code class="docutils literal"><span class="pre">perf</span> <span class="pre">report</span></code> to view the output, or <code class="docutils literal"><span class="pre">perf</span> <span class="pre">top</span></code>.</p> +</div> +</div> +<div class="section" id="launching-new-threads"> +<h3>2. Launching New Threads<a class="headerlink" href="#launching-new-threads" title="Permalink to this headline">¶</a></h3> +<p>We want to run the same function in a loop 100 times in parallel. We have +implemented two solutions inside the <code class="docutils literal"><span class="pre">scheduling</span></code> binary file, located in the +<code class="docutils literal"><span class="pre">kernel_profiling/2-scheduling</span></code> directory.</p> +<p>When executing the <code class="docutils literal"><span class="pre">scheduling</span></code> binary, it prints a message in parallel from +100 running instances. We can tune this execution by running the application +either with the first parameter <code class="docutils literal"><span class="pre">0</span></code> or <code class="docutils literal"><span class="pre">1</span></code>.</p> +<p>Find out which solution is better, and why.</p> +</div> +<div class="section" id="tuning-cp"> +<h3>3. Tuning <code class="docutils literal"><span class="pre">cp</span></code><a class="headerlink" href="#tuning-cp" title="Permalink to this headline">¶</a></h3> +<p>Our goal is to write a copy of the <code class="docutils literal"><span class="pre">cp</span></code> tool integrated in Linux, which has +been implemented by the <code class="docutils literal"><span class="pre">memory</span></code> binary, in the <code class="docutils literal"><span class="pre">kernel_profiling/3-memory</span></code> +directory. It implements two approaches that we can take for the copy operation:</p> +<ul class="simple"> +<li>reading the contents of the source file in a buffer in memory using the +<code class="docutils literal"><span class="pre">read()</span></code> system call, and writing that buffer to the destination file using +the <code class="docutils literal"><span class="pre">write()</span></code> system call;</li> +<li>mapping the source and destination files to memory using the <code class="docutils literal"><span class="pre">mmap</span></code> system +call, and copying the contents of the source file to the destination in +memory.</li> +</ul> +<p>Another tunable parameter that we're going to use is the block size of to copies +that we're going to make, either through reads/writes or in memory.</p> +<p>1) Investigate which of the two copying mechanisms is faster. For this step, you +will use the 1024 block size.</p> +<p>2) Once you have found which copying mechanism is faster, change the block size +parameter and see which value gives you the best copies. Why?</p> +</div> +<div class="section" id="i-o-latency"> +<h3>4. I/O Latency<a class="headerlink" href="#i-o-latency" title="Permalink to this headline">¶</a></h3> +<p>We have written a module that reads the content of a disk. Insert the <code class="docutils literal"><span class="pre">bio.ko</span></code> +module, located in the <code class="docutils literal"><span class="pre">4-bio</span></code> module, we see a large spike in the system's +load, as can be seen in the <code class="docutils literal"><span class="pre">top</span></code> command, but we see that the system is still +responsive.</p> +<p>Investigate what is causing the increased load to the system. Is it an I/O issue, +or is it a scheduling issue?</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Try to trace the I/O operations using <code class="docutils literal"><span class="pre">perf</span></code>, or use the +<code class="docutils literal"><span class="pre">iosnoop.sh</span></code> script in order to inspect what I/O is happening at a +certain point.</p> +</div> +</div> +<div class="section" id="bad-elf"> +<h3>5. Bad ELF<a class="headerlink" href="#bad-elf" title="Permalink to this headline">¶</a></h3> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">This is a bonus exercise that has been tested on a native Linux system. +It may run under the QEMU virtual machine, but the behavior was weird in our testing. +We recommend you used a native (or VirtualBox or VMware) Linux system.</p> +</div> +<p>We managed to build (as part of a <a class="reference external" href="https://github.com/unikraft/unikraft">Unikraft</a> build) an ELF file that is valid when doing static analysis, but that can't be executed. +The file is <code class="docutils literal"><span class="pre">bad_elf</span></code>, located in the <code class="docutils literal"><span class="pre">5-bad-elf/</span></code> folder.</p> +<p>Running it triggers a <em>segmentation fault</em> message. +Running it using <code class="docutils literal"><span class="pre">strace</span></code> show an error with <code class="docutils literal"><span class="pre">execve()</span></code>.</p> +<div class="code highlight-none"><div class="highlight"><pre><span></span>... skels/kernel_profiling/5-bad-elf$ ./bad_elf +Segmentation fault + +... skels/kernel_profiling/5-bad-elf$ strace ./bad_elf +execve("./bad_elf", ["./bad_elf"], 0x7ffc3349ba50 /* 70 vars \*/) = -1 EINVAL (Invalid argument) +--- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=NULL} --- ++++ killed by SIGSEGV +++ +Segmentation fault (core dumped) +</pre></div> +</div> +<p>The ELF file itself is valid:</p> +<div class="code highlight-none"><div class="highlight"><pre><span></span>... skels/kernel_profiling/5-bad-elf$ readelf -a bad_elf +</pre></div> +</div> +<p>The issue is to be detected in the kernel.</p> +<p>Use either <code class="docutils literal"><span class="pre">perf</span></code>, or, better yet <a class="reference external" href="https://jvns.ca/blog/2017/03/19/getting-started-with-ftrace/">ftrace</a> to inspect the kernel function calls done by the program. +Identify the function call that sends out the <code class="docutils literal"><span class="pre">SIGSEGV</span></code> signal. +Identify the cause of the issue. +Find that cause in the <a class="reference external" href="https://linux.die.net/man/5/elf">manual page elf(5)</a>.</p> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lab11-arm-kernel-development.html" class="btn btn-neutral float-left" title="SO2 Lab 11 - Kernel Development on ARM" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="assign-collaboration.html" class="btn btn-neutral float-right" title="Collaboration" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lab2-kernel-api.html b/refs/pull/405/merge/so2/lab2-kernel-api.html new file mode 100644 index 00000000..7a5f2dcf --- /dev/null +++ b/refs/pull/405/merge/so2/lab2-kernel-api.html @@ -0,0 +1,1125 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lab 02 - Kernel API — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lab 03 - Character device drivers" href="lab3-device-drivers.html" /> + <link rel="prev" title="SO2 Lab 01 - Introduction" href="lab1-intro.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lab 02 - Kernel API</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#overview">Overview</a></li> +<li class="toctree-l3"><a class="reference internal" href="#accessing-memory">Accessing memory</a></li> +<li class="toctree-l3"><a class="reference internal" href="#contexts-of-execution">Contexts of execution</a></li> +<li class="toctree-l3"><a class="reference internal" href="#locking">Locking</a></li> +<li class="toctree-l3"><a class="reference internal" href="#preemptivity">Preemptivity</a></li> +<li class="toctree-l3"><a class="reference internal" href="#linux-kernel-api">Linux Kernel API</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#convention-indicating-errors">Convention indicating errors</a></li> +<li class="toctree-l4"><a class="reference internal" href="#strings-of-characters">Strings of characters</a></li> +<li class="toctree-l4"><a class="reference internal" href="#printk">printk</a></li> +<li class="toctree-l4"><a class="reference internal" href="#memory-allocation">Memory allocation</a></li> +<li class="toctree-l4"><a class="reference internal" href="#lists">lists</a></li> +<li class="toctree-l4"><a class="reference internal" href="#spinlock">Spinlock</a></li> +<li class="toctree-l4"><a class="reference internal" href="#mutex">mutex</a></li> +<li class="toctree-l4"><a class="reference internal" href="#atomic-variables-1">Atomic variables</a></li> +<li class="toctree-l4"><a class="reference internal" href="#atomic-bitwise-operations">Atomic bitwise operations</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#intro">0. Intro</a></li> +<li class="toctree-l4"><a class="reference internal" href="#memory-allocation-in-linux-kernel">1. Memory allocation in Linux kernel</a></li> +<li class="toctree-l4"><a class="reference internal" href="#sleeping-in-atomic-context">2. Sleeping in atomic context</a></li> +<li class="toctree-l4"><a class="reference internal" href="#working-with-kernel-memory">3. Working with kernel memory</a></li> +<li class="toctree-l4"><a class="reference internal" href="#working-with-kernel-lists">4. Working with kernel lists</a></li> +<li class="toctree-l4"><a class="reference internal" href="#working-with-kernel-lists-for-process-handling">5. Working with kernel lists for process handling</a></li> +<li class="toctree-l4"><a class="reference internal" href="#synchronizing-list-work">6. Synchronizing list work</a></li> +<li class="toctree-l4"><a class="reference internal" href="#test-module-calling-in-our-list-module">7. Test module calling in our list module</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lab 02 - Kernel API</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lab2-kernel-api.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lab-02-kernel-api"> +<h1>SO2 Lab 02 - Kernel API<a class="headerlink" href="#so2-lab-02-kernel-api" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<blockquote> +<div><ul class="simple"> +<li>Familiarize yourself with the basic Linux kernel API</li> +<li>Description of memory allocation mechanisms</li> +<li>Description of locking mechanisms</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="overview"> +<h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline">¶</a></h2> +<p>Inside the current lab we present a set of concepts and basic functions required +for starting Linux kernel programming. It is important to note that kernel +programming differs greatly from user space programming. The kernel is a +stand-alone entity that can not use libraries in user-space (not even libc). +As a result, the usual user-space functions (printf, malloc, free, open, read, +write, memcpy, strcpy, etc.) can no longer be used. In conclusion, kernel +programming is based on a totally new and independent API that is unrelated to +the user-space API, whether we refer to POSIX or ANSI C (standard C language +library functions).</p> +</div> +<div class="section" id="accessing-memory"> +<h2>Accessing memory<a class="headerlink" href="#accessing-memory" title="Permalink to this headline">¶</a></h2> +<p>An important difference in kernel programming is how to access and allocate +memory. Due to the fact that kernel programming is very close to the physical +machine, there are important rules for memory management. First, it works with +several types of memory:</p> +<blockquote> +<div><ul class="simple"> +<li>Physical memory</li> +<li>Virtual memory from the kernel address space</li> +<li>Virtual memory from a process's address space</li> +<li>Resident memory - we know for sure that the accessed pages are present in +physical memory</li> +</ul> +</div></blockquote> +<p>Virtual memory in a process's address space can not be considered resident due +to the virtual memory mechanisms implemented by the operating system: pages may +be swapped or simply may not be present in physical memory as a result of the +demand paging mechanism. The memory in the kernel address space can be resident +or not. Both the data and code segments of a module and the kernel stack of a +process are resident. Dynamic memory may or may not be resident, depending on +how it is allocated.</p> +<p>When working with resident memory, things are simple: memory can be accessed at +any time. But if working with non-resident memory, then it can only be accessed +from certain contexts. Non-resident memory can only be accessed from the +process context. Accessing non-resident memory from the context of an +interrupt has unpredictable results and, therefore, when the operating +system detects such access, it will take drastic measures: blocking or +resetting the system to prevent serious corruption.</p> +<p>The virtual memory of a process can not be accessed directly from the kernel. +In general, it is totally discouraged to access the address space of a process, +but there are situations where a device driver needs to do it. The typical case +is where the device driver needs to access a buffer from the user-space. In +this case, the device driver must use special features and not directly access +the buffer. This is necessary to prevent access to invalid memory areas.</p> +<p>Another difference from the user-space scheduling, relative to memory, is due to +the stack, a stack whose size is fixed and limited. A stack of 4K is used in +Linux, and a stack of 12K is used in Windows. For this reason, the +allocation of large structures on stack or the use of recursive calls should +be avoided.</p> +</div> +<div class="section" id="contexts-of-execution"> +<h2>Contexts of execution<a class="headerlink" href="#contexts-of-execution" title="Permalink to this headline">¶</a></h2> +<p>In relation to kernel execution, we distinguish two contexts: process context +and interrupt context. We are in the process context when we run code as a +result of a system call or when we run in the context of a kernel thread. When +we run in a routine to handle an interrupt or a deferrable action, we run in +an interrupt context.</p> +<p>Some of the kernel API calls can block the current process. Common examples are +using a semaphore or waiting for a condition. In this case, the process is +put into the <code class="docutils literal"><span class="pre">WAITING</span></code> state and another process is running. An interesting +situation occurs when a function that can lead to the current process to be +suspended, is called from an interrupt context. In this case, there is no +current process, and therefore the results are unpredictable. Whenever the +operating system detects this condition will generate an error condition that +will cause the operating system to shut down.</p> +</div> +<div class="section" id="locking"> +<h2>Locking<a class="headerlink" href="#locking" title="Permalink to this headline">¶</a></h2> +<p>One of the most important features of kernel programming is parallelism. Linux +supports SMP systems with multiple processors and kernel preemptivity. This +makes kernel programming more difficult because access to global variables must +be synchronized with either spinlock primitives or blocking primitives. Although +it is recommended to use blocking primitives, they can not be used in an +interrupt context, so the only locking solution in the context of an interrupt +is spinlocks.</p> +<p>Spinlocks are used in order to achieve mutual exclusion. When it can not get +access to the critical region, it does not suspend the current process, but it +uses the busy-waiting mechanism (waiting in a <code class="xref c c-func docutils literal"><span class="pre">while()</span></code> loop for the lock +to be released). +The code that runs in the critical region protected by a spinlock is not allowed +to suspend the current process (it must adhere to the execution conditions in +the interrupt context). Moreover, the CPU will not be released except for +the case of an interrupt. Due to the mechanism used, it is important that a +spinlock is being held as little time as possible.</p> +</div> +<div class="section" id="preemptivity"> +<h2>Preemptivity<a class="headerlink" href="#preemptivity" title="Permalink to this headline">¶</a></h2> +<p>Linux uses preemptive kernels. The notion of preemptive multitasking should not +be confused with the notion of a preemptive kernel. The notion of preemptive +multitasking refers to the fact that the operating system forcefully interrupts +a process running in user space when its quantum (time slice) expires, in order +to run another process. +A kernel is preemptive if a process running in kernel mode (as a result of a +system call) can be interrupted so that another process is being run.</p> +<p>Because of preemptivity, when we share resources between two portions of code +that can run from different process contexts, we need to protect ourselves with +synchronization primitives, even in the case of a single processor.</p> +</div> +<div class="section" id="linux-kernel-api"> +<h2>Linux Kernel API<a class="headerlink" href="#linux-kernel-api" title="Permalink to this headline">¶</a></h2> +<div class="section" id="convention-indicating-errors"> +<h3>Convention indicating errors<a class="headerlink" href="#convention-indicating-errors" title="Permalink to this headline">¶</a></h3> +<p>For Linux kernel programming, the convention used for calling functions to +indicate success is the same as in UNIX programming: 0 for success, or a value +other than 0 for failure. +For failures, negative values are returned as shown in the example below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="p">(</span><span class="n">alloc_memory</span><span class="p">()</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">return</span> <span class="o">-</span><span class="n">ENOMEM</span><span class="p">;</span> + +<span class="k">if</span> <span class="p">(</span><span class="n">user_parameter_valid</span><span class="p">()</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EINVAL</span><span class="p">;</span> +</pre></div> +</div> +<p>The exhaustive list of errors and a summary explanation can be found in +<code class="file docutils literal"><span class="pre">include/uapi/asm-generic/errno-base.h</span></code> and in +<code class="file docutils literal"><span class="pre">include/uapi/asm-generic/ernno.h</span></code>.</p> +</div> +<div class="section" id="strings-of-characters"> +<h3>Strings of characters<a class="headerlink" href="#strings-of-characters" title="Permalink to this headline">¶</a></h3> +<p>In Linux, the kernel programmer is provided with the usual routine functions: +<code class="xref c c-func docutils literal"><span class="pre">strcpy()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strncpy()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strlcpy()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strcat()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">strncat()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strlcat()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strcmp()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strncmp()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">strnicmp()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strchr()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strnchr()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strrchr()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">strstr()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">strlen()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">memset()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">memmove()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">memcmp()</span></code>, etc. These functions are declared in the +<code class="file docutils literal"><span class="pre">include/linux/string.h</span></code> header and are implemented in the kernel in the +<code class="file docutils literal"><span class="pre">lib/string.c</span></code> file.</p> +</div> +<div class="section" id="printk"> +<h3>printk<a class="headerlink" href="#printk" title="Permalink to this headline">¶</a></h3> +<p>The printf equivalent in the kernel is printk, defined in +<code class="file docutils literal"><span class="pre">include/linux/printk.h</span></code>. The <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code> syntax is very similar +to <code class="xref c c-func docutils literal"><span class="pre">printf()</span></code>. The first +parameter of <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code> decides the log category in which the current log +falls into:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define KERN_EMERG "<0>" </span><span class="cm">/* system is unusable */</span><span class="cp"></span> +<span class="cp">#define KERN_ALERT "<1>" </span><span class="cm">/* action must be taken immediately */</span><span class="cp"></span> +<span class="cp">#define KERN_CRIT "<2>" </span><span class="cm">/* critical conditions */</span><span class="cp"></span> +<span class="cp">#define KERN_ERR "<3>" </span><span class="cm">/* error conditions */</span><span class="cp"></span> +<span class="cp">#define KERN_WARNING "<4>" </span><span class="cm">/* warning conditions */</span><span class="cp"></span> +<span class="cp">#define KERN_NOTICE "<5>" </span><span class="cm">/* normal but significant condition */</span><span class="cp"></span> +<span class="cp">#define KERN_INFO "<6>" </span><span class="cm">/* informational */</span><span class="cp"></span> +<span class="cp">#define KERN_DEBUG "<7>" </span><span class="cm">/* debug-level messages */</span><span class="cp"></span> +</pre></div> +</div> +<p>Thus, a warning message in the kernel would be sent with:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">printk</span><span class="p">(</span><span class="n">KERN_WARNING</span> <span class="s">"my_module input string %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">buff</span><span class="p">);</span> +</pre></div> +</div> +<p>If the logging level is missing from the <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code> call, logging is done +with the default level at the time of the call. One thing to keep in mind is +that messages sent with <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code> are only visible on the console if and +only if their level exceeds the default level set on the console.</p> +<p>To reduce the size of lines when using <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code>, it is recommended to +use the following help functions instead of directly using the <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code> +call:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">pr_emerg</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span> <span class="p">...);</span> <span class="cm">/* similar to printk(KERN_EMERG pr_fmt(fmt), ...); */</span> +<span class="n">pr_alert</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span> <span class="p">...);</span> <span class="cm">/* similar to printk(KERN_ALERT pr_fmt(fmt), ...); */</span> +<span class="n">pr_crit</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span> <span class="p">...);</span> <span class="cm">/* similar to printk(KERN_CRIT pr_fmt(fmt), ...); */</span> +<span class="n">pr_err</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span> <span class="p">...);</span> <span class="cm">/* similar to printk(KERN_ERR pr_fmt(fmt), ...); */</span> +<span class="n">pr_warn</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span> <span class="p">...);</span> <span class="cm">/* similar to printk(KERN_WARNING pr_fmt(fmt), ...); */</span> +<span class="n">pr_notice</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span> <span class="p">...);</span> <span class="cm">/* similar to printk(KERN_NOTICE pr_fmt(fmt), ...); */</span> +<span class="n">pr_info</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span> <span class="p">...);</span> <span class="cm">/* similar to printk(KERN_INFO pr_fmt(fmt), ...); */</span> +<span class="n">pr_debug</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span> <span class="p">...);</span> <span class="cm">/* similar to printk(KERN_DEBUG pr_fmt(fmt), ...); */</span> +</pre></div> +</div> +<p>A special case is <code class="xref c c-func docutils literal"><span class="pre">pr_debug()</span></code> that calls the <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code> function +only when the <code class="xref c c-macro docutils literal"><span class="pre">DEBUG</span></code> macro is defined or if dynamic debugging is used.</p> +</div> +<div class="section" id="memory-allocation"> +<h3>Memory allocation<a class="headerlink" href="#memory-allocation" title="Permalink to this headline">¶</a></h3> +<p>In Linux only resident memory can be allocated, using <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> call. +A typical <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> call is presented below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/slab.h></span><span class="cp"></span> + +<span class="n">string</span> <span class="o">=</span> <span class="n">kmalloc</span> <span class="p">(</span><span class="n">string_len</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">string</span><span class="p">)</span> <span class="p">{</span> + <span class="c1">//report error: -ENOMEM;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>As you can see, the first parameter indicates the size in bytes of the allocated +area. The function returns a pointer to a memory area that can be directly used +in the kernel, or <code class="xref c c-macro docutils literal"><span class="pre">NULL</span></code> if memory could not be allocated. The second +parameter specifies how allocation should be done and the most commonly used +values for this are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-data docutils literal"><span class="pre">GFP_KERNEL</span></code> - using this value may cause the current process to +be suspended. Thus, it can not be used in the interrupt context.</li> +<li><code class="xref c c-data docutils literal"><span class="pre">GFP_ATOMIC</span></code> - using this value it ensures that the +<code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> function does not suspend the current process. It can be +used anytime.</li> +</ul> +</div></blockquote> +<p>The counterpart to the <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> function is <code class="xref c c-func docutils literal"><span class="pre">kfree()</span></code>, a function +that receives as argument an area allocated by <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code>. This function +does not suspend the current process and can therefore be called from any +context.</p> +</div> +<div class="section" id="lists"> +<h3>lists<a class="headerlink" href="#lists" title="Permalink to this headline">¶</a></h3> +<p>Because linked lists are often used, the Linux kernel API provides a unified +way of defining and using lists. This involves using a +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">list_head</span></code> element in the structure we want to consider as a +list node. The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">list_head</span></code> is defined in +<code class="file docutils literal"><span class="pre">include/linux/list.h</span></code> along with all the other functions that manipulate +the lists. The following code shows the definition of +the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">list_head</span></code> and the use of an element of this type in another +well-known structure in the Linux kernel:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">list_head</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="o">*</span><span class="n">next</span><span class="p">,</span> <span class="o">*</span><span class="n">prev</span><span class="p">;</span> +<span class="p">};</span> + +<span class="k">struct</span> <span class="n">task_struct</span> <span class="p">{</span> + <span class="p">...</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="n">children</span><span class="p">;</span> + <span class="p">...</span> +<span class="p">};</span> +</pre></div> +</div> +<p>The usual routines for working with lists are the following:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-macro docutils literal"><span class="pre">LIST_HEAD(name)</span></code> is used to declare the sentinel of a list</li> +<li><code class="xref c c-func docutils literal"><span class="pre">INIT_LIST_HEAD(struct</span> <span class="pre">list_head</span> <span class="pre">*list)()</span></code> is used to initialize the +sentinel of a list when dynamic allocation is made, by setting the value of +the <code class="xref c c-data docutils literal"><span class="pre">next</span></code> and <code class="xref c c-data docutils literal"><span class="pre">prev</span></code> to list fields.</li> +<li><code class="xref c c-func docutils literal"><span class="pre">list_add(struct</span> <span class="pre">list_head</span> <span class="pre">*new,</span> <span class="pre">struct</span> <span class="pre">list_head</span> <span class="pre">*head)()</span></code> adds the +<code class="xref c c-data docutils literal"><span class="pre">new</span></code> element after the <code class="xref c c-data docutils literal"><span class="pre">head</span></code> element.</li> +<li><code class="xref c c-func docutils literal"><span class="pre">list_del(struct</span> <span class="pre">list_head</span> <span class="pre">*entry)()</span></code> deletes the item at the +<code class="xref c c-data docutils literal"><span class="pre">entry</span></code> address of the list it belongs to.</li> +<li><code class="xref c c-macro docutils literal"><span class="pre">list_entry(ptr,</span> <span class="pre">type,</span> <span class="pre">member)</span></code> returns the structure with the +type <code class="xref c c-type docutils literal"><span class="pre">type</span></code> that contains the element <code class="xref c c-data docutils literal"><span class="pre">ptr</span></code> from the list, +having the name <code class="xref c c-member docutils literal"><span class="pre">member</span></code> within the structure.</li> +<li><code class="xref c c-macro docutils literal"><span class="pre">list_for_each(pos,</span> <span class="pre">head)</span></code> iterates over a list using +<code class="xref c c-data docutils literal"><span class="pre">pos</span></code> as a cursor.</li> +<li><code class="xref c c-macro docutils literal"><span class="pre">list_for_each_safe(pos,</span> <span class="pre">n,</span> <span class="pre">head)</span></code> iterates over a list using +<code class="xref c c-data docutils literal"><span class="pre">pos</span></code> as a cursor and <code class="xref c c-data docutils literal"><span class="pre">n</span></code> as a temporary cursor. +This macro is used to delete an item from the list.</li> +</ul> +</div></blockquote> +<p>The following code shows how to use these routines:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/slab.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/list.h></span><span class="cp"></span> + +<span class="k">struct</span> <span class="n">pid_list</span> <span class="p">{</span> + <span class="kt">pid_t</span> <span class="n">pid</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="n">list</span><span class="p">;</span> +<span class="p">};</span> + +<span class="n">LIST_HEAD</span><span class="p">(</span><span class="n">my_list</span><span class="p">);</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">add_pid</span><span class="p">(</span><span class="kt">pid_t</span> <span class="n">pid</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">pid_list</span> <span class="o">*</span><span class="n">ple</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="k">sizeof</span> <span class="o">*</span><span class="n">ple</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">ple</span><span class="p">)</span> + <span class="k">return</span> <span class="o">-</span><span class="n">ENOMEM</span><span class="p">;</span> + + <span class="n">ple</span><span class="o">-></span><span class="n">pid</span> <span class="o">=</span> <span class="n">pid</span><span class="p">;</span> + <span class="n">list_add</span><span class="p">(</span><span class="o">&</span><span class="n">ple</span><span class="o">-></span><span class="n">list</span><span class="p">,</span> <span class="o">&</span><span class="n">my_list</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">del_pid</span><span class="p">(</span><span class="kt">pid_t</span> <span class="n">pid</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="o">*</span><span class="n">i</span><span class="p">,</span> <span class="o">*</span><span class="n">tmp</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">pid_list</span> <span class="o">*</span><span class="n">ple</span><span class="p">;</span> + + <span class="n">list_for_each_safe</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">tmp</span><span class="p">,</span> <span class="o">&</span><span class="n">my_list</span><span class="p">)</span> <span class="p">{</span> + <span class="n">ple</span> <span class="o">=</span> <span class="n">list_entry</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="k">struct</span> <span class="n">pid_list</span><span class="p">,</span> <span class="n">list</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">ple</span><span class="o">-></span><span class="n">pid</span> <span class="o">==</span> <span class="n">pid</span><span class="p">)</span> <span class="p">{</span> + <span class="n">list_del</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> + <span class="n">kfree</span><span class="p">(</span><span class="n">ple</span><span class="p">);</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> + <span class="p">}</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="o">-</span><span class="n">EINVAL</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">destroy_list</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="o">*</span><span class="n">i</span><span class="p">,</span> <span class="o">*</span><span class="n">n</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">pid_list</span> <span class="o">*</span><span class="n">ple</span><span class="p">;</span> + + <span class="n">list_for_each_safe</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="o">&</span><span class="n">my_list</span><span class="p">)</span> <span class="p">{</span> + <span class="n">ple</span> <span class="o">=</span> <span class="n">list_entry</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="k">struct</span> <span class="n">pid_list</span><span class="p">,</span> <span class="n">list</span><span class="p">);</span> + <span class="n">list_del</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> + <span class="n">kfree</span><span class="p">(</span><span class="n">ple</span><span class="p">);</span> + <span class="p">}</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The evolution of the list can be seen in the following figure:</p> +<a class="reference internal image-reference" href="../_images/list_evolution1.png"><img alt="../_images/list_evolution1.png" src="../_images/list_evolution1.png" style="width: 85%;" /></a> +<p>You see the stack type behavior introduced by the <code class="xref c c-macro docutils literal"><span class="pre">list_add</span></code> macro, +and the use of a sentinel.</p> +<p>From the above example, it can be noticed that the way to define and use a list +(double-linked) is generic and, at the same time, it does not introduce an +additional overhead. The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">list_head</span></code> is used to maintain the +links between the list elements. It can be noticed that iterating over the list +is also done with this structure, and that retrieving a list element can be done +using <code class="xref c c-macro docutils literal"><span class="pre">list_entry</span></code>. This idea of implementing and using a list is not +new, as it has already been described in The Art of Computer Programming by +Donald Knuth in the 1980s.</p> +<p>Several kernel list functions and macro definitions are presented and explained +in the <code class="file docutils literal"><span class="pre">include/linux/list.h</span></code> header.</p> +</div> +<div class="section" id="spinlock"> +<h3>Spinlock<a class="headerlink" href="#spinlock" title="Permalink to this headline">¶</a></h3> +<p><code class="xref c c-type docutils literal"><span class="pre">spinlock_t</span></code> (defined in <code class="file docutils literal"><span class="pre">linux/spinlock.h</span></code>) is the basic type +that implements the spinlock concept in Linux. It describes a spinlock, and the +operations associated with a spinlock are <code class="xref c c-func docutils literal"><span class="pre">spin_lock_init()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">spin_lock()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">spin_unlock()</span></code>. An example of use is given below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/spinlock.h></span><span class="cp"></span> + +<span class="n">DEFINE_SPINLOCK</span><span class="p">(</span><span class="n">lock1</span><span class="p">);</span> +<span class="n">spinlock_t</span> <span class="n">lock2</span><span class="p">;</span> + +<span class="n">spin_lock_init</span><span class="p">(</span><span class="o">&</span><span class="n">lock2</span><span class="p">);</span> + +<span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock1</span><span class="p">);</span> +<span class="cm">/* critical region */</span> +<span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock1</span><span class="p">);</span> + +<span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock2</span><span class="p">);</span> +<span class="cm">/* critical region */</span> +<span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock2</span><span class="p">);</span> +</pre></div> +</div> +<p>In Linux, you can use reader-writer spinlocks, useful for readers-writers +problems. +These types of locks are identified by <code class="xref c c-type docutils literal"><span class="pre">rwlock_t</span></code>, and the functions +that can work on a reader-writer spinlock are +<code class="xref c c-func docutils literal"><span class="pre">rwlock_init()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">read_lock()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">write_lock()</span></code>. +An example of use:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/spinlock.h></span><span class="cp"></span> + +<span class="n">DEFINE_RWLOCK</span><span class="p">(</span><span class="n">lock</span><span class="p">);</span> + +<span class="k">struct</span> <span class="n">pid_list</span> <span class="p">{</span> + <span class="kt">pid_t</span> <span class="n">pid</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="n">list</span><span class="p">;</span> +<span class="p">};</span> + +<span class="kt">int</span> <span class="nf">have_pid</span><span class="p">(</span><span class="k">struct</span> <span class="n">list_head</span> <span class="o">*</span><span class="n">lh</span><span class="p">,</span> <span class="kt">int</span> <span class="n">pid</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="o">*</span><span class="n">i</span><span class="p">;</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">elem</span><span class="p">;</span> + + <span class="n">read_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> + <span class="n">list_for_each</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lh</span><span class="p">)</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">pid_list</span> <span class="o">*</span><span class="n">pl</span> <span class="o">=</span> <span class="n">list_entry</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="k">struct</span> <span class="n">pid_list</span><span class="p">,</span> <span class="n">list</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">pl</span><span class="o">-></span><span class="n">pid</span> <span class="o">==</span> <span class="n">pid</span><span class="p">)</span> <span class="p">{</span> + <span class="n">read_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> + <span class="k">return</span> <span class="mi">1</span><span class="p">;</span> + <span class="p">}</span> + <span class="p">}</span> + <span class="n">read_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">void</span> <span class="nf">add_pid</span><span class="p">(</span><span class="k">struct</span> <span class="n">list_head</span> <span class="o">*</span><span class="n">lh</span><span class="p">,</span> <span class="k">struct</span> <span class="n">pid_list</span> <span class="o">*</span><span class="n">pl</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">write_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> + <span class="n">list_add</span><span class="p">(</span><span class="o">&</span><span class="n">pl</span><span class="o">-></span><span class="n">list</span><span class="p">,</span> <span class="n">lh</span><span class="p">);</span> + <span class="n">write_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="mutex"> +<h3>mutex<a class="headerlink" href="#mutex" title="Permalink to this headline">¶</a></h3> +<p>A mutex is a variable of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mutex</span></code> type (defined in +<code class="file docutils literal"><span class="pre">linux/mutex.h</span></code>). +Functions and macros for working with mutexes are listed below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/mutex.h></span><span class="cp"></span> + +<span class="cm">/* functions for mutex initialization */</span> +<span class="kt">void</span> <span class="nf">mutex_init</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">mutex</span><span class="p">);</span> +<span class="n">DEFINE_MUTEX</span><span class="p">(</span><span class="n">name</span><span class="p">);</span> + +<span class="cm">/* functions for mutex acquire */</span> +<span class="kt">void</span> <span class="nf">mutex_lock</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">mutex</span><span class="p">);</span> + +<span class="cm">/* functions for mutex release */</span> +<span class="kt">void</span> <span class="nf">mutex_unlock</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">mutex</span><span class="p">);</span> +</pre></div> +</div> +<p>Operations are similar to classic mutex operations in user-space or spinlock +operations: the mutex is acquired before entering the critical region and it is +released after exiting the critical region. Unlike spinlocks, these operations +can only be used in process context.</p> +</div> +<div class="section" id="atomic-variables-1"> +<span id="atomic-variables"></span><h3>Atomic variables<a class="headerlink" href="#atomic-variables-1" title="Permalink to this headline">¶</a></h3> +<p>Often, you only need to synchronize access to a simple variable, such as a +counter. For this, an <code class="xref c c-type docutils literal"><span class="pre">atomic_t</span></code> type can be used (defined in +<code class="file docutils literal"><span class="pre">include/linux/atomic.h</span></code>), that holds an integer value. Below are some +operations that can be performed on an <code class="xref c c-type docutils literal"><span class="pre">atomic_t</span></code> variable.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><asm/atomic.h></span><span class="cp"></span> + +<span class="kt">void</span> <span class="nf">atomic_set</span><span class="p">(</span><span class="n">atomic_t</span> <span class="o">*</span><span class="n">v</span><span class="p">,</span> <span class="kt">int</span> <span class="n">i</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">atomic_read</span><span class="p">(</span><span class="n">atomic_t</span> <span class="o">*</span><span class="n">v</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">atomic_add</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="n">atomic_t</span> <span class="o">*</span><span class="n">v</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">atomic_sub</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="n">atomic_t</span> <span class="o">*</span><span class="n">v</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">atomic_inc</span><span class="p">(</span><span class="n">atomic_t</span> <span class="o">*</span><span class="n">v</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">atomic_dec</span><span class="p">(</span><span class="n">atomic_t</span> <span class="o">*</span><span class="n">v</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">atomic_inc_and_test</span><span class="p">(</span><span class="n">atomic_t</span> <span class="o">*</span><span class="n">v</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">atomic_dec_and_test</span><span class="p">(</span><span class="n">atomic_t</span> <span class="o">*</span><span class="n">v</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">atomic_cmpxchg</span><span class="p">(</span><span class="n">atomic_t</span> <span class="o">*</span><span class="n">v</span><span class="p">,</span> <span class="kt">int</span> <span class="n">old</span><span class="p">,</span> <span class="kt">int</span> <span class="n">new</span><span class="p">);</span> +</pre></div> +</div> +<div class="section" id="use-of-atomic-variables"> +<h4>Use of atomic variables<a class="headerlink" href="#use-of-atomic-variables" title="Permalink to this headline">¶</a></h4> +<p>A common way of using atomic variables is to store the status of an action +(e.g. a flag). So we can use an atomic variable to mark exclusive actions. For +example, we consider that an atomic variable can have the LOCKED and UNLOCKED +values, and if the respective variable equals LOCKED then a specific function +should return -EBUSY. +Such an usage is shown schematically in the code below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define LOCKED 0</span> +<span class="cp">#define UNLOCKED 1</span> + +<span class="k">static</span> <span class="n">atomic_t</span> <span class="n">flag</span><span class="p">;</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_acquire</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">initial_flag</span><span class="p">;</span> + + <span class="cm">/*</span> +<span class="cm"> * Check if flag is UNLOCKED; if so, lock it and do it atomically.</span> +<span class="cm"> *</span> +<span class="cm"> * This is the atomic equivalent of</span> +<span class="cm"> * if (flag == UNLOCKED)</span> +<span class="cm"> * flag = LOCKED;</span> +<span class="cm"> * else</span> +<span class="cm"> * return -EBUSY;</span> +<span class="cm"> */</span> + <span class="n">initial_flag</span> <span class="o">=</span> <span class="n">atomic_cmpxchg</span><span class="p">(</span><span class="o">&</span><span class="n">flag</span><span class="p">,</span> <span class="n">UNLOCKED</span><span class="p">,</span> <span class="n">LOCKED</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">initial_flag</span> <span class="o">==</span> <span class="n">LOCKED</span><span class="p">)</span> <span class="p">{</span> + <span class="n">printk</span><span class="p">(</span><span class="n">KERN_ALERT</span> <span class="s">"Already locked.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EBUSY</span><span class="p">;</span> + <span class="p">}</span> + + <span class="cm">/* Do your thing after getting the lock. */</span> + <span class="p">[...]</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">my_release</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="cm">/* Release flag; mark it as unlocked. */</span> + <span class="n">atomic_set</span><span class="p">(</span><span class="o">&</span><span class="n">flag</span><span class="p">,</span> <span class="n">UNLOCKED</span><span class="p">);</span> +<span class="p">}</span> + +<span class="kt">void</span> <span class="nf">my_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="p">[...]</span> + <span class="cm">/* Atomic variable is initially unlocked. */</span> + <span class="n">atomic_set</span><span class="p">(</span><span class="o">&</span><span class="n">flag</span><span class="p">,</span> <span class="n">UNLOCKED</span><span class="p">);</span> + + <span class="p">[...]</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The above code is the equivalent of using a trylock (such as +<code class="xref c c-func docutils literal"><span class="pre">pthread_mutex_trylock()</span></code>).</p> +<p>We can also use a variable to store the size of a buffer and for atomic +updates of the respective variable. The code below is such an example:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="n">MAX_SIZE</span><span class="p">];</span> +<span class="k">static</span> <span class="n">atomic_t</span> <span class="n">size</span><span class="p">;</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">add_to_buffer</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">value</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">buffer</span><span class="p">[</span><span class="n">atomic_read</span><span class="p">(</span><span class="o">&</span><span class="n">size</span><span class="p">)]</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span> + <span class="n">atomic_inc</span><span class="p">(</span><span class="o">&</span><span class="n">size</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="nf">remove_from_buffer</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">value</span><span class="p">;</span> + + <span class="n">value</span> <span class="o">=</span> <span class="n">buffer</span><span class="p">[</span><span class="n">atomic_read</span><span class="p">(</span><span class="o">&</span><span class="n">size</span><span class="p">)];</span> + <span class="n">atomic_dec</span><span class="p">(</span><span class="o">&</span><span class="n">size</span><span class="p">);</span> + + <span class="k">return</span> <span class="n">value</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">reset_buffer</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">atomic_set</span><span class="p">(</span><span class="o">&</span><span class="n">size</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> +<span class="p">}</span> + +<span class="kt">void</span> <span class="nf">my_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="p">[...]</span> + <span class="cm">/* Initialized buffer and size. */</span> + <span class="n">atomic_set</span><span class="p">(</span><span class="o">&</span><span class="n">size</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> + <span class="n">memset</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">buffer</span><span class="p">));</span> + + <span class="p">[...]</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="atomic-bitwise-operations"> +<h3>Atomic bitwise operations<a class="headerlink" href="#atomic-bitwise-operations" title="Permalink to this headline">¶</a></h3> +<p>The kernel provides a set of functions (in <code class="file docutils literal"><span class="pre">asm/bitops.h</span></code>) that modify or +test bits in an atomic way.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><asm/bitops.h></span><span class="cp"></span> + +<span class="kt">void</span> <span class="nf">set_bit</span><span class="p">(</span><span class="kt">int</span> <span class="n">nr</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">addr</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">clear_bit</span><span class="p">(</span><span class="kt">int</span> <span class="n">nr</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">addr</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">change_bit</span><span class="p">(</span><span class="kt">int</span> <span class="n">nr</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">addr</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">test_and_set_bit</span><span class="p">(</span><span class="kt">int</span> <span class="n">nr</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">addr</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">test_and_clear_bit</span><span class="p">(</span><span class="kt">int</span> <span class="n">nr</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">addr</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">test_and_change_bit</span><span class="p">(</span><span class="kt">int</span> <span class="n">nr</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">addr</span><span class="p">);</span> +</pre></div> +</div> +<p><code class="xref c c-data docutils literal"><span class="pre">Addr</span></code> represents the address of the memory area whose bits are being +modified or tested and <code class="xref c c-data docutils literal"><span class="pre">nr</span></code> is the bit on which the operation is +performed.</p> +</div> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is kernel_api. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/kernel_api/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="section" id="intro"> +<h3>0. Intro<a class="headerlink" href="#intro" title="Permalink to this headline">¶</a></h3> +<p>Using <a class="reference external" href="http://elixir.free-electrons.com/linux/latest/source">LXR</a> find the definitions of the following symbols in the Linux kernel:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">list_head</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">INIT_LIST_HEAD()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">list_add()</span></code></li> +<li><code class="xref c c-macro docutils literal"><span class="pre">list_for_each</span></code></li> +<li><code class="xref c c-macro docutils literal"><span class="pre">list_entry</span></code></li> +<li><code class="xref c c-macro docutils literal"><span class="pre">container_of</span></code></li> +<li><code class="xref c c-macro docutils literal"><span class="pre">offsetof</span></code></li> +</ul> +</div></blockquote> +</div> +<div class="section" id="memory-allocation-in-linux-kernel"> +<h3>1. Memory allocation in Linux kernel<a class="headerlink" href="#memory-allocation-in-linux-kernel" title="Permalink to this headline">¶</a></h3> +<p>Generate the skeleton for the task named <strong>1-mem</strong> and browse the +contents of the <code class="file docutils literal"><span class="pre">mem.c</span></code> file. Observe the use of <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> +call for memory allocation.</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Compile the source code and load the <code class="file docutils literal"><span class="pre">mem.ko</span></code> module using +<strong class="command">insmod</strong>.</li> +<li>View the kernel messages using the <strong class="command">dmesg</strong> command.</li> +<li>Unload the kernel module using the <strong class="command">rmmod mem</strong> command.</li> +</ol> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Review the <a class="reference internal" href="#memory-allocation">Memory Allocation</a> section in the lab.</p> +</div> +</div> +<div class="section" id="sleeping-in-atomic-context"> +<h3>2. Sleeping in atomic context<a class="headerlink" href="#sleeping-in-atomic-context" title="Permalink to this headline">¶</a></h3> +<p>Generate the skeleton for the task named <strong>2-sched-spin</strong> and browse +the contents of the <code class="file docutils literal"><span class="pre">sched-spin.c</span></code> file.</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Compile the source code and load the module, according the above info: +(<strong class="command">make build</strong> and <strong class="command">make copy</strong>)</li> +<li>Notice that it is waiting for 5 seconds until the insertion +order is complete.</li> +<li>Unload the kernel module.</li> +<li>Look for the lines marked with: <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">0</span></code> to create an atomic +section. Re-compile the source code and reload the module into +the kernel.</li> +</ol> +</div></blockquote> +<p>You should now get an error. Look at the stack trace. What is the +cause of the error?</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">In the error message, follow the line containing the <code class="xref c c-macro docutils literal"><span class="pre">BUG</span></code> +for a description of the error. You are not allowed to sleep in +atomic context. The atomic context is given by a section +between a lock operation and an unlock on a spinlock.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The +<code class="xref c c-func docutils literal"><span class="pre">schedule_timeout()</span></code> function, corroborated with the +<code class="xref c c-macro docutils literal"><span class="pre">set_current_state</span></code> macro, forces the current process to wait +for 5 seconds.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Review the <a class="reference internal" href="#contexts-of-execution">Contexts of execution</a>, <a class="reference internal" href="#locking">Locking</a> and <a class="reference internal" href="#spinlock">Spinlock</a> +sections.</p> +</div> +</div> +<div class="section" id="working-with-kernel-memory"> +<h3>3. Working with kernel memory<a class="headerlink" href="#working-with-kernel-memory" title="Permalink to this headline">¶</a></h3> +<p>Generate the skeleton for the task named <strong>3-memory</strong> directory and +browse the contents of the <code class="file docutils literal"><span class="pre">memory.c</span></code> file. Notice the comments +marked with <code class="docutils literal"><span class="pre">TODO</span></code>. You must allocate 4 structures of type <code class="xref c c-type docutils literal"><span class="pre">struct</span> +<span class="pre">task_info</span></code> and initialize them (in <code class="xref c c-func docutils literal"><span class="pre">memory_init()</span></code>), then print and +free them (in <code class="xref c c-func docutils literal"><span class="pre">memory_exit()</span></code>).</p> +<blockquote> +<div><ol class="arabic"> +<li><p class="first">(TODO 1) Allocate memory for <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_info</span></code> structure and +initialize its fields:</p> +<ul class="simple"> +<li>The <code class="xref c c-member docutils literal"><span class="pre">pid</span></code> field to the PID transmitted as a parameter;</li> +<li>The <code class="xref c c-member docutils literal"><span class="pre">timestamp</span></code> field to the value of the <code class="xref c c-data docutils literal"><span class="pre">jiffies</span></code> +variable, which holds the number of ticks that have occurred since the +system booted.</li> +</ul> +</li> +<li><p class="first">(TODO 2) Allocate <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_info</span></code> for the current process, +the parent process, the next process, the next process of the next +process, with the following information:</p> +<ul class="simple"> +<li>PID of the current process, which can be retrieved from +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code> structure, returned by <code class="xref c c-macro docutils literal"><span class="pre">current</span></code> +macro.</li> +</ul> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Search for <code class="xref c c-type docutils literal"><span class="pre">pid</span></code> in <code class="xref c c-type docutils literal"><span class="pre">task_struct</span></code>.</p> +</div> +<ul class="simple"> +<li>PID of the parent process of the current process.</li> +</ul> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Search for the relevant field from <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code> +structure. Look after "parent".</p> +</div> +<ul class="simple"> +<li>PID of the next process from the list of processes, relative to the +current process.</li> +</ul> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use <code class="xref c c-macro docutils literal"><span class="pre">next_task</span></code> macro, which returns a pointer to the next +process (i.e a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code> structure).</p> +</div> +<ul class="simple"> +<li>PID of the next process of the next process, relative to the current +process.</li> +</ul> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Call the <code class="xref c c-macro docutils literal"><span class="pre">next_task</span></code> macro 2 times.</p> +</div> +</li> +<li><p class="first">(TODO 3) Display the four structures.</p> +<ul class="simple"> +<li>Use <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code> to display their two fields:</li> +</ul> +<p><code class="xref c c-member docutils literal"><span class="pre">pid</span></code> and <code class="xref c c-member docutils literal"><span class="pre">timestamp</span></code>.</p> +</li> +<li><p class="first">(TODO 4) Release the memory occupied by the structures +(use <code class="xref c c-func docutils literal"><span class="pre">kfree()</span></code>).</p> +</li> +</ol> +</div></blockquote> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<ul class="last simple"> +<li>You can access the current process using <code class="xref c c-macro docutils literal"><span class="pre">current</span></code> +macro.</li> +<li>Look for the relevant fields in the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code> +structure (<code class="xref c c-member docutils literal"><span class="pre">pid</span></code>, <code class="xref c c-member docutils literal"><span class="pre">parent</span></code>).</li> +<li>Use the <code class="xref c c-macro docutils literal"><span class="pre">next_task</span></code> macro. The macro returns the pointer to +the next process (ie. a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct*</span></code> structure).</li> +</ul> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code> structure contains two fields to +designate the parent of a task:</p> +<ul class="simple"> +<li><code class="xref c c-member docutils literal"><span class="pre">real_parent</span></code> points to the process that created the +task or to process with pid 1 (init) if the parent +completed its execution.</li> +<li><code class="xref c c-member docutils literal"><span class="pre">parent</span></code> indicates to the current task parent (the +process that will be reported if the task completes +execution).</li> +</ul> +<p class="last">In general, the values of the two fields are the same, but +there are situations where they differ, for example when +using the <code class="xref c c-func docutils literal"><span class="pre">ptrace()</span></code> system call.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Review the <a class="reference internal" href="#memory-allocation">Memory allocation</a> section in the lab.</p> +</div> +</div> +<div class="section" id="working-with-kernel-lists"> +<h3>4. Working with kernel lists<a class="headerlink" href="#working-with-kernel-lists" title="Permalink to this headline">¶</a></h3> +<p>Generate the skeleton for the task named <strong>4-list</strong>. Browse the +contents of the <code class="file docutils literal"><span class="pre">list.c</span></code> file and notice the comments marked with +<code class="docutils literal"><span class="pre">TODO</span></code>. The current process will add the four structures from the +previous exercise into a list. The list will be built in the +<code class="xref c c-func docutils literal"><span class="pre">task_info_add_for_current()</span></code> function which is called when module is +loaded. The list will be printed and deleted in the <code class="xref c c-func docutils literal"><span class="pre">list_exit()</span></code> +function and the <code class="xref c c-func docutils literal"><span class="pre">task_info_purge_list()</span></code> function.</p> +<blockquote> +<div><ol class="arabic simple"> +<li>(TODO 1) Complete the <code class="xref c c-func docutils literal"><span class="pre">task_info_add_to_list()</span></code> function to allocate +a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_info</span></code> structure and add it to the list.</li> +<li>(TODO 2) Complete the <code class="xref c c-func docutils literal"><span class="pre">task_info_purge_list()</span></code> function to delete +all the elements in the list.</li> +<li>Compile the kernel module. Load and unload the module by +following the messages displayed by the kernel.</li> +</ol> +</div></blockquote> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Review the labs <a class="reference internal" href="#lists">Lists</a> section. When deleting items from +the list, you will need to use either the +<code class="xref c c-macro docutils literal"><span class="pre">list_for_each_safe</span></code> or <code class="xref c c-macro docutils literal"><span class="pre">list_for_each_entry_safe</span></code> +macros.</p> +</div> +</div> +<div class="section" id="working-with-kernel-lists-for-process-handling"> +<h3>5. Working with kernel lists for process handling<a class="headerlink" href="#working-with-kernel-lists-for-process-handling" title="Permalink to this headline">¶</a></h3> +<p>Generate the skeleton for the task named <strong>5-list-full</strong>. Browse the +contents of the <code class="file docutils literal"><span class="pre">list-full.c</span></code> and notice comments marked with +<code class="docutils literal"><span class="pre">TODO</span></code>. In addition to the <code class="file docutils literal"><span class="pre">4-list</span></code> functionality we add the +following:</p> +<blockquote> +<div><ul> +<li><p class="first">A <code class="xref c c-member docutils literal"><span class="pre">count</span></code> field showing how many times a process has been "added" +to the list.</p> +</li> +<li><p class="first">If a process is "added" several times, no new entry is created in +the list, but:</p> +<blockquote> +<div><ul class="simple"> +<li>Update the <code class="xref c c-member docutils literal"><span class="pre">timestamp</span></code> field.</li> +<li>Increment <code class="xref c c-member docutils literal"><span class="pre">count</span></code>.</li> +</ul> +</div></blockquote> +</li> +<li><p class="first">To implement the counter facility, add a <code class="xref c c-func docutils literal"><span class="pre">task_info_find_pid()</span></code> +function that searches for a pid in the existing list.</p> +</li> +<li><p class="first">If found, return the reference to the <code class="xref c c-type docutils literal"><span class="pre">task_info</span></code> struct. If +not, return <code class="xref c c-macro docutils literal"><span class="pre">NULL</span></code>.</p> +</li> +<li><p class="first">An expiration facility. If a process was added more than 3 +seconds ago and if it does not have a <code class="xref c c-member docutils literal"><span class="pre">count</span></code> greater than 5 then +it is considered expired and is removed from the list.</p> +</li> +<li><p class="first">The expiration facility is already implemented in the +<code class="xref c c-func docutils literal"><span class="pre">task_info_remove_expired()</span></code> function.</p> +</li> +</ul> +<ol class="arabic"> +<li><p class="first">(TODO 1) Implement the <code class="xref c c-func docutils literal"><span class="pre">task_info_find_pid()</span></code> function.</p> +</li> +<li><p class="first">(TODO 2) Change a field of an item in the list so it does not +expire. It must not satisfy a part of the expiration condition +from <code class="xref c c-func docutils literal"><span class="pre">task_info_remove_expired()</span></code>.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">For <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">2</span></code>, extract the first element from the list (the one +referred by <code class="xref c c-member docutils literal"><span class="pre">head.next</span></code>) and set the <code class="xref c c-member docutils literal"><span class="pre">count</span></code> +field to a large enough value. Use <code class="xref c c-func docutils literal"><span class="pre">atomic_set()</span></code> function.</p> +</div> +</li> +<li><p class="first">Compile, copy, load and unload the kernel module following the displayed +messages. +Kernel module loading will take some time, because <code class="xref c c-func docutils literal"><span class="pre">sleep()</span></code> is +being called by <code class="xref c c-func docutils literal"><span class="pre">schedule_timeout()</span></code> function.</p> +</li> +</ol> +</div></blockquote> +</div> +<div class="section" id="synchronizing-list-work"> +<h3>6. Synchronizing list work<a class="headerlink" href="#synchronizing-list-work" title="Permalink to this headline">¶</a></h3> +<p>Generate the skeleton for the task named <strong>6-list-sync</strong>.</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Browse the code and look for <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">1</span></code> string.</li> +<li>Use a spinlock or a read-write lock to synchronize access to the +list.</li> +<li>Compile, load and unload the kernel module.</li> +</ol> +</div></blockquote> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p class="last">Always lock data, not code!</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Read <a class="reference internal" href="#spinlock">Spinlock</a> section of the lab.</p> +</div> +</div> +<div class="section" id="test-module-calling-in-our-list-module"> +<h3>7. Test module calling in our list module<a class="headerlink" href="#test-module-calling-in-our-list-module" title="Permalink to this headline">¶</a></h3> +<p>Generate the skeleton for the task named <strong>7-list-test</strong> and browse +the contents of the <code class="file docutils literal"><span class="pre">list-test.c</span></code> file. We'll use it as a test +module. It will call functions exported by the <strong>6-list-sync</strong> +task. The exported functions are the ones marked with <strong>extern</strong> in +<code class="file docutils literal"><span class="pre">list-test.c</span></code> file.</p> +<p>Uncomment the commented code from <code class="file docutils literal"><span class="pre">7-list-test.c</span></code>. Look for <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">1</span></code>.</p> +<p>To export the above functions from the module located at <code class="file docutils literal"><span class="pre">6-list-sync/</span></code> +directory, the following steps are required:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Functions must not be static.</li> +<li>Use the <code class="xref c c-macro docutils literal"><span class="pre">EXPORT_SYMBOL</span></code> macro to export the kernel symbols. For +example: <code class="xref c c-macro docutils literal"><span class="pre">EXPORT_SYMBOL(task_info_remove_expired);</span></code>. The +macro must be used for each function after the function is defined. +Browse the code and look for the <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">2</span></code> string in the +<code class="file docutils literal"><span class="pre">list-sync.c</span></code>.</li> +<li>Remove from the module from <strong>6-list-sync</strong> the code that avoids the +expiration of a list item (it is in contradiction to our exercise).</li> +<li>Compile and load the module from <code class="file docutils literal"><span class="pre">6-list-sync/</span></code>. Once loaded, it +exposes exported functions and can be used by the test +module. You can check this by searching for the function names +in <code class="file docutils literal"><span class="pre">/proc/kallsyms</span></code> before and after loading the module.</li> +<li>Compile the test module and then load it.</li> +<li>Use <strong class="command">lsmod</strong> to check that the two modules have been loaded. +What do you notice?</li> +<li>Unload the kernel test module.</li> +</ol> +</div></blockquote> +<p>What should be the unload order of the two modules (the module from +<strong>6-list-sync</strong> and the test module)? What happens if you use another order?</p> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lab1-intro.html" class="btn btn-neutral float-left" title="SO2 Lab 01 - Introduction" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lab3-device-drivers.html" class="btn btn-neutral float-right" title="SO2 Lab 03 - Character device drivers" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lab3-device-drivers.html b/refs/pull/405/merge/so2/lab3-device-drivers.html new file mode 100644 index 00000000..02a99dc1 --- /dev/null +++ b/refs/pull/405/merge/so2/lab3-device-drivers.html @@ -0,0 +1,1235 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lab 03 - Character device drivers — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lab 04 - I/O access and Interrupts" href="lab4-interrupts.html" /> + <link rel="prev" title="SO2 Lab 02 - Kernel API" href="lab2-kernel-api.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lab 03 - Character device drivers</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#laboratory-objectives">Laboratory objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#overview">Overview</a></li> +<li class="toctree-l3"><a class="reference internal" href="#majors-and-minors">Majors and minors</a></li> +<li class="toctree-l3"><a class="reference internal" href="#data-structures-for-a-character-device">Data structures for a character device</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#struct-file-operations"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code></a></li> +<li class="toctree-l4"><a class="reference internal" href="#inode-and-file-structures"><code class="docutils literal"><span class="pre">inode</span></code> and <code class="docutils literal"><span class="pre">file</span></code> structures</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#implementation-of-operations">Implementation of operations</a></li> +<li class="toctree-l3"><a class="reference internal" href="#registration-and-unregistration-of-character-devices">Registration and unregistration of character devices</a></li> +<li class="toctree-l3"><a class="reference internal" href="#access-to-the-address-space-of-the-process">Access to the address space of the process</a></li> +<li class="toctree-l3"><a class="reference internal" href="#open-and-release">Open and release</a></li> +<li class="toctree-l3"><a class="reference internal" href="#read-and-write">Read and write</a></li> +<li class="toctree-l3"><a class="reference internal" href="#ioctl-1">ioctl</a></li> +<li class="toctree-l3"><a class="reference internal" href="#waiting-queues">Waiting queues</a></li> +<li class="toctree-l3"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#intro">0. Intro</a></li> +<li class="toctree-l4"><a class="reference internal" href="#register-unregister">1. Register/unregister</a></li> +<li class="toctree-l4"><a class="reference internal" href="#register-an-already-registered-major">2. Register an already registered major</a></li> +<li class="toctree-l4"><a class="reference internal" href="#open-and-close">3. Open and close</a></li> +<li class="toctree-l4"><a class="reference internal" href="#access-restriction">4. Access restriction</a></li> +<li class="toctree-l4"><a class="reference internal" href="#read-operation">5. Read operation</a></li> +<li class="toctree-l4"><a class="reference internal" href="#write-operation">6. Write operation</a></li> +<li class="toctree-l4"><a class="reference internal" href="#ioctl-operation">7. ioctl operation</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#extra-exercises">Extra Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#ioctl-with-messaging">Ioctl with messaging</a></li> +<li class="toctree-l4"><a class="reference internal" href="#ioctl-with-waiting-queues">Ioctl with waiting queues</a></li> +<li class="toctree-l4"><a class="reference internal" href="#o-nonblock-implementation">O_NONBLOCK implementation</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lab 03 - Character device drivers</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lab3-device-drivers.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lab-03-character-device-drivers"> +<h1>SO2 Lab 03 - Character device drivers<a class="headerlink" href="#so2-lab-03-character-device-drivers" title="Permalink to this headline">¶</a></h1> +<div class="section" id="laboratory-objectives"> +<h2>Laboratory objectives<a class="headerlink" href="#laboratory-objectives" title="Permalink to this headline">¶</a></h2> +<blockquote> +<div><ul class="simple"> +<li>understand the concepts behind character device driver</li> +<li>understand the various operations that can be performed on character devices</li> +<li>working with waiting queues</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="overview"> +<h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline">¶</a></h2> +<p>In UNIX, hardware devices are accessed by the user through special device +files. These files are grouped into the /dev directory, and system calls +<code class="docutils literal"><span class="pre">open</span></code>, <code class="docutils literal"><span class="pre">read</span></code>, <code class="docutils literal"><span class="pre">write</span></code>, <code class="docutils literal"><span class="pre">close</span></code>, <code class="docutils literal"><span class="pre">lseek</span></code>, <code class="docutils literal"><span class="pre">mmap</span></code> etc. are +redirected by the operating system to the device driver associated with the +physical device. The device driver is a kernel component (usually a module) +that interacts with a hardware device.</p> +<p>In the UNIX world there are two categories of device files and thus +device drivers: character and block. This division is done by the speed, +volume and way of organizing the data to be transferred from the device to the +system and vice versa. In the first category, there are slow devices, which +manage a small amount of data, and access to data does not require frequent +seek queries. Examples are devices such as keyboard, mouse, serial ports, +sound card, joystick. In general, operations with these devices (read, write) +are performed sequentially byte by byte. The second category includes devices +where data volume is large, data is organized on blocks, and search is common. +Examples of devices that fall into this category are hard drives, cdroms, ram +disks, magnetic tape drives. For these devices, reading and writing is done at +the data block level.</p> +<p>For the two types of device drivers, the Linux kernel offers different APIs. +If for character devices system calls go directly to device drivers, in case of +block devices, the drivers do not work directly with system calls. In +the case of block devices, communication between the user-space and the block +device driver is mediated by the file management subsystem and the block device +subsystem. The role of these subsystems is to prepare the device driver's +necessary resources (buffers), to keep the recently read data in the cache +buffer, and to order the read and write operations for performance reasons.</p> +</div> +<div class="section" id="majors-and-minors"> +<h2>Majors and minors<a class="headerlink" href="#majors-and-minors" title="Permalink to this headline">¶</a></h2> +<p>In UNIX, the devices traditionally had a unique, fixed identifier associated +with them. This tradition is preserved in Linux, although identifiers can be +dynamically allocated (for compatibility reasons, most drivers still use static +identifiers). The identifier consists of two parts: major and minor. The first +part identifies the device type (IDE disk, SCSI disk, serial port, etc.) +and the second one identifies the device (first disk, second serial port, +etc.). Most times, the major identifies the driver, while the minor identifies +each physical device served by the driver. In general, a driver will have a +major associate and will be responsible for all minors associated with that +major.</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ ls -la /dev/hda? /dev/ttyS? +brw-rw---- <span class="m">1</span> root disk <span class="m">3</span>, <span class="m">1</span> <span class="m">2004</span>-09-18 <span class="m">14</span>:51 /dev/hda1 +brw-rw---- <span class="m">1</span> root disk <span class="m">3</span>, <span class="m">2</span> <span class="m">2004</span>-09-18 <span class="m">14</span>:51 /dev/hda2 +crw-rw---- <span class="m">1</span> root dialout <span class="m">4</span>, <span class="m">64</span> <span class="m">2004</span>-09-18 <span class="m">14</span>:52 /dev/ttyS0 +crw-rw---- <span class="m">1</span> root dialout <span class="m">4</span>, <span class="m">65</span> <span class="m">2004</span>-09-18 <span class="m">14</span>:52 /dev/ttyS1 +</pre></div> +</div> +<p>As can be seen from the example above, device-type information can be found +using the ls command. The special character files are identified by the <code class="docutils literal"><span class="pre">c</span></code> +character in the first column of the command output, and the block type by the +character <code class="docutils literal"><span class="pre">b</span></code>. In columns <code class="docutils literal"><span class="pre">5</span></code> and <code class="docutils literal"><span class="pre">6</span></code> of the result you can see the +major, respectively the minor for each device.</p> +<p>Certain major identifiers are statically assigned to devices (in the +<code class="docutils literal"><span class="pre">Documentation/admin-guide/devices.txt</span></code> file from the kernel sources). When choosing the +identifier for a new device, you can use two methods: static (choose a number +that does not seem to be used already) or dynamically. In /proc/devices are the +loaded devices, along with the major identifier.</p> +<p>To create a device type file, use the <code class="docutils literal"><span class="pre">mknod</span></code> command; the command receives the +type (<code class="docutils literal"><span class="pre">block</span></code> or <code class="docutils literal"><span class="pre">character</span></code>), <code class="docutils literal"><span class="pre">major</span></code> and <code class="docutils literal"><span class="pre">minor</span></code> of the device +(<code class="docutils literal"><span class="pre">mknod</span> <span class="pre">name</span> <span class="pre">type</span> <span class="pre">major</span> <span class="pre">minor</span></code>). Thus, if you want to create a character device +named <code class="docutils literal"><span class="pre">mycdev</span></code> with the major <code class="docutils literal"><span class="pre">42</span></code> and minor <code class="docutils literal"><span class="pre">0</span></code>, use the command:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># mknod /dev/mycdev c 42 0</span> +</pre></div> +</div> +<p>To create the block device with the name <code class="docutils literal"><span class="pre">mybdev</span></code> with the major 240 and minor 0 +the command will be:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># mknod /dev/mybdev b 240 0</span> +</pre></div> +</div> +<p>Next, we'll refer to character devices as drivers.</p> +</div> +<div class="section" id="data-structures-for-a-character-device"> +<h2>Data structures for a character device<a class="headerlink" href="#data-structures-for-a-character-device" title="Permalink to this headline">¶</a></h2> +<p>In the kernel, a character-type device is represented by +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">cdev</span></code>, a structure used to register it in the +system. Most driver operations use three important structures: +<code class="docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code>, <code class="docutils literal"><span class="pre">struct</span> <span class="pre">file</span></code> and <code class="docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code>.</p> +<div class="section" id="struct-file-operations"> +<h3><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code><a class="headerlink" href="#struct-file-operations" title="Permalink to this headline">¶</a></h3> +<p>As mentioned above, the character device drivers receive unaltered system calls +made by users over device-type files. Consequently, implementation of a character +device driver means implementing the system calls specific to files: <code class="docutils literal"><span class="pre">open</span></code>, +<code class="docutils literal"><span class="pre">close</span></code>, <code class="docutils literal"><span class="pre">read</span></code>, <code class="docutils literal"><span class="pre">write</span></code>, <code class="docutils literal"><span class="pre">lseek</span></code>, <code class="docutils literal"><span class="pre">mmap</span></code>, etc. These operations are +described in the fields of the <code class="docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code> structure:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> + +<span class="k">struct</span> <span class="n">file_operations</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">owner</span><span class="p">;</span> + <span class="n">loff_t</span> <span class="p">(</span><span class="o">*</span><span class="n">llseek</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="n">loff_t</span><span class="p">,</span> <span class="kt">int</span><span class="p">);</span> + <span class="kt">ssize_t</span> <span class="p">(</span><span class="o">*</span><span class="n">read</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="kt">char</span> <span class="n">__user</span> <span class="o">*</span><span class="p">,</span> <span class="kt">size_t</span><span class="p">,</span> <span class="n">loff_t</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">ssize_t</span> <span class="p">(</span><span class="o">*</span><span class="n">write</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">__user</span> <span class="o">*</span><span class="p">,</span> <span class="kt">size_t</span><span class="p">,</span> <span class="n">loff_t</span> <span class="o">*</span><span class="p">);</span> + <span class="p">[...]</span> + <span class="kt">long</span> <span class="p">(</span><span class="o">*</span><span class="n">unlocked_ioctl</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">);</span> + <span class="p">[...]</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">open</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">flush</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="n">fl_owner_t</span> <span class="n">id</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">release</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">);</span> + <span class="p">[...]</span> +</pre></div> +</div> +<p>It can be noticed that the signature of the function differs from the system +call that the user uses. The operating system sits between the user and +the device driver to simplify implementation in the device driver.</p> +<p><code class="docutils literal"><span class="pre">open</span></code> does not receive the parameter path or the various parameters that control +the file opening mode. Similarly, <code class="docutils literal"><span class="pre">read</span></code>, <code class="docutils literal"><span class="pre">write</span></code>, <code class="docutils literal"><span class="pre">release</span></code>, <code class="docutils literal"><span class="pre">ioctl</span></code>, <code class="docutils literal"><span class="pre">lseek</span></code> +do not receive as a parameter a file descriptor. Instead, these routines receive as +parameters two structures: <code class="docutils literal"><span class="pre">file</span></code> and <code class="docutils literal"><span class="pre">inode</span></code>. Both structures represent a file, +but from different perspectives.</p> +<dl class="docutils"> +<dt>Most parameters for the presented operations have a direct meaning:</dt> +<dd><ul class="first last simple"> +<li><code class="docutils literal"><span class="pre">file</span></code> and <code class="docutils literal"><span class="pre">inode</span></code> identifies the device type file;</li> +<li><code class="docutils literal"><span class="pre">size</span></code> is the number of bytes to be read or written;</li> +<li><code class="docutils literal"><span class="pre">offset</span></code> is the displacement to be read or written (to be updated +accordingly);</li> +<li><code class="docutils literal"><span class="pre">user_buffer</span></code> user buffer from which it reads / writes;</li> +<li><code class="docutils literal"><span class="pre">whence</span></code> is the way to seek (the position where the search operation starts);</li> +<li><code class="docutils literal"><span class="pre">cmd</span></code> and <code class="docutils literal"><span class="pre">arg</span></code> are the parameters sent by the users to the ioctl call (IO +control).</li> +</ul> +</dd> +</dl> +</div> +<div class="section" id="inode-and-file-structures"> +<h3><code class="docutils literal"><span class="pre">inode</span></code> and <code class="docutils literal"><span class="pre">file</span></code> structures<a class="headerlink" href="#inode-and-file-structures" title="Permalink to this headline">¶</a></h3> +<p>An <code class="docutils literal"><span class="pre">inode</span></code> represents a file from the point of view of the file system. Attributes +of an inode are the size, rights, times associated with the file. An inode uniquely +identifies a file in a file system.</p> +<p>The <code class="docutils literal"><span class="pre">file</span></code> structure is still a file, but closer to the user's point of view. +From the attributes of the file structure we list: the inode, the file name, +the file opening attributes, the file position. All open files at a given time +have associated a <code class="docutils literal"><span class="pre">file</span></code> structure.</p> +<p>To understand the differences between inode and file, we will use an analogy +from object-oriented programming: if we consider a class inode, then the files +are objects, that is, instances of the inode class. Inode represents the static +image of the file (the inode has no state), while the file represents the +dynamic image of the file (the file has state).</p> +<p>Returning to device drivers, the two entities have almost always standard ways +of using: the inode is used to determine the major and minor of the device on +which the operation is performed, and the file is used to determine the flags +with which the file was opened, but also to save and access (later) private +data.</p> +<p>The file structure contains, among many fields:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">f_mode</span></code>, which specifies read (<code class="docutils literal"><span class="pre">FMODE_READ</span></code>) or write +(<code class="docutils literal"><span class="pre">FMODE_WRITE</span></code>);</li> +<li><code class="docutils literal"><span class="pre">f_flags</span></code>, which specifies the file opening flags (<code class="docutils literal"><span class="pre">O_RDONLY</span></code>, +<code class="docutils literal"><span class="pre">O_NONBLOCK</span></code>, <code class="docutils literal"><span class="pre">O_SYNC</span></code>, <code class="docutils literal"><span class="pre">O_APPEND</span></code>, <code class="docutils literal"><span class="pre">O_TRUNC</span></code>, etc.);</li> +<li><code class="docutils literal"><span class="pre">f_op</span></code>, which specifies the operations associated with the file (pointer to +the <code class="docutils literal"><span class="pre">file_operations</span></code> structure );</li> +<li><code class="docutils literal"><span class="pre">private_data</span></code>, a pointer that can be used by the programmer to store +device-specific data; The pointer will be initialized to a memory location +assigned by the programmer.</li> +<li><code class="docutils literal"><span class="pre">f_pos</span></code>, the offset within the file</li> +</ul> +</div></blockquote> +<p>The inode structure contains, among much information, an <code class="docutils literal"><span class="pre">i_cdev</span></code> +field, which is a pointer to the structure that defines the character +device (when the inode corresponds to a character device).</p> +</div> +</div> +<div class="section" id="implementation-of-operations"> +<h2>Implementation of operations<a class="headerlink" href="#implementation-of-operations" title="Permalink to this headline">¶</a></h2> +<p>To implement a device driver, it is recommended that you create a structure +that contains information about the device, information used in the module. In +the case of a driver for a character device, the structure will contain a cdev +structure field to refer to the device. The following example uses the struct +my_device_data:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/cdev.h></span><span class="cp"></span> + +<span class="k">struct</span> <span class="n">my_device_data</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">cdev</span> <span class="n">cdev</span><span class="p">;</span> + <span class="cm">/* my data starts here */</span> + <span class="c1">//...</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_open</span><span class="p">(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="n">my_data</span><span class="p">;</span> + + <span class="n">my_data</span> <span class="o">=</span> <span class="n">container_of</span><span class="p">(</span><span class="n">inode</span><span class="o">-></span><span class="n">i_cdev</span><span class="p">,</span> <span class="k">struct</span> <span class="n">my_device_data</span><span class="p">,</span> <span class="n">cdev</span><span class="p">);</span> + + <span class="n">file</span><span class="o">-></span><span class="n">private_data</span> <span class="o">=</span> <span class="n">my_data</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_read</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> <span class="kt">char</span> <span class="n">__user</span> <span class="o">*</span><span class="n">user_buffer</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">size</span><span class="p">,</span> <span class="n">loff_t</span> <span class="o">*</span><span class="n">offset</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="n">my_data</span><span class="p">;</span> + + <span class="n">my_data</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="p">)</span> <span class="n">file</span><span class="o">-></span><span class="n">private_data</span><span class="p">;</span> + + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>A structure like <code class="docutils literal"><span class="pre">my_device_data</span></code> will contain the data associated with a device. +The <code class="docutils literal"><span class="pre">cdev</span></code> field (<code class="docutils literal"><span class="pre">cdev</span></code> type) is a character-type device and is used to record it +in the system and identify the device. The pointer to the <code class="docutils literal"><span class="pre">cdev</span></code> member can be +found using the <code class="docutils literal"><span class="pre">i_cdev</span></code> field of the <code class="docutils literal"><span class="pre">inode</span></code> structure (using the <code class="docutils literal"><span class="pre">container_of</span></code> +macro). In the private_data field of the file structure, information can be +stored at open which is then available in the <code class="docutils literal"><span class="pre">read</span></code>, <code class="docutils literal"><span class="pre">write</span></code>, <code class="docutils literal"><span class="pre">release</span></code>, etc. +routines.</p> +</div> +<div class="section" id="registration-and-unregistration-of-character-devices"> +<h2>Registration and unregistration of character devices<a class="headerlink" href="#registration-and-unregistration-of-character-devices" title="Permalink to this headline">¶</a></h2> +<p>The registration/unregistration of a device is made by specifying the major and +minor. The <code class="docutils literal"><span class="pre">dev_t</span></code> type is used to keep the identifiers of a device (both major +and minor) and can be obtained using the <code class="docutils literal"><span class="pre">MKDEV</span></code> macro.</p> +<p>For the static assignment and unallocation of device identifiers, the +<code class="docutils literal"><span class="pre">register_chrdev_region</span></code> and <code class="docutils literal"><span class="pre">unregister_chrdev_region</span></code> functions are used:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> + +<span class="kt">int</span> <span class="nf">register_chrdev_region</span><span class="p">(</span><span class="kt">dev_t</span> <span class="n">first</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">count</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">unregister_chrdev_region</span><span class="p">(</span><span class="kt">dev_t</span> <span class="n">first</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">count</span><span class="p">);</span> +</pre></div> +</div> +<p>It is recommended that device identifiers be dynamically assigned to the +<code class="docutils literal"><span class="pre">alloc_chrdev_region</span></code> function.</p> +<p>Below sequence reserves <code class="docutils literal"><span class="pre">my_minor_count</span></code> devices, starting with <code class="docutils literal"><span class="pre">my_major</span></code> +major and <code class="docutils literal"><span class="pre">my_first_minor</span></code> minor (if the max value for minor is exceeded, +move to the next major):</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> +<span class="p">...</span> + +<span class="n">err</span> <span class="o">=</span> <span class="n">register_chrdev_region</span><span class="p">(</span><span class="n">MKDEV</span><span class="p">(</span><span class="n">my_major</span><span class="p">,</span> <span class="n">my_first_minor</span><span class="p">),</span> <span class="n">my_minor_count</span><span class="p">,</span> + <span class="s">"my_device_driver"</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* report error */</span> + <span class="k">return</span> <span class="n">err</span><span class="p">;</span> +<span class="p">}</span> +<span class="p">...</span> +</pre></div> +</div> +<p>After assigning the identifiers, the character device will have to be +initialized (<code class="docutils literal"><span class="pre">cdev_init</span></code>) and the kernel will have to be notified(<code class="docutils literal"><span class="pre">cdev_add</span></code>). The +<code class="docutils literal"><span class="pre">cdev_add</span></code> function must be called only after the device is ready to receive +calls. Removing a device is done using the <code class="docutils literal"><span class="pre">cdev_del</span></code> function.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/cdev.h></span><span class="cp"></span> + +<span class="kt">void</span> <span class="nf">cdev_init</span><span class="p">(</span><span class="k">struct</span> <span class="n">cdev</span> <span class="o">*</span><span class="n">cdev</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file_operations</span> <span class="o">*</span><span class="n">fops</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">cdev_add</span><span class="p">(</span><span class="k">struct</span> <span class="n">cdev</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> <span class="kt">dev_t</span> <span class="n">num</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">count</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">cdev_del</span><span class="p">(</span><span class="k">struct</span> <span class="n">cdev</span> <span class="o">*</span><span class="n">dev</span><span class="p">);</span> +</pre></div> +</div> +<p>The following sequence registers and initializes MY_MAX_MINORS devices:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/cdev.h></span><span class="cp"></span> + +<span class="cp">#define MY_MAJOR 42</span> +<span class="cp">#define MY_MAX_MINORS 5</span> + +<span class="k">struct</span> <span class="n">my_device_data</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">cdev</span> <span class="n">cdev</span><span class="p">;</span> + <span class="cm">/* my data starts here */</span> + <span class="c1">//...</span> +<span class="p">};</span> + +<span class="k">struct</span> <span class="n">my_device_data</span> <span class="n">devs</span><span class="p">[</span><span class="n">MY_MAX_MINORS</span><span class="p">];</span> + +<span class="k">const</span> <span class="k">struct</span> <span class="n">file_operations</span> <span class="n">my_fops</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">owner</span> <span class="o">=</span> <span class="n">THIS_MODULE</span><span class="p">,</span> + <span class="p">.</span><span class="n">open</span> <span class="o">=</span> <span class="n">my_open</span><span class="p">,</span> + <span class="p">.</span><span class="n">read</span> <span class="o">=</span> <span class="n">my_read</span><span class="p">,</span> + <span class="p">.</span><span class="n">write</span> <span class="o">=</span> <span class="n">my_write</span><span class="p">,</span> + <span class="p">.</span><span class="n">release</span> <span class="o">=</span> <span class="n">my_release</span><span class="p">,</span> + <span class="p">.</span><span class="n">unlocked_ioctl</span> <span class="o">=</span> <span class="n">my_ioctl</span> +<span class="p">};</span> + +<span class="kt">int</span> <span class="nf">init_module</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="n">err</span><span class="p">;</span> + + <span class="n">err</span> <span class="o">=</span> <span class="n">register_chrdev_region</span><span class="p">(</span><span class="n">MKDEV</span><span class="p">(</span><span class="n">MY_MAJOR</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">MY_MAX_MINORS</span><span class="p">,</span> + <span class="s">"my_device_driver"</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* report error */</span> + <span class="k">return</span> <span class="n">err</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">for</span><span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">MY_MAX_MINORS</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* initialize devs[i] fields */</span> + <span class="n">cdev_init</span><span class="p">(</span><span class="o">&</span><span class="n">devs</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">cdev</span><span class="p">,</span> <span class="o">&</span><span class="n">my_fops</span><span class="p">);</span> + <span class="n">cdev_add</span><span class="p">(</span><span class="o">&</span><span class="n">devs</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">cdev</span><span class="p">,</span> <span class="n">MKDEV</span><span class="p">(</span><span class="n">MY_MAJOR</span><span class="p">,</span> <span class="n">i</span><span class="p">),</span> <span class="mi">1</span><span class="p">);</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>While the following sequence deletes and unregisters them:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">cleanup_module</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">i</span><span class="p">;</span> + + <span class="k">for</span><span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">MY_MAX_MINORS</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* release devs[i] fields */</span> + <span class="n">cdev_del</span><span class="p">(</span><span class="o">&</span><span class="n">devs</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">cdev</span><span class="p">);</span> + <span class="p">}</span> + <span class="n">unregister_chrdev_region</span><span class="p">(</span><span class="n">MKDEV</span><span class="p">(</span><span class="n">MY_MAJOR</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">MY_MAX_MINORS</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Initialization of the struct my_fops used the initialization +of members by name, defined in C99 standard (see designated +initializers and the file_operations structure). Structure +members who do not explicitly appear in this initialization +will be set to the default value for their type. For +example, after the initialization above, <code class="docutils literal"><span class="pre">my_fops.mmap</span></code> will +be NULL.</p> +</div> +</div> +<div class="section" id="access-to-the-address-space-of-the-process"> +<span id="access-to-process-address-space"></span><h2>Access to the address space of the process<a class="headerlink" href="#access-to-the-address-space-of-the-process" title="Permalink to this headline">¶</a></h2> +<p>A driver for a device is the interface between an application and hardware. As +a result, we often have to access user-space data. Accessing it can not be done +directly (by dereferencing a user-space pointer). Direct access of a +user-space pointer can lead to incorrect behavior (depending on architecture, a +user-space pointer may not be valid or mapped to kernel-space), a kernel oops +(the user-mode pointer can refer to a non-resident memory area) or security +issues. Proper access to user-space data is done by calling the macros / +functions below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><asm/uaccess.h></span><span class="cp"></span> + +<span class="n">put_user</span><span class="p">(</span><span class="n">type</span> <span class="n">val</span><span class="p">,</span> <span class="n">type</span> <span class="o">*</span><span class="n">address</span><span class="p">);</span> +<span class="n">get_user</span><span class="p">(</span><span class="n">type</span> <span class="n">val</span><span class="p">,</span> <span class="n">type</span> <span class="o">*</span><span class="n">address</span><span class="p">);</span> +<span class="kt">unsigned</span> <span class="kt">long</span> <span class="nf">copy_to_user</span><span class="p">(</span><span class="kt">void</span> <span class="n">__user</span> <span class="o">*</span><span class="n">to</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">from</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">n</span><span class="p">);</span> +<span class="kt">unsigned</span> <span class="kt">long</span> <span class="nf">copy_from_user</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">to</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="n">__user</span> <span class="o">*</span><span class="n">from</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">n</span><span class="p">);</span> +</pre></div> +</div> +<p>All macros / functions return 0 in case of success and another value in case of +error and have the following roles:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">put_user</span></code> store the value <code class="docutils literal"><span class="pre">val</span></code> to user-space address <code class="docutils literal"><span class="pre">address</span></code>; +Type can be one on 8, 16, 32, 64 bit (the maximum supported type depends on the +hardware platform);</li> +<li><code class="docutils literal"><span class="pre">get_user</span></code> analogue to the previous function, only that val will be set to a +value identical to the value at the user-space address given by address;</li> +<li><code class="docutils literal"><span class="pre">copy_to_user</span></code> copies <code class="docutils literal"><span class="pre">n</span></code> bytes from the kernel-space, from the address +referenced by <code class="docutils literal"><span class="pre">from</span></code> in user-space to the address referenced by <code class="docutils literal"><span class="pre">to</span></code>;</li> +<li><code class="docutils literal"><span class="pre">copy_from_user</span></code> copies <code class="docutils literal"><span class="pre">n</span></code> bytes from user-space from the address +referenced by <code class="docutils literal"><span class="pre">from</span></code> in kernel-space to the address referenced by <code class="docutils literal"><span class="pre">to</span></code>.</li> +</ul> +</div></blockquote> +<p>A common section of code that works with these functions is:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><asm/uaccess.h></span><span class="cp"></span> + +<span class="cm">/*</span> +<span class="cm"> * Copy at most size bytes to user space.</span> +<span class="cm"> * Return ''0'' on success and some other value on error.</span> +<span class="cm"> */</span> +<span class="k">if</span> <span class="p">(</span><span class="n">copy_to_user</span><span class="p">(</span><span class="n">user_buffer</span><span class="p">,</span> <span class="n">kernel_buffer</span><span class="p">,</span> <span class="n">size</span><span class="p">))</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EFAULT</span><span class="p">;</span> +<span class="k">else</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +</pre></div> +</div> +</div> +<div class="section" id="open-and-release"> +<h2>Open and release<a class="headerlink" href="#open-and-release" title="Permalink to this headline">¶</a></h2> +<p>The <code class="docutils literal"><span class="pre">open</span></code> function performs the initialization of a device. In most cases, +these operations refer to initializing the device and filling in specific data +(if it is the first open call). The release function is about releasing +device-specific resources: unlocking specific data and closing the device if +the last call is close.</p> +<p>In most cases, the open function will have the following structure:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">my_open</span><span class="p">(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="n">my_data</span> <span class="o">=</span> + <span class="n">container_of</span><span class="p">(</span><span class="n">inode</span><span class="o">-></span><span class="n">i_cdev</span><span class="p">,</span> <span class="k">struct</span> <span class="n">my_device_data</span><span class="p">,</span> <span class="n">cdev</span><span class="p">);</span> + + <span class="cm">/* validate access to device */</span> + <span class="n">file</span><span class="o">-></span><span class="n">private_data</span> <span class="o">=</span> <span class="n">my_data</span><span class="p">;</span> + + <span class="cm">/* initialize device */</span> + <span class="p">...</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>A problem that occurs when implementing the <code class="docutils literal"><span class="pre">open</span></code> function is access control. +Sometimes a device needs to be opened once at a time; More specifically, do not +allow the second open before the release. To implement this restriction, you +choose a way to handle an open call for an already open device: it can return +an error (<code class="docutils literal"><span class="pre">-EBUSY</span></code>), block open calls until a release operation, or shut down +the device before do the open.</p> +<p>At the user-space call of the open and close functions on the device, call +my_open and my_release in the driver. An example of a user-space call:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="n">fd</span> <span class="o">=</span> <span class="n">open</span><span class="p">(</span><span class="s">"/dev/my_device"</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="n">fd</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> +<span class="p">}</span> + +<span class="cm">/* do work */</span> +<span class="c1">//..</span> + +<span class="n">close</span><span class="p">(</span><span class="n">fd</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="read-and-write"> +<h2>Read and write<a class="headerlink" href="#read-and-write" title="Permalink to this headline">¶</a></h2> +<p>The read and write operations are reaching the device driver as a +result of an user-space program calling the read or write system calls:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="p">(</span><span class="n">read</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">buffer</span><span class="p">,</span> <span class="n">size</span><span class="p">)</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> +<span class="p">}</span> + +<span class="k">if</span> <span class="p">(</span><span class="n">write</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">buffer</span><span class="p">,</span> <span class="n">size</span><span class="p">)</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The <code class="docutils literal"><span class="pre">read</span></code> and <code class="docutils literal"><span class="pre">write</span></code> functions transfer data between the device and the +user-space: the read function reads the data from the device and transfers it +to the user-space, while writing reads the user-space data and writes it to the +device. The buffer received as a parameter is a user-space pointer, which is +why it is necessary to use the <code class="docutils literal"><span class="pre">copy_to_user</span></code> or <code class="docutils literal"><span class="pre">copy_from_user</span></code> functions.</p> +<p>The value returned by read or write can be:</p> +<blockquote> +<div><ul class="simple"> +<li>the number of bytes transferred; if the returned value is less than the size +parameter (the number of bytes requested), then it means that a partial +transfer was made. Most of the time, the user-space app calls the system call +(read or write) function until the required data number is transferred.</li> +<li>0 to mark the end of the file in the case of read ; if write returns the +value 0 then it means that no byte has been written and that no error has +occurred; In this case, the user-space application retries the write call.</li> +<li>a negative value indicating an error code.</li> +</ul> +</div></blockquote> +<p>To perform a data transfer consisting of several partial transfers, the +following operations should be performed:</p> +<blockquote> +<div><ul class="simple"> +<li>transfer the maximum number of possible bytes between the buffer received +as a parameter and the device (writing to the device/reading from the device +will be done from the offset received as a parameter);</li> +<li>update the offset received as a parameter to the position from which the +next read / write data will begin;</li> +<li>return the number of bytes transferred.</li> +</ul> +</div></blockquote> +<p>The sequence below shows an example for the read function that takes +into account the internal buffer size, user buffer size and the offset:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">my_read</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> <span class="kt">char</span> <span class="n">__user</span> <span class="o">*</span><span class="n">user_buffer</span><span class="p">,</span> + <span class="kt">size_t</span> <span class="n">size</span><span class="p">,</span> <span class="n">loff_t</span> <span class="o">*</span><span class="n">offset</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="n">my_data</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="p">)</span> <span class="n">file</span><span class="o">-></span><span class="n">private_data</span><span class="p">;</span> + <span class="kt">ssize_t</span> <span class="n">len</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">my_data</span><span class="o">-></span><span class="n">size</span> <span class="o">-</span> <span class="o">*</span><span class="n">offset</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">len</span> <span class="o"><=</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> + + <span class="cm">/* read data from my_data->buffer to user buffer */</span> + <span class="k">if</span> <span class="p">(</span><span class="n">copy_to_user</span><span class="p">(</span><span class="n">user_buffer</span><span class="p">,</span> <span class="n">my_data</span><span class="o">-></span><span class="n">buffer</span> <span class="o">+</span> <span class="o">*</span><span class="n">offset</span><span class="p">,</span> <span class="n">len</span><span class="p">))</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EFAULT</span><span class="p">;</span> + + <span class="o">*</span><span class="n">offset</span> <span class="o">+=</span> <span class="n">len</span><span class="p">;</span> + <span class="k">return</span> <span class="n">len</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The images below illustrate the read operation and how data is +transferred between the user-space and the driver:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>when the driver has enough data available (starting with the OFFSET +position) to accurately transfer the required size (SIZE) to the user.</li> +<li>when a smaller amount is transferred than required.</li> +</ol> +</div></blockquote> +<a class="reference internal image-reference" href="../_images/read1.png"><img alt="../_images/read1.png" src="../_images/read1.png" style="width: 49%;" /></a> +<a class="reference internal image-reference" href="../_images/read21.png"><img alt="../_images/read21.png" src="../_images/read21.png" style="width: 49%;" /></a> +<p>We can look at the read operation implemented by the driver as a response to a +user-space read request. In this case, the driver is responsible for advancing +the offset according to how much it reads and returning the read size (which +may be less than what is required).</p> +<p>The structure of the write function is similar:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">my_write</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">__user</span> <span class="o">*</span><span class="n">user_buffer</span><span class="p">,</span> + <span class="kt">size_t</span> <span class="n">size</span><span class="p">,</span> <span class="n">loff_t</span> <span class="o">*</span> <span class="n">offset</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="n">my_data</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="p">)</span> <span class="n">file</span><span class="o">-></span><span class="n">private_data</span><span class="p">;</span> + <span class="kt">ssize_t</span> <span class="n">len</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">my_data</span><span class="o">-></span><span class="n">size</span> <span class="o">-</span> <span class="o">*</span><span class="n">offset</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">len</span> <span class="o"><=</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> + + <span class="cm">/* read data from user buffer to my_data->buffer */</span> + <span class="k">if</span> <span class="p">(</span><span class="n">copy_from_user</span><span class="p">(</span><span class="n">my_data</span><span class="o">-></span><span class="n">buffer</span> <span class="o">+</span> <span class="o">*</span><span class="n">offset</span><span class="p">,</span> <span class="n">user_buffer</span><span class="p">,</span> <span class="n">len</span><span class="p">))</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EFAULT</span><span class="p">;</span> + + <span class="o">*</span><span class="n">offset</span> <span class="o">+=</span> <span class="n">len</span><span class="p">;</span> + <span class="k">return</span> <span class="n">len</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The write operation will respond to a write request from user-space. In +this case, depending on the maximum driver capacity (MAXSIZ), it can +write more or less than the required size.</p> +<a class="reference internal image-reference" href="../_images/write1.png"><img alt="../_images/write1.png" src="../_images/write1.png" style="width: 49%;" /></a> +<a class="reference internal image-reference" href="../_images/write21.png"><img alt="../_images/write21.png" src="../_images/write21.png" style="width: 49%;" /></a> +</div> +<div class="section" id="ioctl-1"> +<span id="ioctl"></span><h2>ioctl<a class="headerlink" href="#ioctl-1" title="Permalink to this headline">¶</a></h2> +<p>In addition to read and write operations, a driver needs the ability to perform +certain physical device control tasks. These operations are accomplished by +implementing a <code class="docutils literal"><span class="pre">ioctl</span></code> function. Initially, the ioctl system call used Big Kernel +Lock. That's why the call was gradually replaced with its unlocked version +called <code class="docutils literal"><span class="pre">unlocked_ioctl</span></code>. You can read more on LWN: +<a class="reference external" href="http://lwn.net/Articles/119652/">http://lwn.net/Articles/119652/</a></p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">long</span> <span class="nf">my_ioctl</span> <span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">cmd</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">arg</span><span class="p">);</span> +</pre></div> +</div> +<p><code class="docutils literal"><span class="pre">cmd</span></code> is the command sent from user-space. If a value is being sent from the +user-space call, it can be accessed directly. If a buffer is fetched, the arg +value will be a pointer to it, and must be accessed through the <code class="docutils literal"><span class="pre">copy_to_user</span></code> +or <code class="docutils literal"><span class="pre">copy_from_user</span></code>.</p> +<p>Before implementing the <code class="docutils literal"><span class="pre">ioctl</span></code> function, the numbers corresponding to the +commands must be chosen. One method is to choose consecutive numbers starting +at 0, but it is recommended to use <code class="docutils literal"><span class="pre">_IOC(dir,</span> <span class="pre">type,</span> <span class="pre">nr,</span> <span class="pre">size)</span></code> macro definition +to generate ioctl codes. The macro definition parameters are as follows:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">dir</span></code> represents the data transfer (<code class="docutils literal"><span class="pre">_IOC_NONE</span></code> , <code class="docutils literal"><span class="pre">_IOC_READ</span></code>, +<code class="docutils literal"><span class="pre">_IOC_WRITE</span></code>).</li> +<li><code class="docutils literal"><span class="pre">type</span></code> represents the magic number (<code class="docutils literal"><span class="pre">Documentation/ioctl/ioctl-number.txt</span></code>);</li> +<li><code class="docutils literal"><span class="pre">nr</span></code> is the ioctl code for the device;</li> +<li><code class="docutils literal"><span class="pre">size</span></code> is the size of the transferred data.</li> +</ul> +</div></blockquote> +<p>The following example shows an implementation for a <code class="docutils literal"><span class="pre">ioctl</span></code> function:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><asm/ioctl.h></span><span class="cp"></span> + +<span class="cp">#define MY_IOCTL_IN _IOC(_IOC_WRITE, 'k', 1, sizeof(my_ioctl_data))</span> + +<span class="k">static</span> <span class="kt">long</span> <span class="nf">my_ioctl</span> <span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">cmd</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">arg</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="n">my_data</span> <span class="o">=</span> + <span class="p">(</span><span class="k">struct</span> <span class="n">my_device_data</span><span class="o">*</span><span class="p">)</span> <span class="n">file</span><span class="o">-></span><span class="n">private_data</span><span class="p">;</span> + <span class="n">my_ioctl_data</span> <span class="n">mid</span><span class="p">;</span> + + <span class="k">switch</span><span class="p">(</span><span class="n">cmd</span><span class="p">)</span> <span class="p">{</span> + <span class="k">case</span> <span class="nl">MY_IOCTL_IN</span><span class="p">:</span> + <span class="k">if</span><span class="p">(</span> <span class="n">copy_from_user</span><span class="p">(</span><span class="o">&</span><span class="n">mid</span><span class="p">,</span> <span class="p">(</span><span class="n">my_ioctl_data</span> <span class="o">*</span><span class="p">)</span> <span class="n">arg</span><span class="p">,</span> + <span class="k">sizeof</span><span class="p">(</span><span class="n">my_ioctl_data</span><span class="p">))</span> <span class="p">)</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EFAULT</span><span class="p">;</span> + + <span class="cm">/* process data and execute command */</span> + + <span class="k">break</span><span class="p">;</span> + <span class="k">default</span><span class="o">:</span> + <span class="k">return</span> <span class="o">-</span><span class="n">ENOTTY</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>At the user-space call for the ioctl function, the my_ioctl function of the +driver will be called. An example of such a user-space call:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="p">(</span><span class="n">ioctl</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">MY_IOCTL_IN</span><span class="p">,</span> <span class="n">buffer</span><span class="p">)</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="waiting-queues"> +<h2>Waiting queues<a class="headerlink" href="#waiting-queues" title="Permalink to this headline">¶</a></h2> +<p>It is often necessary for a thread to wait for an operation to finish, +but it is desirable that this wait is not busy-waiting. Using waiting +queues we can block a thread until an event occurs. When the condition +is satisfied, elsewhere in the kernel, in another process, in an +interrupt or deferrable work, we will wake up the process.</p> +<p>A waiting queue is a list of processes that are waiting for a specific +event. A queue is defined with the <code class="docutils literal"><span class="pre">wait_queue_head_t</span></code> type and can +be used by the functions/macros:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/wait.h></span><span class="cp"></span> + +<span class="n">DECLARE_WAIT_QUEUE_HEAD</span><span class="p">(</span><span class="n">wq_name</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">init_waitqueue_head</span><span class="p">(</span><span class="n">wait_queue_head_t</span> <span class="o">*</span><span class="n">q</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">wait_event</span><span class="p">(</span><span class="n">wait_queue_head_t</span> <span class="n">q</span><span class="p">,</span> <span class="kt">int</span> <span class="n">condition</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">wait_event_interruptible</span><span class="p">(</span><span class="n">wait_queue_head_t</span> <span class="n">q</span><span class="p">,</span> <span class="kt">int</span> <span class="n">condition</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">wait_event_timeout</span><span class="p">(</span><span class="n">wait_queue_head_t</span> <span class="n">q</span><span class="p">,</span> <span class="kt">int</span> <span class="n">condition</span><span class="p">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">wait_event_interruptible_timeout</span><span class="p">(</span><span class="n">wait_queue_head_t</span> <span class="n">q</span><span class="p">,</span> <span class="kt">int</span> <span class="n">condition</span><span class="p">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">wake_up</span><span class="p">(</span><span class="n">wait_queue_head_t</span> <span class="o">*</span><span class="n">q</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">wake_up_interruptible</span><span class="p">(</span><span class="n">wait_queue_head_t</span> <span class="o">*</span><span class="n">q</span><span class="p">);</span> +</pre></div> +</div> +<p>The roles of the macros / functions above are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">init_waitqueue_head()</span></code> initializes the queue; to initialize the +queue at compile time, you can use the <code class="xref c c-macro docutils literal"><span class="pre">DECLARE_WAIT_QUEUE_HEAD</span></code> macro;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">wait_event()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">wait_event_interruptible()</span></code> adds the current thread to the +queue while the condition is false, sets it to TASK_UNINTERRUPTIBLE or +TASK_INTERRUPTIBLE and calls the scheduler to schedule a new thread; Waiting +will be interrupted when another thread will call the wake_up function;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">wait_event_timeout()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">wait_event_interruptible_timeout()</span></code> have the same +effect as the above functions, only waiting can be interrupted at the end of +the timeout received as a parameter;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">wake_up()</span></code> puts all threads off from state TASK_INTERRUPTIBLE and +TASK_UNINTERRUPTIBLE in TASK_RUNNING status; Remove these threads from the +queue;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">wake_up_interruptible()</span></code> same action, but only threads with TASK_INTERRUPTIBLE +status are woken up.</li> +</ul> +</div></blockquote> +<p>A simple example is that of a thread waiting to change the value of a flag. The +initializations are done by the sequence:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/sched.h></span><span class="cp"></span> + +<span class="n">wait_queue_head_t</span> <span class="n">wq</span><span class="p">;</span> +<span class="kt">int</span> <span class="n">flag</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + +<span class="n">init_waitqueue_head</span><span class="p">(</span><span class="o">&</span><span class="n">wq</span><span class="p">);</span> +</pre></div> +</div> +<p>A thread will wait for the flag to be changed to a value other than zero:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">wait_event_interruptible</span><span class="p">(</span><span class="n">wq</span><span class="p">,</span> <span class="n">flag</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">);</span> +</pre></div> +</div> +<p>While another thread will change the flag value and wake up the waiting threads:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">flag</span> <span class="o">=</span> <span class="mi">1</span> <span class="p">;</span> +<span class="n">wake_up_interruptible</span> <span class="p">(</span><span class="o">&</span><span class="n">wq</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is device_drivers. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/device_drivers/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="section" id="intro"> +<h3>0. Intro<a class="headerlink" href="#intro" title="Permalink to this headline">¶</a></h3> +<p>Using <a class="reference external" href="http://elixir.free-electrons.com/linux/latest/source">LXR</a> find the definitions +of the following symbols in the Linux kernel:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">generic_ro_fops</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">vfs_read()</span></code></li> +</ul> +</div></blockquote> +</div> +<div class="section" id="register-unregister"> +<h3>1. Register/unregister<a class="headerlink" href="#register-unregister" title="Permalink to this headline">¶</a></h3> +<p>The driver will control a single device with the <code class="docutils literal"><span class="pre">MY_MAJOR</span></code> major and +<code class="docutils literal"><span class="pre">MY_MINOR</span></code> minor (the macros defined in the kernel/so2_cdev.c file).</p> +<blockquote> +<div><ol class="arabic"> +<li><p class="first">Create <strong>/dev/so2_cdev</strong> character device node using <strong>mknod</strong>.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Read <a class="reference internal" href="#majors-and-minors">Majors and minors</a> section in the lab.</p> +</div> +</li> +<li><p class="first">Implement the registration and deregistration of the device with the name +<code class="docutils literal"><span class="pre">so2_cdev</span></code>, respectively in the init and exit module functions. Implement <strong>TODO 1</strong>.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Read the section <a class="reference internal" href="#registration-and-unregistration-of-character-devices">Registration and unregistration of character devices</a></p> +</div> +</li> +<li><p class="first">Display, using <code class="docutils literal"><span class="pre">pr_info</span></code>, a message after the registration and unregistration +operations to confirm that they were successful. Then load the module into the kernel:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ insmod so2_cdev.ko +</pre></div> +</div> +<p>And see character devices in <code class="docutils literal"><span class="pre">/proc/devices</span></code>:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ cat /proc/devices <span class="p">|</span> less +</pre></div> +</div> +<p>Identify the device type registered with major 42 . Note that <code class="docutils literal"><span class="pre">/proc/devices</span></code> +contains only the device types (major) but not the actual devices (i.e. minors).</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>Entries in /dev are not created by loading the module. These can be created +in two ways:</p> +<ul class="last simple"> +<li>manually, using the <code class="docutils literal"><span class="pre">mknod</span></code> command as we did above.</li> +<li>automatically using udev daemon</li> +</ul> +</div> +</li> +<li><p class="first">Unload the kernel module</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>rmmod so2_cdev +</pre></div> +</div> +</li> +</ol> +</div></blockquote> +</div> +<div class="section" id="register-an-already-registered-major"> +<h3>2. Register an already registered major<a class="headerlink" href="#register-an-already-registered-major" title="Permalink to this headline">¶</a></h3> +<p>Modify <strong>MY_MAJOR</strong> so that it points to an already used major number.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">See <code class="docutils literal"><span class="pre">/proc/devices</span></code> to get an already assigned major.</p> +</div> +<p>See <a class="reference external" href="http://elixir.free-electrons.com/linux/v4.9/source/include/uapi/asm-generic/errno-base.h">errno-base.h</a> +and figure out what does the error code mean. +Return to the initial configuration of the module.</p> +</div> +<div class="section" id="open-and-close"> +<h3>3. Open and close<a class="headerlink" href="#open-and-close" title="Permalink to this headline">¶</a></h3> +<p>Run <code class="docutils literal"><span class="pre">cat</span> <span class="pre">/dev/so2_cdev</span></code> to read data from our char device. +Reading does not work because the driver does not have the open function implemented. +Follow comments marked with TODO 2 and implement them.</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Initialize your device<ul> +<li>add a cdev struct field to <code class="docutils literal"><span class="pre">so2_device_data</span></code> structure.</li> +<li>Read the section <a class="reference internal" href="#registration-and-unregistration-of-character-devices">Registration and unregistration of character devices</a> in the lab.</li> +</ul> +</li> +<li>Implement the open and release functions in the driver.</li> +<li>Display a message in the open and release functions.</li> +<li>Read again <code class="docutils literal"><span class="pre">/dev/so2_cdev</span></code> file. Follow the messages displayed by the kernel. +We still get an error because <code class="docutils literal"><span class="pre">read</span></code> function is not yet implemented.</li> +</ol> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The prototype of a device driver's operations is in the <code class="docutils literal"><span class="pre">file_operations</span></code> +structure. Read <a class="reference internal" href="#open-and-release">Open and release</a> section.</p> +</div> +</div> +<div class="section" id="access-restriction"> +<h3>4. Access restriction<a class="headerlink" href="#access-restriction" title="Permalink to this headline">¶</a></h3> +<p>Restrict access to the device with atomic variables, so that a single process +can open the device at a time. The rest will receive the "device busy" error +(<code class="docutils literal"><span class="pre">-EBUSY</span></code>). Restricting access will be done in the open function displayed by +the driver. Follow comments marked with <strong>TODO 3</strong> and implement them.</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Add an <code class="docutils literal"><span class="pre">atomic_t</span></code> variable to the device structure.</li> +<li>Initialize the variable at module initialization.</li> +<li>Use the variable in the open function to restrict access to the device. We +recommend using <code class="xref c c-func docutils literal"><span class="pre">atomic_cmpxchg()</span></code>.</li> +<li>Reset the variable in the release function to retrieve access to the device.</li> +<li>To test your deployment, you'll need to simulate a long-term use of your +device. To simulate a sleep, call the scheduler at the end of the device opening:</li> +</ol> +</div></blockquote> +<div class="highlight-bash"><div class="highlight"><pre><span></span>set_current_state<span class="o">(</span>TASK_INTERRUPTIBLE<span class="o">)</span><span class="p">;</span> +schedule_timeout<span class="o">(</span><span class="m">1000</span><span class="o">)</span><span class="p">;</span> +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The advantage of the atomic_cmpxchg function is that it can check the +old value of the variable and set it up to a new value, all in one +atomic operation. Read more details about <a class="reference external" href="https://www.khronos.org/registry/OpenCL/sdk/1.1/docs/man/xhtml/atomic_cmpxchg.html">atomic_cmpxchg</a> +An example of use is <a class="reference external" href="http://elixir.free-electrons.com/linux/v4.9/source/lib/dump_stack.c#L24">here</a>.</p> +</div> +</div> +<div class="section" id="read-operation"> +<h3>5. Read operation<a class="headerlink" href="#read-operation" title="Permalink to this headline">¶</a></h3> +<p>Implement the read function in the driver. Follow comments marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">4</span></code> and implement them.</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Keep a buffer in <code class="docutils literal"><span class="pre">so2_device_data</span></code> structure initialized with the value of <code class="docutils literal"><span class="pre">MESSAGE</span></code> macro. +Initializing this buffer will be done in module <code class="docutils literal"><span class="pre">init</span></code> function.</li> +<li>At a read call, copy the contents of the kernel space buffer into the user +space buffer.<ul> +<li>Use the <code class="xref c c-func docutils literal"><span class="pre">copy_to_user()</span></code> function to copy information from kernel space to +user space.</li> +<li>Ignore the size and offset parameters at this time. You can assume that +the buffer in user space is large enough. You do not need to check the +validity of the size argument of the read function.</li> +<li>The value returned by the read call is the number of bytes transmitted +from the kernel space buffer to the user space buffer.</li> +</ul> +</li> +<li>After implementation, test using <code class="docutils literal"><span class="pre">cat</span> <span class="pre">/dev/so2_cdev</span></code>.</li> +</ol> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The command <code class="docutils literal"><span class="pre">cat</span> <span class="pre">/dev/so2_cdev</span></code> does not end (use Ctrl+C). +Read the <a class="reference internal" href="#read-and-write">read and write</a> sections and <a class="reference internal" href="#access-to-the-address-space-of-the-process">Access to the address space of the process</a> +If you want to display the offset value use a construction of the form: +<code class="docutils literal"><span class="pre">pr_info("Offset:</span> <span class="pre">%lld</span> <span class="pre">\n",</span> <span class="pre">*offset)</span></code>; The data type loff_t (used by offset ) is a typedef for long long int.</p> +</div> +<p>The <code class="docutils literal"><span class="pre">cat</span></code> command reads to the end of the file, and the end of the file is +signaled by returning the value 0 in the read. Thus, for a correct implementation, +you will need to update and use the offset received as a parameter in the read +function and return the value 0 when the user has reached the end of the buffer.</p> +<p>Modify the driver so that the <code class="docutils literal"><span class="pre">cat</span></code> commands ends:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Use the size parameter.</li> +<li>For every read, update the offset parameter accordingly.</li> +<li>Ensure that the read function returns the number of bytes that were copied +into the user buffer.</li> +</ol> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">By dereferencing the offset parameter it is possible to read and move the current +position in the file. Its value needs to be updated every time a read is done +successfully.</p> +</div> +</div> +<div class="section" id="write-operation"> +<h3>6. Write operation<a class="headerlink" href="#write-operation" title="Permalink to this headline">¶</a></h3> +<p>Add the ability to write a message into kernel buffer to replace the predefined message. Implement +the write function in the driver. Follow comments marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">5</span></code></p> +<p>Ignore the offset parameter at this time. You can assume that the driver buffer is +large enough. You do not need to check the validity of the write function size +argument.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The prototype of a device driver's operations is in the file_operations +structure. +Test using commands:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nb">echo</span> <span class="s2">"arpeggio"</span>> /dev/so2_cdev +cat /dev/so2_cdev +</pre></div> +</div> +<p class="last">Read the <a class="reference internal" href="#read-and-write">read and write</a> sections and <a class="reference internal" href="#access-to-the-address-space-of-the-process">Access to the address space of the process</a></p> +</div> +</div> +<div class="section" id="ioctl-operation"> +<h3>7. ioctl operation<a class="headerlink" href="#ioctl-operation" title="Permalink to this headline">¶</a></h3> +<p>For this exercise, we want to add the ioctl <code class="docutils literal"><span class="pre">MY_IOCTL_PRINT</span></code> to display the +message from the <code class="docutils literal"><span class="pre">IOCTL_MESSAGE</span></code> macro in the driver. +Follow the comments marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">6</span></code></p> +<p>For this:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Implement the ioctl function in the driver.</li> +<li>We need to use <code class="docutils literal"><span class="pre">user/so2_cdev_test.c</span></code> to call the +ioctl function with the appropriate parameters.</li> +<li>To test, we will use an user-space program (<code class="docutils literal"><span class="pre">user/so2_cdev_test.c</span></code>) +which will call the <code class="docutils literal"><span class="pre">ioctl</span></code> function with the required arguments.</li> +</ol> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The macro <code class="docutils literal"><span class="pre">MY_IOCTL_PRINT</span></code> is defined in the file <code class="docutils literal"><span class="pre">include/so2_cdev.h</span></code>, +which is shared between the kernel module and the user-space program.</p> +<p class="last">Read the <a class="reference internal" href="#ioctl">ioctl</a> section in the lab.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The user-space code is compiled automatically at <code class="docutils literal"><span class="pre">make</span> <span class="pre">build</span></code> and +copied at <code class="docutils literal"><span class="pre">make</span> <span class="pre">copy</span></code>.</p> +<p class="last">Because we need to compile the program for qemu machine which is 32 bit, +if your host is 64 bit then you need to install <code class="docutils literal"><span class="pre">gcc-multilib</span></code> package.</p> +</div> +</div> +</div> +<div class="section" id="extra-exercises"> +<h2>Extra Exercises<a class="headerlink" href="#extra-exercises" title="Permalink to this headline">¶</a></h2> +<div class="section" id="ioctl-with-messaging"> +<h3>Ioctl with messaging<a class="headerlink" href="#ioctl-with-messaging" title="Permalink to this headline">¶</a></h3> +<p>Add two ioctl operations to modify the message associated with the +driver. Use fixed-length buffer ( BUFFER_SIZE ).</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Add the <code class="docutils literal"><span class="pre">ioctl</span></code> function from the driver the following operations:<ul> +<li><code class="docutils literal"><span class="pre">MY_IOCTL_SET_BUFFER</span></code> for writing a message to the device;</li> +<li><code class="docutils literal"><span class="pre">MY_IOCTL_GET_BUFFER</span></code> to read a message from your device.</li> +</ul> +</li> +<li>For testing, pass the required command line arguments to the +user-space program.</li> +</ol> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Read the <a class="reference internal" href="#ioctl">ioctl</a> and <a class="reference internal" href="#access-to-the-address-space-of-the-process">Access to the address space of the process</a> +sections of the lab.</p> +</div> +</div> +<div class="section" id="ioctl-with-waiting-queues"> +<h3>Ioctl with waiting queues<a class="headerlink" href="#ioctl-with-waiting-queues" title="Permalink to this headline">¶</a></h3> +<p>Add two ioctl operations to the device driver for queuing.</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Add the <code class="docutils literal"><span class="pre">ioctl</span></code> function from the driver the following operations:<ul> +<li><code class="docutils literal"><span class="pre">MY_IOCTL_DOWN</span></code> to add the process to a queue;</li> +<li><code class="docutils literal"><span class="pre">MY_IOCTL_UP</span></code> to remove the process from a queue.</li> +</ul> +</li> +<li>Fill the device structure with a <code class="docutils literal"><span class="pre">wait_queue_head_t</span></code> field and a flag.</li> +<li>Do not forget to initialize the wait queue and flag.</li> +<li>Remove exclusive access condition from previous exercise</li> +<li>For testing, pass the required command line arguments to the +user-space program.</li> +</ol> +</div></blockquote> +<p>When the process is added to the queue, it will remain blocked in execution; To +run the queue command open a new console in the virtual machine with Alt+F2 ; +You can return to the previous console with Alt+F1. If you're connected via +SSH to the virtual machine, open a new console.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Read the <a class="reference internal" href="#ioctl">ioctl</a> and <a class="reference internal" href="#waiting-queues">Waiting queues</a> sections in the lab.</p> +</div> +</div> +<div class="section" id="o-nonblock-implementation"> +<h3>O_NONBLOCK implementation<a class="headerlink" href="#o-nonblock-implementation" title="Permalink to this headline">¶</a></h3> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>If a file is open with the <code class="docutils literal"><span class="pre">O_NONBLOCK</span></code> flag, then its +operations will be non-blocking.</p> +<p>In case data is not available when performing a read, the following +happens:</p> +<blockquote class="last"> +<div><ul class="simple"> +<li>if the file has been open with <code class="docutils literal"><span class="pre">O_NONBLOCK</span></code>, the read call +will return <code class="docutils literal"><span class="pre">-EWOULDBLOCK</span></code>.</li> +<li>otherwise, the current task (process) will be placed in a waiting +queue and will be unblocked as soon as data becomes available +(in our case, at write).</li> +</ul> +</div></blockquote> +</div> +<ul class="simple"> +<li>To allow unblocking the read operation, remove the exclusive access +condition from previous exercises.</li> +<li>You can use the queue defined for the previous exercise.</li> +<li>You can ignore the file offset.</li> +<li>Modify the initial size of data to <code class="docutils literal"><span class="pre">0</span></code>, to allow testing.</li> +<li>For testing, pass the required command line arguments to the +user-space program.<ul> +<li>when using the <code class="docutils literal"><span class="pre">n</span></code> option, the test program will change the open flags +to <code class="docutils literal"><span class="pre">O_NONBLOCK</span></code> and then perform a <code class="docutils literal"><span class="pre">read</span></code>.</li> +</ul> +</li> +<li>What are the flags used to open the file when running <code class="docutils literal"><span class="pre">cat</span> <span class="pre">/dev/so2_dev</span></code>?</li> +</ul> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lab2-kernel-api.html" class="btn btn-neutral float-left" title="SO2 Lab 02 - Kernel API" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lab4-interrupts.html" class="btn btn-neutral float-right" title="SO2 Lab 04 - I/O access and Interrupts" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lab4-interrupts.html b/refs/pull/405/merge/so2/lab4-interrupts.html new file mode 100644 index 00000000..ae95c548 --- /dev/null +++ b/refs/pull/405/merge/so2/lab4-interrupts.html @@ -0,0 +1,1291 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lab 04 - I/O access and Interrupts — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lab 05 - Deferred work" href="lab5-deferred-work.html" /> + <link rel="prev" title="SO2 Lab 03 - Character device drivers" href="lab3-device-drivers.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lab 04 - I/O access and Interrupts</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#background-information">Background information</a></li> +<li class="toctree-l3"><a class="reference internal" href="#accessing-the-hardware">Accessing the hardware</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#request-access-to-i-o-ports">Request access to I/O ports</a></li> +<li class="toctree-l4"><a class="reference internal" href="#accessing-i-o-ports">Accessing I/O ports</a></li> +<li class="toctree-l4"><a class="reference internal" href="#accessing-i-o-ports-from-userspace">5. Accessing I/O ports from userspace</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#interrupt-handling">Interrupt handling</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#requesting-an-interrupt">Requesting an interrupt</a></li> +<li class="toctree-l4"><a class="reference internal" href="#implementing-an-interrupt-handler">Implementing an interrupt handler</a></li> +<li class="toctree-l4"><a class="reference internal" href="#locking">Locking</a></li> +<li class="toctree-l4"><a class="reference internal" href="#interrupt-statistics">Interrupt statistics</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#further-reading">Further reading</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#serial-port">Serial Port</a></li> +<li class="toctree-l4"><a class="reference internal" href="#parallel-port">Parallel port</a></li> +<li class="toctree-l4"><a class="reference internal" href="#keyboard-controller">Keyboard controller</a></li> +<li class="toctree-l4"><a class="reference internal" href="#linux-device-drivers">Linux device drivers</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#intro">0. Intro</a></li> +<li class="toctree-l4"><a class="reference internal" href="#keyboard-driver">Keyboard driver</a></li> +<li class="toctree-l4"><a class="reference internal" href="#request-the-i-o-ports">1. Request the I/O ports</a></li> +<li class="toctree-l4"><a class="reference internal" href="#interrupt-handling-routine">2. Interrupt handling routine</a></li> +<li class="toctree-l4"><a class="reference internal" href="#store-ascii-keys-to-buffer">3. Store ASCII keys to buffer</a></li> +<li class="toctree-l4"><a class="reference internal" href="#reading-the-buffer">4. Reading the buffer</a></li> +<li class="toctree-l4"><a class="reference internal" href="#reset-the-buffer">5. Reset the buffer</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#extra-exercises">Extra Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#kfifo">1. kfifo</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lab 04 - I/O access and Interrupts</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lab4-interrupts.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lab-04-i-o-access-and-interrupts"> +<h1>SO2 Lab 04 - I/O access and Interrupts<a class="headerlink" href="#so2-lab-04-i-o-access-and-interrupts" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>communication with peripheral devices</li> +<li>implement interrupt handlers</li> +<li>synchronizing interrupts with process context</li> +</ul> +<p>Keywords: IRQ, I/O port, I/O address, base address, UART, request_region, release_region, inb, outb</p> +</div> +<div class="section" id="background-information"> +<h2>Background information<a class="headerlink" href="#background-information" title="Permalink to this headline">¶</a></h2> +<p>A peripheral device is controlled by writing and reading its +registers. Often, a device has multiple registers that can be accessed +at consecutive addresses either in the memory address space or in the +I/O address space. Each device connected to the I/O bus has a set of +I/O addresses, called I/O ports. I/O ports can be mapped to physical +memory addresses so that the processor can communicate with the device +through instructions that work directly with the memory. For +simplicity, we will directly use I/O ports (without mapping to physical +memory addresses) to communicate with physical devices.</p> +<p>The I/O ports of each device are structured into a set of specialized +registers to provide a uniform programming interface. Thus, most +devices will have the following types of registers:</p> +<ul class="simple"> +<li><strong>Control</strong> registers that receive device commands</li> +<li><strong>Status</strong> registers, which contain information about the device's +internal status</li> +<li><strong>Input</strong> registers from which data is taken from the device</li> +<li><strong>Output</strong> registers in which the data is written to transmit it to the +device</li> +</ul> +<p>Physical ports are differentiated by the number of bits: they can be +8, 16 or 32-bit ports.</p> +<p>For example, the parallel port has 8 8-bit I/O ports starting at base +address 0x378. The data log is found at base address (0x378), status +register at base + 1 (0x379), and control at base address + 2 +(0x37a). The data log is both an entry and exit log.</p> +<p>Although there are devices that can be fully controlled using I/O +ports or special memory areas, there are situations where this is +insufficient. The main problem that needs to be addressed is that +certain events occur at undefined moments in time and it is +inefficient for the processor (CPU) to interrogate the status of the +device repeatedly (polling). The way to solve this problem is using an +Interrupt ReQuest (IRQ) which is a hardware notification by which the +processor is announced that a particular external event happened.</p> +<p>For IRQs to be useful device drivers must implement handlers, i.e. a +particular sequence of code that handles the interrupt. Because in +many situations the number of interrupts available is limited, a +device driver must behave in an orderly fashion with interruptions: +interrupts must be requested before being used and released when they +are no longer needed. In addition, in some situations, device drivers +must share an interrupt or synchronize with interrupts. All of these will be +discussed further.</p> +<p>When we need to access shared resources between an interrupt +routine (A) and code running in process context or in bottom-half +context (B), we must use a special synchronization technique. In (A) +we need to use a spinlock primitive, and in (B) we must disable +interrupts AND use a spinlock primitive. Disabling interrupts is not +enough because the interrupt routine can run on a processor other than +the one running (B).</p> +<p>Using only a spinlock can lead to a deadlock. The classic example of +deadlock in this case is:</p> +<ol class="arabic simple"> +<li>We run a process on the X processor, and we acquire the lock</li> +<li>Before releasing the lock, an interrupt is generated on the X processor</li> +<li>The interrupt handling routine will try to acquire the lock and it +will go into an infinite loop</li> +</ol> +</div> +<div class="section" id="accessing-the-hardware"> +<h2>Accessing the hardware<a class="headerlink" href="#accessing-the-hardware" title="Permalink to this headline">¶</a></h2> +<p>In Linux, the I/O ports access is implemented on all architectures and +there are several APIs that can be used.</p> +<div class="section" id="request-access-to-i-o-ports"> +<h3>Request access to I/O ports<a class="headerlink" href="#request-access-to-i-o-ports" title="Permalink to this headline">¶</a></h3> +<p>Before accessing I/O ports we first must request access to them, to +make sure there is only one user. In order to do so, one must use the +<code class="xref c c-func docutils literal"><span class="pre">request_region()</span></code> function:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/ioport.h></span><span class="cp"></span> + +<span class="k">struct</span> <span class="n">resource</span> <span class="o">*</span><span class="nf">request_region</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">first</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">n</span><span class="p">,</span> + <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">);</span> +</pre></div> +</div> +<p>To release a reserved region one must use the <code class="xref c c-func docutils literal"><span class="pre">release_region()</span></code> function:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">release_region</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">start</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">n</span><span class="p">);</span> +</pre></div> +</div> +<p>For example, the serial port COM1 has the base address 0x3F8 and it +has 8 ports and this is a code snippet of how to request access to +these ports:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/ioport.h></span><span class="cp"></span> + +<span class="cp">#define MY_BASEPORT 0x3F8</span> +<span class="cp">#define MY_NR_PORTS 8</span> + +<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">request_region</span><span class="p">(</span><span class="n">MY_BASEPORT</span><span class="p">,</span> <span class="n">MY_NR_PORTS</span><span class="p">,</span> <span class="s">"com1"</span><span class="p">))</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> + <span class="k">return</span> <span class="o">-</span><span class="n">ENODEV</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>To release the ports one would use something like:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">release_region</span><span class="p">(</span><span class="n">MY_BASEPORT</span><span class="p">,</span> <span class="n">MY_NR_PORTS</span><span class="p">);</span> +</pre></div> +</div> +<p>Most of the time, port requests are done at the driver initialization +or probe time and the port releasing is done at the removal of the +device or module.</p> +<p>All of the port requests can be seen from userspace via the +<code class="file docutils literal"><span class="pre">/proc/ioports</span></code> file:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>$ cat /proc/ioports +<span class="m">0000</span>-001f : dma1 +<span class="m">0020</span>-0021 : pic1 +<span class="m">0040</span>-005f : timer +<span class="m">0060</span>-006f : keyboard +<span class="m">0070</span>-0077 : rtc +<span class="m">0080</span>-008f : dma page reg +00a0-00a1 : pic2 +00c0-00df : dma2 +00f0-00ff : fpu +<span class="m">0170</span>-0177 : ide1 +01f0-01f7 : ide0 +<span class="m">0376</span>-0376 : ide1 +<span class="m">0378</span>-037a : parport0 +037b-037f : parport0 +03c0-03df : vga+ +03f6-03f6 : ide0 +03f8-03ff : serial +... +</pre></div> +</div> +</div> +<div class="section" id="accessing-i-o-ports"> +<h3>Accessing I/O ports<a class="headerlink" href="#accessing-i-o-ports" title="Permalink to this headline">¶</a></h3> +<p>After a driver has obtained the desired I/O port range, one can +perform read or write operations on these ports. Since physical ports +are differentiated by the number of bits (8, 16, or 32 bits), there +are different port access functions depending on their size. The +following port access functions are defined in asm/io.h:</p> +<ul class="simple"> +<li><em>unsigned inb(int port)</em>, reads one byte (8 bits) from port</li> +<li><em>void outb(unsigned char byte, int port)</em>, writes one byte (8 bits) to port</li> +<li><em>unsigned inw(int port)</em>, reads two bytes (16-bit) ports</li> +<li><em>void outw(unsigned short word, int port)</em>, writes two bytes (16-bits) to port</li> +<li><em>unsigned inl (int port)</em>, reads four bytes (32-bits) from port</li> +<li><em>void outl(unsigned long word, int port)</em>, writes four bytes (32-bits) to port</li> +</ul> +<p>The port argument specifies the address of the port where the reads or +writes are done, and its type is platform dependent (may be unsigned +long or unsigned short).</p> +<p>Some devices may have problems when the processor is trying to +transfer data too fast to and from the device. To avoid this issue we +may need to insert a delay after an I/O operation and there are functions +you can use that introduce this delay. Their names are similar to +those described above, with the exception that it ends in _p: inb_p, +outb_p, etc.</p> +<p>For example, the following sequence writes a byte on COM1 serial port +and then reads it:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><asm/io.h></span><span class="cp"></span> +<span class="cp">#define MY_BASEPORT 0x3F8</span> + +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">value</span> <span class="o">=</span> <span class="mh">0xFF</span><span class="p">;</span> +<span class="n">outb</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">MY_BASEPORT</span><span class="p">);</span> +<span class="n">value</span> <span class="o">=</span> <span class="n">inb</span><span class="p">(</span><span class="n">MY_BASEPORT</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="accessing-i-o-ports-from-userspace"> +<h3>5. Accessing I/O ports from userspace<a class="headerlink" href="#accessing-i-o-ports-from-userspace" title="Permalink to this headline">¶</a></h3> +<p>Although the functions described above are defined for device drivers, +they can also be used in user space by including the <sys/io.h> +header. In order to be used, ioperm or iopl must first be called to +get permission to perform port operations. The ioperm function obtains +permission for individual ports, while iopl for the entire I/O address +space. To use these features, the user must be root.</p> +<p>The following sequence used in user space gets permission for the +first 3 ports of the serial port, and then releases them:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><sys/io.h></span><span class="cp"></span> +<span class="cp">#define MY_BASEPORT 0x3F8</span> + +<span class="k">if</span> <span class="p">(</span><span class="n">ioperm</span><span class="p">(</span><span class="n">MY_BASEPORT</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> +<span class="p">}</span> + +<span class="k">if</span> <span class="p">(</span><span class="n">ioperm</span><span class="p">(</span><span class="n">MY_BASEPORT</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span> <span class="p">{</span> + <span class="cm">/* handle error */</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The third parameter of the ioperm function is used to request or +release port permission: 1 to get permission and 0 to release.</p> +</div> +</div> +<div class="section" id="interrupt-handling"> +<h2>Interrupt handling<a class="headerlink" href="#interrupt-handling" title="Permalink to this headline">¶</a></h2> +<div class="section" id="requesting-an-interrupt"> +<h3>Requesting an interrupt<a class="headerlink" href="#requesting-an-interrupt" title="Permalink to this headline">¶</a></h3> +<p>As with other resources, a driver must gain access to an interrupt +line before it can use it and release it at the end of the execution.</p> +<p>In Linux, the request to obtain and release an interrupt is done using +the <code class="xref c c-func docutils literal"><span class="pre">requests_irq()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">free_irq()</span></code> functions:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/interrupt.h></span><span class="cp"></span> + +<span class="k">typedef</span> <span class="nf">irqreturn_t</span> <span class="p">(</span><span class="o">*</span><span class="n">irq_handler_t</span><span class="p">)(</span><span class="kt">int</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">request_irq</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">irq_no</span><span class="p">,</span> <span class="n">irq_handler_t</span> <span class="n">handler</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">dev_name</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">dev_id</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">free_irq</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">irq_no</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">dev_id</span><span class="p">);</span> +</pre></div> +</div> +<p>Note that to get an interrupt, the developer calls +<code class="xref c c-func docutils literal"><span class="pre">request_irq()</span></code>. When calling this function you must specify the +interrupt number (<em>irq_no</em>), a handler that will be called when the +interrupt is generated (<em>handler</em>), flags that will instruct the +kernel about the desired behaviour (<em>flags</em>), the name of the device +using this interrupt (<em>dev_name</em>), and a pointer that can be +configured by the user at any value, and that has no global +significance (<em>dev_id</em>). Most of the time, <em>dev_id</em> will be +pointer to the device driver's private data. When the interrupt is +released, using the <code class="xref c c-func docutils literal"><span class="pre">free_irq()</span></code> function, the developer must +send the same pointer value (<em>dev_id</em>) along with the same interrupt +number (<em>irq_no</em>). The device name (<em>dev_name</em>) is used to display +statistics in <em>/proc/interrupts</em>.</p> +<p>The value that <code class="xref c c-func docutils literal"><span class="pre">request_irq()</span></code> returns is 0 if the entry was +successful or a negative error code indicating the reason for the +failure. A typical value is <em>-EBUSY</em> which means that the interrupt +was already requested by another device driver.</p> +<p>The <em>handler</em> function is executed in interrupt context which means +that we can't call blocking APIs such as <code class="xref c c-func docutils literal"><span class="pre">mutex_lock()</span></code> or +<code class="xref c c-func docutils literal"><span class="pre">msleep()</span></code>. We must also avoid doing a lot of work in the +interrupt handler and instead use deferred work if needed. The actions +performed in the interrupt handler include reading the device +registers to get the status of the device and acknowledge the +interrupt, operations that most of the time can be performed with +non-blocking calls.</p> +<p>There are situations where although a device uses interrupts we can't +read the device's registers in a non-blocking mode (for example a +sensor connected to an I2C or SPI bus whose driver does not guarantee +that bus read / write operations are non-blocking ). In this +situation, in the interruption, we must plan a work-in-process action +(work queue, kernel thread) to access the device's registers. Because +such a situation is relatively common, the kernel provides the +<code class="xref c c-func docutils literal"><span class="pre">request_threaded_irq()</span></code> function to write interrupt handling +routines running in two phases: a process-phase and an interrupt +context phase:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/interrupt.h></span><span class="cp"></span> + +<span class="kt">int</span> <span class="nf">request_threaded_irq</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">irq</span><span class="p">,</span> <span class="n">irq_handler_t</span> <span class="n">handler</span><span class="p">,</span> + <span class="n">irq_handler_t</span> <span class="n">thread_fn</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">dev</span><span class="p">);</span> +</pre></div> +</div> +<p><em>handler</em> is the function running in interrupt context, and will +implement critical operations while the thread_fn function runs in +process context and implements the rest of the operations.</p> +<p>The flags that can be transmitted when an interruption is made are:</p> +<ul class="simple"> +<li><em>IRQF_SHARED</em> announces the kernel that the interrupt can be +shared with other devices. If this flag is not set, then if there is +already a handler associated with the requested interrupt, the +request for interrupt will fail. A shared interrupt is handled in a +special way by the kernel: all the associated interrupt handlers +will be executed until the device that generated the interrupt will +be identified. But how can a device driver know if the interrupt +handling routine was activated by an interrupt generated by the +device it manages? Virtually all devices that offer interrupt +support have a status register that can be interrogated in the +handling routine to see if the interrupt was or was not generated by +the device (for example, in the case of the 8250 serial port, this +status register is IIR - Interrupt Information Register). When +requesting a shared interrupt, the dev_id argument must be unique +and it must not be NULL. Usually it is set to module's private +data.</li> +<li><em>IRQF_ONESHOT</em> interrupt will be reactivated after running the process +context routine; Without this flag, the interrupt will be +reactivated after running the handler routine in the context of +the interrupt</li> +</ul> +<p>Requesting the interrupt can be done either at the initialization of +the driver (<code class="xref c c-func docutils literal"><span class="pre">init_module()</span></code>), when the device is probed, or when +the device is used (e.g. during <em>open</em>).</p> +<p>The following example performs the interrupt request for the COM1 +serial port:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/interrupt.h></span><span class="cp"></span> + +<span class="cp">#define MY_BASEPORT 0x3F8</span> +<span class="cp">#define MY_IRQ 4</span> + +<span class="k">static</span> <span class="nf">my_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="p">[...]</span> + <span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="n">my_data</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">err</span><span class="p">;</span> + + <span class="n">err</span> <span class="o">=</span> <span class="n">request_irq</span><span class="p">(</span><span class="n">MY_IRQ</span><span class="p">,</span> <span class="n">my_handler</span><span class="p">,</span> <span class="n">IRQF_SHARED</span><span class="p">,</span> + <span class="s">"com1"</span><span class="p">,</span> <span class="n">my_data</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* handle error*/</span> + <span class="k">return</span> <span class="n">err</span><span class="p">;</span> + <span class="p">}</span> + <span class="p">[...]</span> +<span class="p">}</span> +</pre></div> +</div> +<p>As you can see, the IRQ for serial port COM1 is 4, which is used in +shared mode (IRQF_SHARED).</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">When requesting a shared interrupt (IRQF_SHARED) the +<em>dev_id</em> argument can not be NULL.</p> +</div> +<p>To release the interrupt associated with the serial port, the +following operations will be executed:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">free_irq</span> <span class="p">(</span><span class="n">MY_IRQ</span><span class="p">,</span> <span class="n">my_data</span><span class="p">);</span> +</pre></div> +</div> +<p>During the initialization function (<code class="xref c c-func docutils literal"><span class="pre">init_module()</span></code>), or in the +function that opens the device, interrupts must be activated for the +device. This operation is dependent on the device, but most often +involves setting a bit from the control register.</p> +<p>As an example, for the 8250 serial port, the following operations must +be performed to enable interrupts:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><asm/io.h></span><span class="cp"></span> +<span class="cp">#define MY_BASEPORT 0x3F8</span> + +<span class="n">outb</span><span class="p">(</span><span class="mh">0x08</span><span class="p">,</span> <span class="n">MY_BASEPORT</span><span class="o">+</span><span class="mi">4</span><span class="p">);</span> +<span class="n">outb</span><span class="p">(</span><span class="mh">0x01</span><span class="p">,</span> <span class="n">MY_BASEPORT</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span> +</pre></div> +</div> +<p>In the above example, two operations are performed:</p> +<ol class="arabic simple"> +<li>All interruptions are activated by setting bit 3 (Aux Output 2) in +the MCR register - Modem Control Register</li> +<li>The RDAI (Transmit Holding Register Empty Interrupt) is activated +by setting the appropriate bit in the IER - Interrupt Enable +Register.</li> +</ol> +</div> +<div class="section" id="implementing-an-interrupt-handler"> +<h3>Implementing an interrupt handler<a class="headerlink" href="#implementing-an-interrupt-handler" title="Permalink to this headline">¶</a></h3> +<p>Lets take a look at the signature of the interrupt handler function:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">irqreturn_t</span> <span class="p">(</span><span class="o">*</span><span class="n">handler</span><span class="p">)(</span><span class="kt">int</span> <span class="n">irq_no</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">dev_id</span><span class="p">);</span> +</pre></div> +</div> +<p>The function receives as parameters the number of the interrupt +(<em>irq_no</em>) and the pointer sent to <code class="xref c c-func docutils literal"><span class="pre">request_irq()</span></code> when the +interrupt was requested. The interrupt handling routine must return a +value with a type of <code class="xref c c-type docutils literal"><span class="pre">typedef</span> <span class="pre">irqreturn_t</span></code>. For the current kernel +version, there are three valid values: <em>IRQ_NONE</em>, <em>IRQ_HANDLED</em>, +and <em>IRQ_WAKE_THREAD</em>. The device driver must return <em>IRQ_NONE</em> if +it notices that the interrupt has not been generated by the device it +is in charge. Otherwise, the device driver must return <em>IRQ_HANDLED</em> +if the interrupt can be handled directly from the interrupt context or +<em>IRQ_WAKE_THREAD</em> to schedule the running of the process context +processing function.</p> +<p>The skeleton for an interrupt handler is:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">irqreturn_t</span> <span class="nf">my_handler</span><span class="p">(</span><span class="kt">int</span> <span class="n">irq_no</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">dev_id</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="n">my_data</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span><span class="p">)</span> <span class="n">dev_id</span><span class="p">;</span> + + <span class="cm">/* if interrupt is not for this device (shared interrupts) */</span> + <span class="cm">/* return IRQ_NONE;*/</span> + + <span class="cm">/* clear interrupt-pending bit */</span> + <span class="cm">/* read from device or write to device*/</span> + + <span class="k">return</span> <span class="n">IRQ_HANDLED</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Typically, the first thing executed in the interrupt handler is to +determine whether the interrupt was generated by the device that the +driver ordered. This usually reads information from the device's +registers to indicate whether the device has generated an +interrupt. The second thing is to reset the interrupt pending bit on +the physical device as most devices will no longer generate +interruptions until this bit has been reset (e.g. for the 8250 +serial port bit 0 in the IIR register must be cleared).</p> +</div> +<div class="section" id="locking"> +<h3>Locking<a class="headerlink" href="#locking" title="Permalink to this headline">¶</a></h3> +<p>Because the interrupt handlers run in interrupt context the actions +that can be performed are limited: unable to access user space memory, +can't call blocking functions. Also, synchronization using spinlocks is +tricky and can lead to deadlocks if the spinlock used is already +acquired by a process that has been interrupted by the running +handler.</p> +<p>However, there are cases where device drivers have to synchronize +using interrupts, such as when data is shared between the interrupt +handler and process context or bottom-half handlers. In these +situations it is necessary to both deactivate the interrupt and use +spinlocks.</p> +<p>There are two ways to disable interrupts: disabling all interrupts, at +the processor level, or disabling a particular interrupt at the device +or interrupt controller level. Processor disabling is faster and is +therefore preferred. For this purpose, there are locking functions +that disable and enable interrupts acquiring and release a spinlock at +the same time: <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock_irqrestore()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irq()</span></code>, and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock_irq()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/spinlock.h></span><span class="cp"></span> + +<span class="kt">void</span> <span class="nf">spin_lock_irqsave</span> <span class="p">(</span><span class="n">spinlock_t</span> <span class="o">*</span> <span class="n">lock</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">spin_unlock_irqrestore</span> <span class="p">(</span><span class="n">spinlock_t</span> <span class="o">*</span> <span class="n">lock</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">spin_lock_irq</span> <span class="p">(</span><span class="n">spinlock_t</span> <span class="o">*</span> <span class="n">lock</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">spin_unlock_irq</span> <span class="p">(</span><span class="n">spinlock_t</span> <span class="o">*</span> <span class="n">lock</span><span class="p">);</span> +</pre></div> +</div> +<p>The <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> function disables interrupts for the +local processor before it obtains the spinlock; The previous state of +the interrupts is saved in <em>flags</em>.</p> +<p>If you are absolutely sure that the interrupts on the current +processor have not already been disabled by someone else and you are +sure you can activate the interrupts when you release the spinlock, +you can use <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irq()</span></code>.</p> +<p>For read / write spinlocks there are similar functions available:</p> +<ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">read_lock_irqsave()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">read_unlock_irqrestore()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">read_lock_irq()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">read_unlock_irq()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">write_lock_irqsave()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">write_unlock_irqrestore()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">write_lock_irq()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">write_unlock_irq()</span></code></li> +</ul> +<p>If we want to disable interrupts at the interrupt controller level +(not recommended because disabling a particular interrupt is slower, +we can not disable shared interrupts) we can do this with +<code class="xref c c-func docutils literal"><span class="pre">disable_irq()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">disable_irq_nosync()</span></code>, and +<code class="xref c c-func docutils literal"><span class="pre">enable_irq()</span></code>. Using these functions will disable the interrupts on +all processors. Calls can be nested: if disable_irq is called twice, +it will require as many calls enable_irq to enable it. The difference +between disable_irq and disable_irq_nosync is that the first one will +wait for the executed handlers to finish. Because of this, +<code class="xref c c-func docutils literal"><span class="pre">disable_irq_nosync()</span></code> is generally faster, but may lead to +races with the interrupts handler, so when not sure use +<code class="xref c c-func docutils literal"><span class="pre">disable_irq()</span></code>.</p> +<p>The following sequence disables and then enables the interrupt for +the COM1 serial port:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define MY_IRQ 4</span> + +<span class="n">disable_irq</span> <span class="p">(</span><span class="n">MY_IRQ</span><span class="p">);</span> +<span class="n">enable_irq</span> <span class="p">(</span><span class="n">MY_IRQ</span><span class="p">);</span> +</pre></div> +</div> +<p>It is also possible to disable interrupts at the device level. This +approach is also slower than disabling interrupts at the processor +level, but it works with shared interrupts. The way to accomplish this +is device specific and it usually means we have to clear a bit from +one of the control registers.</p> +<p>It is also possible to disable all interrupts for the current +processor independent of taking locks. Disabling all interruptions by +device drivers for synchronization purposes is inappropriate because +races are still possible if the interrupt is handled on another +CPU. For reference, the functions that disable / enable interrupts on +the local processor are <code class="xref c c-func docutils literal"><span class="pre">local_irq_disable()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">local_irq_enable()</span></code>.</p> +<p>In order to use a resource shared between process context and the +interrupt handling routine, the functions described above will be used +as follows:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">spinlock_t</span> <span class="n">lock</span><span class="p">;</span> + +<span class="cm">/* IRQ handling routine: interrupt context */</span> +<span class="n">irqreturn_t</span> <span class="nf">kbd_interrupt_handle</span><span class="p">(</span><span class="kt">int</span> <span class="n">irq_no</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span> <span class="n">dev_id</span><span class="p">)</span> +<span class="p">{</span> + <span class="p">...</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> + <span class="cm">/* Critical region - access shared resource */</span> + <span class="n">spin_unlock</span> <span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> + <span class="p">...</span> +<span class="p">}</span> + +<span class="cm">/* Process context: Disable interrupts when locking */</span> +<span class="k">static</span> <span class="kt">void</span> <span class="nf">my_access</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + + <span class="n">spin_lock_irqsave</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="cm">/* Critical region - access shared resource */</span> + <span class="n">spin_unlock_irqrestore</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + + <span class="p">...</span> +<span class="p">}</span> + +<span class="kt">void</span> <span class="nf">my_init</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="p">...</span> + <span class="n">spin_lock_init</span> <span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> + <span class="p">...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The <em>my_access function</em> above runs in process context. To +synchronize access to the shared data, we disable the interrupts and +use the spinlock <em>lock</em>, i.e. the <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock_irqrestore()</span></code> functions.</p> +<p>In the interrupt handling routine, we use the <code class="xref c c-func docutils literal"><span class="pre">spin_lock()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock()</span></code> functions to access the shared resource.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The <em>flags</em> argument for <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock_irqrestore()</span></code> is a value and not a pointer but keep +in mind that <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> function changes the value of +the flag, since this is actually a macro.</p> +</div> +</div> +<div class="section" id="interrupt-statistics"> +<h3>Interrupt statistics<a class="headerlink" href="#interrupt-statistics" title="Permalink to this headline">¶</a></h3> +<p>Information and statistics about system interrupts can be found in +<em>/proc/interrupts</em> or <em>/proc/stat</em>. Only system interrupts with +associated interrupt handlers appear in <em>/proc/interrupts</em>:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span><span class="c1"># cat /proc/interrupts</span> + CPU0 +<span class="m">0</span>: <span class="m">7514294</span> IO-APIC-edge timer +<span class="m">1</span>: <span class="m">4528</span> IO-APIC-edge i8042 +<span class="m">6</span>: <span class="m">2</span> IO-APIC-edge floppy +<span class="m">8</span>: <span class="m">1</span> IO-APIC-edge rtc +<span class="m">9</span>: <span class="m">0</span> IO-APIC-level acpi +<span class="m">12</span>: <span class="m">2301</span> IO-APIC-edge i8042 +<span class="m">15</span>: <span class="m">41</span> IO-APIC-edge ide1 +<span class="m">16</span>: <span class="m">3230</span> IO-APIC-level ioc0 +<span class="m">17</span>: <span class="m">1016</span> IO-APIC-level vmxnet ether +NMI: <span class="m">0</span> +LOC: <span class="m">7229438</span> +ERR: <span class="m">0</span> +MIS: <span class="m">0</span> +</pre></div> +</div> +<p>The first column specifies the IRQ associated with the interrupt. The +following column shows the number of interrupts that were generated +for each processor in the system; The last two columns provide +information about the interrupt controller and the device name that +registered the handler for that interrupt.</p> +<p>The <em>/proc/state</em> file provides information about system activity, +including the number of interruptions generated since the last (re)boot +of the system:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span><span class="c1"># cat /proc/stat | grep in</span> +intr <span class="m">7765626</span> <span class="m">7754228</span> <span class="m">4620</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">2</span> <span class="m">0</span> <span class="m">1</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">2377</span> <span class="m">0</span> <span class="m">0</span> <span class="m">41</span> <span class="m">3259</span> <span class="m">1098</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> +<span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> +<span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> +<span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> +<span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> +<span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> <span class="m">0</span> +</pre></div> +</div> +<p>Each line in the <em>/proc/state</em> file begins with a keyword that +specifies the meaning of the information on the line. For information +on interrupts, this keyword is intr. The first number on the line +represents the total number of interrupts, and the other numbers +represent the number of interrupts for each IRQ, starting at 0. The +counter includes the number of interrupts for all processors in the +system.</p> +</div> +</div> +<div class="section" id="further-reading"> +<h2>Further reading<a class="headerlink" href="#further-reading" title="Permalink to this headline">¶</a></h2> +<div class="section" id="serial-port"> +<h3>Serial Port<a class="headerlink" href="#serial-port" title="Permalink to this headline">¶</a></h3> +<ul class="simple"> +<li><a class="reference external" href="http://en.wikipedia.org/wiki/Serial_port">Serial Port</a></li> +<li><a class="reference external" href="http://www.beyondlogic.org/serial/serial.htm">Interfacing the Serial / RS232 Port</a></li> +</ul> +</div> +<div class="section" id="parallel-port"> +<h3>Parallel port<a class="headerlink" href="#parallel-port" title="Permalink to this headline">¶</a></h3> +<ul class="simple"> +<li><a class="reference external" href="http://www.beyondlogic.org/spp/parallel.htm">Interfacing the Standard Parallel Port</a></li> +<li><a class="reference external" href="http://www.lvr.com/parport.htm">Parallel Port Central</a></li> +</ul> +</div> +<div class="section" id="keyboard-controller"> +<h3>Keyboard controller<a class="headerlink" href="#keyboard-controller" title="Permalink to this headline">¶</a></h3> +<ul class="simple"> +<li><a class="reference external" href="http://en.wikipedia.org/wiki/Intel_8042">Intel 8042</a></li> +<li>drivers/input/serio/i8042.c</li> +<li>drivers/input/keyboard/atkbd.c</li> +</ul> +</div> +<div class="section" id="linux-device-drivers"> +<h3>Linux device drivers<a class="headerlink" href="#linux-device-drivers" title="Permalink to this headline">¶</a></h3> +<ul class="simple"> +<li><a class="reference external" href="http://lwn.net/images/pdf/LDD3/ch09.pdf">Linux Device Drivers, 3rd ed., Ch. 9 - Communicating with Hardware</a></li> +<li><a class="reference external" href="http://lwn.net/images/pdf/LDD3/ch10.pdf">Linux Device Drivers, 3rd ed., Ch. 10 - Interrupt Handling</a></li> +<li><a class="reference external" href="http://tldp.org/LDP/lkmpg/2.6/html/x1256.html">Interrupt Handlers</a></li> +</ul> +</div> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is interrupts. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/interrupts/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="section" id="intro"> +<h3>0. Intro<a class="headerlink" href="#intro" title="Permalink to this headline">¶</a></h3> +<p>Using <a class="reference external" href="http://elixir.free-electrons.com/linux/latest/source">LXR</a>, find the definitions of the following symbols in the Linux kernel:</p> +<ul class="simple"> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">resource</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">request_region()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">__request_region()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">request_irq()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">request_threaded_irq()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">inb()</span></code> for the x86 architecture.</li> +</ul> +<p>Analyze the following Linux code:</p> +<ul class="simple"> +<li>Keyboard initialization function <code class="xref c c-func docutils literal"><span class="pre">i8042_setup_kbd()</span></code></li> +<li>The AT or PS/2 keyboard interrupt function <code class="xref c c-func docutils literal"><span class="pre">atkbd_interrupt()</span></code></li> +</ul> +</div> +<div class="section" id="keyboard-driver"> +<h3>Keyboard driver<a class="headerlink" href="#keyboard-driver" title="Permalink to this headline">¶</a></h3> +<p>The next exercise's objective is to create a driver that uses the +keyboard IRQ, inspect the incoming key codes and stores them in a +buffer. The buffer will be accessible from userspace via character +device driver.</p> +</div> +<div class="section" id="request-the-i-o-ports"> +<h3>1. Request the I/O ports<a class="headerlink" href="#request-the-i-o-ports" title="Permalink to this headline">¶</a></h3> +<p>To start with, we aim to allocate memory in the I/O space for hardware +devices. We will see that we cannot allocate space for the keyboard +because the designated region is already allocated. Then we will allocate +I/O space for unused ports.</p> +<p>The <em>kbd.c</em> file contains a skeleton for the keyboard driver. Browse +the source code and inspect <code class="xref c c-func docutils literal"><span class="pre">kbd_init()</span></code>. Notice that the I/O +ports we need are I8042_STATUS_REG and I8042_DATA_REG.</p> +<p>Follow the sections maked with <strong>TODO 1</strong> in the skeleton. Request the I/O +ports in <code class="xref c c-func docutils literal"><span class="pre">kbd_init()</span></code> and make sure to check for errors and to properly +clean-up in case of errors. When requesting, set the reserving caller's ID +string (<code class="docutils literal"><span class="pre">name</span></code>) with <code class="docutils literal"><span class="pre">MODULE_NAME</span></code> macro. Also, add code to release the I/O +ports in <code class="xref c c-func docutils literal"><span class="pre">kbd_exit()</span></code>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">You can review the <a class="reference internal" href="#request-access-to-i-o-ports">Request access to I/O ports</a> section before +proceeding.</p> +</div> +<p>Now build the module and copy it to the VM image:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +tools/labs $ make copy +</pre></div> +</div> +<p>Now start the VM and insert the module:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>root@qemux86:~# insmod skels/interrupts/kbd.ko +kbd: loading out-of-tree module taints kernel. +insmod: can't insert 'skels/interrupts/kbd.ko': Device or resource busy +</pre></div> +</div> +<p>Notice that you get an error when trying to request the I/O +ports. This is because we already have a driver that has requested the +I/O ports. To validate check the <code class="file docutils literal"><span class="pre">/proc/ioports</span></code> file for the +<code class="docutils literal"><span class="pre">STATUS_REG</span></code> and <code class="docutils literal"><span class="pre">DATA_REG</span></code> values:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>root@qemux86:~# cat /proc/ioports <span class="p">|</span> egrep <span class="s2">"(0060|0064)"</span> +<span class="m">0060</span>-0060 : keyboard +<span class="m">0064</span>-0064 : keyboard +</pre></div> +</div> +<p>Lets find out which driver register these ports and try to remove the +module associated with it.</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>$ find -name <span class="se">\*</span>.c <span class="p">|</span> xargs grep <span class="se">\"</span>keyboard<span class="se">\"</span> + +find -name <span class="se">\*</span>.c <span class="p">|</span> xargs grep <span class="se">\"</span>keyboard<span class="se">\"</span> <span class="p">|</span> egrep <span class="s1">'(0x60|0x64)'</span> +... +./arch/x86/kernel/setup.c:<span class="o">{</span> .name <span class="o">=</span> <span class="s2">"keyboard"</span>, .start <span class="o">=</span> 0x60, .end <span class="o">=</span> 0x60, +./arch/x86/kernel/setup.c:<span class="o">{</span> .name <span class="o">=</span> <span class="s2">"keyboard"</span>, .start <span class="o">=</span> 0x64, .end <span class="o">=</span> 0x64 +</pre></div> +</div> +<p>It looks like the I/O ports are registered by the kernel during the +boot, and we won't be able to remove the associated module. Instead, +let's trick the kernel and register ports 0x61 and 0x65.</p> +<p>Use the function <code class="xref c c-func docutils literal"><span class="pre">request_region()</span></code> (inside the <code class="xref c c-func docutils literal"><span class="pre">kbd_init()</span></code> +function) to allocate the ports and the function <code class="xref c c-func docutils literal"><span class="pre">release_region()</span></code> +(inside the <code class="xref c c-func docutils literal"><span class="pre">kbd_exit()</span></code> function) to release the allocated memory.</p> +<p>This time we can load the module and <em>/proc/ioports</em> shows that the +owner of these ports is our module:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>root@qemux86:~# insmod skels/interrupts/kbd.ko +kbd: loading out-of-tree module taints kernel. +Driver kbd loaded +root@qemux86:~# cat /proc/ioports <span class="p">|</span> grep kbd +<span class="m">0061</span>-0061 : kbd +<span class="m">0065</span>-0065 : kbd +</pre></div> +</div> +<p>Let's remove the module and check that the I/O ports are released:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>root@qemux86:~# rmmod kbd +Driver kbd unloaded +root@qemux86:~# cat /proc/ioports <span class="p">|</span> grep kbd +root@qemux86:~# +</pre></div> +</div> +</div> +<div class="section" id="interrupt-handling-routine"> +<h3>2. Interrupt handling routine<a class="headerlink" href="#interrupt-handling-routine" title="Permalink to this headline">¶</a></h3> +<p>For this task we will implement and register an interrupt handler for +the keyboard interrupt. You can review the <a class="reference internal" href="#requesting-an-interrupt">Requesting an interrupt</a> +section before proceeding.</p> +<p>Follow the sections marked with <strong>TODO 2</strong> in the skeleton.</p> +<p>First, define an empty interrupt handling routine named +<code class="xref c c-func docutils literal"><span class="pre">kbd_interrupt_handler()</span></code>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Since we already have a driver that uses this interrupt we +should report the interrupt as not handled (i.e. return +<code class="xref c c-type docutils literal"><span class="pre">IRQ_NONE</span></code>) so that the original driver still has a +chance to process it.</p> +</div> +<p>Then register the interrupt handler routine using +<code class="xref c c-type docutils literal"><span class="pre">request_irq</span></code>. The interrupt number is defined by the +<cite>I8042_KBD_IRQ</cite> macro. The interrupt handling routine must be +requested with <code class="xref c c-type docutils literal"><span class="pre">IRQF_SHARED</span></code> to share the interrupt line with +the keyboard driver (i8042).</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>For shared interrupts, <em>dev_id</em> can not be NULL . Use +<code class="docutils literal"><span class="pre">&devs[0]</span></code>, that is pointer to <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">kbd</span></code>. This +structure contains all the information needed for device +management. To see the interrupt in <em>/proc/interrupts</em>, do +not use NULL for <em>dev_name</em> . You can use the MODULE_NAME +macro.</p> +<p class="last">If the interrupt requesting fails make sure to properly +cleanup by jumping to the right label, in this case the one +the releases the I/O ports and continues with unregistering +the character device driver.</p> +</div> +<p>Compile, copy and load module in the kernel. Check that the interrupt +line has been registered by looking at <em>/proc/interrupts</em> . Determine +the IRQ number from the source code (see <cite>I8042_KBD_IRQ</cite>) and verify +that there are two drivers registered at this interrupt line (which +means that we have a shared interrupt line): the i8042 initial driver +and our driver.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">More details about the format of the <em>/proc/interrupts</em> can +be found in the <a class="reference internal" href="#interrupt-statistics">Interrupt statistics</a> section.</p> +</div> +<p>Print a message inside the routine to make sure it is called. Compile +and reload the module into the kernel. Check that the interrupt handling +routine is called when you press the keyboard on the virtual machine, +using <strong class="command">dmesg</strong>. Also note that when you use the serial port no +keyboard interrupt is generated.</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">To get access to the keyboard on the virtual machine +boot with "QEMU_DISPLAY=gtk make boot".</p> +</div> +</div> +<div class="section" id="store-ascii-keys-to-buffer"> +<h3>3. Store ASCII keys to buffer<a class="headerlink" href="#store-ascii-keys-to-buffer" title="Permalink to this headline">¶</a></h3> +<p>Next, we want to collect the keystrokes in a buffer whose content we +will then send to the user space. For this routine we will add the +following in the interrupt handling:</p> +<ul class="simple"> +<li>capture the pressed keys (only pressed, ignore released)</li> +<li>identify the ASCII characters.</li> +<li>copy the ASCII characters corresponding to the keystrokes and store +them in the buffer of the device</li> +</ul> +<p>Follow the sections marked <strong>TODO 3</strong> in the skeleton.</p> +<div class="section" id="reading-the-data-register"> +<h4>Reading the data register<a class="headerlink" href="#reading-the-data-register" title="Permalink to this headline">¶</a></h4> +<p>First, fill in the <code class="xref c c-func docutils literal"><span class="pre">i8042_read_data()</span></code> function to read the +<code class="docutils literal"><span class="pre">I8042_DATA_REG</span></code> of the keyboard controller. The function +just needs to return the value of the register. The value of the +registry is also called scancode, which is what is generated at each +keystroke.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Read the <code class="docutils literal"><span class="pre">I8042_DATA_REG</span></code> register using <code class="xref c c-func docutils literal"><span class="pre">inb()</span></code> and +store the value in the local variable <code class="xref c c-type docutils literal"><span class="pre">val</span></code>. +Revisit the <a class="reference internal" href="#accessing-i-o-ports">Accessing I/O ports</a> section.</p> +</div> +<p>Call the <code class="xref c c-func docutils literal"><span class="pre">i8042_read_data()</span></code> in the +<code class="xref c c-func docutils literal"><span class="pre">kbd_interrupt_handler()</span></code> and print the value read.</p> +<p>Print information about the keystrokes in the following format:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">pr_info</span><span class="p">(</span><span class="s">"IRQ:% d, scancode = 0x%x (%u,%c)</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> + <span class="n">irq_no</span><span class="p">,</span> <span class="n">scancode</span><span class="p">,</span> <span class="n">scancode</span><span class="p">,</span> <span class="n">scancode</span><span class="p">);</span> +</pre></div> +</div> +<p>Where scancode is the value of the read register using the +<code class="xref c c-func docutils literal"><span class="pre">i8042_read_data()</span></code> function.</p> +<p>Notice that the scancode (reading of the read register) is not an ASCII +character of the pressed key. We'll have to understand the scancode.</p> +</div> +<div class="section" id="interpreting-the-scancode"> +<h4>Interpreting the scancode<a class="headerlink" href="#interpreting-the-scancode" title="Permalink to this headline">¶</a></h4> +<p>Note that the registry value is a scancode, not the ASCII value of the +character pressed. Also note that an interrupt is sent both when the +key is pressed and when the key is released. We only need to select +the code when the key is pressed and then and decode the ASCII +character.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>To check scancode, we can use the showkey command (showkey +-s).</p> +<p>In this form, the command will display the key scancodes for +10 seconds after the last pressed key end then it will +stop. If you press and release a key you will get two +scancodes: one for the pressed key and one for the released +key. E.g:</p> +<ul class="last"> +<li><p class="first">If you press the ENTER key, you will get the 0x1c ( 0x1c ) +and 0x9c (for the released key)</p> +</li> +<li><p class="first">If you press the key a you will get the 0x1e (key pressed) +and 0x9e (for the key release)</p> +</li> +<li><p class="first">If you press b you will get 0x30 (key pressed) and 0xb0 +(for the release key)</p> +</li> +<li><p class="first">If you press the c key, you will get the 0x2e (key +pressed) 0xae and 0xae (for the released key)</p> +</li> +<li><p class="first">If you press the Shift key you will get the 0x2a (key +pressed) 0xaa and 0xaa (for the released key)</p> +</li> +<li><p class="first">If you press the Ctrl key you will get the 0x1d (key +pressed) and 0x9d (for the release key)</p> +<p>As also indicated in this <a class="reference external" href="http://www.linuxjournal.com/article/1080">article</a>, a key +release scancode is 128 (0x80) higher then a key press +scancode. This is how we can distinguish between a press +key scancode and a release scancode.</p> +<p>A scancode is translated into a keycode that matches a +key. A pressed scanned keycode and a released scancode +have the same keycode. For the keys shown above we have +the following table:</p> +<table border="1" class="docutils"> +<colgroup> +<col width="25%" /> +<col width="25%" /> +<col width="25%" /> +<col width="25%" /> +</colgroup> +<tbody valign="top"> +<tr class="row-odd"><td>Key</td> +<td>Key Press Scancode</td> +<td>Key Release Scancode</td> +<td>Keycode</td> +</tr> +<tr class="row-even"><td>ENTER</td> +<td>0x1c</td> +<td>0x9c</td> +<td>0x1c (28)</td> +</tr> +<tr class="row-odd"><td>a</td> +<td>0x1e</td> +<td>0x9e</td> +<td>0x1e (30)</td> +</tr> +<tr class="row-even"><td>b</td> +<td>0x30</td> +<td>0xb0</td> +<td>0x30 (48)</td> +</tr> +<tr class="row-odd"><td>c</td> +<td>0x2e</td> +<td>0xae</td> +<td>0x2e (46)</td> +</tr> +<tr class="row-even"><td>Shift</td> +<td>0x2a</td> +<td>0xaa</td> +<td>0x2a (42)</td> +</tr> +<tr class="row-odd"><td>Ctrl</td> +<td>0x1d</td> +<td>0x9d</td> +<td>0x1d (29)</td> +</tr> +</tbody> +</table> +<p>The press / release key is performed in the is_key_press() +function and obtaining the ASCII character of a scancode +takes place in the get_ascii() function.</p> +</li> +</ul> +</div> +<p>In the interrupt handler check the scancode to see if the key is +pressed or released then determine the corresponding ASCII +character.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">To check for press / release, use <code class="xref c c-func docutils literal"><span class="pre">is_key_press()</span></code>. +Use <code class="xref c c-func docutils literal"><span class="pre">get_ascii()</span></code> function to get the corresponding +ASCII code. Both functions expect the scancode.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>To display the received information use the following +format.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">pr_info</span><span class="p">(</span><span class="s">"IRQ %d: scancode=0x%x (%u) pressed=%d ch=%c</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> + <span class="n">irq_no</span><span class="p">,</span> <span class="n">scancode</span><span class="p">,</span> <span class="n">scancode</span><span class="p">,</span> <span class="n">pressed</span><span class="p">,</span> <span class="n">ch</span><span class="p">);</span> +</pre></div> +</div> +<p class="last">Where scancode is the value of the data register, and ch is +the value returned by the get_ascii() function.</p> +</div> +</div> +<div class="section" id="store-characters-to-the-buffer"> +<h4>Store characters to the buffer<a class="headerlink" href="#store-characters-to-the-buffer" title="Permalink to this headline">¶</a></h4> +<p>We want to collect the pressed characters (not the other keys) into +a circular buffer that can be consumed from user space.</p> +<p>Update the interrupt handler to add a pressed ASCII character to the +end of the device buffer. If the buffer is full, the character will be +discarded.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>The device buffer is the field <code class="xref c c-type docutils literal"><span class="pre">buf</span></code> in the device's +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">kbd</span></code>. To get the device data from the interrupt handler +use the following construct:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">kbd</span> <span class="o">*</span><span class="n">data</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">kbd</span> <span class="o">*</span><span class="p">)</span> <span class="n">dev_id</span><span class="p">;</span> +</pre></div> +</div> +<p class="last">The buffer's dimension is located in <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">kbd</span></code>'s field, +<code class="xref c c-type docutils literal"><span class="pre">count</span></code>. The <code class="xref c c-type docutils literal"><span class="pre">put_idx</span></code> and <code class="xref c c-type docutils literal"><span class="pre">get_idx</span></code> fields +specify the next writing and reading index. Take a look at the +<code class="xref c c-func docutils literal"><span class="pre">put_char()</span></code> function's implementation to observe how the data is +added to the circular buffer.</p> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p>Synchronize the access to the buffer and the helper +indexes with a spinlock. +Define the spinlock in the device struct <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">kbd</span></code> +and initialize it in <code class="xref c c-func docutils literal"><span class="pre">kbd_init()</span></code>.</p> +<p>Use the <code class="xref c c-func docutils literal"><span class="pre">spin_lock()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">spin_unlock()</span></code> functions +to protect the buffer in the interrupt handler.</p> +<p class="last">Revisit the <a class="reference internal" href="#locking">Locking</a> section.</p> +</div> +</div> +</div> +<div class="section" id="reading-the-buffer"> +<h3>4. Reading the buffer<a class="headerlink" href="#reading-the-buffer" title="Permalink to this headline">¶</a></h3> +<p>In order to have access to the keylogger's data, we have to send it to +the user space. We will do this using the <em>/dev/kbd</em> character device. When +reading from this device, we will get the data from the buffer in the kernel +space, where we collected the keys pressed.</p> +<p>For this step +follow the sections marked with <strong>TODO 4</strong> in the <code class="xref c c-func docutils literal"><span class="pre">kbd_read()</span></code> function.</p> +<p>Implement <code class="xref c c-func docutils literal"><span class="pre">get_char()</span></code> in a similar way to <code class="xref c c-func docutils literal"><span class="pre">put_char()</span></code>. Be careful +when implementing the circular buffer.</p> +<p>In the <code class="xref c c-func docutils literal"><span class="pre">kbd_read()</span></code> function copy the data from the buffer to the +userspace buffer.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use <code class="xref c c-func docutils literal"><span class="pre">get_char()</span></code> to read a character from the buffer +and <code class="xref c c-func docutils literal"><span class="pre">put_user()</span></code> to store it to the user buffer.</p> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p>In the read function, use <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock_irqrestore()</span></code> for locking.</p> +<p class="last">Revisit the <a class="reference internal" href="#locking">Locking</a> section.</p> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p>We cannot use <code class="xref c c-func docutils literal"><span class="pre">put_user()</span></code> or <code class="xref c c-func docutils literal"><span class="pre">copy_to_user()</span></code> +while holding the lock, as userpace access is not permitted from +atomic contexts.</p> +<p class="last">For more info, read the <span class="xref std std-ref">Access to the address space of the +process section</span> in the +previous lab.</p> +</div> +<p>For testing, you will need to create the <em>/dev/kbd</em> character device +driver using the mknod before reading from it. The device master and +minor are defined as <code class="docutils literal"><span class="pre">KBD_MAJOR</span></code> and <code class="docutils literal"><span class="pre">KBD_MINOR</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">mknod</span> <span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">kbd</span> <span class="n">c</span> <span class="mi">42</span> <span class="mi">0</span> +</pre></div> +</div> +<p>Build, copy and boot the virtual machine and load the module. Test it +using the command:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">cat</span> <span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">kbd</span> +</pre></div> +</div> +</div> +<div class="section" id="reset-the-buffer"> +<h3>5. Reset the buffer<a class="headerlink" href="#reset-the-buffer" title="Permalink to this headline">¶</a></h3> +<p>Reset the buffer if the device is written to. For this step follow the +sections marked with <strong>TODO 5</strong> in the skeleton.</p> +<p>Implement <code class="xref c c-func docutils literal"><span class="pre">reset_buffer()</span></code> and add the write operation to <em>kbd_fops</em>.</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p>In the write function Use <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock_irqrestore()</span></code> for locking when resetting the +buffer.</p> +<p class="last">Revisit the <a class="reference internal" href="#locking">Locking</a> section.</p> +</div> +<p>For testing, you will need to create the <em>/dev/kbd</em> character device +driver using the mknod before reading from it. The device master and +minor are defined as <code class="docutils literal"><span class="pre">KBD_MAJOR</span></code> and <code class="docutils literal"><span class="pre">KBD_MINOR</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">mknod</span> <span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">kbd</span> <span class="n">c</span> <span class="mi">42</span> <span class="mi">0</span> +</pre></div> +</div> +<p>Build, copy and boot the virtual machine and load the module. +Test it using the command:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">cat</span> <span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">kbd</span> +</pre></div> +</div> +<p>Press some keys, then run the command <strong class="command">echo "clear" > /dev/kbd</strong>. +Check the buffer's content again. It should be reset.</p> +</div> +</div> +<div class="section" id="extra-exercises"> +<h2>Extra Exercises<a class="headerlink" href="#extra-exercises" title="Permalink to this headline">¶</a></h2> +<div class="section" id="kfifo"> +<h3>1. kfifo<a class="headerlink" href="#kfifo" title="Permalink to this headline">¶</a></h3> +<p>Implement a keylogger using the +<a class="reference external" href="https://elixir.bootlin.com/linux/v4.15/source/include/linux/kfifo.h">kfifo API</a>.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Follow the <a class="reference external" href="https://elixir.bootlin.com/linux/v4.15/source/samples/kfifo">API call examples from the kernel code</a>. +For example, the file <a class="reference external" href="https://elixir.bootlin.com/linux/v4.15/source/samples/kfifo/bytestream-example.c">bytestream-examples.c</a>.</p> +</div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lab3-device-drivers.html" class="btn btn-neutral float-left" title="SO2 Lab 03 - Character device drivers" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lab5-deferred-work.html" class="btn btn-neutral float-right" title="SO2 Lab 05 - Deferred work" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lab5-deferred-work.html b/refs/pull/405/merge/so2/lab5-deferred-work.html new file mode 100644 index 00000000..f46d32dc --- /dev/null +++ b/refs/pull/405/merge/so2/lab5-deferred-work.html @@ -0,0 +1,1107 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lab 05 - Deferred work — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lab 06 - Memory Mapping" href="lab6-memory-mapping.html" /> + <link rel="prev" title="SO2 Lab 04 - I/O access and Interrupts" href="lab4-interrupts.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lab 05 - Deferred work</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#background-information">Background information</a></li> +<li class="toctree-l3"><a class="reference internal" href="#softirqs">Softirqs</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#tasklets">Tasklets</a></li> +<li class="toctree-l4"><a class="reference internal" href="#timers">Timers</a></li> +<li class="toctree-l4"><a class="reference internal" href="#locking">Locking</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#workqueues">Workqueues</a></li> +<li class="toctree-l3"><a class="reference internal" href="#kernel-threads">Kernel threads</a></li> +<li class="toctree-l3"><a class="reference internal" href="#further-reading">Further reading</a></li> +<li class="toctree-l3"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#intro">0. Intro</a></li> +<li class="toctree-l4"><a class="reference internal" href="#timer">1.Timer</a></li> +<li class="toctree-l4"><a class="reference internal" href="#periodic-timer">2. Periodic timer</a></li> +<li class="toctree-l4"><a class="reference internal" href="#timer-control-using-ioctl">3. Timer control using ioctl</a></li> +<li class="toctree-l4"><a class="reference internal" href="#blocking-operations">4. Blocking operations</a></li> +<li class="toctree-l4"><a class="reference internal" href="#workqueues-1">5. Workqueues</a></li> +<li class="toctree-l4"><a class="reference internal" href="#kernel-thread">6. Kernel thread</a></li> +<li class="toctree-l4"><a class="reference internal" href="#buffer-shared-between-timer-and-process">7. Buffer shared between timer and process</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lab 05 - Deferred work</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lab5-deferred-work.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lab-05-deferred-work"> +<h1>SO2 Lab 05 - Deferred work<a class="headerlink" href="#so2-lab-05-deferred-work" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>Understanding deferred work (i.e. code scheduled to be executed at a +later time)</li> +<li>Implementation of common tasks that uses deferred work</li> +<li>Understanding the peculiarities of synchronization for deferred work</li> +</ul> +<p>Keywords: softirq, tasklet, struct tasklet_struct, bottom-half +handlers, jiffies, HZ, timer, struct timer_list, spin_lock_bh, +spin_unlock_bh, workqueue, struct work_struct, kernel thread, events/x</p> +</div> +<div class="section" id="background-information"> +<h2>Background information<a class="headerlink" href="#background-information" title="Permalink to this headline">¶</a></h2> +<p>Deferred work is a class of kernel facilities that allows one to +schedule code to be executed at a later timer. This scheduled code can +run either in the process context or in interruption context depending +on the type of deferred work. Deferred work is used to complement the +interrupt handler functionality since interrupts have important +requirements and limitations:</p> +<ul class="simple"> +<li>The execution time of the interrupt handler must be as small as +possible</li> +<li>In interrupt context we can not use blocking calls</li> +</ul> +<p>Using deferred work we can perform the minimum required work in the +interrupt handler and schedule an asynchronous action from the +interrupt handler to run at a later time and execute the rest of the +operations.</p> +<p>Deferred work that runs in interrupt context is also known as +bottom-half, since its purpose is to execute the rest of the actions +from an interrupt handler (top-half).</p> +<p>Timers are another type of deferred work that are used to schedule the +execution of future actions after a certain amount of time has passed.</p> +<p>Kernel threads are not themselves deferred work, but can be used to +complement the deferred work mechanisms. In general, kernel threads +are used as "workers" to process events whose execution contains +blocking calls.</p> +<p>There are three typical operations that are used with all types of +deferred work:</p> +<ol class="arabic simple"> +<li><strong>Initialization</strong>. Each type is described by a structure whose +fields will have to be initialized. The handler to be scheduled is +also set at this time.</li> +<li><strong>Scheduling</strong>. Schedules the execution of the handler as soon as +possible (or after expiry of a timeout).</li> +<li><strong>Masking</strong> or <strong>Canceling</strong>. Disables the execution of the +handler. This action can be either synchronous (which guarantees +that the handler will not run after the completion of canceling) or +asynchronous.</li> +</ol> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">When doing deferred work cleanup, like freeing the +structures associated with the deferred work or +removing the module and thus the handler code from the +kernel, always use the synchronous type of canceling +the deferred work.</p> +</div> +<p>The main types of deferred work are kernel threads and softirqs. Work +queues are implemented on top of kernel threads and tasklets and +timers on top of softirqs. Bottom-half handlers were the first +implementation of deferred work in Linux, but in the meantime it was +replaced by softirqs. That is why some functions presented +contain <em>bh</em> in their name.</p> +</div> +<div class="section" id="softirqs"> +<h2>Softirqs<a class="headerlink" href="#softirqs" title="Permalink to this headline">¶</a></h2> +<p>softirqs can not be used by device drivers, they are reserved for +various kernel subsystems. Because of this there is a fixed number of +softirqs defined at compile time. For the current kernel version we +have the following types defined:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">enum</span> <span class="p">{</span> + <span class="n">HI_SOFTIRQ</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> + <span class="n">TIMER_SOFTIRQ</span><span class="p">,</span> + <span class="n">NET_TX_SOFTIRQ</span><span class="p">,</span> + <span class="n">NET_RX_SOFTIRQ</span><span class="p">,</span> + <span class="n">BLOCK_SOFTIRQ</span><span class="p">,</span> + <span class="n">IRQ_POLL_SOFTIRQ</span><span class="p">,</span> + <span class="n">TASKLET_SOFTIRQ</span><span class="p">,</span> + <span class="n">SCHED_SOFTIRQ</span><span class="p">,</span> + <span class="n">HRTIMER_SOFTIRQ</span><span class="p">,</span> + <span class="n">RCU_SOFTIRQ</span><span class="p">,</span> + <span class="n">NR_SOFTIRQS</span> +<span class="p">};</span> +</pre></div> +</div> +<p>Each type has a specific purpose:</p> +<ul class="simple"> +<li><em>HI_SOFTIRQ</em> and <em>TASKLET_SOFTIRQ</em> - running tasklets</li> +<li><em>TIMER_SOFTIRQ</em> - running timers</li> +<li><em>NET_TX_SOFIRQ</em> and <em>NET_RX_SOFTIRQ</em> - used by the networking subsystem</li> +<li><em>BLOCK_SOFTIRQ</em> - used by the IO subsystem</li> +<li><em>BLOCK_IOPOLL_SOFTIRQ</em> - used by the IO subsystem to increase performance when the iopoll handler is invoked;</li> +<li><em>SCHED_SOFTIRQ</em> - load balancing</li> +<li><em>HRTIMER_SOFTIRQ</em> - implementation of high precision timers</li> +<li><em>RCU_SOFTIRQ</em> - implementation of RCU type mechanisms <a class="footnote-reference" href="#footnote-1" id="footnote-reference-1">[1]</a></li> +</ul> +<table class="docutils footnote" frame="void" id="footnote-1" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#footnote-reference-1">[1]</a></td><td>RCU is a mechanism by which destructive operations +(e.g. deleting an element from a chained list) are done in two +steps: (1) removing references to deleted data and (2) freeing +the memory of the element. The second setup is done only after +we are sure nobody uses the element anymore. The advantage of +this mechanism is that reading the data can be done without +synchronization. For more information see +Documentation/RCU/rcu.txt.</td></tr> +</tbody> +</table> +<p>The highest priority is the <em>HI_SOFTIRQ</em> type softirqs, followed in +order by the other softirqs defined. <em>RCU_SOFTIRQ</em> has the lowest +priority.</p> +<p>Softirqs are running in interrupt context which means that they can +not call blocking functions. If the sofitrq handler requires calls to +such functions, work queues can be scheduled to execute these blocking +calls.</p> +<div class="section" id="tasklets"> +<h3>Tasklets<a class="headerlink" href="#tasklets" title="Permalink to this headline">¶</a></h3> +<p>A tasklet is a special form of deferred work that runs in interrupt +context, just like softirqs. The main difference between sofirqs and tasklets +is that tasklets can be allocated dynamically and thus they can be used +by device drivers. A tasklet is represented by <code class="xref c c-type docutils literal"><span class="pre">struct</span> +<span class="pre">tasklet</span></code> and as many other kernel structures it needs to be +initialized before being used. A pre-initialized tasklet can be defined +as following:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">handler</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">data</span><span class="p">);</span> + +<span class="n">DECLARE_TASKLET</span><span class="p">(</span><span class="n">tasklet</span><span class="p">,</span> <span class="n">handler</span><span class="p">,</span> <span class="n">data</span><span class="p">);</span> +<span class="n">DECLARE_TASKLET_DISABLED</span><span class="p">(</span><span class="n">tasklet</span><span class="p">,</span> <span class="n">handler</span><span class="p">,</span> <span class="n">data</span><span class="p">);</span> +</pre></div> +</div> +<p>If we want to initialize the tasklet manually we can use the following +approach:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">handler</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">data</span><span class="p">);</span> + +<span class="k">struct</span> <span class="n">tasklet_struct</span> <span class="n">tasklet</span><span class="p">;</span> + +<span class="n">tasklet_init</span><span class="p">(</span><span class="o">&</span><span class="n">tasklet</span><span class="p">,</span> <span class="n">handler</span><span class="p">,</span> <span class="n">data</span><span class="p">);</span> +</pre></div> +</div> +<p>The <em>data</em> parameter will be sent to the handler when it is executed.</p> +<p>Programming tasklets for running is called scheduling. Tasklets are +running from softirqs. Tasklets scheduling is done with:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">tasklet_schedule</span><span class="p">(</span><span class="k">struct</span> <span class="n">tasklet_struct</span> <span class="o">*</span><span class="n">tasklet</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">tasklet_hi_schedule</span><span class="p">(</span><span class="k">struct</span> <span class="n">tasklet_struct</span> <span class="o">*</span><span class="n">tasklet</span><span class="p">);</span> +</pre></div> +</div> +<p>When using <em>tasklet_schedule</em>, a <em>TASKLET_SOFTIRQ</em> softirq is +scheduled and all tasklets scheduled are run. For +<em>tasklet_hi_schedule</em>, a <em>HI_SOFTIRQ</em> softirq is scheduled.</p> +<p>If a tasklet was scheduled multiple times and it did not run between +schedules, it will run once. Once the tasklet has run, it can be +re-scheduled, and will run again at a later timer. Tasklets can be +re-scheduled from their handlers.</p> +<p>Tasklets can be masked and the following functions can be used:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">tasklet_enable</span><span class="p">(</span><span class="k">struct</span> <span class="n">tasklet_struct</span> <span class="o">*</span> <span class="n">tasklet</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">tasklet_disable</span><span class="p">(</span><span class="k">struct</span> <span class="n">tasklet_struct</span> <span class="o">*</span> <span class="n">tasklet</span><span class="p">);</span> +</pre></div> +</div> +<p>Remember that since tasklets are running from softirqs, blocking calls +can not be used in the handler function.</p> +</div> +<div class="section" id="timers"> +<h3>Timers<a class="headerlink" href="#timers" title="Permalink to this headline">¶</a></h3> +<p>A particular type of deferred work, very often used, are timers. They +are defined by <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">timer_list</span></code>. They run in interrupt +context and are implemented on top of softirqs.</p> +<p>To be used, a timer must first be initialized by calling <code class="xref c c-func docutils literal"><span class="pre">timer_setup()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/sched.h></span><span class="cp"></span> + +<span class="kt">void</span> <span class="nf">timer_setup</span><span class="p">(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span> <span class="n">timer</span><span class="p">,</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">function</span><span class="p">)(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span><span class="p">),</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">);</span> +</pre></div> +</div> +<p>The above function initializes the internal fields of the structure +and associates <em>function</em> as the timer handler. Since timers are planned +over softirqs, blocking calls can not be used in the code associated +with the treatment function.</p> +<p>Scheduling a timer is done with <code class="xref c c-func docutils literal"><span class="pre">mod_timer()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="nf">mod_timer</span><span class="p">(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span><span class="n">timer</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">expires</span><span class="p">);</span> +</pre></div> +</div> +<p>Where <em>expires</em> is the time (in the future) to run the handler +function. The function can be used to schedule or reschedule a timer.</p> +<p>The time unit is <em>jiffie</em>. The absolute value of a jiffie +is dependent on the platform and it can be found using the +<code class="xref c c-type docutils literal"><span class="pre">HZ</span></code> macro that defines the number of jiffies for 1 second. To +convert between jiffies (<em>jiffies_value</em>) and seconds (<em>seconds_value</em>), +the following formulas are used:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">jiffies_value</span> <span class="o">=</span> <span class="n">seconds_value</span> <span class="o">*</span> <span class="n">HZ</span> <span class="p">;</span> +<span class="n">seconds_value</span> <span class="o">=</span> <span class="n">jiffies_value</span> <span class="o">/</span> <span class="n">HZ</span> <span class="p">;</span> +</pre></div> +</div> +<p>The kernel maintains a counter that contains the number of jiffies +since the last boot, which can be accessed via the <code class="xref c c-macro docutils literal"><span class="pre">jiffies</span></code> +global variable or macro. We can use it to calculate a time in the +future for timers:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/jiffies.h></span><span class="cp"></span> + +<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">current_jiffies</span><span class="p">,</span> <span class="n">next_jiffies</span><span class="p">;</span> +<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">seconds</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> + +<span class="n">current_jiffies</span> <span class="o">=</span> <span class="n">jiffies</span><span class="p">;</span> +<span class="n">next_jiffies</span> <span class="o">=</span> <span class="n">jiffies</span> <span class="o">+</span> <span class="n">seconds</span> <span class="o">*</span> <span class="n">HZ</span><span class="p">;</span> +</pre></div> +</div> +<p>To stop a timer, use <code class="xref c c-func docutils literal"><span class="pre">del_timer()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">del_timer_sync()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="nf">del_timer</span><span class="p">(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span><span class="n">timer</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">del_timer_sync</span><span class="p">(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span><span class="n">timer</span><span class="p">);</span> +</pre></div> +</div> +<p>These functions can be called for both a scheduled timer and an +unplanned timer. <code class="xref c c-func docutils literal"><span class="pre">del_timer_sync()</span></code> is used to eliminate the +races that can occur on multiprocessor systems, since at the end of +the call it is guaranteed that the timer processing function does not +run on any processor.</p> +<p>A frequent mistake in using timers is that we forget to turn off +timers. For example, before removing a module, we must stop the timers +because if a timer expires after the module is removed, the handler +function will no longer be loaded into the kernel and a kernel oops +will be generated.</p> +<p>The usual sequence used to initialize and schedule a one-second +timeout is:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/sched.h></span><span class="cp"></span> + +<span class="kt">void</span> <span class="nf">timer_function</span><span class="p">(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span><span class="p">);</span> + +<span class="k">struct</span> <span class="n">timer_list</span> <span class="n">timer</span> <span class="p">;</span> +<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">seconds</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> + +<span class="n">timer_setup</span><span class="p">(</span><span class="o">&</span><span class="n">timer</span><span class="p">,</span> <span class="n">timer_function</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> +<span class="n">mod_timer</span><span class="p">(</span><span class="o">&</span><span class="n">timer</span><span class="p">,</span> <span class="n">jiffies</span> <span class="o">+</span> <span class="n">seconds</span> <span class="o">*</span> <span class="n">HZ</span><span class="p">);</span> +</pre></div> +</div> +<p>And to stop it:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">del_timer_sync</span><span class="p">(</span><span class="o">&</span><span class="n">timer</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="locking"> +<h3>Locking<a class="headerlink" href="#locking" title="Permalink to this headline">¶</a></h3> +<p>For synchronization between code running in process context (A) and +code running in softirq context (B) we need to use special locking +primitives. We must use spinlock operations augmented with +deactivation of bottom-half handlers on the current processor in (A), +and in (B) only basic spinlock operations. Using spinlocks makes sure +that we don't have races between multiple CPUs while deactivating the +softirqs makes sure that we don't deadlock in the softirq is scheduled +on the same CPU where we already acquired a spinlock.</p> +<p>We can use the <code class="xref c c-func docutils literal"><span class="pre">local_bh_disable()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">local_bh_enable()</span></code> to disable and enable softirqs handlers (and +since they run on top of softirqs also timers and tasklets):</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">local_bh_disable</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">local_bh_enable</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> +</pre></div> +</div> +<p>Nested calls are allowed, the actual reactivation of the softirqs is +done only when all local_bh_disable() calls have been complemented by +local_bh_enable() calls:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* We assume that softirqs are enabled */</span> +<span class="n">local_bh_disable</span><span class="p">();</span> <span class="cm">/* Softirqs are now disabled */</span> +<span class="n">local_bh_disable</span><span class="p">();</span> <span class="cm">/* Softirqs remain disabled */</span> + +<span class="n">local_bh_enable</span><span class="p">();</span> <span class="cm">/* Softirqs remain disabled */</span> +<span class="n">local_bh_enable</span><span class="p">();</span> <span class="cm">/* Softirqs are now enabled */</span> +</pre></div> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">These above calls will disable the softirqs only on the +local processor and they are usually not safe to use, they must be +complemented with spinlocks.</p> +</div> +<p>Most of the time device drivers will use special versions of spinlocks +calls for synchronization like <code class="xref c c-func docutils literal"><span class="pre">spin_lock_bh()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock_bh()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">spin_lock_bh</span><span class="p">(</span><span class="n">spinlock_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">spin_unlock_bh</span><span class="p">(</span><span class="n">spinlock_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">);</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="workqueues"> +<h2>Workqueues<a class="headerlink" href="#workqueues" title="Permalink to this headline">¶</a></h2> +<p>Workqueues are used to schedule actions to run in process context. The +base unit with which they work is called work. There are two types of +work:</p> +<ul class="simple"> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">work_struct</span></code> - it schedules a task to run at +a later time</li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">delayed_work</span></code> - it schedules a task to run after at +least a given time interval</li> +</ul> +<p>A delayed work uses a timer to run after the specified time +interval. The calls with this type of work are similar to those for +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">work_struct</span></code>, but has <strong>_delayed</strong> in the functions +names.</p> +<p>Before using them a work item must be initialized. There are two types +of macros that can be used, one that declares and initializes the work +item at the same time and one that only initializes the work item (and +the declaration must be done separately):</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/workqueue.h></span><span class="cp"></span> + +<span class="n">DECLARE_WORK</span><span class="p">(</span><span class="n">name</span> <span class="p">,</span> <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">function</span><span class="p">)(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="p">));</span> +<span class="n">DECLARE_DELAYED_WORK</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="kt">void</span><span class="p">(</span><span class="o">*</span><span class="n">function</span><span class="p">)(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="p">));</span> + +<span class="n">INIT_WORK</span><span class="p">(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="n">work</span><span class="p">,</span> <span class="kt">void</span><span class="p">(</span><span class="o">*</span><span class="n">function</span><span class="p">)(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="p">));</span> +<span class="n">INIT_DELAYED_WORK</span><span class="p">(</span><span class="k">struct</span> <span class="n">delayed_work</span> <span class="o">*</span><span class="n">work</span><span class="p">,</span> <span class="kt">void</span><span class="p">(</span><span class="o">*</span><span class="n">function</span><span class="p">)(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="p">));</span> +</pre></div> +</div> +<p><code class="xref c c-func docutils literal"><span class="pre">DECLARE_WORK()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">DECLARE_DELAYED_WORK()</span></code> declare and +initialize a work item, and <code class="xref c c-func docutils literal"><span class="pre">INIT_WORK()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">INIT_DELAYED_WORK()</span></code> initialize an already declared work item.</p> +<p>The following sequence declares and initiates a work item:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/workqueue.h></span><span class="cp"></span> + +<span class="kt">void</span> <span class="nf">my_work_handler</span><span class="p">(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="n">work</span><span class="p">);</span> + +<span class="n">DECLARE_WORK</span><span class="p">(</span><span class="n">my_work</span><span class="p">,</span> <span class="n">my_work_handler</span><span class="p">);</span> +</pre></div> +</div> +<p>Or, if we want to initialize the work item separately:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">my_work_handler</span><span class="p">(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span> <span class="n">work</span><span class="p">);</span> + +<span class="k">struct</span> <span class="n">work_struct</span> <span class="n">my_work</span><span class="p">;</span> + +<span class="n">INIT_WORK</span><span class="p">(</span><span class="o">&</span><span class="n">my_work</span><span class="p">,</span> <span class="n">my_work_handler</span><span class="p">);</span> +</pre></div> +</div> +<p>Once declared and initialized, we can schedule the task using +<code class="xref c c-func docutils literal"><span class="pre">schedule_work()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">schedule_delayed_work()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">schedule_work</span><span class="p">(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="n">work</span><span class="p">);</span> + +<span class="n">schedule_delayed_work</span><span class="p">(</span><span class="k">struct</span> <span class="n">delayed_work</span> <span class="o">*</span><span class="n">work</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">delay</span><span class="p">);</span> +</pre></div> +</div> +<p><code class="xref c c-func docutils literal"><span class="pre">schedule_delayed_work()</span></code> can be used to plan a work item for +execution with a given delay. The delay time unit is jiffies.</p> +<p>Work items can not be masked but they can be canceled by calling +<code class="xref c c-func docutils literal"><span class="pre">cancel_delayed_work_sync()</span></code> or <code class="xref c c-func docutils literal"><span class="pre">cancel_work_sync()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="nf">cancel_work_sync</span><span class="p">(</span><span class="k">struct</span> <span class="n">delayed_work</span> <span class="o">*</span><span class="n">work</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">cancel_delayed_work_sync</span><span class="p">(</span><span class="k">struct</span> <span class="n">delayed_work</span> <span class="o">*</span><span class="n">work</span><span class="p">);</span> +</pre></div> +</div> +<p>The call only stops the subsequent execution of the work item. If the +work item is already running at the time of the call, it will continue +to run. In any case, when these calls return, it is guaranteed that +the task will no longer run.</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">While there are versions of these functions that are +not synchronous (.e.g. <code class="xref c c-func docutils literal"><span class="pre">cancel_work()</span></code>) do not +use them when you are performing cleanup work otherwise +race condition could occur.</p> +</div> +<p>We can wait for a workqueue to complete running all of its work items by calling <code class="xref c c-func docutils literal"><span class="pre">flush_scheduled_work()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">flush_scheduled_work</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span> +</pre></div> +</div> +<p>This function is blocking and, therefore, can not be used in interrupt +context. The function will wait for all work items to be completed. +For delayed work items, <code class="xref c c-type docutils literal"><span class="pre">cancel_delayed_work</span></code> must be called +before <code class="xref c c-func docutils literal"><span class="pre">flush_scheduled_work()</span></code>.</p> +<p>Finally, the following functions can be used to schedule work items on +a particular processor (<code class="xref c c-func docutils literal"><span class="pre">schedule_delayed_work_on()</span></code>), or on all +processors (<code class="xref c c-func docutils literal"><span class="pre">schedule_on_each_cpu()</span></code>):</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="nf">schedule_delayed_work_on</span><span class="p">(</span><span class="kt">int</span> <span class="n">cpu</span><span class="p">,</span> <span class="k">struct</span> <span class="n">delayed_work</span> <span class="o">*</span><span class="n">work</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">delay</span><span class="p">);</span> +<span class="kt">int</span> <span class="nf">schedule_on_each_cpu</span><span class="p">(</span><span class="kt">void</span><span class="p">(</span><span class="o">*</span><span class="n">function</span><span class="p">)(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="p">));</span> +</pre></div> +</div> +<p>A usual sequence to initialize and schedule a work item is the following:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">my_work_handler</span><span class="p">(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="n">work</span><span class="p">);</span> + +<span class="k">struct</span> <span class="n">work_struct</span> <span class="n">my_work</span><span class="p">;</span> + +<span class="n">INIT_WORK</span><span class="p">(</span><span class="o">&</span><span class="n">my_work</span><span class="p">,</span> <span class="n">my_work_handler</span><span class="p">);</span> + +<span class="n">schedule_work</span><span class="p">(</span><span class="o">&</span><span class="n">my_work</span><span class="p">);</span> +</pre></div> +</div> +<p>And for waiting for termination of a work item:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">flush_scheduled_work</span><span class="p">();</span> +</pre></div> +</div> +<p>As you can see, the <em>my_work_handler</em> function receives the task as +the parameter. To be able to access the module's private data, you can +use <code class="xref c c-func docutils literal"><span class="pre">container_of()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">my_device_data</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">work_struct</span> <span class="n">my_work</span><span class="p">;</span> + <span class="c1">// ...</span> +<span class="p">};</span> + +<span class="kt">void</span> <span class="nf">my_work_handler</span><span class="p">(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="n">work</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">my_device_data</span> <span class="o">*</span> <span class="n">my_data</span><span class="p">;</span> + + <span class="n">my_data</span> <span class="o">=</span> <span class="n">container_of</span><span class="p">(</span><span class="n">work</span><span class="p">,</span> <span class="k">struct</span> <span class="n">my_device_data</span><span class="p">,</span> <span class="n">my_work</span><span class="p">);</span> + <span class="c1">// ...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Scheduling work items with the functions above will run the handler in +the context of a kernel thread called <em>events/x</em>, where x is the +processor number. The kernel will initialize a kernel thread (or a +pool of workers) for each processor present in the system:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>$ ps -e +PID TTY TIME CMD +<span class="m">1</span>? <span class="m">00</span>:00:00 init +<span class="m">2</span> ? <span class="m">00</span>:00:00 ksoftirqd / <span class="m">0</span> +<span class="m">3</span> ? <span class="m">00</span>:00:00 events / <span class="m">0</span> <--- kernel thread that runs work items +<span class="m">4</span> ? <span class="m">00</span>:00:00 khelper +<span class="m">5</span> ? <span class="m">00</span>:00:00 kthread +<span class="m">7</span>? <span class="m">00</span>:00:00 kblockd / <span class="m">0</span> +<span class="m">8</span>? <span class="m">00</span>:00:00 kacpid +</pre></div> +</div> +<p>The above functions use a predefined workqueue (called events), and +they run in the context of the <em>events/x</em> thread, as noted +above. Although this is sufficient in most cases, it is a shared +resource and large delays in work items handlers can cause delays for +other queue users. For this reason there are functions for creating +additional queues.</p> +<p>A workqueue is represented by <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">workqueue_struct</span></code>. A new +workqueue can be created with these functions:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">workqueue_struct</span> <span class="o">*</span><span class="nf">create_workqueue</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">);</span> +<span class="k">struct</span> <span class="n">workqueue_struct</span> <span class="o">*</span><span class="nf">create_singlethread_workqueue</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">);</span> +</pre></div> +</div> +<p><code class="xref c c-func docutils literal"><span class="pre">create_workqueue()</span></code> uses one thread for each processor in the +system, and <code class="xref c c-func docutils literal"><span class="pre">create_singlethread_workqueue()</span></code> uses a single +thread.</p> +<p>To add a task in the new queue, use <code class="xref c c-func docutils literal"><span class="pre">queue_work()</span></code> or +<code class="xref c c-func docutils literal"><span class="pre">queue_delayed_work()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="nf">queue_work</span><span class="p">(</span><span class="k">struct</span> <span class="n">workqueue_struct</span> <span class="o">*</span> <span class="n">queue</span><span class="p">,</span> <span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="n">work</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">queue_delayed_work</span><span class="p">(</span><span class="k">struct</span> <span class="n">workqueue_struct</span> <span class="o">*</span><span class="n">queue</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">delayed_work</span> <span class="o">*</span> <span class="n">work</span> <span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">delay</span><span class="p">);</span> +</pre></div> +</div> +<p><code class="xref c c-func docutils literal"><span class="pre">queue_delayed_work()</span></code> can be used to plan a work for execution +with a given delay. The time unit for the delay is jiffies.</p> +<p>To wait for all work items to finish call <code class="xref c c-func docutils literal"><span class="pre">flush_workqueue()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">flush_workqueue</span><span class="p">(</span><span class="k">struct</span> <span class="n">worksqueue_struct</span> <span class="o">*</span> <span class="n">queue</span><span class="p">);</span> +</pre></div> +</div> +<p>And to destroy the workqueue call <code class="xref c c-func docutils literal"><span class="pre">destroy_workqueue()</span></code></p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">destroy_workqueue</span><span class="p">(</span><span class="k">struct</span> <span class="n">workqueue_struct</span> <span class="o">*</span><span class="n">queue</span><span class="p">);</span> +</pre></div> +</div> +<p>The next sequence declares and initializes an additional workqueue, +declares and initializes a work item and adds it to the queue:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">my_work_handler</span><span class="p">(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="n">work</span><span class="p">);</span> + +<span class="k">struct</span> <span class="n">work_struct</span> <span class="n">my_work</span><span class="p">;</span> +<span class="k">struct</span> <span class="n">workqueue_struct</span> <span class="o">*</span> <span class="n">my_workqueue</span><span class="p">;</span> + +<span class="n">my_workqueue</span> <span class="o">=</span> <span class="n">create_singlethread_workqueue</span><span class="p">(</span><span class="s">"my_workqueue"</span><span class="p">);</span> +<span class="n">INIT_WORK</span><span class="p">(</span><span class="o">&</span><span class="n">my_work</span><span class="p">,</span> <span class="n">my_work_handler</span><span class="p">);</span> + +<span class="n">queue_work</span><span class="p">(</span><span class="n">my_workqueue</span><span class="p">,</span> <span class="o">&</span><span class="n">my_work</span><span class="p">);</span> +</pre></div> +</div> +<p>And the next code sample shows how to remove the workqueue:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">flush_workqueue</span><span class="p">(</span><span class="n">my_workqueue</span><span class="p">);</span> +<span class="n">destroy_workqueue</span><span class="p">(</span><span class="n">my_workqueue</span><span class="p">);</span> +</pre></div> +</div> +<p>The work items planned with these functions will run in the context of +a new kernel thread called <em>my_workqueue</em>, the name passed to +<code class="xref c c-func docutils literal"><span class="pre">create_singlethread_workqueue()</span></code>.</p> +</div> +<div class="section" id="kernel-threads"> +<h2>Kernel threads<a class="headerlink" href="#kernel-threads" title="Permalink to this headline">¶</a></h2> +<p>Kernel threads have emerged from the need to run kernel code in +process context. Kernel threads are the basis of the workqueue +mechanism. Essentially, a kernel thread is a thread that only runs in +kernel mode and has no user address space or other user attributes.</p> +<p>To create a kernel thread, use <code class="xref c c-func docutils literal"><span class="pre">kthread_create()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/kthread.h></span><span class="cp"></span> + +<span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="nf">kthread_create</span><span class="p">(</span><span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">threadfn</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">),</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">namefmt</span><span class="p">[],</span> <span class="p">...);</span> +</pre></div> +</div> +<ul class="simple"> +<li><em>threadfn</em> is a function that will be run by the kernel thread</li> +<li><em>data</em> is a parameter to be sent to the function</li> +<li><em>namefmt</em> represents the kernel thread name, as it is displayed in +ps/top ; Can contain sequences %d , %s etc. Which will be replaced +according to the standard printf syntax.</li> +</ul> +<p>For example, the following call:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">kthread_create</span> <span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="s">"%skthread%d"</span><span class="p">,</span> <span class="s">"my"</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> +</pre></div> +</div> +<p>Will create a kernel thread with the name mykthread0.</p> +<p>The kernel thread created with this function will be stopped (in the +<em>TASK_INTERRUPTIBLE</em> state). To start the kernel thread, call the +<code class="xref c c-func docutils literal"><span class="pre">wake_up_process()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/sched.h></span><span class="cp"></span> + +<span class="kt">int</span> <span class="nf">wake_up_process</span><span class="p">(</span><span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">p</span><span class="p">);</span> +</pre></div> +</div> +<p>Alternatively, you can use <code class="xref c c-func docutils literal"><span class="pre">kthread_run()</span></code> to create and run a +kernel thread:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span> <span class="nf">kthread_run</span><span class="p">(</span><span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">threadfn</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">namefmt</span><span class="p">[],</span> <span class="p">...);</span> +</pre></div> +</div> +<p>Even if the programming restrictions for the function running within +the kernel thread are more relaxed and scheduling is closer to +scheduling in userspace, there are, however, some limitations to be +taken into account. We will list below the actions that can or can not +be made from a kernel thread:</p> +<ul class="simple"> +<li>can't access the user address space (even with copy_from_user, +copy_to_user) because a kernel thread does not have a user address +space</li> +<li>can't implement busy wait code that runs for a long time; if the +kernel is compiled without the preemptive option, that code will run +without being preempted by other kernel threads or user processes +thus hogging the system</li> +<li>can call blocking operations</li> +<li>can use spinlocks, but if the hold time of the lock is significant, +it is recommended to use mutexes</li> +</ul> +<p>The termination of a kernel thread is done voluntarily, within the +function running in the kernel thread, by calling <code class="xref c c-func docutils literal"><span class="pre">do_exit()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">fastcall</span> <span class="n">NORET_TYPE</span> <span class="kt">void</span> <span class="nf">do_exit</span><span class="p">(</span><span class="kt">long</span> <span class="n">code</span><span class="p">);</span> +</pre></div> +</div> +<p>Most of the implementations of kernel threads handlers use the same +model and it is recommended to start using the same model to avoid +common mistakes:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/kthread.h></span><span class="cp"></span> + +<span class="n">DECLARE_WAIT_QUEUE_HEAD</span><span class="p">(</span><span class="n">wq</span><span class="p">);</span> + +<span class="c1">// list events to be processed by kernel thread</span> +<span class="k">struct</span> <span class="n">list_head</span> <span class="n">events_list</span><span class="p">;</span> +<span class="k">struct</span> <span class="n">spin_lock</span> <span class="n">events_lock</span><span class="p">;</span> + + +<span class="c1">// structure describing the event to be processed</span> +<span class="k">struct</span> <span class="n">event</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="n">lh</span><span class="p">;</span> + <span class="kt">bool</span> <span class="n">stop</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">};</span> + +<span class="k">struct</span> <span class="n">event</span><span class="o">*</span> <span class="nf">get_next_event</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">event</span> <span class="o">*</span><span class="n">e</span><span class="p">;</span> + + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">events_lock</span><span class="p">);</span> + <span class="n">e</span> <span class="o">=</span> <span class="n">list_first_entry</span><span class="p">(</span><span class="o">&</span><span class="n">events_list</span><span class="p">,</span> <span class="k">struct</span> <span class="n">event</span><span class="o">*</span><span class="p">,</span> <span class="n">lh</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">e</span><span class="p">)</span> + <span class="n">list_del</span><span class="p">(</span><span class="o">&</span><span class="n">e</span><span class="o">-></span><span class="n">lh</span><span class="p">);</span> + <span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">events_lock</span><span class="p">);</span> + + <span class="k">return</span> <span class="n">e</span> +<span class="p">}</span> + +<span class="kt">int</span> <span class="nf">my_thread_f</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">event</span> <span class="o">*</span><span class="n">e</span><span class="p">;</span> + + <span class="k">while</span> <span class="p">(</span><span class="nb">true</span><span class="p">)</span> <span class="p">{</span> + <span class="n">wait_event</span><span class="p">(</span><span class="n">wq</span><span class="p">,</span> <span class="p">(</span><span class="n">e</span> <span class="o">=</span> <span class="n">get_next_event</span><span class="p">));</span> + + <span class="cm">/* Event processing */</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">e</span><span class="o">-></span><span class="n">stop</span><span class="p">)</span> + <span class="k">break</span><span class="p">;</span> + <span class="p">}</span> + + <span class="n">do_exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> +<span class="p">}</span> + +<span class="cm">/* start and start kthread */</span> +<span class="n">kthread_run</span><span class="p">(</span><span class="n">my_thread_f</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="s">"%skthread%d"</span><span class="p">,</span> <span class="s">"my"</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> +</pre></div> +</div> +<p>With the template above, the kernel thread requests can be issued +with:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">send_event</span><span class="p">(</span><span class="k">struct</span> <span class="n">event</span> <span class="o">*</span><span class="n">ev</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">events_lock</span><span class="p">);</span> + <span class="n">list_add</span><span class="p">(</span><span class="o">&</span><span class="n">ev</span><span class="o">-></span><span class="n">lh</span><span class="p">,</span> <span class="o">&</span><span class="n">events_list</span><span class="p">);</span> + <span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">events_lock</span><span class="p">);</span> + <span class="n">wake_up</span><span class="p">(</span><span class="o">&</span><span class="n">wq</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="further-reading"> +<h2>Further reading<a class="headerlink" href="#further-reading" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li><a class="reference external" href="http://lwn.net/images/pdf/LDD3/ch07.pdf">Linux Device Drivers, 3rd ed., Ch. 7: Time, Delays, and Deferred Work</a></li> +<li><a class="reference external" href="http://tldp.org/LDP/lkmpg/2.6/html/x1211.html">Scheduling Tasks</a></li> +<li><a class="reference external" href="http://lwn.net/Articles/23634/">Driver porting: the workqueue interface</a></li> +<li><a class="reference external" href="http://lwn.net/Articles/211279/">Workqueues get a rework</a></li> +<li><a class="reference external" href="http://lwn.net/Articles/65178/">Kernel threads made easy</a></li> +<li><a class="reference external" href="http://www.kernel.org/pub/linux/kernel/people/rusty/kernel-locking/index.html">Unreliable Guide to Locking</a></li> +</ul> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is deferred_work. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/deferred_work/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="section" id="intro"> +<h3>0. Intro<a class="headerlink" href="#intro" title="Permalink to this headline">¶</a></h3> +<p>Using <a class="reference external" href="http://elixir.free-electrons.com/linux/latest/source">LXR</a>, find the definitions of the following symbols:</p> +<ul class="simple"> +<li><code class="xref c c-macro docutils literal"><span class="pre">jiffies</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">timer_list</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">spin_lock_bh</span> <span class="pre">function()</span></code></li> +</ul> +</div> +<div class="section" id="timer"> +<h3>1.Timer<a class="headerlink" href="#timer" title="Permalink to this headline">¶</a></h3> +<p>We're looking at creating a simple kernel module that displays a +message at <em>TIMER_TIMEOUT</em> seconds after the module's kernel load.</p> +<p>Generate the skeleton for the task named <strong>1-2-timer</strong> and follow the +sections marked with <strong>TODO 1</strong> to complete the task.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>Use <cite>pr_info(...)</cite>. Messages will be displayed on the +console and can also be viewed using dmesg. When scheduling +the timer we need to use the absolute time of the system (in +the future) in number of ticks. The current time of the +system in the number of ticks is given by <code class="xref c c-type docutils literal"><span class="pre">jiffies</span></code>. +Thus, the absolute time we need to pass to the timer is +<code class="docutils literal"><span class="pre">jiffies</span> <span class="pre">+</span> <span class="pre">TIMER_TIMEOUT</span> <span class="pre">*</span> <span class="pre">HZ</span></code>.</p> +<p class="last">For more information review the <a class="reference internal" href="#timers">Timers</a> section.</p> +</div> +</div> +<div class="section" id="periodic-timer"> +<h3>2. Periodic timer<a class="headerlink" href="#periodic-timer" title="Permalink to this headline">¶</a></h3> +<p>Modify the previous module to display the message in once every +TIMER_TIMEOUT seconds. Follow the section marked with <strong>TODO 2</strong> in the +skeleton.</p> +</div> +<div class="section" id="timer-control-using-ioctl"> +<h3>3. Timer control using ioctl<a class="headerlink" href="#timer-control-using-ioctl" title="Permalink to this headline">¶</a></h3> +<p>We plan to display information about the current process after N +seconds of receiving a ioctl call from user space. N is transmitted as +ioctl parameter.</p> +<p>Generate the skeleton for the task named <strong>3-4-5-deferred</strong> and +follow the sections marked with <strong>TODO 1</strong> in the skeleton driver.</p> +<p>You will need to implement the following ioctl operations.</p> +<ul class="simple"> +<li>MY_IOCTL_TIMER_SET to schedule a timer to run after a number of +seconds which is received as an argument to ioctl. The timer does +not run periodically. +* This command receives directly a value, not a pointer.</li> +<li>MY_IOCTL_TIMER_CANCEL to deactivate the timer.</li> +</ul> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Review <a class="reference internal" href="lab3-device-drivers.html#ioctl"><span class="std std-ref">ioctl</span></a> for a way to access the ioctl argument.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Review the <a class="reference internal" href="#timers">Timers</a> section for information on enabling / +disabling a timer. In the timer handler, display the current +process identifier (PID) and the process executable image name.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">You can find the current process identifier using the <em>pid</em> +and <em>comm</em> fields of the current process. For details, +review <span class="xref std std-ref">proc-info</span>.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">To use the device driver from userspace you must create the +device character file <em>/dev/deferred</em> using the mknod +utility. Alternatively, you can run the +<em>3-4-5-deferred/kernel/makenode</em> script that performs this +operation.</p> +</div> +<p>Enable and disable the timer by calling user-space ioctl +operations. Use the <em>3-4-5-deferred/user/test</em> program to test +planning and canceling of the timer. The program receives the ioctl +type operation and its parameters (if any) on the command line.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>Run the test executable without arguments to observe the +command line options it accepts.</p> +<p>To enable the timer after 3 seconds use:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="p">.</span><span class="o">/</span><span class="n">test</span> <span class="n">s</span> <span class="mi">3</span> +</pre></div> +</div> +<p>To disable the timer use:</p> +<div class="last highlight-c"><div class="highlight"><pre><span></span><span class="p">.</span><span class="o">/</span><span class="n">test</span> <span class="n">c</span> +</pre></div> +</div> +</div> +<p>Note that every time the current process the timer runs from is +<em>swapper/0</em> with PID 0. This process is the idle process. It is +running when there is nothing else to run on. Because the virtual +machine is very light and does not do much it is natural to see this +process most of the time.</p> +</div> +<div class="section" id="blocking-operations"> +<h3>4. Blocking operations<a class="headerlink" href="#blocking-operations" title="Permalink to this headline">¶</a></h3> +<p>Next we want to see what happens when we perform blocking operations +in a timer routine. For this we try to call in the timer-handling +routines a function called alloc_io() that simulates a blocking +operation.</p> +<p>Modify the module so that when you receive <em>MY_IOCTL_TIMER_ALLOC</em> +command the timer handler will call <code class="xref c c-func docutils literal"><span class="pre">alloc_io()</span></code>. Follow the +sections marked with <strong>TODO 2</strong> in the skeleton.</p> +<p>Use the same timer. To differentiate functionality in the timer +handler, use a flag in the device structure. Use the +<em>TIMER_TYPE_ALLOC</em> and <em>TIMER_TYPE_SET</em> macros defined in the code +skeleton. For initialization, use TIMER_TYPE_NONE.</p> +<p>Run the test program to verify the functionality of task 3. Run the +test program again to call <code class="xref c c-func docutils literal"><span class="pre">alloc_io()</span></code>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The driver causes an error because a blocking function is +called in the atomic context (the timer handler runs +interrupt context).</p> +</div> +</div> +<div class="section" id="workqueues-1"> +<h3>5. Workqueues<a class="headerlink" href="#workqueues-1" title="Permalink to this headline">¶</a></h3> +<p>We will modify the module to prevent the error observed in the +previous task.</p> +<p>To do so, lets call <code class="xref c c-func docutils literal"><span class="pre">alloc_io()</span></code> using workqueues. Schedule a +work item from the timer handler In the work handler (running in +process context) call the <code class="xref c c-func docutils literal"><span class="pre">alloc_io()</span></code>. Follow the sections +marked with <strong>TODO 3</strong> in the skeleton and review the <a class="reference internal" href="#workqueues">Workqueues</a> +section if needed.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Add a new field with the type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">work_struct</span></code> +in your device structure. Initialize this field. Schedule +the work from the timer handler using <code class="xref c c-func docutils literal"><span class="pre">schedule_work()</span></code>. +Schedule the timer handler aften N seconds from the ioctl.</p> +</div> +</div> +<div class="section" id="kernel-thread"> +<h3>6. Kernel thread<a class="headerlink" href="#kernel-thread" title="Permalink to this headline">¶</a></h3> +<p>Implement a simple module that creates a kernel thread that shows the +current process identifier.</p> +<p>Generate the skeleton for the task named <strong>6-kthread</strong> and follow the +TODOs from the skeleton.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>There are two options for creating and running a thread:</p> +<ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">kthread_run()</span></code> to create and run the thread</li> +<li><code class="xref c c-func docutils literal"><span class="pre">kthread_create()</span></code> to create a suspended thread and +then start it running with <code class="xref c c-func docutils literal"><span class="pre">wake_up_process()</span></code>.</li> +</ul> +<p class="last">Review the <a class="reference internal" href="#kernel-threads">Kernel Threads</a> section if needed.</p> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p>Synchronize the thread termination with module unloading:</p> +<ul class="last simple"> +<li>The thread should finish when the module is unloaded</li> +<li>Wait for the kernel thread to exit before continuing +with unloading</li> +</ul> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>For synchronization use two wait queues and two flags.</p> +<p>Review <span class="xref std std-ref">waiting-queues</span> on how to use waiting queue.</p> +<p class="last">Use atomic variables for flags. Review <a class="reference internal" href="lab2-kernel-api.html#atomic-variables"><span class="std std-ref">Atomic variables</span></a>.</p> +</div> +</div> +<div class="section" id="buffer-shared-between-timer-and-process"> +<h3>7. Buffer shared between timer and process<a class="headerlink" href="#buffer-shared-between-timer-and-process" title="Permalink to this headline">¶</a></h3> +<p>The purpose of this task is to exercise the synchronization between a +deferrable action (a timer) and process context. Set up a periodic +timer that monitors a list of processes. If one of the processes +terminate a message is printed. Processes can be dynamically added to +the list. Use the <em>3-4-5-deferred/kernel/</em> skeleton as a base and +follow the <strong>TODO 4</strong> markings to complete the task.</p> +<p>When the <em>MY_IOCTL_TIMER_MON</em> command is received check that the given +process exists and if so add to the monitored list of +processes and then arm the timer after setting its type.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use <code class="xref c c-func docutils literal"><span class="pre">get_proc()</span></code> which checks the pid, finds the +associated <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code> and allocates a +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mon_proc</span></code> item you can add to your +list. Note that the function also increases the reference +counter of the task, so that its memory won't be free when +the task terminates.</p> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">Use a spinlock to protect the access to the list. Note +that since we share data with the timer handler we need +to disable bottom-half handlers in addition to taking +the lock. Review the <a class="reference internal" href="#locking">Locking</a> section.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Collect the information every second from a timer. Use the +existing timer and add new behaviour for it via the +TIMER_TYPE_ACCT. To set the flag, use the <em>t</em> argument of +the test program.</p> +</div> +<p>In the timer handler iterate over the list of monitored processes and +check if they have terminated. If so, print the process name and pid +then remove the process from the list, decrement the task usage +counter so that it's memory can be free and finally free the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mon_proc</span></code> structure.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use the <em>state</em> field of <code class="xref c c-func docutils literal"><span class="pre">struct</span> <span class="pre">task_struct()</span></code>. A +task has terminated if its state is <em>TASK_DEAD</em>.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use <code class="xref c c-func docutils literal"><span class="pre">put_task_struct()</span></code> to decrement the task usage +counter.</p> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">Make sure you protect the list access with a +spinlock. The simple variant will suffice.</p> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">Make sure to use the safe iteration over the list since +we may need to remove an item from the list.</p> +</div> +<p>Rearm the timer after checking the list.</p> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lab4-interrupts.html" class="btn btn-neutral float-left" title="SO2 Lab 04 - I/O access and Interrupts" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lab6-memory-mapping.html" class="btn btn-neutral float-right" title="SO2 Lab 06 - Memory Mapping" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lab6-memory-mapping.html b/refs/pull/405/merge/so2/lab6-memory-mapping.html new file mode 100644 index 00000000..f4528349 --- /dev/null +++ b/refs/pull/405/merge/so2/lab6-memory-mapping.html @@ -0,0 +1,709 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lab 06 - Memory Mapping — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lab 07 - Block Device Drivers" href="lab7-block-device-drivers.html" /> + <link rel="prev" title="SO2 Lab 05 - Deferred work" href="lab5-deferred-work.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lab 06 - Memory Mapping</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#overview">Overview</a></li> +<li class="toctree-l3"><a class="reference internal" href="#structures-used-for-memory-mapping">Structures used for memory mapping</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#struct-page"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code></a></li> +<li class="toctree-l4"><a class="reference internal" href="#struct-vm-area-struct"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code></a></li> +<li class="toctree-l4"><a class="reference internal" href="#struct-mm-struct"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code></a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#device-driver-memory-mapping">Device driver memory mapping</a></li> +<li class="toctree-l3"><a class="reference internal" href="#further-reading">Further reading</a></li> +<li class="toctree-l3"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#mapping-contiguous-physical-memory-to-userspace">1. Mapping contiguous physical memory to userspace</a></li> +<li class="toctree-l4"><a class="reference internal" href="#mapping-non-contiguous-physical-memory-to-userspace">2. Mapping non-contiguous physical memory to userspace</a></li> +<li class="toctree-l4"><a class="reference internal" href="#read-write-operations-in-mapped-memory">3. Read / write operations in mapped memory</a></li> +<li class="toctree-l4"><a class="reference internal" href="#display-memory-mapped-in-procfs">4. Display memory mapped in procfs</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lab 06 - Memory Mapping</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lab6-memory-mapping.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lab-06-memory-mapping"> +<h1>SO2 Lab 06 - Memory Mapping<a class="headerlink" href="#so2-lab-06-memory-mapping" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>Understand address space mapping mechanisms</li> +<li>Learn about the most important structures related to memory management</li> +</ul> +<p>Keywords:</p> +<ul class="simple"> +<li>address space</li> +<li><code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_struct</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">remap_pfn_range</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">SetPageReserved()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">ClearPageReserved()</span></code></li> +</ul> +</div> +<div class="section" id="overview"> +<h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline">¶</a></h2> +<p>In the Linux kernel it is possible to map a kernel address space to a +user address space. This eliminates the overhead of copying user space +information into the kernel space and vice versa. This can be done +through a device driver and the user space device interface +(<code class="file docutils literal"><span class="pre">/dev</span></code>).</p> +<p>This feature can be used by implementing the <code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> operation +in the device driver's <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code> and using the +<code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> system call in user space.</p> +<p>The basic unit for virtual memory management is a page, which size is +usually 4K, but it can be up to 64K on some platforms. Whenever we +work with virtual memory we work with two types of addresses: virtual +address and physical address. All CPU access (including from kernel +space) uses virtual addresses that are translated by the MMU into +physical addresses with the help of page tables.</p> +<p>A physical page of memory is identified by the Page Frame Number +(PFN). The PFN can be easily computed from the physical address by +dividing it with the size of the page (or by shifting the physical +address with PAGE_SHIFT bits to the right).</p> +<a class="reference internal image-reference" href="../_images/paging1.png"><img alt="../_images/paging1.png" src="../_images/paging1.png" style="width: 49%;" /></a> +<p>For efficiency reasons, the virtual address space is divided into +user space and kernel space. For the same reason, the kernel space +contains a memory mapped zone, called <strong>lowmem</strong>, which is contiguously +mapped in physical memory, starting from the lowest possible physical +address (usually 0). The virtual address where lowmem is mapped is +defined by <code class="xref c c-macro docutils literal"><span class="pre">PAGE_OFFSET</span></code>.</p> +<p>On a 32bit system, not all available memory can be mapped in lowmem and +because of that there is a separate zone in kernel space called +<strong>highmem</strong> which can be used to arbitrarily map physical memory.</p> +<p>Memory allocated by <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> resides in lowmem and it is +physically contiguous. Memory allocated by <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code> is not +contiguous and does not reside in lowmem (it has a dedicated zone in +highmem).</p> +<a class="reference internal image-reference" href="../_images/kernel-virtmem-map1.png"><img alt="../_images/kernel-virtmem-map1.png" src="../_images/kernel-virtmem-map1.png" style="width: 49%;" /></a> +</div> +<div class="section" id="structures-used-for-memory-mapping"> +<h2>Structures used for memory mapping<a class="headerlink" href="#structures-used-for-memory-mapping" title="Permalink to this headline">¶</a></h2> +<p>Before discussing about the memory mapping mechanism over a device, +we will present some of the basic structures used by the Linux memory +management subsystem. +Some of the basic structures are: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code>, +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code>, <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code>.</p> +<div class="section" id="struct-page"> +<h3><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code><a class="headerlink" href="#struct-page" title="Permalink to this headline">¶</a></h3> +<p><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code> is used to embed information about all physical +pages in the system. The kernel has a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code> structure +for all pages in the system.</p> +<p>There are many functions that interact with this structure:</p> +<ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">virt_to_page()</span></code> returns the page associated with a virtual +address</li> +<li><code class="xref c c-func docutils literal"><span class="pre">pfn_to_page()</span></code> returns the page associated with a page frame +number</li> +<li><code class="xref c c-func docutils literal"><span class="pre">page_to_pfn()</span></code> return the page frame number associated with a +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">page_address()</span></code> returns the virtual address of a +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code>; this functions can be called only for pages from +lowmem</li> +<li><code class="xref c c-func docutils literal"><span class="pre">kmap()</span></code> creates a mapping in kernel for an arbitrary physical +page (can be from highmem) and returns a virtual address that can be +used to directly reference the page</li> +</ul> +</div> +<div class="section" id="struct-vm-area-struct"> +<h3><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code><a class="headerlink" href="#struct-vm-area-struct" title="Permalink to this headline">¶</a></h3> +<p><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code> holds information about a contiguous +virtual memory area. The memory areas of a process can be viewed by +inspecting the <em>maps</em> attribute of the process via procfs:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>root@qemux86:~# cat /proc/1/maps +<span class="c1">#address perms offset device inode pathname</span> +<span class="m">08048000</span>-08050000 r-xp <span class="m">00000000</span> fe:00 <span class="m">761</span> /sbin/init.sysvinit +<span class="m">08050000</span>-08051000 r--p <span class="m">00007000</span> fe:00 <span class="m">761</span> /sbin/init.sysvinit +<span class="m">08051000</span>-08052000 rw-p <span class="m">00008000</span> fe:00 <span class="m">761</span> /sbin/init.sysvinit +092e1000-09302000 rw-p <span class="m">00000000</span> <span class="m">00</span>:00 <span class="m">0</span> <span class="o">[</span>heap<span class="o">]</span> +4480c000-4482e000 r-xp <span class="m">00000000</span> fe:00 <span class="m">576</span> /lib/ld-2.25.so +4482e000-4482f000 r--p <span class="m">00021000</span> fe:00 <span class="m">576</span> /lib/ld-2.25.so +4482f000-44830000 rw-p <span class="m">00022000</span> fe:00 <span class="m">576</span> /lib/ld-2.25.so +<span class="m">44832000</span>-449a9000 r-xp <span class="m">00000000</span> fe:00 <span class="m">581</span> /lib/libc-2.25.so +449a9000-449ab000 r--p <span class="m">00176000</span> fe:00 <span class="m">581</span> /lib/libc-2.25.so +449ab000-449ac000 rw-p <span class="m">00178000</span> fe:00 <span class="m">581</span> /lib/libc-2.25.so +449ac000-449af000 rw-p <span class="m">00000000</span> <span class="m">00</span>:00 <span class="m">0</span> +b7761000-b7763000 rw-p <span class="m">00000000</span> <span class="m">00</span>:00 <span class="m">0</span> +b7763000-b7766000 r--p <span class="m">00000000</span> <span class="m">00</span>:00 <span class="m">0</span> <span class="o">[</span>vvar<span class="o">]</span> +b7766000-b7767000 r-xp <span class="m">00000000</span> <span class="m">00</span>:00 <span class="m">0</span> <span class="o">[</span>vdso<span class="o">]</span> +bfa15000-bfa36000 rw-p <span class="m">00000000</span> <span class="m">00</span>:00 <span class="m">0</span> <span class="o">[</span>stack<span class="o">]</span> +</pre></div> +</div> +<p>A memory area is characterized by a start address, a stop address, +length, permissions.</p> +<p>A <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code> is created at each <code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> +call issued from user space. A driver that supports the <code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> +operation must complete and initialize the associated +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code>. The most important fields of this +structure are:</p> +<ul class="simple"> +<li><code class="xref c c-member docutils literal"><span class="pre">vm_start</span></code>, <code class="xref c c-member docutils literal"><span class="pre">vm_end</span></code> - the beginning and the end of +the memory area, respectively (these fields also appear in +<code class="file docutils literal"><span class="pre">/proc/<pid>/maps</span></code>);</li> +<li><code class="xref c c-member docutils literal"><span class="pre">vm_file</span></code> - the pointer to the associated file structure (if any);</li> +<li><code class="xref c c-member docutils literal"><span class="pre">vm_pgoff</span></code> - the offset of the area within the file;</li> +<li><code class="xref c c-member docutils literal"><span class="pre">vm_flags</span></code> - a set of flags;</li> +<li><code class="xref c c-member docutils literal"><span class="pre">vm_ops</span></code> - a set of working functions for this area</li> +<li><code class="xref c c-member docutils literal"><span class="pre">vm_next</span></code>, <code class="xref c c-member docutils literal"><span class="pre">vm_prev</span></code> - the areas of the same process +are chained by a list structure</li> +</ul> +</div> +<div class="section" id="struct-mm-struct"> +<h3><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code><a class="headerlink" href="#struct-mm-struct" title="Permalink to this headline">¶</a></h3> +<p><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code> encompasses all memory areas associated +with a process. The <code class="xref c c-member docutils literal"><span class="pre">mm</span></code> field of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code> +is a pointer to the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code> of the current process.</p> +</div> +</div> +<div class="section" id="device-driver-memory-mapping"> +<h2>Device driver memory mapping<a class="headerlink" href="#device-driver-memory-mapping" title="Permalink to this headline">¶</a></h2> +<p>Memory mapping is one of the most interesting features of a Unix +system. From a driver's point of view, the memory-mapping facility +allows direct memory access to a user space device.</p> +<p>To assign a <code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> operation to a driver, the <code class="xref c c-member docutils literal"><span class="pre">mmap</span></code> +field of the device driver's <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code> must be +implemented. If that is the case, the user space process can then use +the <code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> system call on a file descriptor associated with +the device.</p> +<p>The mmap system call takes the following parameters:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="o">*</span><span class="nf">mmap</span><span class="p">(</span><span class="n">caddr_t</span> <span class="n">addr</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">len</span><span class="p">,</span> <span class="kt">int</span> <span class="n">prot</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">flags</span><span class="p">,</span> <span class="kt">int</span> <span class="n">fd</span><span class="p">,</span> <span class="kt">off_t</span> <span class="n">offset</span><span class="p">);</span> +</pre></div> +</div> +<p>To map memory between a device and user space, the user process must +open the device and issue the <code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> system call with the resulting +file descriptor.</p> +<p>The device driver <code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> operation has the following signature:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">mmap</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">filp</span><span class="p">,</span> <span class="k">struct</span> <span class="n">vm_area_struct</span> <span class="o">*</span><span class="n">vma</span><span class="p">);</span> +</pre></div> +</div> +<p>The <em>filp</em> field is a pointer to a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file</span></code> created when +the device is opened from user space. The <em>vma</em> field is used to +indicate the virtual address space where the memory should be mapped +by the device. A driver should allocate memory (using +<code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">alloc_pages()</span></code>) and then +map it to the user address space as indicated by the <em>vma</em> parameter +using helper functions such as <code class="xref c c-func docutils literal"><span class="pre">remap_pfn_range()</span></code>.</p> +<p><code class="xref c c-func docutils literal"><span class="pre">remap_pfn_range()</span></code> will map a contiguous physical address space +into the virtual space represented by <code class="xref c c-type docutils literal"><span class="pre">vm_area_struct</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">int</span> <span class="nf">remap_pfn_range</span> <span class="p">(</span><span class="n">structure</span> <span class="n">vm_area_struct</span> <span class="o">*</span><span class="n">vma</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">addr</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">pfn</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">size</span><span class="p">,</span> <span class="n">pgprot_t</span> <span class="n">prot</span><span class="p">);</span> +</pre></div> +</div> +<p><code class="xref c c-func docutils literal"><span class="pre">remap_pfn_range()</span></code> expects the following parameters:</p> +<ul class="simple"> +<li><em>vma</em> - the virtual memory space in which mapping is made;</li> +<li><em>addr</em> - the virtual address space from where remapping begins; page +tables for the virtual address space between addr and addr + size +will be formed as needed</li> +<li><em>pfn</em> - the page frame number to which the virtual address should be +mapped</li> +<li><em>size</em> - the size (in bytes) of the memory to be mapped</li> +<li><em>prot</em> - protection flags for this mapping</li> +</ul> +<p>Here is an example of using this function that contiguously maps the +physical memory starting at page frame number <em>pfn</em> (memory that was +previously allocated) to the <em>vma->vm_start</em> virtual address:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">vm_area_struct</span> <span class="o">*</span><span class="n">vma</span><span class="p">;</span> +<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">len</span> <span class="o">=</span> <span class="n">vma</span><span class="o">-></span><span class="n">vm_end</span> <span class="o">-</span> <span class="n">vma</span><span class="o">-></span><span class="n">vm_start</span><span class="p">;</span> +<span class="kt">int</span> <span class="n">ret</span> <span class="p">;</span> + +<span class="n">ret</span> <span class="o">=</span> <span class="n">remap_pfn_range</span><span class="p">(</span><span class="n">vma</span><span class="p">,</span> <span class="n">vma</span><span class="o">-></span><span class="n">vm_start</span><span class="p">,</span> <span class="n">pfn</span><span class="p">,</span> <span class="n">len</span><span class="p">,</span> <span class="n">vma</span><span class="o">-></span><span class="n">vm_page_prot</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="n">ret</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="n">pr_err</span><span class="p">(</span><span class="s">"could not map the address area</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EIO</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>To obtain the page frame number of the physical memory we must +consider how the memory allocation was performed. For each +<code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">alloc_pages()</span></code>, we must +used a different approach. For <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> we can use something +like:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">char</span> <span class="o">*</span><span class="n">kmalloc_area</span><span class="p">;</span> + +<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">pfn</span> <span class="o">=</span> <span class="n">virt_to_phys</span><span class="p">((</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">kmalloc_area</span><span class="p">)</span><span class="o">>></span><span class="n">PAGE_SHIFT</span><span class="p">;</span> +</pre></div> +</div> +<p>while for <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">char</span> <span class="o">*</span><span class="n">vmalloc_area</span><span class="p">;</span> + +<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">pfn</span> <span class="o">=</span> <span class="n">vmalloc_to_pfn</span><span class="p">(</span><span class="n">vmalloc_area</span><span class="p">);</span> +</pre></div> +</div> +<p>and finally for <code class="xref c c-func docutils literal"><span class="pre">alloc_pages()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">;</span> + +<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">pfn</span> <span class="o">=</span> <span class="n">page_to_pfn</span><span class="p">(</span><span class="n">page</span><span class="p">);</span> +</pre></div> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p class="last">Note that memory allocated with <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code> is not +physically contiguous so if we want to map a range allocated +with <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code>, we have to map each page individually +and compute the physical address for each page.</p> +</div> +<p>Since the pages are mapped to user space, they might be swapped +out. To avoid this we must set the PG_reserved bit on the page. +Enabling is done using <code class="xref c c-func docutils literal"><span class="pre">SetPageReserved()</span></code> while reseting it +(which must be done before freeing the memory) is done with +<code class="xref c c-func docutils literal"><span class="pre">ClearPageReserved()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">alloc_mmap_pages</span><span class="p">(</span><span class="kt">int</span> <span class="n">npages</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">i</span><span class="p">;</span> + <span class="kt">char</span> <span class="o">*</span><span class="n">mem</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="n">PAGE_SIZE</span> <span class="o">*</span> <span class="n">npages</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">mem</span><span class="p">)</span> + <span class="k">return</span> <span class="n">mem</span><span class="p">;</span> + + <span class="k">for</span><span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">npages</span> <span class="o">*</span> <span class="n">PAGE_SIZE</span><span class="p">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="n">PAGE_SIZE</span><span class="p">)</span> + <span class="n">SetPageReserved</span><span class="p">(</span><span class="n">virt_to_page</span><span class="p">(((</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)</span><span class="n">mem</span><span class="p">)</span> <span class="o">+</span> <span class="n">i</span><span class="p">));</span> + + <span class="k">return</span> <span class="n">mem</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">void</span> <span class="nf">free_mmap_pages</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">mem</span><span class="p">,</span> <span class="kt">int</span> <span class="n">npages</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">i</span><span class="p">;</span> + + <span class="k">for</span><span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">npages</span> <span class="o">*</span> <span class="n">PAGE_SIZE</span><span class="p">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="n">PAGE_SIZE</span><span class="p">)</span> + <span class="n">ClearPageReserved</span><span class="p">(</span><span class="n">virt_to_page</span><span class="p">(((</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)</span><span class="n">mem</span><span class="p">)</span> <span class="o">+</span> <span class="n">i</span><span class="p">));</span> + + <span class="n">kfree</span><span class="p">(</span><span class="n">mem</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="further-reading"> +<h2>Further reading<a class="headerlink" href="#further-reading" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li><a class="reference external" href="http://lwn.net/images/pdf/LDD3/ch15.pdf">Linux Device Drivers 3rd Edition - Chapter 15. Memory Mapping and DMA</a></li> +<li><a class="reference external" href="http://www.xml.com/ldd/chapter/book/ch13.html">Linux Device Driver mmap Skeleton</a></li> +<li><a class="reference external" href="http://lwn.net/Articles/28746/">Driver porting: supporting mmap ()</a></li> +<li><a class="reference external" href="http://www.linuxjournal.com/article/1287">Device Drivers Concluded</a></li> +<li><a class="reference external" href="http://en.wikipedia.org/wiki/Mmap">mmap</a></li> +</ul> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is memory_mapping. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/memory_mapping/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="section" id="mapping-contiguous-physical-memory-to-userspace"> +<h3>1. Mapping contiguous physical memory to userspace<a class="headerlink" href="#mapping-contiguous-physical-memory-to-userspace" title="Permalink to this headline">¶</a></h3> +<p>Implement a device driver that maps contiguous physical memory +(e.g. obtained via <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code>) to userspace.</p> +<p>Review the <a class="reference internal" href="#device-driver-memory-mapping">Device driver memory mapping</a> section, generate the +skeleton for the task named <strong>kmmap</strong> and fill in the areas marked +with <strong>TODO 1</strong>.</p> +<p>Start with allocating a NPAGES+2 memory area page using <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> +in the module init function and find the first address in the area that is +aligned to a page boundary.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>The size of a page is <em>PAGE_SIZE</em>.</p> +<p>Store the allocated area in <em>kmalloc_ptr</em> and the page +aligned address in <em>kmalloc_area</em>:</p> +<p class="last">Use <code class="xref c c-func docutils literal"><span class="pre">PAGE_ALIGN()</span></code> to determine <em>kmalloc_area</em>.</p> +</div> +<p>Enable the PG_reserved bit of each page with +<code class="xref c c-func docutils literal"><span class="pre">SetPageReserved()</span></code>. Clear the bit with +<code class="xref c c-func docutils literal"><span class="pre">ClearPageReserved()</span></code> before freeing the memory.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use <code class="xref c c-func docutils literal"><span class="pre">virt_to_page()</span></code> to translate virtual pages into +physical pages, as required by <code class="xref c c-func docutils literal"><span class="pre">SetPageReserved()</span></code> +and <code class="xref c c-func docutils literal"><span class="pre">ClearPageReserved()</span></code>.</p> +</div> +<p>For verification purpose (using the test below), fill in the first 4 +bytes of each page with the following values: 0xaa, 0xbb, 0xcc, 0xdd.</p> +<p>Implement the <code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> driver function.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>For mapping, use <code class="xref c c-func docutils literal"><span class="pre">remap_pfn_range()</span></code>. The third +argument for <code class="xref c c-func docutils literal"><span class="pre">remap_pfn_range()</span></code> is a page frame number (PFN).</p> +<p>To convert from virtual kernel address to physical address, +use <code class="xref c c-func docutils literal"><span class="pre">virt_to_phys()</span></code>.</p> +<p class="last">To convert a physical address to its PFN, shift the address +with PAGE_SHIFT bits to the right.</p> +</div> +<p>For testing, load the kernel module and run:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>root@qemux86:~# skels/memory_mapping/test/mmap-test <span class="m">1</span> +</pre></div> +</div> +<p>If everything goes well, the test will show "matched" messages.</p> +</div> +<div class="section" id="mapping-non-contiguous-physical-memory-to-userspace"> +<h3>2. Mapping non-contiguous physical memory to userspace<a class="headerlink" href="#mapping-non-contiguous-physical-memory-to-userspace" title="Permalink to this headline">¶</a></h3> +<p>Implement a device driver that maps non-contiguous physical memory +(e.g. obtained via <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code>) to userspace.</p> +<p>Review the <a class="reference internal" href="#device-driver-memory-mapping">Device driver memory mapping</a> section, generate the +skeleton for the task named <strong>vmmap</strong> and fill in the areas marked +with <strong>TODO 1</strong>.</p> +<p>Allocate a memory area of NPAGES with <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code>.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">The size of a page is <em>PAGE_SIZE</em>. +Store the allocated area in <em>vmalloc_area</em>. +Memory allocated by <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code> is paged aligned.</p> +</div> +<p>Enable the PG_reserved bit of each page with +<code class="xref c c-func docutils literal"><span class="pre">SetPageReserved()</span></code>. Clear the bit with +<code class="xref c c-func docutils literal"><span class="pre">ClearPageReserved()</span></code> before freeing the memory.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use <code class="xref c c-func docutils literal"><span class="pre">vmalloc_to_page()</span></code> to translate virtual pages +into physical pages used by the functions +<code class="xref c c-func docutils literal"><span class="pre">SetPageReserved()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">ClearPageReserved()</span></code>.</p> +</div> +<p>For verification purpose (using the test below), fill in the first 4 +bytes of each page with the following values: 0xaa, 0xbb, 0xcc, 0xdd.</p> +<p>Implement the mmap driver function.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">To convert from virtual vmalloc address to physical address, +use <code class="xref c c-func docutils literal"><span class="pre">vmalloc_to_pfn()</span></code> which returns a PFN directly.</p> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p>vmalloc pages are not physically contiguous so it is +needed to use <code class="xref c c-func docutils literal"><span class="pre">remap_pfn_range()</span></code> for each page.</p> +<p>Loop through all virtual pages and for each: +* determine the physical address +* map it with <code class="xref c c-func docutils literal"><span class="pre">remap_pfn_range()</span></code></p> +<p class="last">Make sure that you determine the physical address +each time and that you use a range of one page for mapping.</p> +</div> +<p>For testing, load the kernel module and run:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>root@qemux86:~# skels/memory_mapping/test/mmap-test <span class="m">1</span> +</pre></div> +</div> +<p>If everything goes well, the test will show "matched" messages.</p> +</div> +<div class="section" id="read-write-operations-in-mapped-memory"> +<h3>3. Read / write operations in mapped memory<a class="headerlink" href="#read-write-operations-in-mapped-memory" title="Permalink to this headline">¶</a></h3> +<p>Modify one of the previous modules to allow read / write operations on +your device. This is a didactic exercise to see that the same space +can also be used with the <code class="xref c c-func docutils literal"><span class="pre">mmap()</span></code> call and with <code class="xref c c-func docutils literal"><span class="pre">read()</span></code> +and <code class="xref c c-func docutils literal"><span class="pre">write()</span></code> calls.</p> +<p>Fill in areas marked with <strong>TODO 2</strong>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The offset parameter sent to the read / write operation can +be ignored as all reads / writes from the test program will +be done with 0 offsets.</p> +</div> +<p>For testing, load the kernel module and run:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>root@qemux86:~# skels/memory_mapping/test/mmap-test <span class="m">2</span> +</pre></div> +</div> +</div> +<div class="section" id="display-memory-mapped-in-procfs"> +<h3>4. Display memory mapped in procfs<a class="headerlink" href="#display-memory-mapped-in-procfs" title="Permalink to this headline">¶</a></h3> +<p>Using one of the previous modules, create a procfs file in which you +display the total memory mapped by the calling process.</p> +<p>Fill in the areas marked with <strong>TODO 3</strong>.</p> +<p>Create a new entry in procfs (<code class="xref c c-macro docutils literal"><span class="pre">PROC_ENTRY_NAME</span></code>, defined in +<code class="file docutils literal"><span class="pre">mmap-test.h</span></code>) that will show the total memory mapped by the process +that called the <code class="xref c c-func docutils literal"><span class="pre">read()</span></code> on that file.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use <code class="xref c c-func docutils literal"><span class="pre">proc_create()</span></code>. For the mode parameter, use 0, +and for the parent parameter use NULL. Use +<code class="xref c c-func docutils literal"><span class="pre">my_proc_file_ops()</span></code> for operations.</p> +</div> +<p>In the module exit function, delete the <code class="xref c c-macro docutils literal"><span class="pre">PROC_ENTRY_NAME</span></code> entry +using <code class="xref c c-func docutils literal"><span class="pre">remove_proc_entry()</span></code>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>A (complex) use and description of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> +<span class="pre">seq_file</span></code> interface can be found here in this <a class="reference external" href="http://tldp.org/LDP/lkmpg/2.6/html/x861.html">example</a> .</p> +<p class="last">For this exercise, just a simple use of the interface +described <a class="reference external" href="http://lwn.net/Articles/22355/">here</a> is +sufficient. Check the "extra-simple" API described there.</p> +</div> +<p>In the <code class="xref c c-func docutils literal"><span class="pre">my_seq_show()</span></code> function you will need to:</p> +<ul> +<li><p class="first">Obtain the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code> structure of the current process +using the <code class="xref c c-func docutils literal"><span class="pre">get_task_mm()</span></code> function.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">The current process is available via the <em>current</em> variable +of type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct*</span></code>.</p> +</div> +</li> +<li><p class="first">Iterate through the entire <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code> list +associated with the process.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use the variable <code class="xref c c-data docutils literal"><span class="pre">vma_iterator</span></code> and start from +<code class="xref c c-data docutils literal"><span class="pre">mm->mmap</span></code>. Use the <code class="xref c c-member docutils literal"><span class="pre">vm_next</span></code> field of +the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code> to navigate through +the list of memory areas. Stop when you reach <code class="xref c c-macro docutils literal"><span class="pre">NULL</span></code>.</p> +</div> +</li> +<li><p class="first">Use <em>vm_start</em> and <em>vm_end</em> for each area to compute the total size.</p> +</li> +<li><p class="first">Use <code class="xref c c-func docutils literal"><span class="pre">pr_info("%lx</span> <span class="pre">%lxn,</span> <span class="pre">...)()</span></code> to print <em>vm_start</em> and <em>vm_end</em> for +each area.</p> +</li> +<li><p class="first">To release <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code>, decrement the reference +counter of the structure using <code class="xref c c-func docutils literal"><span class="pre">mmput()</span></code>.</p> +</li> +<li><p class="first">Use <code class="xref c c-func docutils literal"><span class="pre">seq_printf()</span></code> to write to the file. Show only the total count, +no other messages. Do not even show newline (n).</p> +</li> +</ul> +<p>In <code class="xref c c-func docutils literal"><span class="pre">my_seq_open()</span></code> register the display function +(<code class="xref c c-func docutils literal"><span class="pre">my_seq_show()</span></code>) using <code class="xref c c-func docutils literal"><span class="pre">single_open()</span></code>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last"><code class="xref c c-func docutils literal"><span class="pre">single_open()</span></code> can use <code class="xref c c-macro docutils literal"><span class="pre">NULL</span></code> as its third argument.</p> +</div> +<p>For testing, load the kernel module and run:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>root@qemux86:~# skels/memory_mapping/test/mmap-test <span class="m">3</span> +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The test waits for a while (it has an internal sleep +instruction). As long as the test waits, use the +<strong class="command">pmap</strong> command in another console to see the +mappings of the test and compare those to the test results.</p> +</div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lab5-deferred-work.html" class="btn btn-neutral float-left" title="SO2 Lab 05 - Deferred work" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lab7-block-device-drivers.html" class="btn btn-neutral float-right" title="SO2 Lab 07 - Block Device Drivers" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lab7-block-device-drivers.html b/refs/pull/405/merge/so2/lab7-block-device-drivers.html new file mode 100644 index 00000000..2a98751a --- /dev/null +++ b/refs/pull/405/merge/so2/lab7-block-device-drivers.html @@ -0,0 +1,1397 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lab 07 - Block Device Drivers — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lab 08 - File system drivers (Part 1)" href="lab8-filesystems-part1.html" /> + <link rel="prev" title="SO2 Lab 06 - Memory Mapping" href="lab6-memory-mapping.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lab 07 - Block Device Drivers</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#overview">Overview</a></li> +<li class="toctree-l3"><a class="reference internal" href="#register-a-block-i-o-device">Register a block I/O device</a></li> +<li class="toctree-l3"><a class="reference internal" href="#register-a-disk">Register a disk</a></li> +<li class="toctree-l3"><a class="reference internal" href="#struct-gendisk-structure"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="#struct-block-device-operations-structure"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">block_device_operations</span></code> structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="#request-queues-multi-queue-block-layer">Request Queues - Multi-Queue Block Layer</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#software-staging-queues">Software staging queues</a></li> +<li class="toctree-l4"><a class="reference internal" href="#hardware-dispatch-queues">Hardware dispatch queues</a></li> +<li class="toctree-l4"><a class="reference internal" href="#tag-sets">Tag sets</a></li> +<li class="toctree-l4"><a class="reference internal" href="#create-and-delete-a-request-queue">Create and delete a request queue</a></li> +<li class="toctree-l4"><a class="reference internal" href="#useful-functions-for-processing-request-queues">Useful functions for processing request queues</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#requests-for-block-devices">Requests for block devices</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#create-a-request">Create a request</a></li> +<li class="toctree-l4"><a class="reference internal" href="#process-a-request">Process a request</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#struct-bio-structure"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#create-a-struct-bio-structure">Create a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="#submit-a-struct-bio-structure">Submit a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="#wait-for-the-completion-of-a-struct-bio-structure">Wait for the completion of a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="#initialize-a-struct-bio-structure">Initialize a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="#how-to-use-the-content-of-a-struct-bio-structure">How to use the content of a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="#free-a-struct-bio-structure">Free a <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="#set-up-a-request-queue-at-struct-bio-level">Set up a request queue at <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> level</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#further-reading">Further reading</a></li> +<li class="toctree-l3"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#intro">0. Intro</a></li> +<li class="toctree-l4"><a class="reference internal" href="#block-device">1. Block device</a></li> +<li class="toctree-l4"><a class="reference internal" href="#disk-registration">2. Disk registration</a></li> +<li class="toctree-l4"><a class="reference internal" href="#ram-disk">3. RAM disk</a></li> +<li class="toctree-l4"><a class="reference internal" href="#read-data-from-the-disk">4. Read data from the disk</a></li> +<li class="toctree-l4"><a class="reference internal" href="#write-data-to-the-disk">5. Write data to the disk</a></li> +<li class="toctree-l4"><a class="reference internal" href="#processing-requests-from-the-request-queue-at-struct-bio-level">6. Processing requests from the request queue at <code class="docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> level</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lab 07 - Block Device Drivers</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lab7-block-device-drivers.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lab-07-block-device-drivers"> +<h1>SO2 Lab 07 - Block Device Drivers<a class="headerlink" href="#so2-lab-07-block-device-drivers" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<blockquote> +<div><ul class="simple"> +<li>acquiring knowledge about the behavior of the I/O subsystem on Linux</li> +<li>hands-on activities in structures and functions of block devices</li> +<li>acquiring basic skills for utilizing the API for block devices, by solving +exercises</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="overview"> +<h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline">¶</a></h2> +<p>Block devices are characterized by random access to data organized in fixed-size +blocks. Examples of such devices are hard drives, CD-ROM drives, RAM disks, etc. +The speed of block devices is generally much higher than the speed of character +devices, and their performance is also important. This is why the Linux kernel +handles differently these 2 types of devices (it uses a specialized API).</p> +<p>Working with block devices is therefore more complicated than working with +character devices. Character devices have a single current position, while block +devices must be able to move to any position in the device to provide random +access to data. To simplify work with block devices, the Linux kernel provides +an entire subsystem called the block I/O (or block layer) subsystem.</p> +<p>From the kernel perspective, the smallest logical unit of addressing is the +block. Although the physical device can be addressed at sector level, the kernel +performs all disk operations using blocks. Since the smallest unit of physical +addressing is the sector, the size of the block must be a multiple of the size +of the sector. Additionally, the block size must be a power of 2 and can not +exceed the size of a page. The size of the block may vary depending on the file +system used, the most common values being 512 bytes, 1 kilobytes and 4 +kilobytes.</p> +</div> +<div class="section" id="register-a-block-i-o-device"> +<h2>Register a block I/O device<a class="headerlink" href="#register-a-block-i-o-device" title="Permalink to this headline">¶</a></h2> +<p>To register a block I/O device, function <code class="xref c c-func docutils literal"><span class="pre">register_blkdev()</span></code> is used. +To deregister a block I/O device, function <code class="xref c c-func docutils literal"><span class="pre">unregister_blkdev()</span></code> is +used.</p> +<p>Starting with version 4.9 of the Linux kernel, the call to +<code class="xref c c-func docutils literal"><span class="pre">register_blkdev()</span></code> is optional. The only operations performed by this +function are the dynamic allocation of a major (if the major argument is 0 when +calling the function) and creating an entry in <code class="file docutils literal"><span class="pre">/proc/devices</span></code>. In +future kernel versions it may be removed; however, most drivers still call it.</p> +<p>Usually, the call to the register function is performed in the module +initialization function, and the call to the deregister function is performed in +the module exit function. A typical scenario is presented below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> + +<span class="cp">#define MY_BLOCK_MAJOR 240</span> +<span class="cp">#define MY_BLKDEV_NAME "mybdev"</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_block_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">status</span><span class="p">;</span> + + <span class="n">status</span> <span class="o">=</span> <span class="n">register_blkdev</span><span class="p">(</span><span class="n">MY_BLOCK_MAJOR</span><span class="p">,</span> <span class="n">MY_BLKDEV_NAME</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">status</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="n">printk</span><span class="p">(</span><span class="n">KERN_ERR</span> <span class="s">"unable to register mybdev block device</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EBUSY</span><span class="p">;</span> + <span class="p">}</span> + <span class="c1">//...</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">my_block_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="c1">//...</span> + <span class="n">unregister_blkdev</span><span class="p">(</span><span class="n">MY_BLOCK_MAJOR</span><span class="p">,</span> <span class="n">MY_BLKDEV_NAME</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="register-a-disk"> +<h2>Register a disk<a class="headerlink" href="#register-a-disk" title="Permalink to this headline">¶</a></h2> +<p>Although the <code class="xref c c-func docutils literal"><span class="pre">register_blkdev()</span></code> function obtains a major, it does not +provide a device (disk) to the system. For creating and using block devices +(disks), a specialized interface defined in <code class="file docutils literal"><span class="pre">linux/genhd.h</span></code> is used.</p> +<p>The useful functions defined in <code class="file docutils literal"><span class="pre">linux/genhd.h</span></code> are to register /allocate +a disk, add it to the system, and de-register /unmount the disk.</p> +<p>The <code class="xref c c-func docutils literal"><span class="pre">alloc_disk()</span></code> function is used to allocate a disk, and the +<code class="xref c c-func docutils literal"><span class="pre">del_gendisk()</span></code> function is used to deallocate it. Adding the disk to the +system is done using the <code class="xref c c-func docutils literal"><span class="pre">add_disk()</span></code> function.</p> +<p>The <code class="xref c c-func docutils literal"><span class="pre">alloc_disk()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">add_disk()</span></code> functions are typically used in +the module initialization function, and the <code class="xref c c-func docutils literal"><span class="pre">del_gendisk()</span></code> function in +the module exit function.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/genhd.h></span><span class="cp"></span> + +<span class="cp">#define MY_BLOCK_MINORS 1</span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">my_block_dev</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">gendisk</span> <span class="o">*</span><span class="n">gd</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">}</span> <span class="n">dev</span><span class="p">;</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">create_block_device</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_block_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">dev</span><span class="o">-></span><span class="n">gd</span> <span class="o">=</span> <span class="n">alloc_disk</span><span class="p">(</span><span class="n">MY_BLOCK_MINORS</span><span class="p">);</span> + <span class="c1">//...</span> + <span class="n">add_disk</span><span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_block_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="c1">//...</span> + <span class="n">create_block_device</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">delete_block_device</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_block_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="p">)</span> + <span class="n">del_gendisk</span><span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="p">);</span> + <span class="c1">//...</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">my_block_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">delete_block_device</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="p">);</span> + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>As with character devices, it is recommended to use <code class="xref c c-type docutils literal"><span class="pre">my_block_dev</span></code> +structure to store important elements describing the block device.</p> +<p>Note that immediately after calling the <code class="xref c c-func docutils literal"><span class="pre">add_disk()</span></code> function (actually +even during the call), the disk is active and its methods can be called at any +time. As a result, this function should not be called before the driver is fully +initialized and ready to respond to requests for the registered disk.</p> +<p>It can be noticed that the basic structure in working with block devices (disks) +is the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> structure.</p> +<p>After a call to <code class="xref c c-func docutils literal"><span class="pre">del_gendisk()</span></code>, the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> structure +may continue to exist (and the device operations may still be called) if there +are still users (an open operation was called on the device but the associated +release operation has not been called). One solution is to keep the number of +users of the device and call the <code class="xref c c-func docutils literal"><span class="pre">del_gendisk()</span></code> function only when there +are no users left of the device.</p> +</div> +<div class="section" id="struct-gendisk-structure"> +<h2><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> structure<a class="headerlink" href="#struct-gendisk-structure" title="Permalink to this headline">¶</a></h2> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> structure stores information about a disk. As +stated above, such a structure is obtained from the <code class="xref c c-func docutils literal"><span class="pre">alloc_disk()</span></code> call +and its fields must be filled before it is sent to the <code class="xref c c-func docutils literal"><span class="pre">add_disk()</span></code> +function.</p> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> structure has the following important fields:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-member docutils literal"><span class="pre">major</span></code>, <code class="xref c c-member docutils literal"><span class="pre">first_minor</span></code>, <code class="xref c c-member docutils literal"><span class="pre">minor</span></code>, describing +the identifiers used by the disk; a disk must have at least one minor; if +the disk allows the partitioning operation, a minor must be allocated for +each possible partition</li> +<li><code class="xref c c-member docutils literal"><span class="pre">disk_name</span></code>, which represents the disk name as it appears in +<code class="file docutils literal"><span class="pre">/proc/partitions</span></code> and in sysfs (<code class="file docutils literal"><span class="pre">/sys/block</span></code>)</li> +<li><code class="xref c c-member docutils literal"><span class="pre">fops</span></code>, representing operations associated with the disk</li> +<li><code class="xref c c-member docutils literal"><span class="pre">queue</span></code>, which represents the queue of requests</li> +<li><code class="xref c c-member docutils literal"><span class="pre">capacity</span></code>, which is disk capacity in 512 byte sectors; +it is initialized using the <code class="xref c c-func docutils literal"><span class="pre">set_capacity()</span></code> function</li> +<li><code class="xref c c-member docutils literal"><span class="pre">private_data</span></code>, which is a pointer to private data</li> +</ul> +</div></blockquote> +<p>An example of filling a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> structure is presented below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/genhd.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/blkdev.h></span><span class="cp"></span> + +<span class="cp">#define NR_SECTORS 1024</span> + +<span class="cp">#define KERNEL_SECTOR_SIZE 512</span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">my_block_dev</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="n">spinlock_t</span> <span class="n">lock</span><span class="p">;</span> <span class="cm">/* For mutual exclusion */</span> + <span class="k">struct</span> <span class="n">request_queue</span> <span class="o">*</span><span class="n">queue</span><span class="p">;</span> <span class="cm">/* The device request queue */</span> + <span class="k">struct</span> <span class="n">gendisk</span> <span class="o">*</span><span class="n">gd</span><span class="p">;</span> <span class="cm">/* The gendisk structure */</span> + <span class="c1">//...</span> +<span class="p">}</span> <span class="n">dev</span><span class="p">;</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">create_block_device</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_block_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span> +<span class="p">{</span> + <span class="p">...</span> + <span class="cm">/* Initialize the gendisk structure */</span> + <span class="n">dev</span><span class="o">-></span><span class="n">gd</span> <span class="o">=</span> <span class="n">alloc_disk</span><span class="p">(</span><span class="n">MY_BLOCK_MINORS</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="p">)</span> <span class="p">{</span> + <span class="n">printk</span> <span class="p">(</span><span class="n">KERN_NOTICE</span> <span class="s">"alloc_disk failure</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="k">return</span> <span class="o">-</span><span class="n">ENOMEM</span><span class="p">;</span> + <span class="p">}</span> + + <span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="o">-></span><span class="n">major</span> <span class="o">=</span> <span class="n">MY_BLOCK_MAJOR</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="o">-></span><span class="n">first_minor</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="o">-></span><span class="n">fops</span> <span class="o">=</span> <span class="o">&</span><span class="n">my_block_ops</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="o">-></span><span class="n">queue</span> <span class="o">=</span> <span class="n">dev</span><span class="o">-></span><span class="n">queue</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="o">-></span><span class="n">private_data</span> <span class="o">=</span> <span class="n">dev</span><span class="p">;</span> + <span class="n">snprintf</span> <span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="o">-></span><span class="n">disk_name</span><span class="p">,</span> <span class="mi">32</span><span class="p">,</span> <span class="s">"myblock"</span><span class="p">);</span> + <span class="n">set_capacity</span><span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="p">,</span> <span class="n">NR_SECTORS</span><span class="p">);</span> + + <span class="n">add_disk</span><span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_block_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">status</span><span class="p">;</span> + <span class="c1">//...</span> + <span class="n">status</span> <span class="o">=</span> <span class="n">create_block_device</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">status</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">return</span> <span class="n">status</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">delete_block_device</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_block_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="p">)</span> <span class="p">{</span> + <span class="n">del_gendisk</span><span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="p">);</span> + <span class="p">}</span> + <span class="c1">//...</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">my_block_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">delete_block_device</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="p">);</span> + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>As stated before, the kernel considers a disk as a vector of 512 byte sectors. +In reality, the devices may have a different size of the sector. To work with +these devices, the kernel needs to be informed about the real size of a sector, +and for all operations the necessary conversions must be made.</p> +<p>To inform the kernel about the device sector size, a parameter of the request +queue must be set just after the request queue is allocated, using the +<code class="xref c c-func docutils literal"><span class="pre">blk_queue_logical_block_size()</span></code> function. All requests generated by the +kernel will be multiple of this sector size and will be aligned accordingly. +However, communication between the device and the driver will still be performed +in sectors of 512 bytes in size, so conversion should be done each time (an +example of such conversion is when calling the <code class="xref c c-func docutils literal"><span class="pre">set_capacity()</span></code> function +in the code above).</p> +</div> +<div class="section" id="struct-block-device-operations-structure"> +<h2><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">block_device_operations</span></code> structure<a class="headerlink" href="#struct-block-device-operations-structure" title="Permalink to this headline">¶</a></h2> +<p>Just as for a character device, operations in <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code> +should be completed, so for a block device, the operations in +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">block_device_operations</span></code> should be completed. The association +of operations is done through the <code class="xref c c-member docutils literal"><span class="pre">fops</span></code> field in the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code> +structure.</p> +<p>Some of the fields of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">block_device_operations</span></code> structure +are presented below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">block_device_operations</span> <span class="p">{</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">open</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">block_device</span> <span class="o">*</span><span class="p">,</span> <span class="n">fmode_t</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">release</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">gendisk</span> <span class="o">*</span><span class="p">,</span> <span class="n">fmode_t</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">locked_ioctl</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">block_device</span> <span class="o">*</span><span class="p">,</span> <span class="n">fmode_t</span><span class="p">,</span> <span class="kt">unsigned</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">ioctl</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">block_device</span> <span class="o">*</span><span class="p">,</span> <span class="n">fmode_t</span><span class="p">,</span> <span class="kt">unsigned</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">compat_ioctl</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">block_device</span> <span class="o">*</span><span class="p">,</span> <span class="n">fmode_t</span><span class="p">,</span> <span class="kt">unsigned</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">direct_access</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">block_device</span> <span class="o">*</span><span class="p">,</span> <span class="n">sector_t</span><span class="p">,</span> + <span class="kt">void</span> <span class="o">**</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">media_changed</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">gendisk</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">revalidate_disk</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">gendisk</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">getgeo</span><span class="p">)(</span><span class="k">struct</span> <span class="n">block_device</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">hd_geometry</span> <span class="o">*</span><span class="p">);</span> + <span class="n">blk_qc_t</span> <span class="p">(</span><span class="o">*</span><span class="n">submit_bio</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">bio</span> <span class="o">*</span><span class="n">bio</span><span class="p">);</span> + <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">owner</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p><code class="xref c c-func docutils literal"><span class="pre">open()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">release()</span></code> operations are called directly from user +space by utilities that may perform the following tasks: partitioning, file +system creation, file system verification. In a <code class="xref c c-func docutils literal"><span class="pre">mount()</span></code> operation, the +<code class="xref c c-func docutils literal"><span class="pre">open()</span></code> function is called directly from the kernel space, the file +descriptor being stored by the kernel. A driver for a block device can not +differentiate between <code class="xref c c-func docutils literal"><span class="pre">open()</span></code> calls performed from user space and kernel +space.</p> +<p>An example of how to use these two functions is given below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/genhd.h></span><span class="cp"></span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">my_block_dev</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">gendisk</span> <span class="o">*</span> <span class="n">gd</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">}</span> <span class="n">dev</span><span class="p">;</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_block_open</span><span class="p">(</span><span class="k">struct</span> <span class="n">block_device</span> <span class="o">*</span><span class="n">bdev</span><span class="p">,</span> <span class="n">fmode_t</span> <span class="n">mode</span><span class="p">)</span> +<span class="p">{</span> + <span class="c1">//...</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_block_release</span><span class="p">(</span><span class="k">struct</span> <span class="n">gendisk</span> <span class="o">*</span><span class="n">gd</span><span class="p">,</span> <span class="n">fmode_t</span> <span class="n">mode</span><span class="p">)</span> +<span class="p">{</span> + <span class="c1">//...</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">struct</span> <span class="n">block_device_operations</span> <span class="n">my_block_ops</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">owner</span> <span class="o">=</span> <span class="n">THIS_MODULE</span><span class="p">,</span> + <span class="p">.</span><span class="n">open</span> <span class="o">=</span> <span class="n">my_block_open</span><span class="p">,</span> + <span class="p">.</span><span class="n">release</span> <span class="o">=</span> <span class="n">my_block_release</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">create_block_device</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_block_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span> +<span class="p">{</span> + <span class="c1">//....</span> + <span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="o">-></span><span class="n">fops</span> <span class="o">=</span> <span class="o">&</span><span class="n">my_block_ops</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">gd</span><span class="o">-></span><span class="n">private_data</span> <span class="o">=</span> <span class="n">dev</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Please notice that there are no read or write operations. These operations are +performed by the <code class="xref c c-func docutils literal"><span class="pre">request()</span></code> function associated with the request queue +of the disk.</p> +</div> +<div class="section" id="request-queues-multi-queue-block-layer"> +<h2>Request Queues - Multi-Queue Block Layer<a class="headerlink" href="#request-queues-multi-queue-block-layer" title="Permalink to this headline">¶</a></h2> +<p>Drivers for block devices use queues to store the block I/O requests that will +be processed. A request queue is represented by the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request_queue</span></code> structure. The request queue is made up of a +double-linked list of requests and their associated control information. The +requests are added to the queue by higher-level kernel code (for example, file +systems).</p> +<p>The block device driver associates each queue with a handling function, which +will be called for each request in the queue +(the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code> structure).</p> +<p>In earlier version of the Linux kernel, each device driver had associated one or +more request queues (<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request_queue</span></code>), where any client could add +requests, while also being able to reorder them. +The problem with this approach is that it requires a per-queue lock, making it +inefficient in distributed systems.</p> +<p>The <a class="reference external" href="https://www.kernel.org/doc/html/latest/block/blk-mq.html">Multi-Queue Block Queing Mechanism</a> +solves this issue by splitting the device driver queue in two parts:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Software staging queues</li> +<li>Hardware dispatch queues</li> +</ol> +</div></blockquote> +<div class="section" id="software-staging-queues"> +<h3>Software staging queues<a class="headerlink" href="#software-staging-queues" title="Permalink to this headline">¶</a></h3> +<p>The staging queues hold requests from the clients before sending them to the +block device driver. To prevent the waiting for a per-queue lock, a staging +queue is allocated for each CPU or node. A software queue is associated to +only one hardware queue.</p> +<p>While in this queue, the requests can be merged or reordered, according to an +I/O Scheduler, in order to maximize performance. This means that only the +requests coming from the same CPU or node can be optimized.</p> +<p>Staging queues are usually not used by the block device drivers, but only +internally by the I/O subsystem to optimize requests before sending them to the +device drivers.</p> +</div> +<div class="section" id="hardware-dispatch-queues"> +<h3>Hardware dispatch queues<a class="headerlink" href="#hardware-dispatch-queues" title="Permalink to this headline">¶</a></h3> +<p>The hardware queues (<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">blk_mq_hw_ctx</span></code>) are used to send the +requests from the staging queues to the block device driver. +Once in this queue, the requests can't be merged or reordered.</p> +<p>Depending on the underlying hardware, a block device driver can create multiple +hardware queues in order to improve parallelism and maximize performance.</p> +</div> +<div class="section" id="tag-sets"> +<h3>Tag sets<a class="headerlink" href="#tag-sets" title="Permalink to this headline">¶</a></h3> +<p>A block device driver can accept a request before the previous one is completed. +As a consequence, the upper layers need a way to know when a request is +completed. For this, a "tag" is added to each request upon submission and sent +back using a completion notification after the request is completed.</p> +<p>The tags are part of a tag set (<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">blk_mq_tag_set</span></code>), which is +unique to a device. +The tag set structure is allocated and initialized before the request queues +and also stores some of the queues properties.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">blk_mq_tag_set</span> <span class="p">{</span> + <span class="p">...</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">blk_mq_ops</span> <span class="o">*</span><span class="n">ops</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">nr_hw_queues</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">queue_depth</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">cmd_size</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">numa_node</span><span class="p">;</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">driver_data</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">blk_mq_tags</span> <span class="o">**</span><span class="n">tags</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="n">tag_list</span><span class="p">;</span> + <span class="p">...</span> +<span class="p">};</span> +</pre></div> +</div> +<p>Some of the fields in <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">blk_mq_tag_set</span></code> are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">ops</span></code> - Queue operations, most notably the request handling function.</li> +<li><code class="docutils literal"><span class="pre">nr_hw_queues</span></code> - The number of hardware queues allocated for the device</li> +<li><code class="docutils literal"><span class="pre">queue_depth</span></code> - Hardware queues size</li> +<li><code class="docutils literal"><span class="pre">cmd_size</span></code> - Number of extra bytes allocated at the end of the device, to +be used by the block device driver, if needed.</li> +<li><code class="docutils literal"><span class="pre">numa_node</span></code> - In NUMA systems, the index of the node the storage device is +connected to.</li> +<li><code class="docutils literal"><span class="pre">driver_data</span></code> - Data private to the driver, if needed.</li> +<li><code class="docutils literal"><span class="pre">tags</span></code> - Pointer to an array of <code class="docutils literal"><span class="pre">nr_hw_queues</span></code> tag sets.</li> +<li><code class="docutils literal"><span class="pre">tag_list</span></code> - List of request queues using this tag set.</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="create-and-delete-a-request-queue"> +<h3>Create and delete a request queue<a class="headerlink" href="#create-and-delete-a-request-queue" title="Permalink to this headline">¶</a></h3> +<p>Request queues are created using the <code class="xref c c-func docutils literal"><span class="pre">blk_mq_init_queue()</span></code> function and +are deleted using <code class="xref c c-func docutils literal"><span class="pre">blk_cleanup_queue()</span></code>. The first function creates both +the hardware and the software queues and initializes their structures.</p> +<p>Queue properties, including the number of hardware queues, their capacity and +request handling function are configured using the <code class="xref c c-type docutils literal"><span class="pre">blk_mq_tag_set</span></code> +structure, as described above.</p> +<p>An example of using these functions is as follows:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/genhd.h></span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf"><linux/blkdev.h></span><span class="cp"></span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">my_block_dev</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">blk_mq_tag_set</span> <span class="n">tag_set</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">request_queue</span> <span class="o">*</span><span class="n">queue</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">}</span> <span class="n">dev</span><span class="p">;</span> + +<span class="k">static</span> <span class="n">blk_status_t</span> <span class="nf">my_block_request</span><span class="p">(</span><span class="k">struct</span> <span class="n">blk_mq_hw_ctx</span> <span class="o">*</span><span class="n">hctx</span><span class="p">,</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">blk_mq_queue_data</span> <span class="o">*</span><span class="n">bd</span><span class="p">)</span> +<span class="c1">//...</span> + +<span class="k">static</span> <span class="k">struct</span> <span class="n">blk_mq_ops</span> <span class="n">my_queue_ops</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">queue_rq</span> <span class="o">=</span> <span class="n">my_block_request</span><span class="p">,</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">create_block_device</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_block_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span> +<span class="p">{</span> + <span class="cm">/* Initialize tag set. */</span> + <span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">.</span><span class="n">ops</span> <span class="o">=</span> <span class="o">&</span><span class="n">my_queue_ops</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">.</span><span class="n">nr_hw_queues</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">.</span><span class="n">queue_depth</span> <span class="o">=</span> <span class="mi">128</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">.</span><span class="n">numa_node</span> <span class="o">=</span> <span class="n">NUMA_NO_NODE</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">.</span><span class="n">cmd_size</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">.</span><span class="n">flags</span> <span class="o">=</span> <span class="n">BLK_MQ_F_SHOULD_MERGE</span><span class="p">;</span> + <span class="n">err</span> <span class="o">=</span> <span class="n">blk_mq_alloc_tag_set</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span><span class="p">)</span> <span class="p">{</span> + <span class="k">goto</span> <span class="n">out_err</span><span class="p">;</span> + <span class="p">}</span> + + <span class="cm">/* Allocate queue. */</span> + <span class="n">dev</span><span class="o">-></span><span class="n">queue</span> <span class="o">=</span> <span class="n">blk_mq_init_queue</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">IS_ERR</span><span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">queue</span><span class="p">))</span> <span class="p">{</span> + <span class="k">goto</span> <span class="n">out_blk_init</span><span class="p">;</span> + <span class="p">}</span> + + <span class="n">blk_queue_logical_block_size</span><span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">queue</span><span class="p">,</span> <span class="n">KERNEL_SECTOR_SIZE</span><span class="p">);</span> + + <span class="cm">/* Assign private data to queue structure. */</span> + <span class="n">dev</span><span class="o">-></span><span class="n">queue</span><span class="o">-></span><span class="n">queuedata</span> <span class="o">=</span> <span class="n">dev</span><span class="p">;</span> + <span class="c1">//...</span> + +<span class="nl">out_blk_init</span><span class="p">:</span> + <span class="n">blk_mq_free_tag_set</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">);</span> +<span class="nl">out_err</span><span class="p">:</span> + <span class="k">return</span> <span class="o">-</span><span class="n">ENOMEM</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_block_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">status</span><span class="p">;</span> + <span class="c1">//...</span> + <span class="n">status</span> <span class="o">=</span> <span class="n">create_block_device</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">status</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">return</span> <span class="n">status</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">delete_block_device</span><span class="p">(</span><span class="k">struct</span> <span class="n">block_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span> +<span class="p">{</span> + <span class="c1">//...</span> + <span class="n">blk_cleanup_queue</span><span class="p">(</span><span class="n">dev</span><span class="o">-></span><span class="n">queue</span><span class="p">);</span> + <span class="n">blk_mq_free_tag_set</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="o">-></span><span class="n">tag_set</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">my_block_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">delete_block_device</span><span class="p">(</span><span class="o">&</span><span class="n">dev</span><span class="p">);</span> + <span class="c1">//...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>After initializing the tag set structure, the tag lists are allocated using the +<code class="xref c c-func docutils literal"><span class="pre">blk_mq_alloc_tag_set()</span></code> function. +The pointer to the function which will process the requests +(<code class="xref c c-func docutils literal"><span class="pre">my_block_request()</span></code>) is filled in the <code class="docutils literal"><span class="pre">my_queue_ops</span></code> structure and +then the pointer to this structure is added to the tag set.</p> +<p>The queue is created using the <code class="xref c c-func docutils literal"><span class="pre">blk_mq_init_queue()</span></code> function, based on +the information added in the tag set.</p> +<p>As part of the request queue initialization, you can configure the +<code class="xref c c-member docutils literal"><span class="pre">queuedata</span></code> field, which is equivalent to the <code class="xref c c-member docutils literal"><span class="pre">private_data</span></code> +field in other structures.</p> +</div> +<div class="section" id="useful-functions-for-processing-request-queues"> +<h3>Useful functions for processing request queues<a class="headerlink" href="#useful-functions-for-processing-request-queues" title="Permalink to this headline">¶</a></h3> +<p>The <code class="docutils literal"><span class="pre">queue_rq</span></code> function from <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">blk_mq_ops</span></code> is used to handle +requests for working with the block device. +This function is the equivalent of read and write functions encountered on +character devices. The function receives the requests for the device as +arguments and can use various functions for processing them.</p> +<p>The functions used to process the requests in the handler are described below:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">blk_mq_start_request()</span></code> - must be called before starting processing +a request;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">blk_mq_requeue_request()</span></code> - to re-send the request in the queue;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">blk_mq_end_request()</span></code> - to end request processing and notify the +upper layers.</li> +</ul> +</div></blockquote> +</div> +</div> +<div class="section" id="requests-for-block-devices"> +<h2>Requests for block devices<a class="headerlink" href="#requests-for-block-devices" title="Permalink to this headline">¶</a></h2> +<p>A request for a block device is described by <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code> +structure.</p> +<p>The fields of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code> structure include:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-member docutils literal"><span class="pre">cmd_flags</span></code>: a series of flags including direction (reading or +writing); to find out the direction, the macrodefinition +<code class="xref c c-macro docutils literal"><span class="pre">rq_data_dir</span></code> is used, which returns 0 for a read request and 1 +for a write request on the device;</li> +<li><code class="xref c c-member docutils literal"><span class="pre">__sector</span></code>: the first sector of the transfer request; if the +device sector has a different size, the appropriate conversion should be +done. To access this field, use the <code class="xref c c-macro docutils literal"><span class="pre">blk_rq_pos</span></code> macro;</li> +<li><code class="xref c c-member docutils literal"><span class="pre">__data_len</span></code>: the total number of bytes to be transferred; to +access this field the <code class="xref c c-macro docutils literal"><span class="pre">blk_rq_bytes</span></code> macro is used;</li> +<li>generally, data from the current <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> will be +transferred; the data size is obtained using the +<code class="xref c c-macro docutils literal"><span class="pre">blk_rq_cur_bytes</span></code> macro;</li> +<li><code class="xref c c-member docutils literal"><span class="pre">bio</span></code>, a dynamic list of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structures that +is a set of buffers associated to the request; this field is accessed by +macrodefinition <code class="xref c c-macro docutils literal"><span class="pre">rq_for_each_segment</span></code> if there are multiple +buffers, or by <code class="xref c c-macro docutils literal"><span class="pre">bio_data</span></code> macrodefinition in case there is only +one associated buffer;</li> +</ul> +</div></blockquote> +<p>We will discuss more about the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure and its +associated operations in the <span class="xref std std-ref">bio_structure</span> section.</p> +<div class="section" id="create-a-request"> +<h3>Create a request<a class="headerlink" href="#create-a-request" title="Permalink to this headline">¶</a></h3> +<p>Read /write requests are created by code layers superior to the kernel I/O +subsystem. Typically, the subsystem that creates requests for block devices is +the file management subsystem. The I/O subsystem acts as an interface between +the file management subsystem and the block device driver. The main operations +under the responsibility of the I/O subsystem are adding requests to the queue +of the specific block device and sorting and merging requests according to +performance considerations.</p> +</div> +<div class="section" id="process-a-request"> +<h3>Process a request<a class="headerlink" href="#process-a-request" title="Permalink to this headline">¶</a></h3> +<p>The central part of a block device driver is the request handling function +(<code class="docutils literal"><span class="pre">queue_rq</span></code>). In previous examples, the function that fulfilled this role was +<code class="xref c c-func docutils literal"><span class="pre">my_block_request()</span></code>. As stated in the +<a class="reference internal" href="#create-and-delete-a-request-queue">Create and delete a request queue</a> section, this function is associated to the +driver when creating the tag set structure.</p> +<p>This function is called when the kernel considers that the driver should process +I/O requests. The function must start processing the requests from the queue, +but it is not mandatory to finish them, as requests may be finished by other +parts of the driver.</p> +<p>The request function runs in an atomic context and must follow the rules for +atomic code (it does not need to call functions that can cause sleep, etc.).</p> +<p>Calling the function that processes the requests is asynchronous relative +to the actions of any userspace process and no assumptions about the process +in which the respective function is running should be made. Also, it should not +be assumed that the buffer provided by a request is from kernel space or user +space, any operation that accesses the userspace being erroneous.</p> +<p>One of the simplest request handling function is presented below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">blk_status_t</span> <span class="nf">my_block_request</span><span class="p">(</span><span class="k">struct</span> <span class="n">blk_mq_hw_ctx</span> <span class="o">*</span><span class="n">hctx</span><span class="p">,</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">blk_mq_queue_data</span> <span class="o">*</span><span class="n">bd</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">request</span> <span class="o">*</span><span class="n">rq</span> <span class="o">=</span> <span class="n">bd</span><span class="o">-></span><span class="n">rq</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">my_block_dev</span> <span class="o">*</span><span class="n">dev</span> <span class="o">=</span> <span class="n">q</span><span class="o">-></span><span class="n">queuedata</span><span class="p">;</span> + + <span class="n">blk_mq_start_request</span><span class="p">(</span><span class="n">rq</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">blk_rq_is_passthrough</span><span class="p">(</span><span class="n">rq</span><span class="p">))</span> <span class="p">{</span> + <span class="n">printk</span> <span class="p">(</span><span class="n">KERN_NOTICE</span> <span class="s">"Skip non-fs request</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="n">blk_mq_end_request</span><span class="p">(</span><span class="n">rq</span><span class="p">,</span> <span class="n">BLK_STS_IOERR</span><span class="p">);</span> + <span class="k">goto</span> <span class="n">out</span><span class="p">;</span> + <span class="p">}</span> + + <span class="cm">/* do work */</span> + <span class="p">...</span> + + <span class="n">blk_mq_end_request</span><span class="p">(</span><span class="n">rq</span><span class="p">,</span> <span class="n">BLK_STS_OK</span><span class="p">);</span> + +<span class="nl">out</span><span class="p">:</span> + <span class="k">return</span> <span class="n">BLK_STS_OK</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The <code class="xref c c-func docutils literal"><span class="pre">my_block_request()</span></code> function performs the following operations:</p> +<blockquote> +<div><ul class="simple"> +<li>Get a pointer to the request structure from the <code class="docutils literal"><span class="pre">bd</span></code> argument and start +its processing using the <code class="xref c c-func docutils literal"><span class="pre">blk_mq_start_request()</span></code> function.</li> +<li>A block device can receive calls which do not transfer data blocks (e.g. +low level operations on the disk, instructions referring to special ways of +accessing the device). Most drivers do not know how to handle these +requests and return an error.</li> +<li>To return an error, <code class="xref c c-func docutils literal"><span class="pre">blk_mq_end_request()</span></code> function is called, +<code class="docutils literal"><span class="pre">BLK_STS_IOERR</span></code> being the second argument.</li> +<li>The request is processed according to the needs of the associated device.</li> +<li>The request ends. In this case, <code class="xref c c-func docutils literal"><span class="pre">blk_mq_end_request()</span></code> function is +called in order to complete the request.</li> +</ul> +</div></blockquote> +</div> +</div> +<div class="section" id="struct-bio-structure"> +<h2><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure<a class="headerlink" href="#struct-bio-structure" title="Permalink to this headline">¶</a></h2> +<p>Each <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code> structure is an I/O block request, but may come +from combining more independent requests from a higher level. The sectors to be +transferred for a request can be scattered into the main memory but they always +correspond to a set of consecutive sectors on the device. The request is +represented as a series of segments, each corresponding to a buffer in memory. +The kernel can combine requests that refer to adjacent sectors but will not +combine write requests with read requests into a single +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code> structure.</p> +<p>A <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code> structure is implemented as a linked list of +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structures together with information that allows the +driver to retain its current position while processing the request.</p> +<p>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure is a low-level description of a portion of +a block I/O request.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">bio</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">gendisk</span> <span class="o">*</span><span class="n">bi_disk</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">bi_opf</span><span class="p">;</span> <span class="cm">/* bottom bits req flags, top bits REQ_OP. Use accessors. */</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">bio_vec</span> <span class="o">*</span><span class="n">bi_io_vec</span><span class="p">;</span> <span class="cm">/* the actual vec list */</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">bvec_iter</span> <span class="n">bi_iter</span><span class="p">;</span> + <span class="o">/</span><span class="p">...</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">bi_private</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">};</span> +</pre></div> +</div> +<p>In turn, the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure contains a <code class="xref c c-member docutils literal"><span class="pre">bi_io_vec</span></code> +vector of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio_vec</span></code> structures. It consists of the individual +pages in the physical memory to be transferred, the offset within the page and +the size of the buffer. To iterate through a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure, +we need to iterate through the vector of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio_vec</span></code> and transfer +the data from every physical page. To simplify vector iteration, the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bvec_iter</span></code> structure is used. This structure maintains +information about how many buffers and sectors were consumed during the +iteration. The request type is encoded in the <code class="xref c c-member docutils literal"><span class="pre">bi_opf</span></code> field; to +determine it, use the <code class="xref c c-func docutils literal"><span class="pre">bio_data_dir()</span></code> function.</p> +<div class="section" id="create-a-struct-bio-structure"> +<h3>Create a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure<a class="headerlink" href="#create-a-struct-bio-structure" title="Permalink to this headline">¶</a></h3> +<p>Two functions can be used to create a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">bio_alloc()</span></code>: allocates space for a new structure; the structure +must be initialized;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">bio_clone()</span></code>: makes a copy of an existing <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> +structure; the newly obtained structure is initialized with the values of +the cloned structure fields; the buffers are shared with the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure that has been cloned so that access to the +buffers has to be done carefully to avoid access to the same memory area +from the two clones;</li> +</ul> +</div></blockquote> +<p>Both functions return a new <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure.</p> +</div> +<div class="section" id="submit-a-struct-bio-structure"> +<h3>Submit a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure<a class="headerlink" href="#submit-a-struct-bio-structure" title="Permalink to this headline">¶</a></h3> +<p>Usually, a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure is created by the higher levels of +the kernel (usually the file system). A structure thus created is then +transmitted to the I/O subsystem that gathers more <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> +structures into a request.</p> +<p>For submitting a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure to the associated I/O device +driver, the <code class="xref c c-func docutils literal"><span class="pre">submit_bio()</span></code> function is used. The function receives as +argument an initialized <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure that will be added to +a request from the request queue of an I/O device. From that queue, it can be +processed by the I/O device driver using a specialized function.</p> +</div> +<div class="section" id="wait-for-the-completion-of-a-struct-bio-structure"> +<span id="bio-completion"></span><h3>Wait for the completion of a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure<a class="headerlink" href="#wait-for-the-completion-of-a-struct-bio-structure" title="Permalink to this headline">¶</a></h3> +<p>Submitting a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure to a driver has the effect of +adding it to a request from the request queue from where it will be further +processed. Thus, when the <code class="xref c c-func docutils literal"><span class="pre">submit_bio()</span></code> function returns, it is not +guaranteed that the processing of the structure has finished. If you want to +wait for the processing of the request to be finished, use the +<code class="xref c c-func docutils literal"><span class="pre">submit_bio_wait()</span></code> function.</p> +<p>To be notified when the processing of a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure ends +(when we do not use <code class="xref c c-func docutils literal"><span class="pre">submit_bio_wait()</span></code> function), the +<code class="xref c c-member docutils literal"><span class="pre">bi_end_io</span></code> field of the structure should be used. This field +specifies the function that will be called at the end of the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure processing. You can use the +<code class="xref c c-member docutils literal"><span class="pre">bi_private</span></code> field of the structure to pass information to the +function.</p> +</div> +<div class="section" id="initialize-a-struct-bio-structure"> +<h3>Initialize a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure<a class="headerlink" href="#initialize-a-struct-bio-structure" title="Permalink to this headline">¶</a></h3> +<p>Once a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure has been allocated and before being +transmitted, it must be initialized.</p> +<p>Initializing the structure involves filling in its important fields. As +mentioned above, the <code class="xref c c-member docutils literal"><span class="pre">bi_end_io</span></code> field is used to specify the function +called when the processing of the structure is finished. The +<code class="xref c c-member docutils literal"><span class="pre">bi_private</span></code> field is used to store useful data that can be accessed +in the function pointed by <code class="xref c c-member docutils literal"><span class="pre">bi_end_io</span></code>.</p> +<p>The <code class="xref c c-member docutils literal"><span class="pre">bi_opf</span></code> field specifies the type of operation.</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">bio</span> <span class="o">*</span><span class="n">bio</span> <span class="o">=</span> <span class="n">bio_alloc</span><span class="p">(</span><span class="n">GFP_NOIO</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> +<span class="c1">//...</span> +<span class="n">bio</span><span class="o">-></span><span class="n">bi_disk</span> <span class="o">=</span> <span class="n">bdev</span><span class="o">-></span><span class="n">bd_disk</span><span class="p">;</span> +<span class="n">bio</span><span class="o">-></span><span class="n">bi_iter</span><span class="p">.</span><span class="n">bi_sector</span> <span class="o">=</span> <span class="n">sector</span><span class="p">;</span> +<span class="n">bio</span><span class="o">-></span><span class="n">bi_opf</span> <span class="o">=</span> <span class="n">REQ_OP_READ</span><span class="p">;</span> +<span class="n">bio_add_page</span><span class="p">(</span><span class="n">bio</span><span class="p">,</span> <span class="n">page</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="n">offset</span><span class="p">);</span> +<span class="c1">//...</span> +</pre></div> +</div> +<p>In the code snippet above we specified the block device to which we sent the +following: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure, startup sector, operation +(<code class="xref c c-data docutils literal"><span class="pre">REQ_OP_READ</span></code> or <code class="xref c c-data docutils literal"><span class="pre">REQ_OP_WRITE</span></code>) and content. The content of a +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure is a buffer described by: a physical page, +the offset in the page and the size of the bufer. A page can be assigned using +the <code class="xref c c-func docutils literal"><span class="pre">alloc_page()</span></code> call.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The <code class="xref c c-data docutils literal"><span class="pre">size</span></code> field of the <code class="xref c c-func docutils literal"><span class="pre">bio_add_page()</span></code> call must be +a multiple of the device sector size.</p> +</div> +</div> +<div class="section" id="how-to-use-the-content-of-a-struct-bio-structure"> +<span id="bio-content"></span><h3>How to use the content of a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure<a class="headerlink" href="#how-to-use-the-content-of-a-struct-bio-structure" title="Permalink to this headline">¶</a></h3> +<p>To use the content of a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure, the structure's +support pages must be mapped to the kernel address space from where they can be +accessed. For mapping /unmapping, use the <code class="xref c c-macro docutils literal"><span class="pre">kmap_atomic</span></code> and +the <code class="xref c c-macro docutils literal"><span class="pre">kunmap_atomic</span></code> macros.</p> +<p>A typical example of use is:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">void</span> <span class="nf">my_block_transfer</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_block_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">start</span><span class="p">,</span> + <span class="kt">size_t</span> <span class="n">len</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">buffer</span><span class="p">,</span> <span class="kt">int</span> <span class="n">dir</span><span class="p">);</span> + + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">my_xfer_bio</span><span class="p">(</span><span class="k">struct</span> <span class="n">my_block_dev</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> <span class="k">struct</span> <span class="n">bio</span> <span class="o">*</span><span class="n">bio</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">bio_vec</span> <span class="n">bvec</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">bvec_iter</span> <span class="n">i</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">dir</span> <span class="o">=</span> <span class="n">bio_data_dir</span><span class="p">(</span><span class="n">bio</span><span class="p">);</span> + + <span class="cm">/* Do each segment independently. */</span> + <span class="n">bio_for_each_segment</span><span class="p">(</span><span class="n">bvec</span><span class="p">,</span> <span class="n">bio</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span> <span class="p">{</span> + <span class="n">sector_t</span> <span class="n">sector</span> <span class="o">=</span> <span class="n">i</span><span class="p">.</span><span class="n">bi_sector</span><span class="p">;</span> + <span class="kt">char</span> <span class="o">*</span><span class="n">buffer</span> <span class="o">=</span> <span class="n">kmap_atomic</span><span class="p">(</span><span class="n">bvec</span><span class="p">.</span><span class="n">bv_page</span><span class="p">);</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">offset</span> <span class="o">=</span> <span class="n">bvec</span><span class="p">.</span><span class="n">bv_offset</span><span class="p">;</span> + <span class="kt">size_t</span> <span class="n">len</span> <span class="o">=</span> <span class="n">bvec</span><span class="p">.</span><span class="n">bv_len</span><span class="p">;</span> + + <span class="cm">/* process mapped buffer */</span> + <span class="n">my_block_transfer</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">sector</span><span class="p">,</span> <span class="n">len</span><span class="p">,</span> <span class="n">buffer</span> <span class="o">+</span> <span class="n">offset</span><span class="p">,</span> <span class="n">dir</span><span class="p">);</span> + + <span class="n">kunmap_atomic</span><span class="p">(</span><span class="n">buffer</span><span class="p">);</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>As it can be seen from the example above, iterating through a +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> requires iterating through all of its segments. A segment +(<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio_vec</span></code>) is defined by the physical address page, the offset +in the page and its size.</p> +<p>To simplify the processing of a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code>, use the +<code class="xref c c-macro docutils literal"><span class="pre">bio_for_each_segment</span></code> macrodefinition. It will iterate through all +segments, and will also update global information stored in an iterator +(<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bvec_iter</span></code>) such as the current sector as well as other +internal information (segment vector index, number of bytes left to be +processed, etc.) .</p> +<p>You can store information in the mapped buffer, or extract information.</p> +<p>In case request queues are used and you needed to process the requests +at <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> level, use the <code class="xref c c-macro docutils literal"><span class="pre">rq_for_each_segment</span></code> +macrodefinition instead of the <code class="xref c c-macro docutils literal"><span class="pre">bio_for_each_segment</span></code> macrodefinition. +This macrodefinition iterates through each segment of each +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure of a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code> structure and +updates a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">req_iterator</span></code> structure. The +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">req_iterator</span></code> contains the current <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> +structure and the iterator that traverses its segments.</p> +<p>A typical example of use is:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">bio_vec</span> <span class="n">bvec</span><span class="p">;</span> +<span class="k">struct</span> <span class="n">req_iterator</span> <span class="n">iter</span><span class="p">;</span> + +<span class="n">rq_for_each_segment</span><span class="p">(</span><span class="n">bvec</span><span class="p">,</span> <span class="n">req</span><span class="p">,</span> <span class="n">iter</span><span class="p">)</span> <span class="p">{</span> + <span class="n">sector_t</span> <span class="n">sector</span> <span class="o">=</span> <span class="n">iter</span><span class="p">.</span><span class="n">iter</span><span class="p">.</span><span class="n">bi_sector</span><span class="p">;</span> + <span class="kt">char</span> <span class="o">*</span><span class="n">buffer</span> <span class="o">=</span> <span class="n">kmap_atomic</span><span class="p">(</span><span class="n">bvec</span><span class="p">.</span><span class="n">bv_page</span><span class="p">);</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">offset</span> <span class="o">=</span> <span class="n">bvec</span><span class="p">.</span><span class="n">bv_offset</span><span class="p">;</span> + <span class="kt">size_t</span> <span class="n">len</span> <span class="o">=</span> <span class="n">bvec</span><span class="p">.</span><span class="n">bv_len</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">dir</span> <span class="o">=</span> <span class="n">bio_data_dir</span><span class="p">(</span><span class="n">iter</span><span class="p">.</span><span class="n">bio</span><span class="p">);</span> + + <span class="n">my_block_transfer</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">sector</span><span class="p">,</span> <span class="n">len</span><span class="p">,</span> <span class="n">buffer</span> <span class="o">+</span> <span class="n">offset</span><span class="p">,</span> <span class="n">dir</span><span class="p">);</span> + + <span class="n">kunmap_atomic</span><span class="p">(</span><span class="n">buffer</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="free-a-struct-bio-structure"> +<h3>Free a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure<a class="headerlink" href="#free-a-struct-bio-structure" title="Permalink to this headline">¶</a></h3> +<p>Once a kernel subsystem uses a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure, it will have to +release the reference to it. This is done by calling <code class="xref c c-func docutils literal"><span class="pre">bio_put()</span></code> function.</p> +</div> +<div class="section" id="set-up-a-request-queue-at-struct-bio-level"> +<h3>Set up a request queue at <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> level<a class="headerlink" href="#set-up-a-request-queue-at-struct-bio-level" title="Permalink to this headline">¶</a></h3> +<p>We have previously seen how we can specify a function to be used to process +requests sent to the driver. The function receives as argument the requests and +carries out processing at <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code> level.</p> +<p>If, for flexibility reasons, we need to specify a function that carries +out processing at <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure level, we no longer +use request queues and we will need to fill the <code class="docutils literal"><span class="pre">submit_bio</span></code> field in the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">block_device_operations</span></code> associated to the driver.</p> +<p>Below is a typical example of initializing a function that carries out +processing at <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure level:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="c1">// the declaration of the function that carries out processing</span> +<span class="c1">// :c:type:`struct bio` structures</span> +<span class="k">static</span> <span class="n">blk_qc_t</span> <span class="nf">my_submit_bio</span><span class="p">(</span><span class="k">struct</span> <span class="n">bio</span> <span class="o">*</span><span class="n">bio</span><span class="p">);</span> + +<span class="k">struct</span> <span class="n">block_device_operations</span> <span class="n">my_block_ops</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">owner</span> <span class="o">=</span> <span class="n">THIS_MODULE</span><span class="p">,</span> + <span class="p">.</span><span class="n">submit_bio</span> <span class="o">=</span> <span class="n">my_submit_bio</span> + <span class="p">...</span> +<span class="p">};</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="further-reading"> +<h2>Further reading<a class="headerlink" href="#further-reading" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li><a class="reference external" href="http://static.lwn.net/images/pdf/LDD3/ch16.pdf">Linux Device Drivers 3rd Edition, Chapter 16. Block Drivers</a></li> +<li>Linux Kernel Development, Second Edition – Chapter 13. The Block I/O Layer</li> +<li><a class="reference external" href="https://lwn.net/Articles/58719/">A simple block driver</a></li> +<li><a class="reference external" href="https://lwn.net/Articles/25711/">The gendisk interface</a></li> +<li><a class="reference external" href="https://lwn.net/Articles/26404/">The bio structure</a></li> +<li><a class="reference external" href="https://lwn.net/Articles/27055/">Request queues</a></li> +<li><a class="reference external" href="https://elixir.bootlin.com/linux/v4.15/source/Documentation/block/request.txt">Documentation/block/request.txt - Struct request documentation</a></li> +<li><a class="reference external" href="https://elixir.bootlin.com/linux/v4.15/source/Documentation/block/biodoc.txt">Documentation/block/biodoc.txt - Notes on the Generic Block Layer</a></li> +<li><a class="reference external" href="https://elixir.bootlin.com/linux/v4.15/source/drivers/block/brd.c">drivers/block/brd/c - RAM backed block disk driver</a></li> +<li><a class="reference external" href="https://www.linuxjournal.com/article/6931">I/O Schedulers</a></li> +</ul> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is block_device_drivers. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/block_device_drivers/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="section" id="intro"> +<h3>0. Intro<a class="headerlink" href="#intro" title="Permalink to this headline">¶</a></h3> +<p>Using <a class="reference external" href="http://elixir.free-electrons.com/linux/latest/source">LXR</a> find the definitions of the following symbols in the Linux kernel:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio_vec</span></code></li> +<li><code class="xref c c-macro docutils literal"><span class="pre">bio_for_each_segment</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">gendisk</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">block_device_operations</span></code></li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code></li> +</ul> +</div></blockquote> +</div> +<div class="section" id="block-device"> +<h3>1. Block device<a class="headerlink" href="#block-device" title="Permalink to this headline">¶</a></h3> +<p>Create a kernel module that allows you to register or deregister a block device. +Start from the files in the <code class="file docutils literal"><span class="pre">1-2-3-6-ram-disk/kernel</span></code> directory in the +lab skeleton.</p> +<p>Follow the comments marked with <strong>TODO 1</strong> in the laboratory skeleton. Use the +existing macrodefinitions (<code class="xref c c-macro docutils literal"><span class="pre">MY_BLOCK_MAJOR</span></code>, +<code class="xref c c-macro docutils literal"><span class="pre">MY_BLKDEV_NAME</span></code>). Check the value returned by the register function, +and in case of error, return the error code.</p> +<p>Compile the module, copy it to the virtual machine and insert it into the +kernel. Verify that your device was successfully created inside the +<code class="file docutils literal"><span class="pre">/proc/devices</span></code>. +You will see a device with major 240.</p> +<p>Unload the kernel module and check that the device was unregistered.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Review the <a class="reference internal" href="#register-a-block-i-o-device">Register a block I/O device</a> section.</p> +</div> +<p>Change the <code class="xref c c-macro docutils literal"><span class="pre">MY_BLOCK_MAJOR</span></code> value to 7. Compile the module, copy it to +the virtual machine, and insert it into the kernel. Notice that the insertion +fails because there is already another driver/device registered in the kernel +with the major 7.</p> +<p>Restore the 240 value for the <code class="xref c c-macro docutils literal"><span class="pre">MY_BLOCK_MAJOR</span></code> macro.</p> +</div> +<div class="section" id="disk-registration"> +<h3>2. Disk registration<a class="headerlink" href="#disk-registration" title="Permalink to this headline">¶</a></h3> +<p>Modify the previous module to add a disk associated with the driver. Analyze the +macrodefinitions, <code class="xref c c-type docutils literal"><span class="pre">my_block_dev</span></code> structure and existing functions from +the <code class="file docutils literal"><span class="pre">ram-disk.c</span></code> file.</p> +<p>Follow the comments marked with <strong>TODO 2</strong>. Use the +<code class="xref c c-func docutils literal"><span class="pre">create_block_device()</span></code> and the <code class="xref c c-func docutils literal"><span class="pre">delete_block_device()</span></code> functions.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Review the <a class="reference internal" href="#register-a-disk">Register a disk</a> and <a class="reference internal" href="#process-a-request">Process a request</a> sections.</p> +</div> +<p>Fill in the <code class="xref c c-func docutils literal"><span class="pre">my_block_request()</span></code> function to process the request +without actually processing your request: display the "request received" message +and the following information: start sector, total size, data size from the +current <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure, direction. To validate a request type, +use the <code class="xref c c-func docutils literal"><span class="pre">blk_rq_is_passthrough()</span></code> (the function returns 0 in the case in +which we are interested, i.e. when the request is generated by the file system).</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">To find the needed info, review the <a class="reference internal" href="#requests-for-block-devices">Requests for block devices</a> +section.</p> +</div> +<p>Use the <code class="xref c c-func docutils literal"><span class="pre">blk_mq_end_request()</span></code> function to finish processing the +request.</p> +<p>Insert the module into the kernel and inspect the messages printed +by the module. When a device is added, a request is sent to the device. Check +the presence of <code class="file docutils literal"><span class="pre">/dev/myblock</span></code> and if it doesn't exist, create the device +using the command:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>mknod /dev/myblock b <span class="m">240</span> <span class="m">0</span> +</pre></div> +</div> +<p>To generate writing requests, use the command:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span><span class="nb">echo</span> <span class="s2">"abc"</span>> /dev/myblock +</pre></div> +</div> +<p>Notice that a write request is preceded by a read request. The request +is done to read the block from the disk and "update" its content with the +data provided by the user, without overwriting the rest. After reading and +updating, writing takes place.</p> +</div> +<div class="section" id="ram-disk"> +<h3>3. RAM disk<a class="headerlink" href="#ram-disk" title="Permalink to this headline">¶</a></h3> +<p>Modify the previous module to create a RAM disk: requests to the device will +result in reads/writes in a memory area.</p> +<p>The memory area <code class="xref c c-data docutils literal"><span class="pre">dev->data</span></code> is already allocated in the source code of +the module using <code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code> and deallocated using <code class="xref c c-func docutils literal"><span class="pre">vfree()</span></code>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Review the <a class="reference internal" href="#process-a-request">Process a request</a> section.</p> +</div> +<p>Follow the comments marked with <strong>TODO 3</strong> to complete the +<code class="xref c c-func docutils literal"><span class="pre">my_block_transfer()</span></code> function to write/read the request information +in/from the memory area. The function will be called for each request within +the queue processing function: <code class="xref c c-func docutils literal"><span class="pre">my_block_request()</span></code>. To write/read +to/from the memory area, use <code class="xref c c-func docutils literal"><span class="pre">memcpy()</span></code>. To determine the write/read +information, use the fields of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">request</span></code> structure.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">To find out the size of the request data, use the +<code class="xref c c-macro docutils literal"><span class="pre">blk_rq_cur_bytes</span></code> macro. Do not use the +<code class="xref c c-macro docutils literal"><span class="pre">blk_rq_bytes</span></code> macro.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">To find out the buffer associated to the request, use +<code class="xref c c-data docutils literal"><span class="pre">bio_data`(:c:data:`rq->bio</span></code>).</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">A description of useful macros is in the <a class="reference internal" href="#requests-for-block-devices">Requests for block devices</a> +section.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">You can find useful information in the +<a class="reference external" href="https://github.com/martinezjavier/ldd3/blob/master/sbull/sbull.c">block device driver example</a> +from <a class="reference external" href="http://lwn.net/Kernel/LDD3/">Linux Device Driver</a>.</p> +</div> +<p>For testing, use the test file <code class="file docutils literal"><span class="pre">user/ram-disk-test.c</span></code>. +The test program is compiled automatically at <code class="docutils literal"><span class="pre">make</span> <span class="pre">build</span></code>, copied to the +virtual machine at <code class="docutils literal"><span class="pre">make</span> <span class="pre">copy</span></code> and can be run on the QEMU virtual machine +using the command:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>./ram-disk-test +</pre></div> +</div> +<p>There is no need to insert the module into the kernel, it will be inserted by +the <code class="docutils literal"><span class="pre">ram-disk-test</span></code> command.</p> +<p>Some tests may fail because of lack of synchronization between the transmitted +data (flush).</p> +</div> +<div class="section" id="read-data-from-the-disk"> +<h3>4. Read data from the disk<a class="headerlink" href="#read-data-from-the-disk" title="Permalink to this headline">¶</a></h3> +<p>The purpose of this exercise is to read data from the +<code class="xref c c-macro docutils literal"><span class="pre">PHYSICAL_DISK_NAME</span></code> disk (<code class="file docutils literal"><span class="pre">/dev/vdb</span></code>) directly from the kernel.</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention</p> +<p>Before solving the exercise, we need to make sure the disk is +added to the virtual machine.</p> +<p>Check the variable <code class="docutils literal"><span class="pre">QEMU_OPTS</span></code> from <code class="file docutils literal"><span class="pre">qemu/Makefile</span></code>. +There should already be two extra disks added using <code class="docutils literal"><span class="pre">-drive</span> <span class="pre">...</span></code>.</p> +<p class="last">If there are not, generate a file that we will use as +the disk image using the command: +<strong class="command">dd if=/dev/zero of=qemu/mydisk.img bs=1024 count=1</strong> +and add the following option: +<strong class="command">-drive file=qemu/mydisk.img,if=virtio,format=raw</strong> +to <code class="file docutils literal"><span class="pre">qemu/Makefile</span></code> (in the <code class="xref c c-data docutils literal"><span class="pre">QEMU_OPTS</span></code> variable, +after the root disk).</p> +</div> +<p>Follow the comments marked with <strong>TODO 4</strong> in the directory <code class="file docutils literal"><span class="pre">4-5-relay/</span></code> +and implement <code class="xref c c-func docutils literal"><span class="pre">open_disk()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">close_disk()</span></code>. +Use the <code class="xref c c-func docutils literal"><span class="pre">blkdev_get_by_path()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">blkdev_put()</span></code> functions. The +device must be opened in read-write mode exclusively +(<code class="xref c c-macro docutils literal"><span class="pre">FMODE_READ</span></code> | <code class="xref c c-macro docutils literal"><span class="pre">FMODE_WRITE</span></code> | <code class="xref c c-macro docutils literal"><span class="pre">FMODE_EXCL</span></code>), and +as holder you must use the current module (<code class="xref c c-macro docutils literal"><span class="pre">THIS_MODULE</span></code>).</p> +<p>Implement the <code class="xref c c-func docutils literal"><span class="pre">send_test_bio()</span></code> function. You will have to create a new +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure and fill it, submit it and wait for it. Read the +first sector of the disk. To wait, call the <code class="xref c c-func docutils literal"><span class="pre">submit_bio_wait()</span></code> function.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p>The first sector of the disk is the sector with the index 0. +This value must be used to initialize the field +<code class="xref c c-member docutils literal"><span class="pre">bi_iter.bi_sector</span></code> of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code>.</p> +<p class="last">For the read operation, use the <code class="xref c c-macro docutils literal"><span class="pre">REQ_OP_READ</span></code> macro to +initialize the <code class="xref c c-member docutils literal"><span class="pre">bi_opf</span></code> field of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code>.</p> +</div> +<p>After finishing the operation, display the first 3 bytes of data read by +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure. Use the format <code class="docutils literal"><span class="pre">"%</span> <span class="pre">02x"</span></code> for <code class="xref c c-func docutils literal"><span class="pre">printk()</span></code> +to display the data and the <code class="xref c c-macro docutils literal"><span class="pre">kmap_atomic</span></code> and <code class="xref c c-macro docutils literal"><span class="pre">kunmap_atomic</span></code> +macros respectively.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">As an argument for the <code class="xref c c-func docutils literal"><span class="pre">kmap_atomic()</span></code> function, just use the +page which is allocated above in the code, in the <code class="xref c c-data docutils literal"><span class="pre">page</span></code> +variable.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Review the sections <a class="reference internal" href="#bio-content"><span class="std std-ref">How to use the content of a struct bio structure</span></a> and <a class="reference internal" href="#bio-completion"><span class="std std-ref">Wait for the completion of a struct bio structure</span></a>.</p> +</div> +<p>For testing, use the <code class="file docutils literal"><span class="pre">test-relay-disk</span></code> script, which is copied on the +virtual machine when running <strong class="command">make copy</strong>. If it is not copied, make +sure it is executable:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>chmod +x test-relay-disk +</pre></div> +</div> +<p>There is no need to load the module into the kernel, it will be loaded by +<strong class="command">test-relay-disk</strong>.</p> +<p>Use the command below to run the script:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>./test-relay-disk +</pre></div> +</div> +<p>The script writes "abc" at the beginning of the disk indicated by +<code class="xref c c-macro docutils literal"><span class="pre">PHYSICAL_DISK_NAME</span></code>. After running, the module will display 61 62 63 +(the corresponding hexadecimal values of letters "a", "b" and "c").</p> +</div> +<div class="section" id="write-data-to-the-disk"> +<h3>5. Write data to the disk<a class="headerlink" href="#write-data-to-the-disk" title="Permalink to this headline">¶</a></h3> +<p>Follow the comments marked with <strong>TODO 5</strong> to write a message +(<code class="xref c c-macro docutils literal"><span class="pre">BIO_WRITE_MESSAGE</span></code>) on the disk.</p> +<p>The <code class="xref c c-func docutils literal"><span class="pre">send_test_bio()</span></code> function receives as argument the operation type +(read or write). Call in the <code class="xref c c-func docutils literal"><span class="pre">relay_init()</span></code> function the function for +reading and in the <code class="xref c c-func docutils literal"><span class="pre">relay_exit()</span></code> function the function for writing. We +recommend using the <code class="xref c c-macro docutils literal"><span class="pre">REQ_OP_READ</span></code> and the <code class="xref c c-macro docutils literal"><span class="pre">REQ_OP_WRITE</span></code> +macros.</p> +<p>Inside the <code class="xref c c-func docutils literal"><span class="pre">send_test_bio()</span></code> function, if the operation is write, fill in +the buffer associated to the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure with the message +<code class="xref c c-macro docutils literal"><span class="pre">BIO_WRITE_MESSAGE</span></code>. Use the <code class="xref c c-macro docutils literal"><span class="pre">kmap_atomic</span></code> and the +<code class="xref c c-macro docutils literal"><span class="pre">kunmap_atomic</span></code> macros to work with the buffer associated to the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">You need to update the type of the operation associated to the +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure by setting the <code class="xref c c-member docutils literal"><span class="pre">bi_opf</span></code> field +accordingly.</p> +</div> +<p>For testing, run the <code class="file docutils literal"><span class="pre">test-relay-disk</span></code> script using the command:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>./test-relay-disk +</pre></div> +</div> +<p>The script will display the <code class="docutils literal"><span class="pre">"read</span> <span class="pre">from</span> <span class="pre">/dev/sdb:</span> <span class="pre">64</span> <span class="pre">65</span> <span class="pre">66"</span></code> message at the +standard output.</p> +</div> +<div class="section" id="processing-requests-from-the-request-queue-at-struct-bio-level"> +<h3>6. Processing requests from the request queue at <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> level<a class="headerlink" href="#processing-requests-from-the-request-queue-at-struct-bio-level" title="Permalink to this headline">¶</a></h3> +<p>In the implementation from Exercise 3, we have only processed a +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio_vec</span></code> of the current <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> from the request. +We want to process all <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio_vec</span></code> structures from all +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structures. +For this, we will iterate through all <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> requests and through +all <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio_vec</span></code> structures (also called segments) of each +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code>.</p> +<p>Add, within the ramdisk implementation (<code class="file docutils literal"><span class="pre">1-2-3-6-ram-disk/</span></code> directory), +support for processing the requests from the request queue at +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> level. Follow the comments marked with <strong>TODO 6</strong>.</p> +<p>Set the <code class="xref c c-macro docutils literal"><span class="pre">USE_BIO_TRANSFER</span></code> macro to 1.</p> +<p>Implement the <code class="xref c c-func docutils literal"><span class="pre">my_xfer_request()</span></code> function. Use the +<code class="xref c c-macro docutils literal"><span class="pre">rq_for_each_segment</span></code> macro to iterate through the <code class="xref c c-type docutils literal"><span class="pre">bio_vec</span></code> +structures of each <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> from the request.</p> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Review the indications and the code snippets from the +<a class="reference internal" href="#bio-content"><span class="std std-ref">How to use the content of a struct bio structure</span></a> section.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> segment iterator to get the current +sector (<code class="xref c c-member docutils literal"><span class="pre">iter.iter.bi_sector</span></code>).</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use the request iterator to get the reference to the current +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> (<code class="xref c c-member docutils literal"><span class="pre">iter.bio</span></code>).</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">Use the <code class="xref c c-macro docutils literal"><span class="pre">bio_data_dir</span></code> macro to find the reading or writing +direction for a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code>.</p> +</div> +<p>Use the <code class="xref c c-macro docutils literal"><span class="pre">kmap_atomic</span></code> or the <code class="xref c c-macro docutils literal"><span class="pre">kunmap_atomic</span></code> macros to map +the pages of each <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">bio</span></code> structure and access its associated +buffers. For the actual transfer, call the <code class="xref c c-func docutils literal"><span class="pre">my_block_transfer()</span></code> function +implemented in the previous exercise.</p> +<p>For testing, use the <code class="file docutils literal"><span class="pre">ram-disk-test.c</span></code> test file:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>./ram-disk-test +</pre></div> +</div> +<p>There is no need to insert the module into the kernel, it will be inserted by +the <strong class="command">ram-disk-test</strong> executable.</p> +<p>Some tests may crash because of lack of synchronization between the transmitted +data (flush).</p> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lab6-memory-mapping.html" class="btn btn-neutral float-left" title="SO2 Lab 06 - Memory Mapping" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lab8-filesystems-part1.html" class="btn btn-neutral float-right" title="SO2 Lab 08 - File system drivers (Part 1)" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lab8-filesystems-part1.html b/refs/pull/405/merge/so2/lab8-filesystems-part1.html new file mode 100644 index 00000000..3be92acc --- /dev/null +++ b/refs/pull/405/merge/so2/lab8-filesystems-part1.html @@ -0,0 +1,980 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lab 08 - File system drivers (Part 1) — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lab 09 - File system drivers (Part 2)" href="lab9-filesystems-part2.html" /> + <link rel="prev" title="SO2 Lab 07 - Block Device Drivers" href="lab7-block-device-drivers.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lab 08 - File system drivers (Part 1)</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#virtual-filesystem-vfs">Virtual Filesystem (VFS)</a></li> +<li class="toctree-l3"><a class="reference internal" href="#the-general-file-system-model">The general file system model</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#superblock">superblock</a></li> +<li class="toctree-l4"><a class="reference internal" href="#inode">inode</a></li> +<li class="toctree-l4"><a class="reference internal" href="#file">file</a></li> +<li class="toctree-l4"><a class="reference internal" href="#dentry">dentry</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#register-and-unregister-filesystems">Register and unregister filesystems</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#functions-mount-kill-sb">Functions mount, kill_sb</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#superblock-in-vfs">Superblock in VFS</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#the-struct-super-block-structure">The <code class="docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="#superblock-operations">Superblock operations</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#the-fill-super-function">The <code class="docutils literal"><span class="pre">fill_super()</span></code> function</a></li> +<li class="toctree-l3"><a class="reference internal" href="#buffer-cache">Buffer cache</a></li> +<li class="toctree-l3"><a class="reference internal" href="#functions-and-useful-macros">Functions and useful macros</a></li> +<li class="toctree-l3"><a class="reference internal" href="#further-reading">Further reading</a></li> +<li class="toctree-l3"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#myfs">myfs</a></li> +<li class="toctree-l4"><a class="reference internal" href="#minfs">minfs</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lab 08 - File system drivers (Part 1)</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lab8-filesystems-part1.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lab-08-file-system-drivers-part-1"> +<h1>SO2 Lab 08 - File system drivers (Part 1)<a class="headerlink" href="#so2-lab-08-file-system-drivers-part-1" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<blockquote> +<div><ul class="simple"> +<li>acquiring knowledge about the Virtual Filesystem (VFS) in Linux and understanding concepts regarding 'inode', 'dentry', 'file', superblock and data block.</li> +<li>understanding the process of mounting a file system inside VFS.</li> +<li>knowledge regarding various file system types and understanding differences between file systems with physical support (on disk) and the ones without physical support.</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="virtual-filesystem-vfs"> +<h2>Virtual Filesystem (VFS)<a class="headerlink" href="#virtual-filesystem-vfs" title="Permalink to this headline">¶</a></h2> +<p>The Virtual Filesystem (also known as VFS) is a component of the kernel that handles all system calls related to files and file systems. +VFS is a generic interface between the user and a particular file system. +This abstraction simplifies the implementation of file systems and provides an easier integration of multiple file systems. This way, the implementation of a file system is accomplished by using the API provided by the VFS, and the generic hardware and I/O subsystem communication parts are handled by VFS.</p> +<p>From a functional point of view, file systems can be grouped into:</p> +<blockquote> +<div><ul class="simple"> +<li>disk file systems (ext3, ext4, xfs, fat, ntfs, etc.)</li> +<li>network file systems (nfs, smbfs/cifs, ncp, etc.)</li> +<li>virtual filesystems (procfs, sysfs, sockfs, pipefs, etc.)</li> +</ul> +</div></blockquote> +<p>A Linux kernel instance will use VFS for the hierarchy (a tree) of directories and files. +A new file system will be added as a VFS subtree using the mount operation. +A file system is usually mounted from the environment for which it was built (from a block type device, from network, etc.). +In particular, however, the VFS can use a normal file as a virtual block device, so it is possible to mount disk file systems over normal files. This way, stacks of file systems can be created.</p> +<p>The basic idea of VFS is to provide a single file model that can represent files from any file system. +The file system driver is responsible for bringing to the common denominator. +This way the kernel can create a single directory structure that contains the entire system. +There will be a file system that will be the root, the rest being mounted in its various directories.</p> +</div> +<div class="section" id="the-general-file-system-model"> +<h2>The general file system model<a class="headerlink" href="#the-general-file-system-model" title="Permalink to this headline">¶</a></h2> +<p>The general file system model, to which any implemented file system needs to be reduced, consists of several well-defined entities: <code class="xref c c-type docutils literal"><span class="pre">superblock</span></code>, <code class="xref c c-type docutils literal"><span class="pre">inode</span></code>, <code class="xref c c-type docutils literal"><span class="pre">file</span></code>, and <code class="xref c c-type docutils literal"><span class="pre">dentry</span></code>. +These entities are file system metadata (they contain information about data or other metadata).</p> +<p>Model entities interact using some VFS or kernel subsystems: dentry cache, inode cache, buffer cache. +Each entity is treated as an object: it has a associated data structure and a pointer to a table of methods. The induction of particular behavior for each component is done by replacing the associated methods.</p> +<div class="section" id="superblock"> +<h3>superblock<a class="headerlink" href="#superblock" title="Permalink to this headline">¶</a></h3> +<p>The superblock stores the information needed for a mounted file system:</p> +<blockquote> +<div><ul class="simple"> +<li>inode and blocks locations</li> +<li>file system block size</li> +<li>maximum filename length</li> +<li>maximum file size</li> +<li>the location of the root inode</li> +</ul> +</div></blockquote> +<div class="section" id="localization"> +<h4>Localization:<a class="headerlink" href="#localization" title="Permalink to this headline">¶</a></h4> +<blockquote> +<div><ul class="simple"> +<li>In the case of disk file systems, the superblock has a correspondent in the first block of the disk. (Filesystem Control Block).</li> +<li>In VFS, all superblocks of filesystems are retained in a list of structures of type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> and the methods in structures of type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_operations</span></code>.</li> +</ul> +</div></blockquote> +</div> +</div> +<div class="section" id="inode"> +<h3>inode<a class="headerlink" href="#inode" title="Permalink to this headline">¶</a></h3> +<p>The inode (index node) keeps information about a file in the general sense (abstraction): regular file, directory, special file (pipe, fifo), block device, character device, link, or anything that can be abstracted as a file.</p> +<p>An inode stores information like:</p> +<blockquote> +<div><ul class="simple"> +<li>file type;</li> +<li>file size;</li> +<li>access rights;</li> +<li>access or modify time;</li> +<li>location of data on the disk (pointers to disk blocks containing data).</li> +</ul> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Usually, the inode does not contain the file name. The name is stored by the <code class="xref c c-type docutils literal"><span class="pre">dentry</span></code> entity. This way, an inode can have multiple names (hardlinks).</p> +</div> +<div class="section" id="localization-1"> +<h4>Localization:<a class="headerlink" href="#localization-1" title="Permalink to this headline">¶</a></h4> +<p>Like the superblock, the <code class="xref c c-type docutils literal"><span class="pre">inode</span></code> has a disk correspondent. +The inodes on disk are generally grouped into a specialized area (inode area) separated from the data blocks area; In some file systems, the equivalents of the inodes are spread in the file system structure (FAT); +As a VFS entity, an inode is represented by the structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code> and by the operations with it defined in the structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode_operations</span></code>.</p> +<p>Each inode is generally identified by a number. On Linux, the <code class="docutils literal"><span class="pre">-i</span></code> argument of the <code class="docutils literal"><span class="pre">ls</span></code> command shows the inode number associated with each file:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">razvan@valhalla:~/school/so2/wiki$</span> ls -i +<span class="go">1277956 lab10.wiki 1277962 lab9.wikibak 1277964 replace_lxr.sh</span> +<span class="go">1277954 lab9.wiki 1277958 link.txt 1277955 homework.wiki</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="file"> +<h3>file<a class="headerlink" href="#file" title="Permalink to this headline">¶</a></h3> +<p>File is the component of the file system model that is closest to the user. +The structure exists only as a VFS entity in memory and has no physical correspondent on disk.</p> +<p>While the inode abstracts a file on the disk, the file structure abstracts an open file. +From the point of view of the process, the file entity abstracts the file. From the point of view of the file system implementation, however, the inode is the entity that abstracts the file.</p> +<p>The file structure maintains information such as:</p> +<blockquote> +<div><ul class="simple"> +<li>file cursor position;</li> +<li>file opening rights;</li> +<li>pointer to the associated inode (eventually its index).</li> +</ul> +</div></blockquote> +<div class="section" id="localization-2"> +<h4>Localization:<a class="headerlink" href="#localization-2" title="Permalink to this headline">¶</a></h4> +<blockquote> +<div><ul class="simple"> +<li>The structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file</span></code> is the associated VFS entity, and the structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code> represents the operations associated with it.</li> +</ul> +</div></blockquote> +</div> +</div> +<div class="section" id="dentry"> +<h3>dentry<a class="headerlink" href="#dentry" title="Permalink to this headline">¶</a></h3> +<p>The dentry (directory entry) associates an inode with a file name.</p> +<p>Generally, a dentry structure contains two fields:</p> +<blockquote> +<div><ul class="simple"> +<li>an integer that identifies the inode;</li> +<li>a string representing its name.</li> +</ul> +</div></blockquote> +<p>The dentry is a specific part of a path that can be a directory or a file. For example, for the path <code class="docutils literal"><span class="pre">/bin/vi</span></code>, dentry objects will be created for <code class="docutils literal"><span class="pre">/</span></code>, <code class="docutils literal"><span class="pre">bin</span></code>, and <code class="docutils literal"><span class="pre">vi</span></code> (a total of 3 dentry objects).</p> +<blockquote> +<div><ul class="simple"> +<li>the dentry has a correspondent on the disk, but the correspondence is not direct because each file system keeps the dentries in a specific way</li> +<li>in VFS, the dentry entity is represented by the structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">dentry</span></code> and the operations with it are defined in the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">dentry_operations</span></code> structure.</li> +</ul> +</div></blockquote> +</div> +</div> +<div class="section" id="register-and-unregister-filesystems"> +<span id="registerunregistersection"></span><h2>Register and unregister filesystems<a class="headerlink" href="#register-and-unregister-filesystems" title="Permalink to this headline">¶</a></h2> +<p>In the current version, the Linux kernel supports about 50 file systems, including:</p> +<blockquote> +<div><ul class="simple"> +<li>ext2/ ext4</li> +<li>reiserfs</li> +<li>xfs</li> +<li>fat</li> +<li>ntfs</li> +<li>iso9660</li> +<li>udf for CDs and DVDs</li> +<li>hpfs</li> +</ul> +</div></blockquote> +<p>On a single system, however, it is unlikely that there will be more than 5-6 file systems. For this reason, file systems (or, more correctly, file system types) are implemented as modules and can be loaded or unloaded at any time.</p> +<p>In order to be able to dynamically load / unload a file system module, a file system registration / deregistration API is required. The structure describing a particular file system is <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_system_type</span></code>:</p> +<blockquote> +<div><blockquote> +<div><div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/fs.h></span><span class="cp"></span> + +<span class="k">struct</span> <span class="n">file_system_type</span> <span class="p">{</span> + <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">fs_flags</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">dentry</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="n">mount</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">file_system_type</span> <span class="o">*</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span> + <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">kill_sb</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">super_block</span> <span class="o">*</span><span class="p">);</span> + <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">owner</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">file_system_type</span> <span class="o">*</span> <span class="n">next</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">hlist_head</span> <span class="n">fs_supers</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">lock_class_key</span> <span class="n">s_lock_key</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">lock_class_key</span> <span class="n">s_umount_key</span><span class="p">;</span> + <span class="c1">//...</span> +<span class="p">};</span> +</pre></div> +</div> +</div></blockquote> +<ul class="simple"> +<li><code class="docutils literal"><span class="pre">name</span></code> is a string representing the name that will identify a file system (the argument passed to <code class="docutils literal"><span class="pre">mount</span> <span class="pre">-t</span></code>).</li> +<li><code class="docutils literal"><span class="pre">owner</span></code> is <code class="docutils literal"><span class="pre">THIS_MODULE</span></code> for file systems implemented in modules, and <code class="docutils literal"><span class="pre">NULL</span></code> if they are written directly into the kernel.</li> +<li>The <code class="docutils literal"><span class="pre">mount</span></code> function reads the superblock from the disk in memory when loading the file system. The function is unique to each file system.</li> +<li>The <code class="docutils literal"><span class="pre">kill_sb</span></code> function releases the super-block from memory.</li> +<li><code class="docutils literal"><span class="pre">fs_flags</span></code> specifies the flags with which the file system must be mounted. An example of such flag is <code class="docutils literal"><span class="pre">FS_REQUIRES_DEV</span></code> that specifies to VFS that the file system needs a disk (it is not a virtual file system).</li> +<li><code class="docutils literal"><span class="pre">fs_supers</span></code> is a list containing all the superblocks associated with this file system. Since the same file system can be mounted multiple times, there will be a separate superblock for each mount.</li> +</ul> +</div></blockquote> +<p>The <em>registration of a file system</em> into the kernel is generally performed in the module initialization function. For registration, the programmer will have to</p> +<blockquote> +<div><ol class="arabic simple"> +<li>initialize a structure of type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_system_type</span></code> with the name, the flags, the function that implements the superblock reading operation and the reference to the structure that identifies the current module</li> +<li>call the <code class="xref c c-func docutils literal"><span class="pre">register_filesystem()</span></code> function.</li> +</ol> +</div></blockquote> +<p>When unloading the module, you must unregister the file system by calling the <code class="xref c c-func docutils literal"><span class="pre">unregister_filesystem()</span></code> function.</p> +<p>An example of registering a virtual file system is found in the code for <code class="docutils literal"><span class="pre">ramfs</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="k">struct</span> <span class="n">file_system_type</span> <span class="n">ramfs_fs_type</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="s">"ramfs"</span><span class="p">,</span> + <span class="p">.</span><span class="n">mount</span> <span class="o">=</span> <span class="n">ramfs_mount</span><span class="p">,</span> + <span class="p">.</span><span class="n">kill_sb</span> <span class="o">=</span> <span class="n">ramfs_kill_sb</span><span class="p">,</span> + <span class="p">.</span><span class="n">fs_flags</span> <span class="o">=</span> <span class="n">FS_USERNS_MOUNT</span><span class="p">,</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="n">__init</span> <span class="nf">init_ramfs_fs</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">test_and_set_bit</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">&</span><span class="n">once</span><span class="p">))</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> + <span class="k">return</span> <span class="n">register_filesystem</span><span class="p">(</span><span class="o">&</span><span class="n">ramfs_fs_type</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<div class="section" id="functions-mount-kill-sb"> +<span id="functionsmountkillsbsection"></span><h3>Functions mount, kill_sb<a class="headerlink" href="#functions-mount-kill-sb" title="Permalink to this headline">¶</a></h3> +<p>When mounting the file system, the kernel calls the mount function defined within the structure <code class="xref c c-type docutils literal"><span class="pre">file_system_type</span></code>. The function makes a set of initializations and returns a dentry (the structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">dentry</span></code>) that represents the mount point directory. Usually <code class="xref c c-func docutils literal"><span class="pre">mount()</span></code> is a simple function that calls one of the functions:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">mount_bdev()</span></code>, which mounts a file system stored on a block device</li> +<li><code class="xref c c-func docutils literal"><span class="pre">mount_single()</span></code>, which mounts a file system that shares an instance between all mount operations</li> +<li><code class="xref c c-func docutils literal"><span class="pre">mount_nodev()</span></code>, which mounts a file system that is not on a physical device</li> +<li><code class="xref c c-func docutils literal"><span class="pre">mount_pseudo()</span></code>, a helper function for pseudo-file systems (<code class="docutils literal"><span class="pre">sockfs</span></code>, <code class="docutils literal"><span class="pre">pipefs</span></code>, generally file systems that can not be mounted)</li> +</ul> +</div></blockquote> +<p>These functions get as parameter a pointer to a function <code class="xref c c-func docutils literal"><span class="pre">fill_super()</span></code> that will be called after the superblock initialization to finish its initialization by the driver. An example of such a function can be found in the <code class="docutils literal"><span class="pre">fill_super</span></code> section.</p> +<p>When unmounting the file system, the kernel calls <code class="xref c c-func docutils literal"><span class="pre">kill_sb()</span></code>, which performs cleanup operations and invokes one of the functions:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">kill_block_super()</span></code>, which unmounts a file system on a block device</li> +<li><code class="xref c c-func docutils literal"><span class="pre">kill_anon_super()</span></code>, which unmounts a virtual file system (information is generated when requested)</li> +<li><code class="xref c c-func docutils literal"><span class="pre">kill_litter_super()</span></code>, which unmounts a file system that is not on a physical device (the information is kept in memory)</li> +</ul> +</div></blockquote> +<p>An example for a file system without disk support is the <code class="xref c c-func docutils literal"><span class="pre">ramfs_mount()</span></code> function in the <code class="docutils literal"><span class="pre">ramfs</span></code> file system:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">dentry</span> <span class="o">*</span><span class="nf">ramfs_mount</span><span class="p">(</span><span class="k">struct</span> <span class="n">file_system_type</span> <span class="o">*</span><span class="n">fs_type</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">flags</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">dev_name</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="n">mount_nodev</span><span class="p">(</span><span class="n">fs_type</span><span class="p">,</span> <span class="n">flags</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">ramfs_fill_super</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<p>An example for a file system from disk is the <code class="xref c c-func docutils literal"><span class="pre">minix_mount()</span></code> function in the <code class="docutils literal"><span class="pre">minix</span></code> file system:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">dentry</span> <span class="o">*</span><span class="nf">minix_mount</span><span class="p">(</span><span class="k">struct</span> <span class="n">file_system_type</span> <span class="o">*</span><span class="n">fs_type</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">flags</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">dev_name</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="n">mount_bdev</span><span class="p">(</span><span class="n">fs_type</span><span class="p">,</span> <span class="n">flags</span><span class="p">,</span> <span class="n">dev_name</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">minix_fill_super</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="superblock-in-vfs"> +<h2>Superblock in VFS<a class="headerlink" href="#superblock-in-vfs" title="Permalink to this headline">¶</a></h2> +<p>The superblock exists both as a physical entity (entity on disk) and as a VFS entity (within the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> structure). +The superblock contains only metainformation and is used to write and read metadata from the disk (inodes, directory entries). +A superblock (and implicitly the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> structure) will contain information about the block device used, the list of inodes, a pointer to the inode of the file system root directory, and a pointer to the superblock operations.</p> +<div class="section" id="the-struct-super-block-structure"> +<h3>The <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> structure<a class="headerlink" href="#the-struct-super-block-structure" title="Permalink to this headline">¶</a></h3> +<p>Part of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> structure definition is presented below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">super_block</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="kt">dev_t</span> <span class="n">s_dev</span><span class="p">;</span> <span class="cm">/* identifier */</span> + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">s_blocksize_bits</span><span class="p">;</span> <span class="cm">/* block size in bits */</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">s_blocksize</span><span class="p">;</span> <span class="cm">/* block size in bytes */</span> + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">s_dirt</span><span class="p">;</span> <span class="cm">/* dirty flag */</span> + <span class="n">loff_t</span> <span class="n">s_maxbytes</span><span class="p">;</span> <span class="cm">/* max file size */</span> + <span class="k">struct</span> <span class="n">file_system_type</span> <span class="o">*</span><span class="n">s_type</span><span class="p">;</span> <span class="cm">/* filesystem type */</span> + <span class="k">struct</span> <span class="n">super_operations</span> <span class="o">*</span><span class="n">s_op</span><span class="p">;</span> <span class="cm">/* superblock methods */</span> + <span class="c1">//...</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">s_flags</span><span class="p">;</span> <span class="cm">/* mount flags */</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">s_magic</span><span class="p">;</span> <span class="cm">/* filesystem’s magic number */</span> + <span class="k">struct</span> <span class="n">dentry</span> <span class="o">*</span><span class="n">s_root</span><span class="p">;</span> <span class="cm">/* directory mount point */</span> + <span class="c1">//...</span> + <span class="kt">char</span> <span class="n">s_id</span><span class="p">[</span><span class="mi">32</span><span class="p">];</span> <span class="cm">/* informational name */</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">s_fs_info</span><span class="p">;</span> <span class="cm">/* filesystem private info */</span> +<span class="p">};</span> +</pre></div> +</div> +<dl class="docutils"> +<dt>The superblock stores global information for an instance of a file system:</dt> +<dd><ul class="first last simple"> +<li>the physical device on which it resides</li> +<li>block size</li> +<li>the maximum size of a file</li> +<li>file system type</li> +<li>the operations it supports</li> +<li>magic number (identifies the file system)</li> +<li>the root directory <code class="docutils literal"><span class="pre">dentry</span></code></li> +</ul> +</dd> +</dl> +<p>Additionally, a generic pointer (<code class="docutils literal"><span class="pre">void</span> <span class="pre">*</span></code>) stores the private data of the file system. +The superblock can be viewed as an abstract object to which its own data is added when there is a concrete implementation.</p> +</div> +<div class="section" id="superblock-operations"> +<span id="superblocksection"></span><h3>Superblock operations<a class="headerlink" href="#superblock-operations" title="Permalink to this headline">¶</a></h3> +<p>The superblock operations are described by the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_operations</span></code> structure:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">super_operations</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">write_inode</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">writeback_control</span> <span class="o">*</span><span class="n">wbc</span><span class="p">);</span> + <span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="n">alloc_inode</span><span class="p">)(</span><span class="k">struct</span> <span class="n">super_block</span> <span class="o">*</span><span class="n">sb</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">destroy_inode</span><span class="p">)(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="p">);</span> + + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">put_super</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">super_block</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">statfs</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">dentry</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">kstatfs</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">remount_fs</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">super_block</span> <span class="o">*</span><span class="p">,</span> <span class="kt">int</span> <span class="o">*</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="p">);</span> + <span class="c1">//...</span> +<span class="p">};</span> +</pre></div> +</div> +<p>The fields of the structure are function pointers with the following meanings:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">write_inode</span></code>, <code class="docutils literal"><span class="pre">alloc_inode</span></code>, <code class="docutils literal"><span class="pre">destroy_inode</span></code> write, allocate, respectively release resources associated with an inode and are described in the next lab</li> +<li><code class="docutils literal"><span class="pre">put_super</span></code> is called when the superblock is released at <code class="docutils literal"><span class="pre">umount</span></code>; within this function, any resources (generally memory) from the file system's private data must be released;</li> +<li><code class="docutils literal"><span class="pre">remount_fs</span></code> is called when the kernel detects a remount attempt (mount flag <code class="docutils literal"><span class="pre">MS_REMOUNTM</span></code>); most of the time here must be detected if a switch from read-only to read-write or vice versa is attempted; this can be done simply because both the old flags (in <code class="docutils literal"><span class="pre">sb->s_flags</span></code>) and the new flags (the <code class="docutils literal"><span class="pre">flags</span></code> argument) can be accessed; <code class="docutils literal"><span class="pre">data</span></code> is a pointer to the data sent by <code class="xref c c-func docutils literal"><span class="pre">mount()</span></code> that represent file system specific options;</li> +<li><code class="docutils literal"><span class="pre">statfs</span></code> is called when a <code class="docutils literal"><span class="pre">statfs</span></code> system call is done (try <code class="docutils literal"><span class="pre">stat</span> <span class="pre">–f</span></code> or <code class="docutils literal"><span class="pre">df</span></code>); this call must fill the fields of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">kstatfs</span></code> structure, as it is done, for example, in the <code class="xref c c-func docutils literal"><span class="pre">ext4_statfs()</span></code> function.</li> +</ul> +</div></blockquote> +</div> +</div> +<div class="section" id="the-fill-super-function"> +<span id="fillsupersection"></span><h2>The <code class="xref c c-func docutils literal"><span class="pre">fill_super()</span></code> function<a class="headerlink" href="#the-fill-super-function" title="Permalink to this headline">¶</a></h2> +<p>As specified, the <code class="xref c c-func docutils literal"><span class="pre">fill_super()</span></code> function is called to terminate the superblock initialization. This initialization involves filling the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> structure fields and the initialization of the root directory inode.</p> +<p>An example of implementation is the <code class="xref c c-func docutils literal"><span class="pre">ramfs_fill_super()</span></code> function which is called to initialize the remaining fields in the superblock:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><linux/pagemap.h></span><span class="cp"></span> + +<span class="cp">#define RAMFS_MAGIC 0x858458f6</span> + +<span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">super_operations</span> <span class="n">ramfs_ops</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">statfs</span> <span class="o">=</span> <span class="n">simple_statfs</span><span class="p">,</span> + <span class="p">.</span><span class="n">drop_inode</span> <span class="o">=</span> <span class="n">generic_delete_inode</span><span class="p">,</span> + <span class="p">.</span><span class="n">show_options</span> <span class="o">=</span> <span class="n">ramfs_show_options</span><span class="p">,</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">ramfs_fill_super</span><span class="p">(</span><span class="k">struct</span> <span class="n">super_block</span> <span class="o">*</span><span class="n">sb</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">int</span> <span class="n">silent</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">ramfs_fs_info</span> <span class="o">*</span><span class="n">fsi</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">err</span><span class="p">;</span> + + <span class="n">save_mount_options</span><span class="p">(</span><span class="n">sb</span><span class="p">,</span> <span class="n">data</span><span class="p">);</span> + + <span class="n">fsi</span> <span class="o">=</span> <span class="n">kzalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">ramfs_fs_info</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + <span class="n">sb</span><span class="o">-></span><span class="n">s_fs_info</span> <span class="o">=</span> <span class="n">fsi</span><span class="p">;</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">fsi</span><span class="p">)</span> + <span class="k">return</span> <span class="o">-</span><span class="n">ENOMEM</span><span class="p">;</span> + + <span class="n">err</span> <span class="o">=</span> <span class="n">ramfs_parse_options</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="o">&</span><span class="n">fsi</span><span class="o">-></span><span class="n">mount_opts</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">err</span><span class="p">)</span> + <span class="k">return</span> <span class="n">err</span><span class="p">;</span> + + <span class="n">sb</span><span class="o">-></span><span class="n">s_maxbytes</span> <span class="o">=</span> <span class="n">MAX_LFS_FILESIZE</span><span class="p">;</span> + <span class="n">sb</span><span class="o">-></span><span class="n">s_blocksize</span> <span class="o">=</span> <span class="n">PAGE_SIZE</span><span class="p">;</span> + <span class="n">sb</span><span class="o">-></span><span class="n">s_blocksize_bits</span> <span class="o">=</span> <span class="n">PAGE_SHIFT</span><span class="p">;</span> + <span class="n">sb</span><span class="o">-></span><span class="n">s_magic</span> <span class="o">=</span> <span class="n">RAMFS_MAGIC</span><span class="p">;</span> + <span class="n">sb</span><span class="o">-></span><span class="n">s_op</span> <span class="o">=</span> <span class="o">&</span><span class="n">ramfs_ops</span><span class="p">;</span> + <span class="n">sb</span><span class="o">-></span><span class="n">s_time_gran</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> + + <span class="n">inode</span> <span class="o">=</span> <span class="n">ramfs_get_inode</span><span class="p">(</span><span class="n">sb</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">S_IFDIR</span> <span class="o">|</span> <span class="n">fsi</span><span class="o">-></span><span class="n">mount_opts</span><span class="p">.</span><span class="n">mode</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> + <span class="n">sb</span><span class="o">-></span><span class="n">s_root</span> <span class="o">=</span> <span class="n">d_make_root</span><span class="p">(</span><span class="n">inode</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">sb</span><span class="o">-></span><span class="n">s_root</span><span class="p">)</span> + <span class="k">return</span> <span class="o">-</span><span class="n">ENOMEM</span><span class="p">;</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The kernel provides generic function to implement operations with file system structures. +The <code class="xref c c-func docutils literal"><span class="pre">generic_delete_inode()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">simple_statfs()</span></code> functions used in the above code are such functions and can be used to implement the drivers if their functionality is sufficient.</p> +<p>The <code class="xref c c-func docutils literal"><span class="pre">ramfs_fill_super()</span></code> function in the above code fills some fields in the superblock, then reads the root inode and allocates the root dentry. +Reading the root inode is done in the <code class="xref c c-func docutils literal"><span class="pre">ramfs_get_inode()</span></code> function, and consists of allocating a new inode using <code class="xref c c-func docutils literal"><span class="pre">new_inode()</span></code> and initializing it. In order to free the inode, <code class="xref c c-func docutils literal"><span class="pre">iput()</span></code> is used, and <code class="xref c c-func docutils literal"><span class="pre">d_make_root()</span></code> is used to allocate the root dentry.</p> +<p>An example implementation for a disk file system is the <code class="xref c c-func docutils literal"><span class="pre">minix_fill_super()</span></code> function in the minix file system. +The functionality for the disk file system is similar to that of the virtual file system, with the exception of using the buffer cache. +Also, the minix file system keeps private data using the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minix_sb_info</span></code> structure. +A large part of this function deals with the initialization of these private data. +The private data is allocated using the <code class="xref c c-func docutils literal"><span class="pre">kzalloc()</span></code> function and stored in the <code class="docutils literal"><span class="pre">s_fs_info</span></code> field of the superblock structure.</p> +<p>VFS functions typically get as arguments the superblock, an inode and/or a dentry that contain a pointer to the superblock so that these private data can be easily accessed.</p> +</div> +<div class="section" id="buffer-cache"> +<span id="buffercachesection"></span><h2>Buffer cache<a class="headerlink" href="#buffer-cache" title="Permalink to this headline">¶</a></h2> +<p>Buffer cache is a kernel subsystem that handles caching (both read and write) blocks from block devices. +The base entity used by buffer cache is the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">buffer_head</span></code> structure. +The most important fields in this structure are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">b_data</span></code>, pointer to a memory area where the data was read from or where the data must be written to</li> +<li><code class="docutils literal"><span class="pre">b_size</span></code>, buffer size</li> +<li><code class="docutils literal"><span class="pre">b_bdev</span></code>, the block device</li> +<li><code class="docutils literal"><span class="pre">b_blocknr</span></code>, the number of block on the device that has been loaded or needs to be saved on the disk</li> +<li><code class="docutils literal"><span class="pre">b_state</span></code>, the status of the buffer</li> +</ul> +</div></blockquote> +<p>There are some important functions that work with these structures:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">__bread()</span></code>: reads a block with the given number and given size in a <code class="docutils literal"><span class="pre">buffer_head</span></code> structure; in case of success returns a pointer to the <code class="docutils literal"><span class="pre">buffer_head</span></code> structure, otherwise it returns <code class="docutils literal"><span class="pre">NULL</span></code>;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">sb_bread()</span></code>: does the same thing as the previous function, but the size of the read block is taken from the superblock, as well as the device from which the read is done;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">mark_buffer_dirty()</span></code>: marks the buffer as dirty (sets the <code class="docutils literal"><span class="pre">BH_Dirty</span></code> bit); the buffer will be written to the disk at a later time (from time to time the <code class="docutils literal"><span class="pre">bdflush</span></code> kernel thread wakes up and writes the buffers to disk);</li> +<li><code class="xref c c-func docutils literal"><span class="pre">brelse()</span></code>: frees up the memory used by the buffer, after it has previously written the buffer on disk if needed;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">map_bh()</span></code>: associates the buffer-head with the corresponding sector.</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="functions-and-useful-macros"> +<h2>Functions and useful macros<a class="headerlink" href="#functions-and-useful-macros" title="Permalink to this headline">¶</a></h2> +<p>The super block typically contains a map of occupied blocks (by inodes, dentries, data) in the form of a bitmap (vector of bits). To work with such maps, it is recommend to use the following features:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">find_first_zero_bit()</span></code>, to find the first zero bit in a memory area. The size parameter means the number of bits in the search area;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">test_and_set_bit()</span></code>, to set a bit and get the old value;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">test_and_clear_bit()</span></code>, to delete a bit and get the old value;</li> +<li><code class="xref c c-func docutils literal"><span class="pre">test_and_change_bit()</span></code>, to invert the value of a bit and get the old value.</li> +</ul> +</div></blockquote> +<p>The following macrodefinitions can be used to verify the type of an inode:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">S_ISDIR</span></code> (<code class="docutils literal"><span class="pre">inode->i_mode</span></code>) to check if the inode is a directory;</li> +<li><code class="docutils literal"><span class="pre">S_ISREG</span></code> (<code class="docutils literal"><span class="pre">inode->i_mode</span></code>) to check if the inode is a regular file (not a link or device file).</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="further-reading"> +<h2>Further reading<a class="headerlink" href="#further-reading" title="Permalink to this headline">¶</a></h2> +<ol class="arabic simple"> +<li>Robert Love -- Linux Kernel Development, Second Edition -- Chapter +12. The Virtual Filesystem</li> +<li>Understanding the Linux Kernel, 3rd edition - Chapter 12. The Virtual +Filesystem</li> +<li><a class="reference external" href="http://www.coda.cs.cmu.edu/doc/talks/linuxvfs/">Linux Virtual File System (presentation)</a></li> +<li><a class="reference external" href="http://www.cyberciti.biz/tips/understanding-unixlinux-file-system-part-i.html">Understanding Unix/Linux Filesystem</a></li> +<li><a class="reference external" href="http://lwn.net/Articles/57369/">Creating Linux virtual filesystems</a></li> +<li><a class="reference external" href="http://www.tldp.org/LDP/tlk/fs/filesystem.html">The Linux Documentation Project - VFS</a></li> +<li><a class="reference external" href="http://www.linux.it/~rubini/docs/vfs/vfs.html">The "Virtual File System" in Linux</a></li> +<li><a class="reference external" href="http://inglorion.net/documents/tutorials/tutorfs/">A Linux Filesystem Tutorial</a></li> +<li><a class="reference external" href="http://www.win.tue.nl/~aeb/linux/lk/lk-8.html">The Linux Virtual File System</a></li> +<li><a class="reference external" href="http://lxr.free-electrons.com/source/Documentation/filesystems/vfs.txt">Documentation/filesystems/vfs.txt</a></li> +<li><a class="reference external" href="http://lxr.free-electrons.com/source/fs/">File systems sources</a></li> +</ol> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is filesystems. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/filesystems/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p class="last">In order to have a better understanding of what we do well and we can do +better, what factors affect your implication in teaching, extracurricular +but also professional activities, we ask you to complete <a class="reference external" href="https://forms.office.com/r/SqBF2kfzk5">this survey</a>. The survey is a short one, +having answers with check marks, with an estimated completion time of +3-5 minutes. Obviously, we will send you the analysis of the survey and +use it to improve the teaching activities.</p> +</div> +<div class="section" id="myfs"> +<h3>myfs<a class="headerlink" href="#myfs" title="Permalink to this headline">¶</a></h3> +<p>To begin, we plan to get familiar with the interface exposed by the Linux kernel and the Virtual File System (VFS) component. That is why, for the beginning, we will work with a simple, virtual file system (i.e. without physical disk support). The file system is called <code class="docutils literal"><span class="pre">myfs</span></code>.</p> +<p>For this we will access the <code class="docutils literal"><span class="pre">myfs/</span></code> subdirectory in the laboratory skeleton. We will implement the superblock operations within this lab, and the next lab will continue with the inode operations.</p> +<div class="section" id="register-and-unregister-the-myfs-file-system"> +<h4>1. Register and unregister the myfs file system<a class="headerlink" href="#register-and-unregister-the-myfs-file-system" title="Permalink to this headline">¶</a></h4> +<p>The first step in working with the file system is to register and unregister it. We want to do this for the file system described in <code class="docutils literal"><span class="pre">myfs.c</span></code>. Check the file contents and follow the directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">1</span></code>.</p> +<p>The steps you need to take are described in the section <a class="reference internal" href="#registerunregistersection"><span class="std std-ref">Register and unregister filesystems</span></a>. Use the <code class="docutils literal"><span class="pre">"myfs"</span></code> string for the file system name.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>Within the file system structure, use the <code class="docutils literal"><span class="pre">myfs_mount</span></code> function present in the code skeleton to fill the superblock (done when mounting). In <code class="docutils literal"><span class="pre">myfs_mount</span></code> call the function specific to a file system without disk support. As an argument for the specific mount function, use the function of type <code class="docutils literal"><span class="pre">fill_super</span></code> defined in the code skeleton. You can review the <a class="reference internal" href="#functionsmountkillsbsection"><span class="std std-ref">Functions mount, kill_sb</span></a> section.</p> +<p class="last">To destroy the superblock (done at unmounting) use <code class="docutils literal"><span class="pre">kill_litter_super</span></code>, also a function specific to a file system without disk support. The function is already implemented, you need to fill it in the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_system_type</span></code> structure.</p> +</div> +<p>After completing the sections marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">1</span></code> , compile the module, copy it to the QEMU virtual machine, and start the virtual machine. Load the kernel module and then check the presence of the <code class="docutils literal"><span class="pre">myfs</span></code> file system within the <code class="docutils literal"><span class="pre">/proc/filesystems</span></code> file.</p> +<p>At the moment, the file system is only registered, it does not expose operations to use it. If we try to mount it, the operation will fail. To try mounting, we create mount point <code class="docutils literal"><span class="pre">/mnt/myfs/</span></code>.</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> mkdir -p /mnt/myfs +</pre></div> +</div> +<p>and then we use the <code class="docutils literal"><span class="pre">mount</span></code> command:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> mount -t myfs none /mnt/myfs +</pre></div> +</div> +<p>The error message we get shows that we have not implemented the operations that work on the superblock. We will have to implement the operations on the superblock and initialize the root inode. We will do this further.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The <code class="docutils literal"><span class="pre">none</span></code> argument sent to the <code class="docutils literal"><span class="pre">mount</span></code> command indicates that we do not have a device from which to mount, the file system being a virtual one. Similarly, this is how the <code class="docutils literal"><span class="pre">procfs</span></code> or <code class="docutils literal"><span class="pre">sysfs</span></code> filesystems are mounted on Linux systems.</p> +</div> +</div> +<div class="section" id="completing-myfs-superblock"> +<h4>2. Completing myfs superblock<a class="headerlink" href="#completing-myfs-superblock" title="Permalink to this headline">¶</a></h4> +<p>To be able to mount the file system, we need to fill its superblock's fields, that is, a generic VFS structure of type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code>. +We will fill out the structure within the <code class="xref c c-func docutils literal"><span class="pre">myfs_fill_super()</span></code> function; the superblock is represented by the variable <code class="docutils literal"><span class="pre">sb</span></code> passed as an argument to the function. +Follow the hints marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">2</span></code>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>To fill the <code class="docutils literal"><span class="pre">myfs_fill_super</span></code> function, you can start from the example in the section <a class="reference internal" href="#fillsupersection"><span class="std std-ref">The fill_super() function</span></a>.</p> +<p class="last">For the superblock structure fields, use the macros defined within the code skeleton wherever possible.</p> +</div> +<p>The <code class="docutils literal"><span class="pre">s_op</span></code> field in the superblock structure must be initialized to the superblock operations structures (type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_operations</span></code>). You need to define such a structure.</p> +<p>For information on defining the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_operations</span></code> structure and filling the superblock, see the section <a class="reference internal" href="#superblocksection"><span class="std std-ref">Superblock operations</span></a>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Initialize the <code class="docutils literal"><span class="pre">drop_inode</span></code> and <code class="docutils literal"><span class="pre">statfs</span></code> fields of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_operations</span></code> structure.</p> +</div> +<p>Although the superblock will be properly initialized at this time, the mount operation will continue to fail. +In order for the operation to be successfully completed, the root inode will have to be initialized, which we will do for the next exercise.</p> +</div> +<div class="section" id="initialize-myfs-root-inode"> +<h4>3. Initialize myfs root inode<a class="headerlink" href="#initialize-myfs-root-inode" title="Permalink to this headline">¶</a></h4> +<p>The root inode is the inode of the file system root directory (i.e. <code class="docutils literal"><span class="pre">/</span></code>). +Initialization is done when the file system is mounted. +The <code class="docutils literal"><span class="pre">myfs_fill_super</span></code> function, called at mount, is the one that calls the <code class="docutils literal"><span class="pre">myfs_get_inode</span></code> function that creates and initializes an inode. +Typically, this function is used to create and initialize all inodes; In this exercise, however, we will only create the root inode.</p> +<p>The <code class="xref c c-type docutils literal"><span class="pre">inode</span></code> is allocated inside the <code class="docutils literal"><span class="pre">myfs_get_inode</span></code> function (local variable <code class="docutils literal"><span class="pre">inode</span></code>, allocated using the <code class="xref c c-func docutils literal"><span class="pre">new_inode()</span></code> function call).</p> +<p>To successfully complete mounting the file system, you will need to fill the <code class="docutils literal"><span class="pre">myfs_get_inode</span></code> function. Follow directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">3</span></code>. A starting point is the <a class="reference external" href="https://elixir.bootlin.com/linux/latest/source/fs/ramfs/inode.c#L63">ramfs_get_inode</a> function.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>To initialize <code class="docutils literal"><span class="pre">uid</span></code>, <code class="docutils literal"><span class="pre">gid</span></code> and <code class="docutils literal"><span class="pre">mode</span></code> , you can use the <code class="xref c c-func docutils literal"><span class="pre">inode_init_owner()</span></code> function as it is used in <code class="xref c c-func docutils literal"><span class="pre">ramfs_get_inode()</span></code>. +When you call <code class="xref c c-func docutils literal"><span class="pre">inode_init_owner()</span></code>, use <code class="docutils literal"><span class="pre">NULL</span></code> as the second parameter because there is no parent directory for the created inode.</p> +<p>Initialize the <code class="docutils literal"><span class="pre">i_atime</span></code>, <code class="docutils literal"><span class="pre">i_ctime</span></code>, and <code class="docutils literal"><span class="pre">i_mtime</span></code> of the VFS inode to the value returned by the <code class="xref c c-func docutils literal"><span class="pre">current_time()</span></code> function.</p> +<p>You will need to initialize the operations for the inode of type directory. To do this, follow the steps:</p> +<blockquote class="last"> +<div><ol class="arabic simple"> +<li>Check if this is a directory type inode using the <code class="docutils literal"><span class="pre">S_ISDIR</span></code> macro.</li> +<li>For the <code class="docutils literal"><span class="pre">i_op</span></code> and <code class="docutils literal"><span class="pre">i_fop</span></code> fields, use kernel functions that are already implemented:<ul> +<li>for <code class="docutils literal"><span class="pre">i_op</span></code>: <code class="xref c c-type docutils literal"><span class="pre">simple_dir_inode_operations</span></code>.</li> +<li>for <code class="docutils literal"><span class="pre">i_fop</span></code>: <code class="xref c c-type docutils literal"><span class="pre">simple_dir_operations</span></code></li> +</ul> +</li> +<li>Increase the number of links for the directory using the <code class="xref c c-func docutils literal"><span class="pre">inc_nlink()</span></code> function.</li> +</ol> +</div></blockquote> +</div> +</div> +<div class="section" id="test-myfs-mount-and-unmount"> +<h4>4. Test myfs mount and unmount<a class="headerlink" href="#test-myfs-mount-and-unmount" title="Permalink to this headline">¶</a></h4> +<p>Now we can mount the filesystem. +Follow the steps above to compile the kernel module, copy to the virtual machine, and start the virtual machine, then insert the kernel module, create the mount point <code class="docutils literal"><span class="pre">/mnt/myfs/</span></code>, and mount the file system. +We verify that the file system was mounted by inspecting the <code class="docutils literal"><span class="pre">/proc/mounts</span></code> file.</p> +<p>What inode number does the <code class="docutils literal"><span class="pre">/mnt/myfs</span></code> directory have? Why?</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>To display the inode number of a directory, use the command:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">ls -di /path/to/directory</span> +</pre></div> +</div> +<p class="last">where <code class="docutils literal"><span class="pre">/path/to/directory/</span></code> is the path to the directory whose inode number we want to display.</p> +</div> +<p>We check myfs file system statistics using the following command:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">stat -f /mnt/myfs</span> +</pre></div> +</div> +<p>We want to see what the mount point <code class="docutils literal"><span class="pre">/mnt/myfs</span></code> contains and if we can create files. +For this we run the commands:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ls -la /mnt/myfs +<span class="gp">#</span> touch /mnt/myfs/a.txt +</pre></div> +</div> +<p>We can see that we can not create the <code class="docutils literal"><span class="pre">a.txt</span></code> file on the file system. +This is because we have not implemented the operations to work with inodes in the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_operations</span></code> structure. +We will implement these operations within the next lab.</p> +<p>Unmount the file system using the command</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">umount /mnt/myfs</span> +</pre></div> +</div> +<p>Unload the kernel module corresponding to the file system as well.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>To test the entire functionality, you can use the <code class="docutils literal"><span class="pre">test-myfs.sh</span></code> script:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">./test-myfs.sh</span> +</pre></div> +</div> +<p>The script is copied to the virtual machine using <code class="docutils literal"><span class="pre">make</span> <span class="pre">copy</span></code> only if it is executable:</p> +<div class="last highlight-console"><div class="highlight"><pre><span></span><span class="gp">student@workstation:~/linux/tools/labs$</span> chmod +x skels/filesystems/myfs/test-myfs.sh +</pre></div> +</div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The statistics displayed for the file system are minimal because the information is provided by the simple_statfs function.</p> +</div> +</div> +</div> +<div class="section" id="minfs"> +<h3>minfs<a class="headerlink" href="#minfs" title="Permalink to this headline">¶</a></h3> +<p>Next, we will implement the basics of a very simple file system, called <code class="docutils literal"><span class="pre">minfs</span></code>, with disk support. +We will use a disk in the virtual machine that we will format and mount with the <code class="docutils literal"><span class="pre">minfs</span></code> filesystem.</p> +<p>For this we will access the <code class="docutils literal"><span class="pre">minfs/kernel</span></code> directory from the laboratory skeleton and work with the code in <code class="docutils literal"><span class="pre">minfs.c</span></code>. +Just like <code class="docutils literal"><span class="pre">myfs</span></code> we will not implement the operations for working with inodes. We will just limit to working with the superblock and, therefore, mounting. +The rest of the operations will be implemented in the next lab.</p> +<p>Follow the diagram below to clarify the role of structures within the <code class="docutils literal"><span class="pre">minfs</span></code> file system.</p> +<img alt="../_images/minfs1.png" src="../_images/minfs1.png" /> +<div class="section" id="registering-and-unregistering-the-minfs-file-system"> +<h4>1. Registering and unregistering the minfs file system<a class="headerlink" href="#registering-and-unregistering-the-minfs-file-system" title="Permalink to this headline">¶</a></h4> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>Before solving the exercise, we need to add a disk to the virtual machine. To do this, generate a file that we will use as the disk image using the following command:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">dd if=/dev/zero of=mydisk.img bs=1M count=100</span> +</pre></div> +</div> +<p class="last">and add the <code class="docutils literal"><span class="pre">-drive</span> <span class="pre">file=mydisk.img,if=virtio,format=raw</span></code> argument to the <code class="docutils literal"><span class="pre">qemu</span></code> command in <code class="docutils literal"><span class="pre">qemu/Makefile</span></code> (in the <code class="docutils literal"><span class="pre">QEMU_OPTS</span></code> variable). +The new argument for the <code class="docutils literal"><span class="pre">qemu</span></code> command must be added after the one for the existing disk (<code class="docutils literal"><span class="pre">YOCTO_IMAGE</span></code>).</p> +</div> +<p>To register and unregister the file system, you will need to fill the <code class="docutils literal"><span class="pre">minfs_fs_type</span></code> and <code class="docutils literal"><span class="pre">minfs_mount</span></code> functions in <code class="docutils literal"><span class="pre">minfs.c</span></code>. Follow the directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">1</span></code>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>In the file system structure, for mount, use the <code class="docutils literal"><span class="pre">minfs_mount</span></code> function from in the code skeleton. +In this function, call the function to mount a file system with disk support (See the <a class="reference internal" href="#functionsmountkillsbsection"><span class="std std-ref">Functions mount, kill_sb</span></a> section. Use <code class="xref c c-func docutils literal"><span class="pre">mount_bdev()</span></code>). +Choose the most suitable function for destroying the superblock (done at unmount); keep in mind that it is a file system with disk support. Use the <code class="xref c c-func docutils literal"><span class="pre">kill_block_super()</span></code> function.</p> +<p>Initialize the <code class="docutils literal"><span class="pre">fs_flags</span></code> field of the <code class="xref c c-type docutils literal"><span class="pre">minfs_fs_type</span></code> structure with the appropriate value for a file system with disk support. See the section <a class="reference internal" href="#registerunregistersection"><span class="std std-ref">Register and unregister filesystems</span></a>.</p> +<p class="last">The function for filling the superblock is <code class="docutils literal"><span class="pre">minfs_fill_super</span></code>.</p> +</div> +<p>After completing the sections marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">1</span></code>, compile the module, copy it into the QEMU virtual machine, and start the virtual machine. +Load the kernel module and then check the presence of the <code class="docutils literal"><span class="pre">minfs</span></code> file system within the <code class="docutils literal"><span class="pre">/proc/filesystems</span></code> file.</p> +<p>To test the mounting of the <code class="docutils literal"><span class="pre">minfs</span></code> file system we will need to format the disk with its structure. Formatting requires the <code class="docutils literal"><span class="pre">mkfs.minfs</span></code> formatting tool from the <code class="docutils literal"><span class="pre">minfs/user</span></code> directory. The utility is automatically compiled when running <code class="docutils literal"><span class="pre">make</span> <span class="pre">build</span></code> and copied to the virtual machine at <code class="docutils literal"><span class="pre">make</span> <span class="pre">copy</span></code>.</p> +<p>After compiling, copying, and starting the virtual machine, format the <code class="docutils literal"><span class="pre">/dev/vdd</span></code> using the formatting utility:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ./mkfs.minfs /dev/vdd +</pre></div> +</div> +<p>Load the kernel module:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> insmod minfs.ko +</pre></div> +</div> +<p>Create mount point <code class="docutils literal"><span class="pre">/mnt/minfs/</span></code>:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> mkdir -p /mnt/minfs/ +</pre></div> +</div> +<p>and mount the filesystem</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> mount -t minfs /dev/vdd /mnt/minfs/ +</pre></div> +</div> +<p>The operation fails because the root inode is not initialized.</p> +</div> +<div class="section" id="completing-minfs-superblock"> +<h4>2. Completing minfs superblock<a class="headerlink" href="#completing-minfs-superblock" title="Permalink to this headline">¶</a></h4> +<p>To be able to mount the file system, you will need to fill the superblock (i.e a structure with type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code>) within the <code class="docutils literal"><span class="pre">minfs_fill_super</span></code> function; it is the <code class="docutils literal"><span class="pre">s</span></code> argument of the function. +The structure of operations on the superblock is already defined: <code class="docutils literal"><span class="pre">minfs_ops</span></code>. +Follow the directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">2</span></code>. You can also follow the implementation of the <a class="reference external" href="https://elixir.bootlin.com/linux/latest/source/fs/minix/inode.c#L153">minix_fill_super</a> function.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>Some structures are found in the header file <code class="docutils literal"><span class="pre">minfs.h</span></code>.</p> +<p>For information on working with buffers, go to the <a class="reference internal" href="#buffercachesection"><span class="std std-ref">Buffer cache</span></a> section.</p> +<p>Read the first block on the disk (block with index 0). +To read the block, use the <code class="xref c c-func docutils literal"><span class="pre">sb_bread()</span></code> function. +Cast the read data (the <code class="docutils literal"><span class="pre">b_data</span></code> field in the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">buffer_head</span></code> structure) to the structure storing the <code class="docutils literal"><span class="pre">minfs</span></code> superblock information on the disk: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minfs_super_block</span></code>, defined in the source code file.</p> +<p class="last">Structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minfs_super_block</span></code> holds file system-specific information that is not found in the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> generic structure (in this case only version). +Those additional information (found in <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minfs_super_block</span></code> (on disk) but not in <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> (VFS)) will be stored in the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minfs_sb_info</span></code> structure.</p> +</div> +<p>To check the functionality, we need a function for reading the root inode. +For the time being, use the <code class="docutils literal"><span class="pre">myfs_get_inode</span></code> function from <code class="docutils literal"><span class="pre">myfs</span></code> file system exercises. +Copy the function into the source code and call it the same as you did for myfs. +The third argument when calling the <code class="docutils literal"><span class="pre">myfs_get_inode</span></code> function is the inode creation permissions, similar to the virtual file system exercise (myfs).</p> +<p>Validate the implementation by executing the commands from the previous exercise.</p> +</div> +<div class="section" id="creating-and-destroying-minfs-inodes"> +<h4>3. Creating and destroying minfs inodes<a class="headerlink" href="#creating-and-destroying-minfs-inodes" title="Permalink to this headline">¶</a></h4> +<p>For mounting, we need to initialize the root inode, and to get the root inode, we need to implement the functions to work with inodes. +That is, you need to implement the <code class="docutils literal"><span class="pre">minfs_alloc_inode</span></code> and <code class="docutils literal"><span class="pre">minfs_destroy_inode</span></code> functions. +Follow the directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">3</span></code>. You can use the <code class="xref c c-func docutils literal"><span class="pre">minix_alloc_inode()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">minix_destroy_inode()</span></code> functions as a model.</p> +<p>For the implementation, look at the macros and structures in the <code class="docutils literal"><span class="pre">minfs.h</span></code> header file.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>For memory allocation/deallocation in <code class="docutils literal"><span class="pre">minfs_alloc_inode</span></code> and <code class="docutils literal"><span class="pre">minfs_destroy_inode</span></code>, we recommend using <code class="xref c c-func docutils literal"><span class="pre">kzalloc()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">kfree()</span></code>.</p> +<p>In <code class="docutils literal"><span class="pre">minfs_alloc_inode</span></code> allocate structures with type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code>, but only return structures with type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code>, i.e. return those given by the <code class="docutils literal"><span class="pre">vfs_inode</span></code> field.</p> +<p>In the <code class="docutils literal"><span class="pre">minfs_alloc_inode</span></code> function, call <code class="xref c c-func docutils literal"><span class="pre">inode_init_once()</span></code> to initialize the inode.</p> +<p class="last">In the <code class="docutils literal"><span class="pre">destroy_inode</span></code> function, you can access the structure with type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code> using the <code class="docutils literal"><span class="pre">container_of</span></code> macro.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">In this exercise, you have implemented the <code class="docutils literal"><span class="pre">minfs_alloc_inode</span></code> and <code class="docutils literal"><span class="pre">minfs_destroy_inode</span></code> functions, but they are not yet called. The correctness of the implementation will be checked at the end of the next exercise.</p> +</div> +</div> +<div class="section" id="initialize-minfs-root-inode"> +<h4>4. Initialize minfs root inode<a class="headerlink" href="#initialize-minfs-root-inode" title="Permalink to this headline">¶</a></h4> +<p>Initializing the root inode is required in order to mount the file system. +For this, you will need to complete the <code class="docutils literal"><span class="pre">minfs_ops</span></code> structure with the <code class="docutils literal"><span class="pre">minfs_alloc_inode</span></code> and <code class="docutils literal"><span class="pre">minfs_destroy_inode</span></code> functions and fill the <code class="docutils literal"><span class="pre">minfs_iget</span></code> function.</p> +<p>The <code class="docutils literal"><span class="pre">minfs_iget</span></code> function is the function called to allocate a VFS inode (i.e. <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code>) and fill it with minfs inode-specific information from the disk (i.e. <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode</span></code>).</p> +<p>Follow the directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">4</span></code>. +Fill out the <code class="docutils literal"><span class="pre">alloc_inode</span></code> and <code class="docutils literal"><span class="pre">destroy_inode</span></code> fields of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_operations</span></code> structure with the functions implemented in the previous step.</p> +<p>The information about the root inode is found in the second block on the disk (the inode with index 1). +Make <code class="docutils literal"><span class="pre">minfs_iget</span></code> read the root minfs inode from the disk (<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode</span></code>) and fill in the VFS inode (<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code>).</p> +<p>In the <code class="docutils literal"><span class="pre">minfs_fill_super</span></code> function, replace the <code class="docutils literal"><span class="pre">myfs_get_inode</span></code> call with the <code class="docutils literal"><span class="pre">minfs_iget</span></code> function call.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>To implement the <code class="docutils literal"><span class="pre">minfs_iget</span></code> function, follow the implementation of <a class="reference external" href="https://elixir.bootlin.com/linux/v4.15/source/fs/minix/inode.c#L460">V1_minix_iget</a>. +To read a block, use the <code class="xref c c-func docutils literal"><span class="pre">sb_bread()</span></code> function. +Cast the read data (the <code class="docutils literal"><span class="pre">b_data</span></code> field of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">buffer_head</span></code> structure) to the minfs inode from the disk (<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode</span></code>).</p> +<p>The <code class="docutils literal"><span class="pre">i_uid</span></code>, <code class="docutils literal"><span class="pre">i_gid</span></code>, <code class="docutils literal"><span class="pre">i_mode</span></code>, <code class="docutils literal"><span class="pre">i_size</span></code> must be filled in the VFS inode with the values in the minfs inode structure read from disk. +To initialize the <code class="docutils literal"><span class="pre">i_uid</span></code> and <code class="docutils literal"><span class="pre">i_gid</span> <span class="pre">fields</span></code>, use the functions <code class="xref c c-func docutils literal"><span class="pre">i_uid_write()</span></code> , and <code class="xref c c-func docutils literal"><span class="pre">i_gid_write()</span></code>.</p> +<p>Initialize the <code class="docutils literal"><span class="pre">i_atime</span></code> , <code class="docutils literal"><span class="pre">i_ctime</span></code>, and <code class="docutils literal"><span class="pre">i_mtime</span></code> fields of the VFS inode to the value returned by the <code class="xref c c-func docutils literal"><span class="pre">current_time()</span></code> function.</p> +<p>You will need to initialize the operations for the inode with type directory. To do this, follow the steps:</p> +<blockquote class="last"> +<div><ol class="arabic simple"> +<li>Check if this is a directory type inode using the <code class="docutils literal"><span class="pre">S_ISDIR</span></code> macro.</li> +<li>For the <code class="docutils literal"><span class="pre">i_op</span></code> and <code class="docutils literal"><span class="pre">i_fop</span></code> fields, use kernel functions already implemented:<ul> +<li>for <code class="docutils literal"><span class="pre">i_op</span></code>: <code class="xref c c-func docutils literal"><span class="pre">simple_dir_inode_operations()</span></code> .</li> +<li>for <code class="docutils literal"><span class="pre">i_fop</span></code>: <code class="xref c c-func docutils literal"><span class="pre">simple_dir_operations()</span></code></li> +</ul> +</li> +<li>Increment the number of links for the directory using the <code class="xref c c-func docutils literal"><span class="pre">inc_nlink()</span></code> function.</li> +</ol> +</div></blockquote> +</div> +</div> +<div class="section" id="testing-of-minfs-mount-and-unmount"> +<h4>5. Testing of minfs mount and unmount<a class="headerlink" href="#testing-of-minfs-mount-and-unmount" title="Permalink to this headline">¶</a></h4> +<p>Now we can mount the filesystem. +Follow the steps above to compile the kernel module, copy to the virtual machine, start the virtual machine, and then insert the kernel module, create mount point <code class="docutils literal"><span class="pre">/mnt/minfs/</span></code> and mount the file system. +We verify that the file system was mounted by investigating the <code class="docutils literal"><span class="pre">/proc/mounts</span></code> file.</p> +<p>We check that everything is fine by listing the mount point contents <code class="docutils literal"><span class="pre">/mnt/minfs/</span></code>:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ls /mnt/minfs/ +</pre></div> +</div> +<p>After mount and verification, unmount the file system and unload the module from the kernel.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>Alternatively, to test the entire functionality, you can use the <code class="docutils literal"><span class="pre">test-minfs.sh</span></code> script:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ./test-minfs.sh +</pre></div> +</div> +<p>The script is copied to the virtual machine when running the <code class="docutils literal"><span class="pre">make</span> <span class="pre">copy</span></code> command only if is executable.</p> +<div class="last highlight-console"><div class="highlight"><pre><span></span><span class="gp">student@workstation:~/linux/tools/labs$</span> chmod +x skels/filesystems/minfs/user/test-minfs.sh +</pre></div> +</div> +</div> +</div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lab7-block-device-drivers.html" class="btn btn-neutral float-left" title="SO2 Lab 07 - Block Device Drivers" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lab9-filesystems-part2.html" class="btn btn-neutral float-right" title="SO2 Lab 09 - File system drivers (Part 2)" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lab9-filesystems-part2.html b/refs/pull/405/merge/so2/lab9-filesystems-part2.html new file mode 100644 index 00000000..1a31376f --- /dev/null +++ b/refs/pull/405/merge/so2/lab9-filesystems-part2.html @@ -0,0 +1,1236 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lab 09 - File system drivers (Part 2) — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lab 10 - Networking" href="lab10-networking.html" /> + <link rel="prev" title="SO2 Lab 08 - File system drivers (Part 1)" href="lab8-filesystems-part1.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lab 09 - File system drivers (Part 2)</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lab-objectives">Lab objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#inode">Inode</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#the-inode-structure">The inode structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="#inode-operations">Inode operations</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#the-file-structure">The file structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="#regular-files-inodes">Regular files inodes</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#regular-files-inode-operations">Regular files inode operations</a></li> +<li class="toctree-l4"><a class="reference internal" href="#address-space-operations">Address space operations</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#dentry-structure">Dentry structure</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#dentry-operations">Dentry operations</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#directory-inodes-operations">Directory inodes operations</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#creating-an-inode">Creating an inode</a></li> +<li class="toctree-l4"><a class="reference internal" href="#creating-a-directory">Creating a directory</a></li> +<li class="toctree-l4"><a class="reference internal" href="#creating-a-link">Creating a link</a></li> +<li class="toctree-l4"><a class="reference internal" href="#creating-a-symbolic-link">Creating a symbolic link</a></li> +<li class="toctree-l4"><a class="reference internal" href="#deleting-a-link">Deleting a link</a></li> +<li class="toctree-l4"><a class="reference internal" href="#deleting-a-directory">Deleting a directory</a></li> +<li class="toctree-l4"><a class="reference internal" href="#searching-for-an-inode-in-a-directory">Searching for an inode in a directory</a></li> +<li class="toctree-l4"><a class="reference internal" href="#iterating-through-entries-in-a-directory">Iterating through entries in a directory</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#bitmap-operations">Bitmap operations</a></li> +<li class="toctree-l3"><a class="reference internal" href="#further-reading">Further reading</a></li> +<li class="toctree-l3"><a class="reference internal" href="#exercises">Exercises</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#myfs">myfs</a></li> +<li class="toctree-l4"><a class="reference internal" href="#minfs">minfs</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lab 09 - File system drivers (Part 2)</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lab9-filesystems-part2.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lab-09-file-system-drivers-part-2"> +<h1>SO2 Lab 09 - File system drivers (Part 2)<a class="headerlink" href="#so2-lab-09-file-system-drivers-part-2" title="Permalink to this headline">¶</a></h1> +<div class="section" id="lab-objectives"> +<h2>Lab objectives<a class="headerlink" href="#lab-objectives" title="Permalink to this headline">¶</a></h2> +<blockquote> +<div><ul class="simple"> +<li>Improving the knowledge about inode, file and dentry.</li> +<li>Acquiring knowledge about adding support for working with regular files and directories in VFS (<em>Virtual File System</em>).</li> +<li>Acquiring knowledge about the internal implementation of a file system.</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="inode"> +<h2>Inode<a class="headerlink" href="#inode" title="Permalink to this headline">¶</a></h2> +<p>The inode is an essential component of a UNIX file system and, at the same time, an important component of VFS. An inode is a metadata (it has information about information). +An inode uniquely identifies a file on disk and holds information about it (uid, gid, access rights, access times, pointers to data blocks, etc.). +An important aspect is that an inode does not have information about the file name (it is retained by the associated <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">dentry</span></code> structure).</p> +<p>The inode refers to a file on the disk. To refer an open file (associated with a file descriptor within a process), the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file</span></code> structure is used. +An inode can have any number of (zero or more) <code class="docutils literal"><span class="pre">file</span></code> structures associated (multiple processes can open the same file, or a process can open the same file several times).</p> +<p>Inode exists both as a VFS entity (in memory) and as a disk entity (for UNIX, HFS, NTFS, etc.). +The inode in VFS is represented by the structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code>. +Like the other structures in VFS, <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code> is a generic structure that covers the options for all supported file types, even those that do not have an associated disk entity (such as FAT).</p> +<div class="section" id="the-inode-structure"> +<h3>The inode structure<a class="headerlink" href="#the-inode-structure" title="Permalink to this headline">¶</a></h3> +<p>The inode structure is the same for all file systems. In general, file systems also have private information. These are referenced through the <code class="docutils literal"><span class="pre">i_private</span></code> field of the structure. +Conventionally, the structure that keeps that particular information is called <code class="docutils literal"><span class="pre"><fsname>_inode_info</span></code>, where <code class="docutils literal"><span class="pre">fsname</span></code> represents the file system name. For example, minix and ext4 filesystems store particular information in structures <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">minix_inode_info</span></code>, or <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">ext4_inode_info</span></code>.</p> +<p>Some of the important fields of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code> are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">i_sb</span></code> : The superblock structure of the file system the inode belongs to.</li> +<li><code class="docutils literal"><span class="pre">i_rdev</span></code>: the device on which this file system is mounted</li> +<li><code class="docutils literal"><span class="pre">i_ino</span></code> : the number of the inode (uniquely identifies the inode within the file system)</li> +<li><code class="docutils literal"><span class="pre">i_blkbits</span></code>: number of bits used for the block size == log<sub>2</sub>(block size)</li> +<li><code class="docutils literal"><span class="pre">i_mode</span></code>, <code class="docutils literal"><span class="pre">i_uid</span></code>, <code class="docutils literal"><span class="pre">i_gid</span></code>: access rights, uid, gid</li> +<li><code class="docutils literal"><span class="pre">i_size</span></code>: file/directory/etc. size in bytes</li> +<li><code class="docutils literal"><span class="pre">i_mtime</span></code>, <code class="docutils literal"><span class="pre">i_atime</span></code>, <code class="docutils literal"><span class="pre">i_ctime</span></code>: change, access, and creation time</li> +<li><code class="docutils literal"><span class="pre">i_nlink</span></code>: the number of names entries (dentries) that use this inode; for file systems without links (either hard or symbolic) this is always set to 1</li> +<li><code class="docutils literal"><span class="pre">i_blocks</span></code>: the number of blocks used by the file (all blocks, not just data); this is only used by the quota subsystem</li> +<li><code class="docutils literal"><span class="pre">i_op</span></code>, <code class="docutils literal"><span class="pre">i_fop</span></code>: pointers to operations structures: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode_operations</span></code> and <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code>; <code class="docutils literal"><span class="pre">i_mapping->a_ops</span></code> contains a pointer to <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">address_space_operations</span></code>.</li> +<li><code class="docutils literal"><span class="pre">i_count</span></code>: the inode counter indicating how many kernel components use it.</li> +</ul> +</div></blockquote> +<p>Some functions that can be used to work with inodes:</p> +<blockquote> +<div><ul> +<li><p class="first"><code class="xref c c-func docutils literal"><span class="pre">new_inode()</span></code>: creates a new inode, sets the <code class="docutils literal"><span class="pre">i_nlink</span></code> field to 1 and initializes <code class="docutils literal"><span class="pre">i_blkbits</span></code>, <code class="docutils literal"><span class="pre">i_sb</span></code> and <code class="docutils literal"><span class="pre">i_dev</span></code>;</p> +</li> +<li><p class="first"><code class="xref c c-func docutils literal"><span class="pre">insert_inode_hash()</span></code>: adds the inode to the hash table of inodes; an interesting effect of this call is that the inode will be written to the disk if it is marked as dirty;</p> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p class="last">An inode created with <code class="xref c c-func docutils literal"><span class="pre">new_inode()</span></code> is not in the hash table, and unless you have serious reasons not to, you must enter it in the hash table;</p> +</div> +</li> +<li><p class="first"><code class="xref c c-func docutils literal"><span class="pre">mark_inode_dirty()</span></code>: marks the inode as dirty; at a later moment, it will be written on the disc;</p> +</li> +<li><p class="first"><code class="xref c c-func docutils literal"><span class="pre">iget_locked()</span></code>: loads the inode with the given number from the disk, if it is not already loaded;</p> +</li> +<li><p class="first"><code class="xref c c-func docutils literal"><span class="pre">unlock_new_inode()</span></code>: used in conjunction with <code class="xref c c-func docutils literal"><span class="pre">iget_locked()</span></code>, releases the lock on the inode;</p> +</li> +<li><p class="first"><code class="xref c c-func docutils literal"><span class="pre">iput()</span></code>: tells the kernel that the work on the inode is finished; if no one else uses it, it will be destroyed (after being written on the disk if it is maked as dirty);</p> +</li> +<li><p class="first"><code class="xref c c-func docutils literal"><span class="pre">make_bad_inode()</span></code>: tells the kernel that the inode can not be used; It is generally used from the function that reads the inode when the inode could not be read from the disk, being invalid.</p> +</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="inode-operations"> +<h3>Inode operations<a class="headerlink" href="#inode-operations" title="Permalink to this headline">¶</a></h3> +<div class="section" id="getting-an-inode"> +<h4>Getting an inode<a class="headerlink" href="#getting-an-inode" title="Permalink to this headline">¶</a></h4> +<p>One of the main inode operations is obtaining an inode (the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code> in VFS). +Until version <code class="docutils literal"><span class="pre">2.6.24</span></code> of the Linux kernel, the developer defined a <code class="docutils literal"><span class="pre">read_inode</span></code> function. +Starting with version <code class="docutils literal"><span class="pre">2.6.25</span></code>, the developer must define a <code class="docutils literal"><span class="pre"><fsname>_iget</span></code> where <code class="docutils literal"><span class="pre"><fsname></span></code> is the name of the file system. +This function is responsible with finding the VFS inode if it exists or creating a new one and filling it with the information from the disk.</p> +<p>Generally, this function will call <code class="xref c c-func docutils literal"><span class="pre">iget_locked()</span></code> to get the inode structure from VFS. If the inode is newly created then it will need to read the inode from the disk (using <code class="xref c c-func docutils literal"><span class="pre">sb_bread()</span></code>) and fill in the useful information.</p> +<p>An example of such a function is <code class="xref c c-func docutils literal"><span class="pre">minix_iget()</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="nf">V1_minix_iget</span><span class="p">(</span><span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">buffer_head</span> <span class="o">*</span> <span class="n">bh</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">minix_inode</span> <span class="o">*</span> <span class="n">raw_inode</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">minix_inode_info</span> <span class="o">*</span><span class="n">minix_inode</span> <span class="o">=</span> <span class="n">minix_i</span><span class="p">(</span><span class="n">inode</span><span class="p">);</span> + <span class="kt">int</span> <span class="n">i</span><span class="p">;</span> + + <span class="n">raw_inode</span> <span class="o">=</span> <span class="n">minix_V1_raw_inode</span><span class="p">(</span><span class="n">inode</span><span class="o">-></span><span class="n">i_sb</span><span class="p">,</span> <span class="n">inode</span><span class="o">-></span><span class="n">i_ino</span><span class="p">,</span> <span class="o">&</span><span class="n">bh</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">raw_inode</span><span class="p">)</span> <span class="p">{</span> + <span class="n">iget_failed</span><span class="p">(</span><span class="n">inode</span><span class="p">);</span> + <span class="k">return</span> <span class="n">ERR_PTR</span><span class="p">(</span><span class="o">-</span><span class="n">EIO</span><span class="p">);</span> + <span class="p">...</span> +<span class="p">}</span> + +<span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">minix_iget</span><span class="p">(</span><span class="k">struct</span> <span class="n">super_block</span> <span class="o">*</span><span class="n">sb</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">ino</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span><span class="p">;</span> + + <span class="n">inode</span> <span class="o">=</span> <span class="n">iget_locked</span><span class="p">(</span><span class="n">sb</span><span class="p">,</span> <span class="n">ino</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">inode</span><span class="p">)</span> + <span class="k">return</span> <span class="n">ERR_PTR</span><span class="p">(</span><span class="o">-</span><span class="n">ENOMEM</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="n">inode</span><span class="o">-></span><span class="n">i_state</span> <span class="o">&</span> <span class="n">I_NEW</span><span class="p">))</span> + <span class="k">return</span> <span class="n">inode</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">INODE_VERSION</span><span class="p">(</span><span class="n">inode</span><span class="p">)</span> <span class="o">==</span> <span class="n">MINIX_V1</span><span class="p">)</span> + <span class="k">return</span> <span class="n">V1_minix_iget</span><span class="p">(</span><span class="n">inode</span><span class="p">);</span> + <span class="p">...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The minix_iget function gets the VFS inode using <code class="xref c c-func docutils literal"><span class="pre">iget_locked()</span></code>. +If the inode is already existing (not new == the <code class="docutils literal"><span class="pre">I_NEW</span></code> flag is not set) the function returns. +Otherwise, the function calls the <code class="xref c c-func docutils literal"><span class="pre">V1_minix_iget()</span></code> function that will read the inode from the disk using <code class="xref c c-func docutils literal"><span class="pre">minix_V1_raw_inode()</span></code> and then complete the VFS inode with the read information.</p> +</div> +<div class="section" id="superoperations"> +<h4>Superoperations<a class="headerlink" href="#superoperations" title="Permalink to this headline">¶</a></h4> +<p>Many of the superoperations (components of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_operations</span></code> structure used by the superblock) are used when working with inodes. These operations are described next:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">alloc_inode</span></code>: allocates an inode. +Usually, this funcion allocates a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre"><fsname>_inode_info</span></code> structure and performs basic VFS inode initialization (using <code class="xref c c-func docutils literal"><span class="pre">inode_init_once()</span></code>); +minix uses for allocation the <code class="xref c c-func docutils literal"><span class="pre">kmem_cache_alloc()</span></code> function that interacts with the SLAB subsystem. +For each allocation, the cache construction is called, which in the case of minix is the <code class="xref c c-func docutils literal"><span class="pre">init_once()</span></code> function. +Alternatively, <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> can be used, in which case the <code class="xref c c-func docutils literal"><span class="pre">inode_init_once()</span></code> function should be called. +The <code class="xref c c-func docutils literal"><span class="pre">alloc_inode()</span></code> function will be called by the <code class="xref c c-func docutils literal"><span class="pre">new_inode()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">iget_locked()</span></code> functions.</li> +<li><code class="docutils literal"><span class="pre">write_inode</span></code> : saves/updates the inode received as a parameter on disk; to update the inode, though inefficient, for beginners it is recommended to use the following sequence of operations:<ul> +<li>load the inode from the disk using the <code class="xref c c-func docutils literal"><span class="pre">sb_bread()</span></code> function;</li> +<li>modify the buffer according to the saved inode;</li> +<li>mark the buffer as dirty using <code class="xref c c-func docutils literal"><span class="pre">mark_buffer_dirty()</span></code>; the kernel will then handle its writing on the disk;</li> +<li>an example is the <code class="xref c c-func docutils literal"><span class="pre">minix_write_inode()</span></code> function in the <code class="docutils literal"><span class="pre">minix</span></code> file system</li> +</ul> +</li> +<li><code class="docutils literal"><span class="pre">evict_inode</span></code>: removes any information about the inode with the number received in the <code class="docutils literal"><span class="pre">i_ino</span></code> field from the disk and memory (both the inode on the disk and the associated data blocks). This involves performing the following operations:<ul> +<li>delete the inode from the disk;</li> +<li>updates disk bitmaps (if any);</li> +<li>delete the inode from the page cache by calling <code class="xref c c-func docutils literal"><span class="pre">truncate_inode_pages()</span></code>;</li> +<li>delete the inode from memory by calling <code class="xref c c-func docutils literal"><span class="pre">clear_inode()</span></code> ;</li> +<li>an example is the <code class="xref c c-func docutils literal"><span class="pre">minix_evict_inode()</span></code> function from the minix file system.</li> +</ul> +</li> +<li><code class="docutils literal"><span class="pre">destroy_inode</span></code> releases the memory occupied by inode</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="inode-operations-1"> +<h4>inode_operations<a class="headerlink" href="#inode-operations-1" title="Permalink to this headline">¶</a></h4> +<p>The inode operations are described by the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode_operations</span></code> structure.</p> +<p>Inodes are of several types: file, directory, special file (pipe, fifo), block device, character device, link etc. +For this reason, the operations that an inode needs to implement are different for each type of inode. +Below are detailed operations for a <a class="reference internal" href="#fileinodes"><span class="std std-ref">file type inode</span></a> and a <a class="reference internal" href="#directoryinodes"><span class="std std-ref">directory inode</span></a>.</p> +<p>The operations of an inode are initialized and accessed using the <code class="docutils literal"><span class="pre">i_op</span></code> field of the structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code>.</p> +</div> +</div> +</div> +<div class="section" id="the-file-structure"> +<h2>The file structure<a class="headerlink" href="#the-file-structure" title="Permalink to this headline">¶</a></h2> +<p>The <code class="docutils literal"><span class="pre">file</span></code> structure corresponds to a file open by a process and exists only in memory, being associated with an inode. +It is the closest VFS entity to user-space; the structure fields contain familiar information of a user-space file (access mode, file position, etc.) and the operations with it are performed by known system calls (<code class="docutils literal"><span class="pre">read</span></code>, <code class="docutils literal"><span class="pre">write</span></code> , etc.).</p> +<p>The file operations are described by the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code> structure.</p> +<p>The file operations for a file system are initialized using the <code class="docutils literal"><span class="pre">i_fop</span></code> field of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode</span></code> structure. +When opening a file, the VFS initializes the <code class="docutils literal"><span class="pre">f_op</span></code> field of the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file</span></code> structure with address of <code class="docutils literal"><span class="pre">inode->i_fop</span></code>, such that subsequent system calls use the value stored in the <code class="docutils literal"><span class="pre">file->f_op</span></code>.</p> +</div> +<div class="section" id="regular-files-inodes"> +<span id="fileinodes"></span><h2>Regular files inodes<a class="headerlink" href="#regular-files-inodes" title="Permalink to this headline">¶</a></h2> +<p>To work with the inode, the <code class="docutils literal"><span class="pre">i_op</span></code> and <code class="docutils literal"><span class="pre">i_fop</span></code> fields of the inode structure must be filled in. +The type of the inode determines the operations that it needs to implement.</p> +<div class="section" id="regular-files-inode-operations"> +<span id="fileoperations"></span><h3>Regular files inode operations<a class="headerlink" href="#regular-files-inode-operations" title="Permalink to this headline">¶</a></h3> +<p>In the <code class="docutils literal"><span class="pre">minix</span></code> file system, the <code class="docutils literal"><span class="pre">minix_file_inode_operations</span></code> structure is defined for the operations on an inode and for the file operations the <code class="docutils literal"><span class="pre">minix_file_operations</span></code> structure is defined:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">const</span> <span class="k">struct</span> <span class="n">file_operations</span> <span class="n">minix_file_operations</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">llseek</span> <span class="o">=</span> <span class="n">generic_file_llseek</span><span class="p">,</span> + <span class="p">.</span><span class="n">read_iter</span> <span class="o">=</span> <span class="n">generic_file_read_iter</span><span class="p">,</span> + <span class="c1">//...</span> + <span class="p">.</span><span class="n">write_iter</span> <span class="o">=</span> <span class="n">generic_file_write_iter</span><span class="p">,</span> + <span class="c1">//...</span> + <span class="p">.</span><span class="n">mmap</span> <span class="o">=</span> <span class="n">generic_file_mmap</span><span class="p">,</span> + <span class="c1">//...</span> +<span class="p">};</span> + +<span class="k">const</span> <span class="k">struct</span> <span class="n">inode_operations</span> <span class="n">minix_file_inode_operations</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">setattr</span> <span class="o">=</span> <span class="n">minix_setattr</span><span class="p">,</span> + <span class="p">.</span><span class="n">getattr</span> <span class="o">=</span> <span class="n">minix_getattr</span><span class="p">,</span> +<span class="p">};</span> + + <span class="c1">//...</span> + <span class="k">if</span> <span class="p">(</span><span class="n">S_ISREG</span><span class="p">(</span><span class="n">inode</span><span class="o">-></span><span class="n">i_mode</span><span class="p">))</span> <span class="p">{</span> + <span class="n">inode</span><span class="o">-></span><span class="n">i_op</span> <span class="o">=</span> <span class="o">&</span><span class="n">minix_file_inode_operations</span><span class="p">;</span> + <span class="n">inode</span><span class="o">-></span><span class="n">i_fop</span> <span class="o">=</span> <span class="o">&</span><span class="n">minix_file_operations</span><span class="p">;</span> + <span class="p">}</span> + <span class="c1">//...</span> +</pre></div> +</div> +<p>The functions <code class="xref c c-func docutils literal"><span class="pre">generic_file_llseek()</span></code> , <code class="xref c c-func docutils literal"><span class="pre">generic_file_mmap()</span></code> , <code class="xref c c-func docutils literal"><span class="pre">generic_file_read_iter()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">generic_file_write_iter()</span></code> are implemented in the kernel.</p> +<p>For simple file systems, only the truncation operation (<code class="docutils literal"><span class="pre">truncate</span></code> system call) must be implemented. +Although initially there was a dedicated operation, starting with 3.14 the operation was embedded in <code class="docutils literal"><span class="pre">setattr</span></code>: if the paste size is different from the current size of the inode, then a truncate operation must be performed. +An example of implementing this verification is in the <code class="xref c c-func docutils literal"><span class="pre">minix_setattr()</span></code> function:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">minix_setattr</span><span class="p">(</span><span class="k">struct</span> <span class="n">dentry</span> <span class="o">*</span><span class="n">dentry</span><span class="p">,</span> <span class="k">struct</span> <span class="n">iattr</span> <span class="o">*</span><span class="n">attr</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span> <span class="o">=</span> <span class="n">d_inode</span><span class="p">(</span><span class="n">dentry</span><span class="p">);</span> + <span class="kt">int</span> <span class="n">error</span><span class="p">;</span> + + <span class="n">error</span> <span class="o">=</span> <span class="n">setattr_prepare</span><span class="p">(</span><span class="n">dentry</span><span class="p">,</span> <span class="n">attr</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">error</span><span class="p">)</span> + <span class="k">return</span> <span class="n">error</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">((</span><span class="n">attr</span><span class="o">-></span><span class="n">ia_valid</span> <span class="o">&</span> <span class="n">ATTR_SIZE</span><span class="p">)</span> <span class="o">&&</span> + <span class="n">attr</span><span class="o">-></span><span class="n">ia_size</span> <span class="o">!=</span> <span class="n">i_size_read</span><span class="p">(</span><span class="n">inode</span><span class="p">))</span> <span class="p">{</span> + <span class="n">error</span> <span class="o">=</span> <span class="n">inode_newsize_ok</span><span class="p">(</span><span class="n">inode</span><span class="p">,</span> <span class="n">attr</span><span class="o">-></span><span class="n">ia_size</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">error</span><span class="p">)</span> + <span class="k">return</span> <span class="n">error</span><span class="p">;</span> + + <span class="n">truncate_setsize</span><span class="p">(</span><span class="n">inode</span><span class="p">,</span> <span class="n">attr</span><span class="o">-></span><span class="n">ia_size</span><span class="p">);</span> + <span class="n">minix_truncate</span><span class="p">(</span><span class="n">inode</span><span class="p">);</span> + <span class="p">}</span> + + <span class="n">setattr_copy</span><span class="p">(</span><span class="n">inode</span><span class="p">,</span> <span class="n">attr</span><span class="p">);</span> + <span class="n">mark_inode_dirty</span><span class="p">(</span><span class="n">inode</span><span class="p">);</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>The truncate operation involves:</p> +<blockquote> +<div><ul class="simple"> +<li>freeing blocks of data on the disk that are now extra (if the new dimension is smaller than the old one) or allocating new blocks (for cases where the new dimension is larger)</li> +<li>updating disk bit maps (if used);</li> +<li>updating the inode;</li> +<li>filling with zero the space that was left unused from the last block using the <code class="xref c c-func docutils literal"><span class="pre">block_truncate_page()</span></code> function.</li> +</ul> +</div></blockquote> +<p>An example of the implementation of the cropping operation is the <code class="xref c c-func docutils literal"><span class="pre">minix_truncate()</span></code> function in the <code class="docutils literal"><span class="pre">minix</span></code> file system.</p> +</div> +<div class="section" id="address-space-operations"> +<span id="addressspaceoperations"></span><h3>Address space operations<a class="headerlink" href="#address-space-operations" title="Permalink to this headline">¶</a></h3> +<p>There is a close link between the address space of a process and files: the execution of the programs is done almost exclusively by mapping the file into the process address space. +Because this approach works very well and is quite general, it can also be used for regular system calls such as <code class="docutils literal"><span class="pre">read</span></code> and <code class="docutils literal"><span class="pre">write</span></code>.</p> +<p>The structure that describes the address space is <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">address_space</span></code>, and the operations with it are described by the structure <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">address_space_operations</span></code>. To initialize the address space operations, fill <code class="docutils literal"><span class="pre">inode->i_mapping->a_ops</span></code> of the file type inode.</p> +<p>An example is the <code class="docutils literal"><span class="pre">minix_aops</span></code> structure in the minix file system:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">address_space_operations</span> <span class="n">minix_aops</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">readpage</span> <span class="o">=</span> <span class="n">minix_readpage</span><span class="p">,</span> + <span class="p">.</span><span class="n">writepage</span> <span class="o">=</span> <span class="n">minix_writepage</span><span class="p">,</span> + <span class="p">.</span><span class="n">write_begin</span> <span class="o">=</span> <span class="n">minix_write_begin</span><span class="p">,</span> + <span class="p">.</span><span class="n">write_end</span> <span class="o">=</span> <span class="n">generic_write_end</span><span class="p">,</span> + <span class="p">.</span><span class="n">bmap</span> <span class="o">=</span> <span class="n">minix_bmap</span> +<span class="p">};</span> + +<span class="c1">//...</span> +<span class="k">if</span> <span class="p">(</span><span class="n">S_ISREG</span><span class="p">(</span><span class="n">inode</span><span class="o">-></span><span class="n">i_mode</span><span class="p">))</span> <span class="p">{</span> + <span class="n">inode</span><span class="o">-></span><span class="n">i_mapping</span><span class="o">-></span><span class="n">a_ops</span> <span class="o">=</span> <span class="o">&</span><span class="n">minix_aops</span><span class="p">;</span> +<span class="p">}</span> +<span class="c1">//...</span> +</pre></div> +</div> +<p>The <code class="xref c c-func docutils literal"><span class="pre">generic_write_end()</span></code> function is already implemented. +Most of the specific functions are very easy to implement, as follows:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">minix_writepage</span><span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">,</span> <span class="k">struct</span> <span class="n">writeback_control</span> <span class="o">*</span><span class="n">wbc</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="n">block_write_full_page</span><span class="p">(</span><span class="n">page</span><span class="p">,</span> <span class="n">minix_get_block</span><span class="p">,</span> <span class="n">wbc</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">minix_readpage</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="n">block_read_full_page</span><span class="p">(</span><span class="n">page</span><span class="p">,</span> <span class="n">minix_get_block</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">minix_write_failed</span><span class="p">(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="n">mapping</span><span class="p">,</span> <span class="n">loff_t</span> <span class="n">to</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">inode</span> <span class="o">=</span> <span class="n">mapping</span><span class="o">-></span><span class="n">host</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">to</span> <span class="o">></span> <span class="n">inode</span><span class="o">-></span><span class="n">i_size</span><span class="p">)</span> <span class="p">{</span> + <span class="n">truncate_pagecache</span><span class="p">(</span><span class="n">inode</span><span class="p">,</span> <span class="n">inode</span><span class="o">-></span><span class="n">i_size</span><span class="p">);</span> + <span class="n">minix_truncate</span><span class="p">(</span><span class="n">inode</span><span class="p">);</span> + <span class="p">}</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">minix_write_begin</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> <span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="n">mapping</span><span class="p">,</span> + <span class="n">loff_t</span> <span class="n">pos</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">len</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">flags</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">page</span> <span class="o">**</span><span class="n">pagep</span><span class="p">,</span> <span class="kt">void</span> <span class="o">**</span><span class="n">fsdata</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">ret</span><span class="p">;</span> + + <span class="n">ret</span> <span class="o">=</span> <span class="n">block_write_begin</span><span class="p">(</span><span class="n">mapping</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">len</span><span class="p">,</span> <span class="n">flags</span><span class="p">,</span> <span class="n">pagep</span><span class="p">,</span> + <span class="n">minix_get_block</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">unlikely</span><span class="p">(</span><span class="n">ret</span><span class="p">))</span> + <span class="n">minix_write_failed</span><span class="p">(</span><span class="n">mapping</span><span class="p">,</span> <span class="n">pos</span> <span class="o">+</span> <span class="n">len</span><span class="p">);</span> + + <span class="k">return</span> <span class="n">ret</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="n">sector_t</span> <span class="nf">minix_bmap</span><span class="p">(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="n">mapping</span><span class="p">,</span> <span class="n">sector_t</span> <span class="n">block</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="n">generic_block_bmap</span><span class="p">(</span><span class="n">mapping</span><span class="p">,</span> <span class="n">block</span><span class="p">,</span> <span class="n">minix_get_block</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<p>All that needs to be done is to implement <code class="xref c c-type docutils literal"><span class="pre">minix_get_block</span></code>, which has to translate a block of a file into a block on the device. +If the flag <code class="docutils literal"><span class="pre">create</span></code> received as a parameter is set, a new block must be allocated. +In case a new block is created, the bit map must be updated accordingly. +To notify the kernel not to read the block from the disk, <code class="docutils literal"><span class="pre">bh</span></code> must be marked with <code class="xref c c-func docutils literal"><span class="pre">set_buffer_new()</span></code>. The buffer must be associated with the block through <code class="xref c c-func docutils literal"><span class="pre">map_bh()</span></code>.</p> +</div> +</div> +<div class="section" id="dentry-structure"> +<h2>Dentry structure<a class="headerlink" href="#dentry-structure" title="Permalink to this headline">¶</a></h2> +<p>Directories operations use the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">dentry</span></code> structure. +Its main task is to make links between inodes and filenames. +The important fields of this structure are presented below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">dentry</span> <span class="p">{</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">d_inode</span><span class="p">;</span> <span class="cm">/* associated inode */</span> + <span class="c1">//...</span> + <span class="k">struct</span> <span class="n">dentry</span> <span class="o">*</span><span class="n">d_parent</span><span class="p">;</span> <span class="cm">/* dentry object of parent */</span> + <span class="k">struct</span> <span class="n">qstr</span> <span class="n">d_name</span><span class="p">;</span> <span class="cm">/* dentry name */</span> + <span class="c1">//...</span> + + <span class="k">struct</span> <span class="n">dentry_operations</span> <span class="o">*</span><span class="n">d_op</span><span class="p">;</span> <span class="cm">/* dentry operations table */</span> + <span class="k">struct</span> <span class="n">super_block</span> <span class="o">*</span><span class="n">d_sb</span><span class="p">;</span> <span class="cm">/* superblock of file */</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">d_fsdata</span><span class="p">;</span> <span class="cm">/* filesystem-specific data */</span> + <span class="c1">//...</span> +<span class="p">};</span> +</pre></div> +</div> +<p>Fields meaning:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">d_inode</span></code>: the inode referenced by this dentry;</li> +<li><code class="docutils literal"><span class="pre">d_parent</span></code>: the dentry associated with the parent directory;</li> +<li><code class="docutils literal"><span class="pre">d_name</span></code>: a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">qstr</span></code> structure that contains the fields <code class="docutils literal"><span class="pre">name</span></code> and <code class="docutils literal"><span class="pre">len</span></code> (the name and the length of the name).</li> +<li><code class="docutils literal"><span class="pre">d_op</span></code>: operations with dentries, represented by the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">dentry_operations</span></code> structure. +The kernel implements default operations so there is no need to (re)implement them. Some file systems can do optimizations based on the specific structure of the dentries.</li> +<li><code class="docutils literal"><span class="pre">d_fsdata</span></code>: field reserved for the file system that implements dentry operations;</li> +</ul> +</div></blockquote> +<div class="section" id="dentry-operations"> +<h3>Dentry operations<a class="headerlink" href="#dentry-operations" title="Permalink to this headline">¶</a></h3> +<p>The most commonly operations applied to dentries are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">d_make_root</span></code>: allocates the root dentry. It is generally used in the function that is called to read the superblock (<code class="docutils literal"><span class="pre">fill_super</span></code>), which must initialize the root directory. +So the root inode is obtained from the superblock and is used as an argument to this function, to fill the <code class="docutils literal"><span class="pre">s_root</span></code> field from the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">super_block</span></code> structure.</li> +<li><code class="docutils literal"><span class="pre">d_add</span></code>: associates a dentry with an inode; the dentry received as a parameter in the calls discussed above signifies the entry (name, length) that needs to be created. This function will be used when creating/loading a new inode that does not have a dentry associated with it and has not yet been introduced to the hash table of inodes (at <code class="docutils literal"><span class="pre">lookup</span></code>);</li> +<li><code class="docutils literal"><span class="pre">d_instantiate</span></code>: The lighter version of the previous call, in which the dentry was previously added in the hash table.</li> +</ul> +</div></blockquote> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p class="last"><code class="docutils literal"><span class="pre">d_instantiate</span></code> must be used to implement create calls (<code class="docutils literal"><span class="pre">mkdir</span></code>, <code class="docutils literal"><span class="pre">mknod</span></code>, <code class="docutils literal"><span class="pre">rename</span></code>, <code class="docutils literal"><span class="pre">symlink</span></code>) and NOT <code class="docutils literal"><span class="pre">d_add</span></code>.</p> +</div> +</div> +</div> +<div class="section" id="directory-inodes-operations"> +<span id="directoryinodes"></span><h2>Directory inodes operations<a class="headerlink" href="#directory-inodes-operations" title="Permalink to this headline">¶</a></h2> +<p>The operations for directory type inodes have a higher complexity level than the ones for files. +The developer must define operations for inodes and operations for files. +In <code class="docutils literal"><span class="pre">minix</span></code>, these operations are defined in <code class="xref c c-type docutils literal"><span class="pre">minix_dir_inode_operations</span></code> and <code class="xref c c-type docutils literal"><span class="pre">minix_dir_operations</span></code>:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">inode_operations</span> <span class="n">minix_dir_inode_operations</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">create</span> <span class="o">=</span> <span class="n">minix_create</span><span class="p">,</span> + <span class="p">.</span><span class="n">lookup</span> <span class="o">=</span> <span class="n">minix_lookup</span><span class="p">,</span> + <span class="p">.</span><span class="n">link</span> <span class="o">=</span> <span class="n">minix_link</span><span class="p">,</span> + <span class="p">.</span><span class="n">unlink</span> <span class="o">=</span> <span class="n">minix_unlink</span><span class="p">,</span> + <span class="p">.</span><span class="n">symlink</span> <span class="o">=</span> <span class="n">minix_symlink</span><span class="p">,</span> + <span class="p">.</span><span class="n">mkdir</span> <span class="o">=</span> <span class="n">minix_mkdir</span><span class="p">,</span> + <span class="p">.</span><span class="n">rmdir</span> <span class="o">=</span> <span class="n">minix_rmdir</span><span class="p">,</span> + <span class="p">.</span><span class="n">mknod</span> <span class="o">=</span> <span class="n">minix_mknod</span><span class="p">,</span> + <span class="c1">//...</span> +<span class="p">};</span> + +<span class="k">struct</span> <span class="n">file_operations</span> <span class="n">minix_dir_operations</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">llseek</span> <span class="o">=</span> <span class="n">generic_file_llseek</span><span class="p">,</span> + <span class="p">.</span><span class="n">read</span> <span class="o">=</span> <span class="n">generic_read_dir</span><span class="p">,</span> + <span class="p">.</span><span class="n">iterate</span> <span class="o">=</span> <span class="n">minix_readdir</span><span class="p">,</span> + <span class="c1">//...</span> +<span class="p">};</span> + + <span class="c1">//...</span> + <span class="k">if</span> <span class="p">(</span><span class="n">S_ISDIR</span><span class="p">(</span><span class="n">inode</span><span class="o">-></span><span class="n">i_mode</span><span class="p">))</span> <span class="p">{</span> + <span class="n">inode</span><span class="o">-></span><span class="n">i_op</span> <span class="o">=</span> <span class="o">&</span><span class="n">minix_dir_inode_operations</span><span class="p">;</span> + <span class="n">inode</span><span class="o">-></span><span class="n">i_fop</span> <span class="o">=</span> <span class="o">&</span><span class="n">minix_dir_operations</span><span class="p">;</span> + <span class="n">inode</span><span class="o">-></span><span class="n">i_mapping</span><span class="o">-></span><span class="n">a_ops</span> <span class="o">=</span> <span class="o">&</span><span class="n">minix_aops</span><span class="p">;</span> + <span class="p">}</span> + <span class="c1">//...</span> +</pre></div> +</div> +<p>The only function already implemented is <code class="xref c c-func docutils literal"><span class="pre">generic_read_dir()</span></code>.</p> +<p>The functions that implement the operations on directory inodes are the ones described below.</p> +<div class="section" id="creating-an-inode"> +<h3>Creating an inode<a class="headerlink" href="#creating-an-inode" title="Permalink to this headline">¶</a></h3> +<p>The inode creation function is indicated by the field <code class="docutils literal"><span class="pre">create</span></code> in the <code class="docutils literal"><span class="pre">inode_operations</span></code> structure. +In the minix case, the function is <code class="xref c c-func docutils literal"><span class="pre">minix_create()</span></code>. +This function is called by the <code class="docutils literal"><span class="pre">open</span></code> and <code class="docutils literal"><span class="pre">creat</span></code> system calls. Such a function performs the following operations:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Introduces a new entry into the physical structure on the disk; the update of the bit maps on the disk must not be forgotten.</li> +<li>Configures access rights to those received as a parameter.</li> +<li>Marks the inode as dirty with the <code class="xref c c-func docutils literal"><span class="pre">mark_inode_dirty()</span></code> function.</li> +<li>Instantiates the directory entry (<code class="docutils literal"><span class="pre">dentry</span></code>) with the <code class="docutils literal"><span class="pre">d_instantiate</span></code> function.</li> +</ol> +</div></blockquote> +</div> +<div class="section" id="creating-a-directory"> +<h3>Creating a directory<a class="headerlink" href="#creating-a-directory" title="Permalink to this headline">¶</a></h3> +<p>The directory creation function is indicated by the <code class="docutils literal"><span class="pre">mkdir</span></code> field in the <code class="docutils literal"><span class="pre">inode_operations</span></code> structure. +In the minix case, the function is <code class="xref c c-func docutils literal"><span class="pre">minix_mkdir()</span></code>. +This function is called by the <code class="docutils literal"><span class="pre">mkdir</span></code> system call. Such a function performs the following operations:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Calls <code class="xref c c-func docutils literal"><span class="pre">minix_create()</span></code>.</li> +<li>Allocates a data block for the directory.</li> +<li>Creates the <code class="docutils literal"><span class="pre">"."</span></code> and <code class="docutils literal"><span class="pre">".."</span></code> entries.</li> +</ol> +</div></blockquote> +</div> +<div class="section" id="creating-a-link"> +<h3>Creating a link<a class="headerlink" href="#creating-a-link" title="Permalink to this headline">¶</a></h3> +<p>The link creation function (hard link) is indicated by the <code class="docutils literal"><span class="pre">link</span></code> field in the <code class="docutils literal"><span class="pre">inode_operations</span></code> structure. +In the minix case, the function is <code class="xref c c-func docutils literal"><span class="pre">minix_link()</span></code>. +This function is called by the <code class="docutils literal"><span class="pre">link</span></code> system call. Such a function performs the following operations:</p> +<blockquote> +<div><ul class="simple"> +<li>Binds the new dentry to the inode.</li> +<li>Increments the <code class="docutils literal"><span class="pre">i_nlink</span></code> field of the inode.</li> +<li>Marks the inode as dirty using the <code class="xref c c-func docutils literal"><span class="pre">mark_inode_dirty()</span></code> function.</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="creating-a-symbolic-link"> +<h3>Creating a symbolic link<a class="headerlink" href="#creating-a-symbolic-link" title="Permalink to this headline">¶</a></h3> +<p>The symbolic link creation function is indicated by the <code class="docutils literal"><span class="pre">symlink</span></code> field in the <code class="docutils literal"><span class="pre">inode_operations</span></code> structure. +In the minix case, the function is <code class="xref c c-func docutils literal"><span class="pre">minix_symlink()</span></code>. +The operations to be performed are similar to <code class="docutils literal"><span class="pre">minix_link</span></code> with the differences being given by the fact that a symbolic link is created.</p> +</div> +<div class="section" id="deleting-a-link"> +<h3>Deleting a link<a class="headerlink" href="#deleting-a-link" title="Permalink to this headline">¶</a></h3> +<p>The link delete function (hard link) is indicated by the <code class="docutils literal"><span class="pre">unlink</span></code> field in the <code class="docutils literal"><span class="pre">inode_operations</span></code> structure. +In the minix case, the function is <code class="xref c c-func docutils literal"><span class="pre">minix_unlink()</span></code>. +This function is called by the <code class="docutils literal"><span class="pre">unlink</span></code> system call. Such a function performs the following operations:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Deletes the directory entry given as a parameter from the physical disk structure.</li> +<li>Decrements the <code class="docutils literal"><span class="pre">i_nlink</span></code> counter of the inode to which the entry points (otherwise the inode will never be deleted).</li> +</ol> +</div></blockquote> +</div> +<div class="section" id="deleting-a-directory"> +<h3>Deleting a directory<a class="headerlink" href="#deleting-a-directory" title="Permalink to this headline">¶</a></h3> +<p>The directory delete function is indicated by the <code class="docutils literal"><span class="pre">rmdir</span></code> field in the <code class="docutils literal"><span class="pre">inode_operations</span></code> structure. +In the minix case, the function is <code class="xref c c-func docutils literal"><span class="pre">minix_rmdir()</span></code>. +This function is called by the <code class="docutils literal"><span class="pre">rmdir</span></code> system call. +Such a function performs the following operations:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Performs the operations done by <code class="docutils literal"><span class="pre">minix_unlink</span></code>.</li> +<li>Ensures that the directory is empty; otherwise, returns <code class="docutils literal"><span class="pre">ENOTEMPTY</span></code>.</li> +<li>Also deletes the data blocks.</li> +</ol> +</div></blockquote> +</div> +<div class="section" id="searching-for-an-inode-in-a-directory"> +<h3>Searching for an inode in a directory<a class="headerlink" href="#searching-for-an-inode-in-a-directory" title="Permalink to this headline">¶</a></h3> +<p>The function that searches for an entry in a directory and extracts the inode is indicated by the <code class="docutils literal"><span class="pre">lookup</span></code> field in the <code class="docutils literal"><span class="pre">inode_operations</span></code> structure. +In the minix case, the function is <code class="docutils literal"><span class="pre">minix_lookup</span></code>. +This function is called indirectly when information about the inode associated with an entry in a directory is needed. +Such a function performs the following operations:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Searches in the directory indicated by <code class="docutils literal"><span class="pre">dir</span></code> the entry having the name <code class="docutils literal"><span class="pre">dentry->d_name.name</span></code>.</li> +<li>If the entry is found, it will return <code class="docutils literal"><span class="pre">NULL</span></code> and associate the inode with the name using the <code class="xref c c-func docutils literal"><span class="pre">d_add()</span></code> function.</li> +<li>Otherwise, returns <code class="docutils literal"><span class="pre">ERR_PTR</span></code>.</li> +</ol> +</div></blockquote> +</div> +<div class="section" id="iterating-through-entries-in-a-directory"> +<h3>Iterating through entries in a directory<a class="headerlink" href="#iterating-through-entries-in-a-directory" title="Permalink to this headline">¶</a></h3> +<p>The function which iterates through the entries in a directory (lists the directory contents) is indicated by the field <code class="docutils literal"><span class="pre">iterate</span></code> in the <code class="docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code> structure. +In the minix case, the function is <code class="docutils literal"><span class="pre">minix_readdir</span></code>. +This function is called by the <code class="docutils literal"><span class="pre">readdir</span></code> system call.</p> +<p>The function returns either all entries in the directory or just a part when the buffer allocated for it is not available. +A call of this function can return:</p> +<blockquote> +<div><ul class="simple"> +<li>a number equal to the existing number of entries if there is enough space in the corresponding user space buffer;</li> +<li>a number smaller than the actual number of entries, as much as there was space in the corresponding user space buffer;</li> +<li><code class="docutils literal"><span class="pre">0</span></code>, where there are no more entries to read.</li> +</ul> +</div></blockquote> +<p>The function will be called consecutively until all available entries are read. The function is called at least twice.</p> +<blockquote> +<div><ul class="simple"> +<li>It is only called twice if:<ul> +<li>the first call reads all entries and returns their number;</li> +<li>the second call returns 0, having no other entries to read.</li> +</ul> +</li> +<li>It is called more than twice if the first call does not return the total number of entries.</li> +</ul> +</div></blockquote> +<p>The function performs the following operations:</p> +<blockquote> +<div><ol class="arabic simple"> +<li>Iterates over the entries (the dentries) from the current directory.</li> +<li>For each dentry found, increments <code class="docutils literal"><span class="pre">ctx->pos</span></code>.</li> +<li>For each valid dentry (an inode other than <code class="docutils literal"><span class="pre">0</span></code>, for example), calls the <code class="xref c c-func docutils literal"><span class="pre">dir_emit()</span></code> function.</li> +<li>If the <code class="xref c c-func docutils literal"><span class="pre">dir_emit()</span></code> function returns a value other than zero, it means that the buffer in the user space is full and the function returns.</li> +</ol> +</div></blockquote> +<p>The arguments of the <code class="docutils literal"><span class="pre">dir_emit</span></code> function are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">ctx</span></code> is the directory iteration context, passed as an argument to the <code class="docutils literal"><span class="pre">iterate</span></code> function;</li> +<li><code class="docutils literal"><span class="pre">name</span></code> is the name of the entry (a string of characters);</li> +<li><code class="docutils literal"><span class="pre">name_len</span></code> is the length of the entry name;</li> +<li><code class="docutils literal"><span class="pre">ino</span></code> is the inode number associated with the entry;</li> +<li><code class="docutils literal"><span class="pre">type</span></code> identifies the entry type: <code class="docutils literal"><span class="pre">DT_REG</span></code> (file), <code class="docutils literal"><span class="pre">DT_DIR</span></code> (directory), <code class="docutils literal"><span class="pre">DT_UNKNOWN</span></code> etc. <code class="docutils literal"><span class="pre">DT_UNKNOWN</span></code> can be used when the entry type is unknown.</li> +</ul> +</div></blockquote> +</div> +</div> +<div class="section" id="bitmap-operations"> +<span id="bitmapoperations"></span><h2>Bitmap operations<a class="headerlink" href="#bitmap-operations" title="Permalink to this headline">¶</a></h2> +<p>When working with the file systems, management information (what block is free or busy, what inode is free or busy) is stored using bitmaps. +For this we often need to use bit operations. Such operations are:</p> +<blockquote> +<div><ul class="simple"> +<li>searching the first 0 bit: representing a free block or inode</li> +<li>marking a bit as 1: marking a busy block or inode</li> +</ul> +</div></blockquote> +<p>The bitmap operations are found in headers from <code class="docutils literal"><span class="pre">include/asm-generic/bitops</span></code>, especially in <code class="docutils literal"><span class="pre">find.h</span></code> and <code class="docutils literal"><span class="pre">atomic.h</span></code>. Usual functions, with names indicating their role, are:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">find_first_zero_bit()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">find_first_bit()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">set_bit()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">clear_bit()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">test_and_set_bit()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">test_and_clear_bit()</span></code></li> +</ul> +</div></blockquote> +<p>These functions usually receive the address of the bitmap, possibly its size (in bytes) and, if necessary, the index of the bit that needs to be activated (set) or deactivated (clear).</p> +<p>Some usage examples are listed below:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">map</span><span class="p">;</span> +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">array_map</span><span class="p">[</span><span class="n">NUM_BYTES</span><span class="p">];</span> +<span class="kt">size_t</span> <span class="n">idx</span><span class="p">;</span> +<span class="kt">int</span> <span class="n">changed</span><span class="p">;</span> + +<span class="cm">/* Find first zero bit in 32 bit integer. */</span> +<span class="n">idx</span> <span class="o">=</span> <span class="n">find_first_zero_bit</span><span class="p">(</span><span class="o">&</span><span class="n">map</span><span class="p">,</span> <span class="mi">32</span><span class="p">);</span> +<span class="n">printk</span> <span class="p">(</span><span class="n">KERN_ALERT</span> <span class="s">"The %zu-th bit is the first zero bit.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">idx</span><span class="p">);</span> + +<span class="cm">/* Find first one bit in NUM_BYTES bytes array. */</span> +<span class="n">idx</span> <span class="o">=</span> <span class="n">find_first_bit</span><span class="p">(</span><span class="n">array_map</span><span class="p">,</span> <span class="n">NUM_BYTES</span> <span class="o">*</span> <span class="mi">8</span><span class="p">);</span> +<span class="n">printk</span> <span class="p">(</span><span class="n">KERN_ALERT</span> <span class="s">"The %zu-th bit is the first one bit.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">idx</span><span class="p">);</span> + +<span class="cm">/*</span> +<span class="cm"> * Clear the idx-th bit in integer.</span> +<span class="cm"> * It is assumed idx is less the number of bits in integer.</span> +<span class="cm"> */</span> +<span class="n">clear_bit</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="o">&</span><span class="n">map</span><span class="p">);</span> + +<span class="cm">/*</span> +<span class="cm"> * Test and set the idx-th bit in array.</span> +<span class="cm"> * It is assumed idx is less the number of bits in array.</span> +<span class="cm"> */</span> +<span class="n">changed</span> <span class="o">=</span> <span class="n">__test_and_set_bit</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="o">&</span><span class="n">sbi</span><span class="o">-></span><span class="n">imap</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="n">changed</span><span class="p">)</span> + <span class="n">printk</span><span class="p">(</span><span class="n">KERN_ALERT</span> <span class="s">"%zu-th bit changed</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">idx</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="further-reading"> +<h2>Further reading<a class="headerlink" href="#further-reading" title="Permalink to this headline">¶</a></h2> +<ol class="arabic simple"> +<li>Robert Love -- Linux Kernel Development, Second Edition -- Chapter +12. The Virtual Filesystem</li> +<li>Understanding the Linux Kernel, 3rd edition - Chapter 12. The Virtual +Filesystem</li> +<li><a class="reference external" href="http://www.coda.cs.cmu.edu/doc/talks/linuxvfs/">Linux Virtual File System (presentation)</a></li> +<li><a class="reference external" href="http://www.cyberciti.biz/tips/understanding-unixlinux-file-system-part-i.html">Understanding Unix/Linux Filesystem</a></li> +<li><a class="reference external" href="http://lwn.net/Articles/57369/">Creating Linux virtual filesystems</a></li> +<li><a class="reference external" href="http://www.tldp.org/LDP/tlk/fs/filesystem.html">The Linux Documentation Project - VFS</a></li> +<li><a class="reference external" href="http://www.linux.it/~rubini/docs/vfs/vfs.html">The "Virtual File System" in Linux</a></li> +<li><a class="reference external" href="http://inglorion.net/documents/tutorials/tutorfs/">A Linux Filesystem Tutorial</a></li> +<li><a class="reference external" href="http://www.win.tue.nl/~aeb/linux/lk/lk-8.html">The Linux Virtual File System</a></li> +<li><a class="reference external" href="http://lxr.free-electrons.com/source/Documentation/filesystems/vfs.txt">Documentation/filesystems/vfs.txt</a></li> +<li><a class="reference external" href="http://lxr.free-electrons.com/source/fs/">File systems sources</a></li> +</ol> +</div> +<div class="section" id="exercises"> +<h2>Exercises<a class="headerlink" href="#exercises" title="Permalink to this headline">¶</a></h2> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>We strongly encourage you to use the setup from <a class="reference external" href="https://gitlab.cs.pub.ro/so2/so2-labs">this repository</a>.</p> +<dl class="docutils"> +<dt>To solve exercises, you need to perform these steps:</dt> +<dd><ul class="first last simple"> +<li>prepare skeletons from templates</li> +<li>build modules</li> +<li>start the VM and test the module in the VM.</li> +</ul> +</dd> +</dl> +<p>The current lab name is filesystems. See the exercises for the task name.</p> +<p>The skeleton code is generated from full source examples located in +<code class="file docutils literal"><span class="pre">tools/labs/templates</span></code>. To solve the tasks, start by generating +the skeleton code for a complete lab:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make clean +tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name> make skels +</pre></div> +</div> +<p>You can also generate the skeleton for a single task, using</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ <span class="nv">LABS</span><span class="o">=</span><lab name>/<task name> make skels +</pre></div> +</div> +<p>Once the skeleton drivers are generated, build the source:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make build +</pre></div> +</div> +<p>Then, start the VM:</p> +<div class="highlight-shell"><div class="highlight"><pre><span></span>tools/labs $ make console +</pre></div> +</div> +<p>The modules are placed in /home/root/skels/filesystems/<task_name>.</p> +<p>You DO NOT need to STOP the VM when rebuilding modules! +The local <cite>skels</cite> directory is shared with the VM.</p> +<p class="last">Review the <a class="reference internal" href="#exercises">Exercises</a> section for more detailed information.</p> +</div> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p>Before starting the exercises or generating the skeletons, please run <strong>git pull</strong> inside the Linux repo, +to make sure you have the latest version of the exercises.</p> +<p>If you have local changes, the pull command will fail. Check for local changes using <code class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></code>. +If you want to keep them, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span></code> before <code class="docutils literal"><span class="pre">pull</span></code> and <code class="docutils literal"><span class="pre">git</span> <span class="pre">stash</span> <span class="pre">pop</span></code> after. +To discard the changes, run <code class="docutils literal"><span class="pre">git</span> <span class="pre">reset</span> <span class="pre">--hard</span> <span class="pre">master</span></code>.</p> +<p class="last">If you already generated the skeleton before <code class="docutils literal"><span class="pre">git</span> <span class="pre">pull</span></code> you will need to generate it again.</p> +</div> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>In this lab, we will continue the implementation of the file systems started in the previous one. +For this, we will generate the laboratory skeleton using the following command:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">TODO=5 LABS=filesystems make skels</span> +</pre></div> +</div> +<p class="last">After this, we will start the implementation from <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">5</span></code>.</p> +</div> +<div class="section" id="myfs"> +<h3>myfs<a class="headerlink" href="#myfs" title="Permalink to this headline">¶</a></h3> +<p>For the exercises below, we will use the <code class="docutils literal"><span class="pre">myfs</span></code> file system whose implementation we started with the previous lab. +We stopped after mounting the file system and now we will continue with the operations for regular files and directories. +At the end of these exercises, we will be able to create, modify and delete regular directories and files.</p> +<p>We will mostly use the <code class="docutils literal"><span class="pre">inode</span></code> and <code class="docutils literal"><span class="pre">dentry</span></code> VFS structures. +The <code class="docutils literal"><span class="pre">inode</span></code> structure defines a file (of any type: regular, directory, link), while the <code class="docutils literal"><span class="pre">dentry</span></code> structure defines a name, which is an entry in a directory.</p> +<p>For this we will access the <code class="docutils literal"><span class="pre">myfs</span></code> directory in the lab skeleton. +The previously generated skeleton contains the solution for the previous lab; we will start from this. As in the previous lab, we will use the <code class="docutils literal"><span class="pre">ramfs</span></code> file system as a starting point.</p> +<div class="section" id="directory-operations"> +<h4>1. Directory operations<a class="headerlink" href="#directory-operations" title="Permalink to this headline">¶</a></h4> +<p>To begin with, we will implement the operations for working with directories. +The operations of creating a file or deleting a file are also directory operations; these operations result in adding or deleting a directory entry (<em>dentry</em>).</p> +<p>At the end of this exercise we will be able to create and delete entries in the file system. We will not be able to read and write to regular files; we will do so in the next exercise.</p> +<p>Follow directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">5</span></code> which will guide you through the steps you need to take.</p> +<p>You will need to specify the following directory operations:</p> +<blockquote> +<div><ul class="simple"> +<li>create a file (<code class="docutils literal"><span class="pre">create</span></code> function)</li> +<li>search (<code class="docutils literal"><span class="pre">lookup</span></code> function)</li> +<li>link (<code class="docutils literal"><span class="pre">link</span></code> function)</li> +<li>create directory (<code class="docutils literal"><span class="pre">mkdir</span></code> function)</li> +<li>deletion (<code class="docutils literal"><span class="pre">rmdir</span></code> and <code class="docutils literal"><span class="pre">unlink</span></code> functions)</li> +<li>create node (<code class="docutils literal"><span class="pre">mknod</span></code>)</li> +<li>rename (<code class="docutils literal"><span class="pre">rename</span></code> function)</li> +</ul> +</div></blockquote> +<p>For this, define the <code class="docutils literal"><span class="pre">myfs_dir_inode_operations</span></code> structure in the code, where marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">5</span></code>. +To begin, just define the structure <code class="docutils literal"><span class="pre">myfs_dir_inode_operations</span></code>; you will define the structures <code class="docutils literal"><span class="pre">myfs_file_operations</span></code>, <code class="docutils literal"><span class="pre">myfs_file_inode_operations</span></code> , and <code class="docutils literal"><span class="pre">myfs_aops</span></code> in the next exercise.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>Read the section <a class="reference internal" href="#directoryinodes"><span class="std std-ref">Directory inodes operations</span></a></p> +<p class="last">As a model, you are following the <code class="docutils literal"><span class="pre">ramfs_dir_inode_operations</span></code> structure.</p> +</div> +<p>Implement the <code class="docutils literal"><span class="pre">mkdir</span></code>, <code class="docutils literal"><span class="pre">mknod</span></code> and <code class="docutils literal"><span class="pre">create</span></code> operations inside <code class="docutils literal"><span class="pre">myfs_mkdir</span></code>, <code class="docutils literal"><span class="pre">myfs_mknod</span></code> and <code class="docutils literal"><span class="pre">myfs_create</span></code>. +These operations will allow you to create directories and files in the file system.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>We recommend making the code modular using a <code class="docutils literal"><span class="pre">mknod</span></code> function, which you can also use for the next exercise. +For inode reading and allocation, use <code class="docutils literal"><span class="pre">myfs_get_inode</span></code>, which is already implemented.</p> +<p>As a model, follow the next functions implemented in the <code class="docutils literal"><span class="pre">ramfs</span></code> file system:</p> +<blockquote class="last"> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">ramfs_mknod()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">ramfs_mkdir()</span></code></li> +<li><code class="xref c c-func docutils literal"><span class="pre">ramfs_create()</span></code></li> +</ul> +</div></blockquote> +</div> +<p>For the other functions, use generic calls (<code class="docutils literal"><span class="pre">simple_*</span></code>) already defined in VFS.</p> +<p>In the <code class="docutils literal"><span class="pre">myfs_get_inode</span></code> function, initialize the operations fields of the directory inodes:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">i_op</span></code> must be initialized to the address of the structure <code class="docutils literal"><span class="pre">myfs_dir_inode_operations</span></code>;</li> +<li><code class="docutils literal"><span class="pre">i_fop</span></code> must be initialized to the address of the structure <code class="docutils literal"><span class="pre">simple_dir_operations</span></code>, defined in VFS.</li> +</ul> +</div></blockquote> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p><code class="docutils literal"><span class="pre">i_op</span></code> is a pointer to a structure of type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode_operations</span></code> containing operations that have to do with the inode, which are, for a directory, creating a new entry, listing entries, deleting entries, etc.</p> +<p class="last"><code class="docutils literal"><span class="pre">i_fop</span></code> is a pointer to a structure of type <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code> containing operations that have to do with the <code class="docutils literal"><span class="pre">file</span></code> structure associated with the inode, such as <code class="docutils literal"><span class="pre">read</span></code>, <code class="docutils literal"><span class="pre">write</span></code>, and <code class="docutils literal"><span class="pre">lseek</span></code>.</p> +</div> +<div class="section" id="testing"> +<h5>Testing<a class="headerlink" href="#testing" title="Permalink to this headline">¶</a></h5> +<p>Once the module is done, we can test the creation of files and directories. +To do this, we compile the kernel module (using <code class="docutils literal"><span class="pre">make</span> <span class="pre">build</span></code>) and copy the resulting file (<code class="docutils literal"><span class="pre">myfs.ko</span></code>) and the test scripts (<code class="docutils literal"><span class="pre">test-myfs-{1,2}.sh</span></code>) in the virtual machine directory (using <code class="docutils literal"><span class="pre">make</span> <span class="pre">copy</span></code>).</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The test scripts are copied to the virtual machine using <code class="docutils literal"><span class="pre">make</span> <span class="pre">copy</span></code> only if they are executable:</p> +<div class="last highlight-console"><div class="highlight"><pre><span></span><span class="gp">student@workstation:~/linux/tools/labs$</span> chmod +x skels/filesystems/myfs/test-myfs-*.sh +</pre></div> +</div> +</div> +<p>After starting the virtual machine, insert the module, create the mount point and mount the file system:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> insmod myfs.ko +<span class="gp">#</span> mkdir -p /mnt/myfs +<span class="gp">#</span> mount -t myfs none /mnt/myfs +</pre></div> +</div> +<p>Now we can create file hierarchies and subdirectories in the mounted directory (<code class="docutils literal"><span class="pre">/mnt/myfs</span></code>). +We use commands like the ones below:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> touch /mnt/myfs/peanuts.txt +<span class="gp">#</span> mkdir -p /mnt/myfs/mountain/forest +<span class="gp">#</span> touch /mnt/myfs/mountain/forest/tree.txt +<span class="gp">#</span> rm /mnt/myfs/mountain/forest/tree.txt +<span class="gp">#</span> rmdir /mnt/myfs/mountain/forest +</pre></div> +</div> +<p>At this time we can not read or write files. When running commands such as the following ones we will get errors.</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> <span class="nb">echo</span> <span class="s2">"chocolate"</span> > /mnt/myfs/peanuts.txt +<span class="gp">#</span> cat /mnt/myfs/peanuts.txt +</pre></div> +</div> +<p>This happens because we have not implemented the operations for working with files; we will do so further.</p> +<p>To unload the kernel module, use the command</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="go">umount /mnt/myfs</span> +<span class="go">rmmod myfs</span> +</pre></div> +</div> +<p>To test the functionality provided by the kernel module, we can use the dedicated script <code class="docutils literal"><span class="pre">test-myfs-1.sh</span></code>. +If the implementation is correct, no error messages will be displayed.</p> +</div> +</div> +<div class="section" id="file-operations"> +<h4>2. File operations<a class="headerlink" href="#file-operations" title="Permalink to this headline">¶</a></h4> +<p>We want to implement the operations for working with files, which are used for accessing a file's content: read, write, truncate, etc. +For this you will specify the operations described in the structures <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">inode_operations</span></code>, <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">file_operations</span></code> and <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">address_space_operations</span></code>.</p> +<p>Follow the locations marked with <code class="docutils literal"><span class="pre">TODO</span></code> 6 which will guide you through the steps you need to take.</p> +<p>Start by defining <code class="docutils literal"><span class="pre">myfs_file_inode_operations</span></code> and <code class="docutils literal"><span class="pre">myfs_file_operations</span></code>.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>Read the section <a class="reference internal" href="#fileoperations"><span class="std std-ref">Regular files inode operations</span></a>.</p> +<p>Use the generic function provided by VFS.</p> +<p class="last">An example of implementation is the <code class="docutils literal"><span class="pre">ramfs</span></code> file system. +Follow the implementation of <code class="docutils literal"><span class="pre">ramfs_file_inode_operations</span></code> and <code class="docutils literal"><span class="pre">ramfs_file_operations</span></code>.</p> +</div> +<p>Inside the function <code class="docutils literal"><span class="pre">myfs_get_inode</span></code>, initialize the operations fields for the regular file inodes:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="docutils literal"><span class="pre">i_op</span></code> must be initialized to <code class="docutils literal"><span class="pre">myfs_file_inode_operations</span></code>;</li> +<li><code class="docutils literal"><span class="pre">i_fop</span></code> msust be initialized to <code class="docutils literal"><span class="pre">myfs_file_operations</span></code>.</li> +</ul> +</div></blockquote> +<p>Continue with defining the structure <code class="docutils literal"><span class="pre">myfs_aops</span></code>.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>Read the section <a class="reference internal" href="#addressspaceoperations"><span class="std std-ref">Address space operations</span></a>.</p> +<p>Use the generic functions provided by VFS.</p> +<p>An implementation example is the <code class="docutils literal"><span class="pre">ramfs</span></code> file system: the <code class="docutils literal"><span class="pre">ramfs_aops</span></code> structure.</p> +<p class="last">You do not need to define the function of type <code class="docutils literal"><span class="pre">set_page_dirty</span></code>.</p> +</div> +<p>Initialize the <code class="docutils literal"><span class="pre">i_mapping->a_ops</span></code> field of the inode structure to <code class="docutils literal"><span class="pre">myfs_aops</span></code>.</p> +<div class="section" id="testing-1"> +<h5>Testing<a class="headerlink" href="#testing-1" title="Permalink to this headline">¶</a></h5> +<p>For testing, we use the steps described in the previous exercise. +In addition to those steps, we will now be able to read, write and modify a file using commands like the ones below:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> <span class="nb">echo</span> <span class="s2">"chocolate"</span> > /mnt/myfs/peanuts.txt +<span class="gp">#</span> cat /mnt/myfs/peanuts.txt +</pre></div> +</div> +<p>To test the functionality provided by the module, we can use the dedicated script:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ./test-myfs-2.sh +</pre></div> +</div> +<p>If the implementation is correct, no error messages will be displayed when running the above script.</p> +</div> +</div> +</div> +<div class="section" id="minfs"> +<h3>minfs<a class="headerlink" href="#minfs" title="Permalink to this headline">¶</a></h3> +<p>For the exercises below, we will use the minfs file system whose development started in the previous lab. +This is a file system with disk support. +We stopped after mounting the file system and now we will continue with the operations on regular files and directories. +At the end of these exercises we will be able to create and delete entries in the file system.</p> +<p>We will mainly use the <code class="xref c c-type docutils literal"><span class="pre">inode</span></code> and <code class="xref c c-type docutils literal"><span class="pre">dentry</span></code> VFS structures. +The inode structure defines a file (of any type: regular, directory, link), while the dentry structure defines a name, which is a directory entry.</p> +<p>For this we will access the <code class="docutils literal"><span class="pre">minfs/kernel</span></code> directory from the laboratory skeleton. +The generated skeleton contains the solution from the previous lab; we will start from this. +As in the previous lab, we will use the <code class="docutils literal"><span class="pre">minix</span></code> file system as a starting point.</p> +<p>We will use the formatting tool <code class="docutils literal"><span class="pre">mkfs.minfs</span></code> in the <code class="docutils literal"><span class="pre">minfs/user</span></code> directory which is automatically compiled when running <code class="docutils literal"><span class="pre">make</span> <span class="pre">build</span></code> and copied to the virtual machine at <code class="docutils literal"><span class="pre">make</span> <span class="pre">copy</span></code>.</p> +<p>The formatting tool prepares a virtual machine disk using a command like</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ./mkfs.minfs /dev/vdb +</pre></div> +</div> +<p>After formatting, the disk has a structure like the one in the diagram below:</p> +<img alt="../_images/minfs_arch1.png" src="../_images/minfs_arch1.png" /> +<p>As shown in the diagram, <code class="docutils literal"><span class="pre">minfs</span></code> is a minimalist file system. +<code class="docutils literal"><span class="pre">minfs</span></code> contains a maximum of 32 inodes, each inode having a single data block (the file size is limited to block size). +The super block contains a 32-bit map (<code class="docutils literal"><span class="pre">imap</span></code>), each bit indicating the use of an inode.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Before you start working, go through the <code class="docutils literal"><span class="pre">minfs/kernel/minfs.h</span></code> header file. +This file contains the structures and macros that will be used in these exercises. +These structures and macros define the file system as described in the diagram above.</p> +</div> +<div class="section" id="iterate-operation"> +<h4>1. Iterate operation<a class="headerlink" href="#iterate-operation" title="Permalink to this headline">¶</a></h4> +<p>At first we want to be able to list the contents of the root directory. +For this we must be able to read the entries in the root directory, which means implementing the <code class="docutils literal"><span class="pre">iterate</span></code> operation. +The <code class="docutils literal"><span class="pre">iterate</span></code> operation is a field within the <code class="docutils literal"><span class="pre">minfs_dir_operations</span></code> structure (of type <code class="docutils literal"><span class="pre">file_operations</span></code>) and is implemented by the function <code class="docutils literal"><span class="pre">minfs_readdir</span></code>. We need to implement this function.</p> +<p>Follow directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">5</span></code> which will guide you through the steps you need to take.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>Read the section <a class="reference internal" href="#directoryinodes"><span class="std std-ref">Directory inodes operations</span></a></p> +<p>As a starting point, follow the <code class="xref c c-func docutils literal"><span class="pre">minix_readdir()</span></code> function. +The function is rather complicated, but it gives you an insight into the steps you have to do.</p> +<p class="last">Follow, in <code class="docutils literal"><span class="pre">minfs.c</span></code> and <code class="docutils literal"><span class="pre">minfs.h</span></code>, the definitions of structures <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code>, <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode</span></code> and <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_dir_entry</span></code>. +You will use them in the <code class="docutils literal"><span class="pre">minfs_readdir</span></code> implementation.</p> +</div> +<p>Obtain the inode and the structure <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code> associated with the directory. +The structure <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code> is useful to find out the directory's data block. +From this structure you get the <code class="docutils literal"><span class="pre">data_block</span></code> field, representing the data block index on the disk.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p class="last">To get the structure <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code> structure, use <code class="xref c c-func docutils literal"><span class="pre">list_entry()</span></code> or <code class="xref c c-func docutils literal"><span class="pre">container_of()</span></code>.</p> +</div> +<p>Use <code class="xref c c-func docutils literal"><span class="pre">sb_bread()</span></code> to read the directory data block.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>The data block of the directory is indicated by the <code class="docutils literal"><span class="pre">data_block</span></code> field of the structure <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code> corresponding to the directory.</p> +<p class="last">The data in the block is referenced by the <code class="docutils literal"><span class="pre">b_data</span></code> field of the <code class="docutils literal"><span class="pre">buffer_head</span></code> structure (the usual code will be <code class="docutils literal"><span class="pre">bh->b_data</span></code>). +This block (being the data block of a directory) contains an array of at most <code class="docutils literal"><span class="pre">MINFS_NUM_ENTRIES</span></code> entries of type <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_dir_entry</span></code> (directory entries specific to <code class="docutils literal"><span class="pre">minfs</span></code>). +Use casting to <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_dir_entry</span> <span class="pre">*</span></code> to work with the data in the block.</p> +</div> +<p>Iterate over all the entries in the data block and fill the user space buffer inside the <code class="docutils literal"><span class="pre">for</span></code> loop.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>For each index, get the corresponding entry of the <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_dir_entry</span></code> by using pointer arithmetics on the <code class="docutils literal"><span class="pre">bh->b_data</span></code> field. +Ignore dentries that have an <code class="docutils literal"><span class="pre">ino</span></code> field equal to 0. Such a dentry is a free slot in the director's dentry list.</p> +<p>For each valid entry, there is an existing call <code class="xref c c-func docutils literal"><span class="pre">dir_emit()</span></code> with the appropriate parameters. This is the call that sends the dentries to the caller (and then to user space).</p> +<p class="last">Check the call examples in <code class="xref c c-func docutils literal"><span class="pre">qnx6_readdir()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">minix_readdir()</span></code>.</p> +</div> +<div class="section" id="testing-2"> +<h5>Testing<a class="headerlink" href="#testing-2" title="Permalink to this headline">¶</a></h5> +<p>Once the module is done, we can test the listing of the root directory contents. +To do this, we compile the kernel module (<code class="docutils literal"><span class="pre">make</span> <span class="pre">build</span></code>) and copy the result to the virtual machine together with the test scripts (<code class="docutils literal"><span class="pre">minfs/user/test-minfs-{0,1}.sh</span></code>) and the formatting utility (<code class="docutils literal"><span class="pre">minfs/user/mkfs.minfs</span></code>) using <code class="docutils literal"><span class="pre">make</span> <span class="pre">copy</span></code>, then start the machine.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The test scripts are copied to the virtual machine only if they are executable:</p> +<div class="last highlight-console"><div class="highlight"><pre><span></span><span class="gp">student@eg106:~/src/linux/tools/labs$</span> chmod +x skels/filesystems/minfs/user/test-minfs*.sh +</pre></div> +</div> +</div> +<p>After we start the virtual machine, we format the <code class="docutils literal"><span class="pre">/dev/vdb</span></code> disk, create the mount point and mount the file system:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ./mkfs.minfs /dev/vdb +<span class="gp">#</span> mkdir -p /mnt/minfs +<span class="gp">#</span> mount -t minfs /dev/vdb /mnt/minfs +</pre></div> +</div> +<p>Now we can list the contents of the root directory:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ls -l /mnt/minfs +</pre></div> +</div> +<p>We notice that there is already a file (<code class="docutils literal"><span class="pre">a.txt</span></code>); it is created by the formatting utility.</p> +<p>We also notice that we are not allowed to display information for a file using the <code class="docutils literal"><span class="pre">ls</span></code> command. +This is because we have not implemented the <code class="docutils literal"><span class="pre">lookup</span></code> function. We will implement it in the next exercise.</p> +<p>To test the functionality provided by the module, we can use the dedicated script:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ./test-minfs-0.sh +<span class="gp">#</span> ./test-minfs-1.sh +</pre></div> +</div> +</div> +</div> +<div class="section" id="lookup-operation"> +<h4>2. Lookup operation<a class="headerlink" href="#lookup-operation" title="Permalink to this headline">¶</a></h4> +<p>To properly list the contents of a directory, we need to implement the search functionality, ie the <code class="docutils literal"><span class="pre">lookup</span></code> operation. +The <code class="docutils literal"><span class="pre">lookup</span></code> operation is a field within the <code class="docutils literal"><span class="pre">minfs_dir_inode_operations</span></code> structure (of type <code class="docutils literal"><span class="pre">inode_operations</span></code>) and is implemented by the <code class="docutils literal"><span class="pre">minfs_lookup</span></code> function. +This function (<code class="docutils literal"><span class="pre">minfs_lookup</span></code>) needs to be implemented. +We will actually implement the <code class="docutils literal"><span class="pre">minfs_find_entry</span></code> function called by <code class="docutils literal"><span class="pre">minfs_lookup</span></code> .</p> +<p>Follow directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">6</span></code> which will tell you the steps you need to take.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>Read the section <a class="reference internal" href="#directoryinodes"><span class="std std-ref">Directory inodes operations</span></a></p> +<p class="last">As a starting point, read the functions <code class="xref c c-func docutils literal"><span class="pre">qnx6_find_entry()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">minix_find_entry()</span></code>.</p> +</div> +<p>In the <code class="docutils literal"><span class="pre">minfs_find_entry</span></code> function, iterate over the directory where the dentry is: <code class="docutils literal"><span class="pre">dentry->d_parent->d_inode</span></code>. +Iterating means going through the entries in the directory's data block (of type <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_dir_entry</span></code>) and locate, if it exists, the requested entry.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>From the structure of type <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code> corresponding to the directory, find out the data block index and read it (<code class="docutils literal"><span class="pre">sb_read</span></code>). +You will access the block contents using <code class="docutils literal"><span class="pre">bh->b_data</span></code>. +The directory data block contains an array of at most <code class="docutils literal"><span class="pre">MINFS_NUM_ENTRIES</span></code> entries of type <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_dir_entry</span></code>. +Use pointer arithmetics to get entries of type <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_dir_entry</span></code> from the data block (<code class="docutils literal"><span class="pre">bh->b_data</span></code>).</p> +<p>Check the presence of the name (stored in the local variable <code class="docutils literal"><span class="pre">name</span></code>) in the directory (if there is an entry in the data block whose name is a string equal to the given name). Use <code class="xref c c-func docutils literal"><span class="pre">strcmp()</span></code> to verify.</p> +<p>Ignore dentries that have an <code class="docutils literal"><span class="pre">ino</span></code> field equal to <code class="docutils literal"><span class="pre">0</span></code>. Those dentries are free slots in the directory dentry list.</p> +<p class="last">Store in the <code class="docutils literal"><span class="pre">final_de</span></code> variable the dentry found. +If you do not find any dentry, then the <code class="docutils literal"><span class="pre">final_de</span></code> variable will have the value <code class="docutils literal"><span class="pre">NULL</span></code>, the value with which it was initialized.</p> +</div> +<p>Comment the <code class="docutils literal"><span class="pre">simple_lookup</span></code> call in the <code class="docutils literal"><span class="pre">minfs_lookup</span></code> function to invoke the implementation of <code class="docutils literal"><span class="pre">minfs_readdir</span></code>.</p> +<div class="section" id="testing-3"> +<h5>Testing<a class="headerlink" href="#testing-3" title="Permalink to this headline">¶</a></h5> +<p>For testing, we use the steps described in the previous exercise. +The long file listing (<code class="docutils literal"><span class="pre">ls</span> <span class="pre">-l</span></code>) of the contents of a directory (root directory) will display permissions and other file-specific information:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ls -l /mnt/minfs +</pre></div> +</div> +<p>To test the functionality provided by the module, we can use the dedicated scripts:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ./test-minfs-0.sh +<span class="gp">#</span> ./test-minfs-1.sh +</pre></div> +</div> +<p>If the implementation is correct, no error messages will be displayed when running the scripts above.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>After mounting the file system using the command</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> mount -t minfs /dev/vdb /mnt/minfs +</pre></div> +</div> +<p>we try to create a file using the command</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> touch /mnt/minfs/peanuts.txt +</pre></div> +</div> +<p class="last">We notice that we get an error because we did not implement the directory operations that allow us to create a file. +We will do this for the next exercise.</p> +</div> +</div> +</div> +<div class="section" id="create-operation"> +<h4>3. Create operation<a class="headerlink" href="#create-operation" title="Permalink to this headline">¶</a></h4> +<p>In order to allow the creation of a file in a directory, we must implement the <code class="docutils literal"><span class="pre">create</span></code> operation. +The <code class="docutils literal"><span class="pre">create</span></code> operation is a field in the <code class="docutils literal"><span class="pre">minfs_dir_inode_operations</span></code> structure (of type <code class="xref c c-type docutils literal"><span class="pre">inode_operations</span></code>) and is implemented by the <code class="docutils literal"><span class="pre">minfs_create</span></code> function. We need to implement this function. +In fact, we will implement the <code class="docutils literal"><span class="pre">minfs_new_inode</span></code> (which creates and initializes an inode) and <code class="docutils literal"><span class="pre">minfs_add_link</span></code> which adds a link (or name or <em>dentry</em>) for the created inode.</p> +<p>Follow directions marked with <code class="docutils literal"><span class="pre">TODO</span> <span class="pre">7</span></code> which will guide you through the steps you need to take.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>Read the section <a class="reference internal" href="#directoryinodes"><span class="std std-ref">Directory inodes operations</span></a></p> +<p class="last">Inspect the code in the <code class="docutils literal"><span class="pre">minfs_create</span></code> and the skeleton of functions <code class="docutils literal"><span class="pre">minfs_new_inode</span></code> and <code class="docutils literal"><span class="pre">minfs_add_link</span></code>.</p> +</div> +<p>Implement the function <code class="docutils literal"><span class="pre">minfs_new_inode</span></code>. Inside this function you will create (using <code class="xref c c-func docutils literal"><span class="pre">new_inode()</span></code>) and initialize an inode. The initialization is done using the data from disk.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>Use the <code class="xref c c-func docutils literal"><span class="pre">minix_new_inode()</span></code> function as a model. +Find the first free inode in imap (<code class="docutils literal"><span class="pre">sbi->imap</span></code>). +Use bitwise operations (<code class="docutils literal"><span class="pre">find_first_zero_bit</span></code> and <code class="docutils literal"><span class="pre">set_bit</span></code>). +Read the <a class="reference internal" href="#bitmapoperations"><span class="std std-ref">Bitmap operations</span></a> section.</p> +<p>The buffer for the superblock (<code class="docutils literal"><span class="pre">sbi->sbh</span></code>) must be marked as dirty .</p> +<p class="last">You must initialize the usual fields as it is done for the <code class="docutils literal"><span class="pre">myfs</span></code> file system. +Initialize the <code class="docutils literal"><span class="pre">i_mode</span></code> field to <code class="docutils literal"><span class="pre">0</span></code> in the call to <code class="docutils literal"><span class="pre">inode_init_owner</span></code>. It will be initialized in the caller later.</p> +</div> +<p>Implement the <code class="docutils literal"><span class="pre">minfs_add_link</span></code> function. The function adds a new dentry (<code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_dir_entry</span></code>) to the parent directory data block (<code class="docutils literal"><span class="pre">dentry->d_parent->d_inode</span></code>).</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p class="last">Use the function <code class="docutils literal"><span class="pre">minix_add_link</span></code> function as a model.</p> +</div> +<p>In <code class="docutils literal"><span class="pre">minfs_add_link</span></code> we want to find the first free place for the dentry. +For this, you will iterate over the directory data block and you will find the first free entry. A free dentry has the <code class="docutils literal"><span class="pre">ino</span></code> field equal to <code class="docutils literal"><span class="pre">0</span></code>.</p> +<div class="admonition tip"> +<p class="first admonition-title">Tip</p> +<p>In order to work with the directory, get the inode of type <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code> corresponding to the parent directory (the <strong>dir</strong> inode). +Do not use the variable <code class="docutils literal"><span class="pre">inode</span></code> to get <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code>; that inode belongs to the file, not to the parent directory inside which you want to add the link/dentry. +To get the <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code> structure, use <code class="xref c c-func docutils literal"><span class="pre">container_of()</span></code>.</p> +<p>The structure <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_inode_info</span></code> is useful for finding the directory data block (the one indicated by the <code class="docutils literal"><span class="pre">dentry->d_parent->d_inode</span></code>, which is the <code class="docutils literal"><span class="pre">dir</span></code> variable). +From this structure, get the <code class="docutils literal"><span class="pre">data_block</span></code> field, representing index of the data block on the disk. +This block contains the entries in the directory. Use <code class="xref c c-func docutils literal"><span class="pre">sb_bread()</span></code> to read the block and then <code class="docutils literal"><span class="pre">bh->b_data</span></code> to refer to the data. +The block contains at most <code class="docutils literal"><span class="pre">MINFS_NUM_ENTRIES</span></code> entries of type <code class="docutils literal"><span class="pre">struct</span> <span class="pre">minfs_dir_entry</span></code>.</p> +<p>If all entries are occupied, return <code class="docutils literal"><span class="pre">-ENOSPC</span></code>.</p> +<p>Iterate over the entries in the data block using the variable <code class="docutils literal"><span class="pre">de</span></code> and extract the first free entry (for which the <code class="docutils literal"><span class="pre">ino</span></code> field is <code class="docutils literal"><span class="pre">0</span></code>).</p> +<p>When you have found a free place, fill in the corresponding entry:</p> +<blockquote> +<div><ul class="simple"> +<li>the <code class="docutils literal"><span class="pre">inode->i_ino</span></code> field in <code class="docutils literal"><span class="pre">de->ino</span></code></li> +<li>the <code class="docutils literal"><span class="pre">dentry->d_name.name</span></code> field in <code class="docutils literal"><span class="pre">de->name</span></code></li> +</ul> +</div></blockquote> +<p class="last">Then mark the buffer dirty.</p> +</div> +<div class="section" id="testing-4"> +<h5>Testing<a class="headerlink" href="#testing-4" title="Permalink to this headline">¶</a></h5> +<p>For testing, we use the steps described in the previous exercise. +Now we can create files within the file system:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> touch /mnt/minfs/peanuts.txt +</pre></div> +</div> +<p>To test the functionality provided by the module, we can use the dedicated script:</p> +<div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">#</span> ./test-minfs-2.sh +</pre></div> +</div> +<p>If the deployment is valid, no error messages will be displayed following the above script run.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The current implementation of the <code class="docutils literal"><span class="pre">minfs</span></code> file system is not definitive. +To be complete, the implementations needs function to delete files, create and delete directories, rename entries, and modify the contents of a file.</p> +</div> +</div> +</div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lab8-filesystems-part1.html" class="btn btn-neutral float-left" title="SO2 Lab 08 - File system drivers (Part 1)" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lab10-networking.html" class="btn btn-neutral float-right" title="SO2 Lab 10 - Networking" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec1-intro-slides.html b/refs/pull/405/merge/so2/lec1-intro-slides.html new file mode 100644 index 00000000..9b49f9f8 --- /dev/null +++ b/refs/pull/405/merge/so2/lec1-intro-slides.html @@ -0,0 +1,769 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>SO2 Lecture 01 - Course overview and Linux kernel introduction — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="up" title="Operating Systems 2" href="index.html" /> + <link rel="next" title="SO2 Lecture 02 - System calls" href="lec2-syscalls.html" /> + <link rel="prev" title="SO2 - General Rules and Grading" href="grading.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-so2-lecture-01-course-overview-and-linux-kernel-introduction slide level-1"> + +<h1>SO2 Lecture 01 - Course overview and Linux kernel introduction</h1> + + + + + +</article> +<article class="admonition-echipa slide level-2"> + +<h2>Echipa</h2> + +<ul class="simple"> +<li>Daniel Băluță (Daniel), Răzvan Deaconescu (Răzvan, RD), Claudiu +Ghioc (Claudiu), Valentin Ghiță (Vali), Sergiu Weisz (Sergiu), +Octavian Purdilă (Tavi)</li> +<li>Alexandru Militaru (Alex), Teodora Șerbănescu (Teo), Ștefan +Teodorescu (Ștefan, Fane), Mihai Popescu (Mihai, Mișu), +Constantin Răducanu, Daniel Dinca, Laurențiu Ștefan</li> +<li>Mult succes în noul semestru!</li> +</ul> + + + + +</article> +<article class="admonition-pozitionare-curs slide level-2"> + +<h2>Poziționare curs</h2> + +<img alt="../_images/ditaa-fbe06955ffc165cbdc9cb6074abf0db807b3c5cd.png" src="../_images/ditaa-fbe06955ffc165cbdc9cb6074abf0db807b3c5cd.png" /> + + + + +</article> +<article class="admonition-resurse slide level-2"> + +<h2>Resurse</h2> + +<ul class="simple"> +<li>Linux Kernel Labs: <a class="reference external" href="https://linux-kernel-labs.github.io/">https://linux-kernel-labs.github.io/</a></li> +<li>mailing list: <a class="reference external" href="mailto:so2%40cursuri.cs.pub.ro">so2<span>@</span>cursuri<span>.</span>cs<span>.</span>pub<span>.</span>ro</a></li> +<li>Facebook</li> +<li>vmchecker</li> +<li>catalog Google, calendar Google</li> +<li>LXR: <a class="reference external" href="https://elixir.bootlin.com/linux/v5.10.14/source">https://elixir.bootlin.com/linux/v5.10.14/source</a></li> +<li>cs.curs.pub.ro - rol de portal</li> +<li>karma awards</li> +</ul> + + + + +</article> +<article class="admonition-comunitate slide level-2"> + +<h2>Comunitate</h2> + +<ul class="simple"> +<li>tutorial contribuții: <a class="reference external" href="https://linux-kernel-labs.github.io/refs/heads/master/info/contributing.html">https://linux-kernel-labs.github.io/refs/heads/master/info/contributing.html</a></li> +<li>corecții, ajustări, precizări, informații utile</li> +<li>listă de discuții</li> +<li>răspundeți la întrebările colegilor voștri</li> +<li>propuneți subiecte de discuție care au legătură cu disciplina</li> +<li>Facebook</li> +<li>sugestii, propuneri, feedback</li> +<li>Primiți puncte de karma</li> +</ul> + + + + +</article> +<article class="admonition-notare slide level-2"> + +<h2>Notare</h2> + +<ul class="simple"> +<li>2 puncte activitate la laborator</li> +<li>3 puncte „examen”, notare pe parcurs</li> +<li>5 puncte teme de casă</li> +<li>Activități "extra"</li> +<li>Punctajul din teme de casă + activitați extra ce depăsește 5 +puncte e corelat direct proportional cu nota de la examen</li> +<li>Tema 0 - 0,5 puncte</li> +<li>Temele 1, 2, 3 - câte 1,5 puncte fiecare</li> +<li>Condiţii de promovare: nota finală 4.5, nota minimă examen 3</li> +</ul> + + + + +</article> +<article class="admonition-obiectivele-cursului slide level-2"> + +<h2>Obiectivele cursului</h2> + +<ul class="simple"> +<li>Prezentarea structurii interne a unui sistem de operare</li> +<li>Target: sisteme de operare de uz general</li> +<li>Structura și componentele unui kernel monolitic</li> +<li>Procese, FS, Networking</li> +<li>Memory management</li> +<li>Exemplificare pe Linux</li> +</ul> + + + + +</article> +<article class="admonition-obiectivele-laboratorului-si-a-temelor slide level-2"> + +<h2>Obiectivele laboratorului si a temelor</h2> + +<ul class="simple"> +<li>Însușirea cunoștințelor necesare implementării de device drivere</li> +<li>Înțelegerea în profunzime a cunoștințelor prin rezolvarea de +exerciții</li> +</ul> + + + + +</article> +<article class="admonition-cursuri-necesare slide level-2"> + +<h2>Cursuri necesare</h2> + +<ul class="simple"> +<li>Programare: C</li> +<li>SD: tabele de dispersie, arbori echilibrați</li> +<li>IOCLA: lucrul cu registre și instrucțiuni de bază (adunări, comparaţii, salturi)</li> +<li>CN: TLB/CAM, memorie, procesor, I/O</li> +<li>PC, RL: ethernet, IP, sockeți</li> +<li>SO: procese, fișiere, thread-uri, memorie virtuală</li> +</ul> + + + + +</article> +<article class="admonition-despre-curs slide level-2"> + +<h2>Despre curs</h2> + +<ul class="simple"> +<li>12 cursuri</li> +<li>interactiv</li> +<li>participaţi la discuţii</li> +<li>întrebaţi atunci când nu aţi înţeles</li> +<li>destul de “dens”, se recomandă călduros parcurgerea suportului bibliografic înainte şi după curs</li> +<li>1h:20 prezentare + 20min teste si discutii pe marginea testului</li> +</ul> + + + + +</article> +<article class="admonition-lista-cursuri slide level-2"> + +<h2>Lista cursuri</h2> + +<table class="hlist"><tr><td><ul class="simple"> +<li>Introducere</li> +<li>Apeluri de sistem</li> +<li>Procese</li> +<li>Întreruperi</li> +<li>Sincronizare</li> +<li>Adresarea memoriei</li> +</ul> +</td><td><ul class="simple"> +<li>Gestiunea memoriei</li> +<li>Gestiunea fișierelor</li> +<li>Kernel debugging</li> +<li>Gestiunea rețelei</li> +<li>Virtualizare</li> +<li>Kernel profiling</li> +</ul> +</td></tr></table> + + + + +</article> +<article class="admonition-despre-laborator slide level-2"> + +<h2>Despre laborator</h2> + +<ul class="simple"> +<li>Kernel Modules and Device Drivers</li> +<li>15 min prezentare / 80 de minute lucru</li> +<li>se punctează activitatea</li> +<li>learn by doing</li> +</ul> + + + + +</article> +<article class="admonition-despre-teme slide level-2"> + +<h2>Despre teme</h2> + +<ul class="simple"> +<li>necesare: aprofundare API (laborator) și concepte (curs)</li> +<li>teste publice</li> +<li>suport de testare (vmchecker)</li> +<li>relativ puţin cod de scris dar relativ dificile</li> +<li>dificultatea constă în acomodarea cu noul mediu</li> +</ul> + + + + +</article> +<article class="admonition-lista-teme slide level-2"> + +<h2>Lista teme</h2> + +<ul class="simple"> +<li>Tema 0 - Kernel API</li> +<li>Kprobe based tracer</li> +<li>Driver pentru portul serial</li> +<li>Software RAID</li> +<li>SO2 Transport Protocol</li> +</ul> + + + + +</article> +<article class="admonition-bibliografie-curs slide level-2"> + +<h2>Bibliografie curs</h2> + +<ul class="simple"> +<li>Linux Kernel Development, 3rd edition, Robert Love, Addison +Wesley, 2010</li> +<li>Understanding the Linux Kernel, 3rd edition, Daniel P. Bovet & +Marco Cesati, O'Reilly 2005</li> +<li>Linux Networking Architecture, Klaus Wehrle, Frank Pahlke, +Hartmut Ritter, Daniel Muller, Marc Bechler, Prentice Hall 2004</li> +<li>Understanding Linux Network Internals, Christian Benvenuti, O'Reilly 2005</li> +</ul> + + + + +</article> +<article class="admonition-bibliografie-laborator slide level-2"> + +<h2>Bibliografie laborator</h2> + +<ul class="simple"> +<li>Linux Device Drivers, 3nd edition, Alessandro Rubini & Jonathan +Corbet, O'Reilly 2006</li> +<li>Linux Kernel in a Nutshell, Greg Kroah-Hartman, O'Reilly 2005</li> +</ul> + + + + +</article> +<article class="admonition-introduction slide level-2"> + +<h2>Introduction</h2> + +<ul class="simple"> +<li>Basic operating systems terms and concepts</li> +<li>Overview of the Linux kernel</li> +</ul> + + + + +</article> +<article class="admonition-user-vs-kernel slide level-2"> + +<h2>User vs Kernel</h2> + +<ul class="simple"> +<li>Execution modes<ul> +<li>Kernel mode</li> +<li>User mode</li> +</ul> +</li> +<li>Memory protection<ul> +<li>Kernel-space</li> +<li>User-space</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-typical-operating-system-architecture slide level-2"> + +<h2>Typical operating system architecture</h2> + +<img alt="../_images/ditaa-48374873962ca32ada36c14ab9a83b60f112a1e0.png" src="../_images/ditaa-48374873962ca32ada36c14ab9a83b60f112a1e0.png" /> + + + + +</article> +<article class="admonition-monolithic-kernel slide level-2"> + +<h2>Monolithic kernel</h2> + +<img alt="../_images/ditaa-3dc899167df5e16a230c434cf5d6964cb5868482.png" src="../_images/ditaa-3dc899167df5e16a230c434cf5d6964cb5868482.png" /> + + + + +</article> +<article class="admonition-micro-kernel slide level-2"> + +<h2>Micro-kernel</h2> + +<img alt="../_images/ditaa-c8a3d93d0109b7be6f608871d16adff4aaa933da.png" src="../_images/ditaa-c8a3d93d0109b7be6f608871d16adff4aaa933da.png" /> + + + + +</article> +<article class="admonition-monolithic-kernels-can-be-modular slide level-2"> + +<h2>Monolithic kernels <em>can</em> be modular</h2> + +<ul class="simple"> +<li>Components can enabled or disabled at compile time</li> +<li>Support of loadable kernel modules (at runtime)</li> +<li>Organize the kernel in logical, independent subsystems</li> +<li>Strict interfaces but with low performance overhead: macros, +inline functions, function pointers</li> +</ul> + + + + +</article> +<article class="admonition-hybrid-kernels slide level-2"> + +<h2>"Hybrid" kernels</h2> + +<p>Many operating systems and kernel experts have dismissed the label +as meaningless, and just marketing. Linus Torvalds said of this +issue:</p> +<p>"As to the whole 'hybrid kernel' thing - it's just marketing. It's +'oh, those microkernels had good PR, how can we try to get good PR +for our working kernel? Oh, I know, let's use a cool name and try +to imply that it has all the PR advantages that that other system +has'."</p> + + + + +</article> +<article class="admonition-address-space slide level-2"> + +<h2>Address space</h2> + +<ul class="simple"> +<li>Physical address space<ul> +<li>RAM and peripheral memory</li> +</ul> +</li> +<li>Virtual address space<ul> +<li>How the CPU sees the memory (when in protected / paging mode)</li> +<li>Process address space</li> +<li>Kernel address space</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-user-and-kernel-sharing-the-virtual-address-space slide level-2"> + +<h2>User and kernel sharing the virtual address space</h2> + +<img alt="../_images/ditaa-a5f93e0d17ccdc2ba24828b620d7227f7fc75e33.png" src="../_images/ditaa-a5f93e0d17ccdc2ba24828b620d7227f7fc75e33.png" /> + + + + +</article> +<article class="admonition-execution-contexts slide level-2"> + +<h2>Execution contexts</h2> + +<ul class="simple"> +<li>Process context<ul> +<li>Code that runs in user mode, part of a process</li> +<li>Code that runs in kernel mode, as a result of a system call +issued by a process</li> +</ul> +</li> +<li>Interrupt context<ul> +<li>Code that runs as a result of an interrupt</li> +<li>Always runs in kernel mode</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-multi-tasking slide level-2"> + +<h2>Multi-tasking</h2> + +<ul class="simple"> +<li>An OS that supports the "simultaneous" execution of multiple processes</li> +<li>Implemented by fast switching between running processes to allow +the user to interact with each program</li> +<li>Implementation:<ul> +<li>Cooperative</li> +<li>Preemptive</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-preemptive-kernel slide level-2"> + +<h2>Preemptive kernel</h2> + +<p>Preemptive multitasking and preemptive kernels are different terms.</p> +<p>A kernel is preemptive if a process can be preempted while running +in kernel mode.</p> +<p>However, note that non-preemptive kernels may support preemptive +multitasking.</p> + + + + +</article> +<article class="admonition-pageable-kernel-memory slide level-2"> + +<h2>Pageable kernel memory</h2> + +<p>A kernel supports pageable kernel memory if parts of kernel memory +(code, data, stack or dynamically allocated memory) can be swapped +to disk.</p> + + + + +</article> +<article class="admonition-kernel-stack slide level-2"> + +<h2>Kernel stack</h2> + +<p>Each process has a kernel stack that is used to maintain the +function call chain and local variables state while it is executing +in kernel mode, as a result of a system call.</p> +<p>The kernel stack is small (4KB - 12 KB) so the kernel developer has +to avoid allocating large structures on stack or recursive calls +that are not properly bounded.</p> + + + + +</article> +<article class="admonition-portability slide level-2"> + +<h2>Portability</h2> + +<ul class="simple"> +<li>Architecture and machine specific code (C & ASM)</li> +<li>Independent architecture code (C):<ul> +<li>kernel core (further split in multiple subsystems)</li> +<li>device drivers</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-asymmetric-multiprocessing-asmp slide level-2"> + +<h2>Asymmetric MultiProcessing (ASMP)</h2> + +<img alt="../_images/ditaa-cb16db58a2489307b74d4f70256a48c81c65f6c6.png" src="../_images/ditaa-cb16db58a2489307b74d4f70256a48c81c65f6c6.png" /> + + + + +</article> +<article class="admonition-symmetric-multiprocessing-smp slide level-2"> + +<h2>Symmetric MultiProcessing (SMP)</h2> + +<img alt="../_images/ditaa-08aff771b3ff7a5525df7b0c090e28c836502788.png" src="../_images/ditaa-08aff771b3ff7a5525df7b0c090e28c836502788.png" /> + + + + +</article> +<article class="admonition-cpu-scalability slide level-2"> + +<h2>CPU Scalability</h2> + +<ul class="simple"> +<li>Use lock free algorithms when possible</li> +<li>Use fine grained locking for high contention areas</li> +<li>Pay attention to algorithm complexity</li> +</ul> + + + + +</article> +<article class="admonition-linux-development-model slide level-2"> + +<h2>Linux development model</h2> + +<ul class="simple"> +<li>Open source, GPLv2 License</li> +<li>Contributors: companies, academia and independent developers</li> +<li>Development cycle: 3 – 4 months which consists of a 1 - 2 week +merge window followed by bug fixing</li> +<li>Features are only allowed in the merge window</li> +<li>After the merge window a release candidate is done on a weekly +basis (rc1, rc2, etc.)</li> +</ul> + + + + +</article> +<article class="admonition-maintainer-hierarchy slide level-2"> + +<h2>Maintainer hierarchy</h2> + +<ul class="simple"> +<li>Linus Torvalds is the maintainer of the Linux kernel and merges pull +requests from subsystem maintainers</li> +<li>Each subsystem has one or more maintainers that accept patches or +pull requests from developers or device driver maintainers</li> +<li>Each maintainer has its own git tree, e.g.:<ul> +<li>Linux Torvalds: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git</li> +<li>David Miller (networking): git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git/</li> +</ul> +</li> +<li>Each subsystem may maintain a -next tree where developers can submit +patches for the next merge window</li> +</ul> + + + + +</article> +<article class="admonition-linux-source-code-layout slide level-2"> + +<h2>Linux source code layout</h2> + +<img alt="../_images/ditaa-f45246aade5ecc7cfb71f7f103a57f95fc7c2b9e.png" src="../_images/ditaa-f45246aade5ecc7cfb71f7f103a57f95fc7c2b9e.png" /> + + + + +</article> +<article class="admonition-linux-kernel-architecture slide level-2"> + +<h2>Linux kernel architecture</h2> + +<a class="reference internal image-reference" href="../_images/ditaa-b9ffae65be16d30be11b5eca188a7a143b1b8227.png"><img alt="../_images/ditaa-b9ffae65be16d30be11b5eca188a7a143b1b8227.png" src="../_images/ditaa-b9ffae65be16d30be11b5eca188a7a143b1b8227.png" style="height: 100%;" /></a> + + + + +</article> +<article class="admonition-arch slide level-2"> + +<h2>arch</h2> + +<ul class="simple"> +<li>Architecture specific code</li> +<li>May be further sub-divided in machine specific code</li> +<li>Interfacing with the boot loader and architecture specific +initialization</li> +<li>Access to various hardware bits that are architecture or machine +specific such as interrupt controller, SMP controllers, BUS +controllers, exceptions and interrupt setup, virtual memory handling</li> +<li>Architecture optimized functions (e.g. memcpy, string operations, +etc.)</li> +</ul> + + + + +</article> +<article class="admonition-device-drivers slide level-2"> + +<h2>Device drivers</h2> + +<ul class="simple"> +<li>Unified device model</li> +<li>Each subsystem has its own specific driver interfaces</li> +<li>Many device driver types (TTY, serial, SCSI, fileystem, ethernet, +USB, framebuffer, input, sound, etc.)</li> +</ul> + + + + +</article> +<article class="admonition-process-management slide level-2"> + +<h2>Process management</h2> + +<ul class="simple"> +<li>Unix basic process management and POSIX threads support</li> +<li>Processes and threads are abstracted as tasks</li> +<li>Operating system level virtualization<ul> +<li>Namespaces</li> +<li>Control groups</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-memory-management slide level-2"> + +<h2>Memory management</h2> + +<ul class="simple"> +<li>Management of the physical memory: allocating and freeing memory</li> +<li>Management of the virtual memory: paging, swapping, demand +paging, copy on write</li> +<li>User services: user address space management (e.g. mmap(), brk(), +shared memory)</li> +<li>Kernel services: SL*B allocators, vmalloc</li> +</ul> + + + + +</article> +<article class="admonition-block-i-o-management slide level-2"> + +<h2>Block I/O management</h2> + +<a class="reference internal image-reference" href="../_images/ditaa-0a96997f269a7a9cd0cdc9c9125f6e62e549be94.png"><img alt="../_images/ditaa-0a96997f269a7a9cd0cdc9c9125f6e62e549be94.png" src="../_images/ditaa-0a96997f269a7a9cd0cdc9c9125f6e62e549be94.png" style="height: 100%;" /></a> + + + + +</article> +<article class="admonition-virtual-filesystem-switch slide level-2"> + +<h2>Virtual Filesystem Switch</h2> + +<a class="reference internal image-reference" href="../_images/ditaa-afa57a07e21b1b842554278abe30fea575278452.png"><img alt="../_images/ditaa-afa57a07e21b1b842554278abe30fea575278452.png" src="../_images/ditaa-afa57a07e21b1b842554278abe30fea575278452.png" style="height: 100%;" /></a> + + + + +</article> +<article class="admonition-networking-stack slide level-2"> + +<h2>Networking stack</h2> + +<a class="reference internal image-reference" href="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png"><img alt="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png" src="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png" style="height: 100%;" /></a> + + + + +</article> +<article class="admonition-linux-security-modules slide level-2"> + +<h2>Linux Security Modules</h2> + +<ul class="simple"> +<li>Hooks to extend the default Linux security model</li> +<li>Used by several Linux security extensions:<ul> +<li>Security Enhancened Linux</li> +<li>AppArmor</li> +<li>Tomoyo</li> +<li>Smack</li> +</ul> +</li> +</ul> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec1-intro.html b/refs/pull/405/merge/so2/lec1-intro.html new file mode 100644 index 00000000..01327636 --- /dev/null +++ b/refs/pull/405/merge/so2/lec1-intro.html @@ -0,0 +1,916 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lecture 01 - Course overview and Linux kernel introduction — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lecture 02 - System calls" href="lec2-syscalls.html" /> + <link rel="prev" title="SO2 - General Rules and Grading" href="grading.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lecture 01 - Course overview and Linux kernel introduction</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#echipa">Echipa</a></li> +<li class="toctree-l3"><a class="reference internal" href="#pozitionare-curs">Poziționare curs</a></li> +<li class="toctree-l3"><a class="reference internal" href="#resurse">Resurse</a></li> +<li class="toctree-l3"><a class="reference internal" href="#comunitate">Comunitate</a></li> +<li class="toctree-l3"><a class="reference internal" href="#notare">Notare</a></li> +<li class="toctree-l3"><a class="reference internal" href="#obiectivele-cursului">Obiectivele cursului</a></li> +<li class="toctree-l3"><a class="reference internal" href="#obiectivele-laboratorului-si-a-temelor">Obiectivele laboratorului si a temelor</a></li> +<li class="toctree-l3"><a class="reference internal" href="#cursuri-necesare">Cursuri necesare</a></li> +<li class="toctree-l3"><a class="reference internal" href="#despre-curs">Despre curs</a></li> +<li class="toctree-l3"><a class="reference internal" href="#lista-cursuri">Lista cursuri</a></li> +<li class="toctree-l3"><a class="reference internal" href="#despre-laborator">Despre laborator</a></li> +<li class="toctree-l3"><a class="reference internal" href="#despre-teme">Despre teme</a></li> +<li class="toctree-l3"><a class="reference internal" href="#lista-teme">Lista teme</a></li> +<li class="toctree-l3"><a class="reference internal" href="#bibliografie-curs">Bibliografie curs</a></li> +<li class="toctree-l3"><a class="reference internal" href="#bibliografie-laborator">Bibliografie laborator</a></li> +<li class="toctree-l3"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="#basic-operating-systems-terms-and-concepts">Basic operating systems terms and concepts</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#user-vs-kernel">User vs Kernel</a></li> +<li class="toctree-l4"><a class="reference internal" href="#typical-operating-system-architecture">Typical operating system architecture</a></li> +<li class="toctree-l4"><a class="reference internal" href="#monolithic-kernel">Monolithic kernel</a></li> +<li class="toctree-l4"><a class="reference internal" href="#micro-kernel">Micro kernel</a></li> +<li class="toctree-l4"><a class="reference internal" href="#micro-kernels-vs-monolithic-kernels">Micro-kernels vs monolithic kernels</a></li> +<li class="toctree-l4"><a class="reference internal" href="#address-space">Address space</a></li> +<li class="toctree-l4"><a class="reference internal" href="#user-and-kernel-sharing-the-virtual-address-space">User and kernel sharing the virtual address space</a></li> +<li class="toctree-l4"><a class="reference internal" href="#execution-contexts">Execution contexts</a></li> +<li class="toctree-l4"><a class="reference internal" href="#multi-tasking">Multi-tasking</a></li> +<li class="toctree-l4"><a class="reference internal" href="#preemptive-kernel">Preemptive kernel</a></li> +<li class="toctree-l4"><a class="reference internal" href="#pageable-kernel-memory">Pageable kernel memory</a></li> +<li class="toctree-l4"><a class="reference internal" href="#kernel-stack">Kernel stack</a></li> +<li class="toctree-l4"><a class="reference internal" href="#portability">Portability</a></li> +<li class="toctree-l4"><a class="reference internal" href="#asymmetric-multiprocessing-asmp">Asymmetric MultiProcessing (ASMP)</a></li> +<li class="toctree-l4"><a class="reference internal" href="#symmetric-multiprocessing-smp">Symmetric MultiProcessing (SMP)</a></li> +<li class="toctree-l4"><a class="reference internal" href="#cpu-scalability">CPU Scalability</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#overview-of-the-linux-kernel">Overview of the Linux kernel</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#linux-development-model">Linux development model</a></li> +<li class="toctree-l4"><a class="reference internal" href="#maintainer-hierarchy">Maintainer hierarchy</a></li> +<li class="toctree-l4"><a class="reference internal" href="#linux-source-code-layout">Linux source code layout</a></li> +<li class="toctree-l4"><a class="reference internal" href="#linux-kernel-architecture">Linux kernel architecture</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lecture 01 - Course overview and Linux kernel introduction</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lec1-intro.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lecture-01-course-overview-and-linux-kernel-introduction"> +<h1>SO2 Lecture 01 - Course overview and Linux kernel introduction<a class="headerlink" href="#so2-lecture-01-course-overview-and-linux-kernel-introduction" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="lec1-intro-slides.html">View slides</a></p> +<span class="admonition-so2-lecture-01-course-overview-and-linux-kernel-introduction"></span><div class="section" id="echipa"> +<h2>Echipa<a class="headerlink" href="#echipa" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-echipa simple"> +<li>Daniel Băluță (Daniel), Răzvan Deaconescu (Răzvan, RD), Claudiu +Ghioc (Claudiu), Valentin Ghiță (Vali), Sergiu Weisz (Sergiu), +Octavian Purdilă (Tavi)</li> +<li>Alexandru Militaru (Alex), Teodora Șerbănescu (Teo), Ștefan +Teodorescu (Ștefan, Fane), Mihai Popescu (Mihai, Mișu), +Constantin Răducanu, Daniel Dinca, Laurențiu Ștefan</li> +<li>Mult succes în noul semestru!</li> +</ul> +</div> +<div class="section" id="pozitionare-curs"> +<h2>Poziționare curs<a class="headerlink" href="#pozitionare-curs" title="Permalink to this headline">¶</a></h2> +<img alt="../_images/ditaa-fbe06955ffc165cbdc9cb6074abf0db807b3c5cd.png" class="admonition-pozitionare-curs" src="../_images/ditaa-fbe06955ffc165cbdc9cb6074abf0db807b3c5cd.png" /> +</div> +<div class="section" id="resurse"> +<h2>Resurse<a class="headerlink" href="#resurse" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-resurse simple"> +<li>Linux Kernel Labs: <a class="reference external" href="https://linux-kernel-labs.github.io/">https://linux-kernel-labs.github.io/</a></li> +<li>mailing list: <a class="reference external" href="mailto:so2%40cursuri.cs.pub.ro">so2<span>@</span>cursuri<span>.</span>cs<span>.</span>pub<span>.</span>ro</a></li> +<li>Facebook</li> +<li>vmchecker</li> +<li>catalog Google, calendar Google</li> +<li>LXR: <a class="reference external" href="https://elixir.bootlin.com/linux/v5.10.14/source">https://elixir.bootlin.com/linux/v5.10.14/source</a></li> +<li>cs.curs.pub.ro - rol de portal</li> +<li>karma awards</li> +</ul> +</div> +<div class="section" id="comunitate"> +<h2>Comunitate<a class="headerlink" href="#comunitate" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-comunitate simple"> +<li>tutorial contribuții: <a class="reference external" href="https://linux-kernel-labs.github.io/refs/heads/master/info/contributing.html">https://linux-kernel-labs.github.io/refs/heads/master/info/contributing.html</a></li> +<li>corecții, ajustări, precizări, informații utile</li> +<li>listă de discuții</li> +<li>răspundeți la întrebările colegilor voștri</li> +<li>propuneți subiecte de discuție care au legătură cu disciplina</li> +<li>Facebook</li> +<li>sugestii, propuneri, feedback</li> +<li>Primiți puncte de karma</li> +</ul> +</div> +<div class="section" id="notare"> +<h2>Notare<a class="headerlink" href="#notare" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-notare simple"> +<li>2 puncte activitate la laborator</li> +<li>3 puncte „examen”, notare pe parcurs</li> +<li>5 puncte teme de casă</li> +<li>Activități "extra"</li> +<li>Punctajul din teme de casă + activitați extra ce depăsește 5 +puncte e corelat direct proportional cu nota de la examen</li> +<li>Tema 0 - 0,5 puncte</li> +<li>Temele 1, 2, 3 - câte 1,5 puncte fiecare</li> +<li>Condiţii de promovare: nota finală 4.5, nota minimă examen 3</li> +</ul> +</div> +<div class="section" id="obiectivele-cursului"> +<h2>Obiectivele cursului<a class="headerlink" href="#obiectivele-cursului" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-obiectivele-cursului simple"> +<li>Prezentarea structurii interne a unui sistem de operare</li> +<li>Target: sisteme de operare de uz general</li> +<li>Structura și componentele unui kernel monolitic</li> +<li>Procese, FS, Networking</li> +<li>Memory management</li> +<li>Exemplificare pe Linux</li> +</ul> +</div> +<div class="section" id="obiectivele-laboratorului-si-a-temelor"> +<h2>Obiectivele laboratorului si a temelor<a class="headerlink" href="#obiectivele-laboratorului-si-a-temelor" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-obiectivele-laboratorului-si-a-temelor simple"> +<li>Însușirea cunoștințelor necesare implementării de device drivere</li> +<li>Înțelegerea în profunzime a cunoștințelor prin rezolvarea de +exerciții</li> +</ul> +</div> +<div class="section" id="cursuri-necesare"> +<h2>Cursuri necesare<a class="headerlink" href="#cursuri-necesare" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-cursuri-necesare simple"> +<li>Programare: C</li> +<li>SD: tabele de dispersie, arbori echilibrați</li> +<li>IOCLA: lucrul cu registre și instrucțiuni de bază (adunări, comparaţii, salturi)</li> +<li>CN: TLB/CAM, memorie, procesor, I/O</li> +<li>PC, RL: ethernet, IP, sockeți</li> +<li>SO: procese, fișiere, thread-uri, memorie virtuală</li> +</ul> +</div> +<div class="section" id="despre-curs"> +<h2>Despre curs<a class="headerlink" href="#despre-curs" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-despre-curs simple"> +<li>12 cursuri</li> +<li>interactiv</li> +<li>participaţi la discuţii</li> +<li>întrebaţi atunci când nu aţi înţeles</li> +<li>destul de “dens”, se recomandă călduros parcurgerea suportului bibliografic înainte şi după curs</li> +<li>1h:20 prezentare + 20min teste si discutii pe marginea testului</li> +</ul> +</div> +<div class="section" id="lista-cursuri"> +<h2>Lista cursuri<a class="headerlink" href="#lista-cursuri" title="Permalink to this headline">¶</a></h2> +<table class="hlist"><tr><td><ul class="simple"> +<li>Introducere</li> +<li>Apeluri de sistem</li> +<li>Procese</li> +<li>Întreruperi</li> +<li>Sincronizare</li> +<li>Adresarea memoriei</li> +</ul> +</td><td><ul class="simple"> +<li>Gestiunea memoriei</li> +<li>Gestiunea fișierelor</li> +<li>Kernel debugging</li> +<li>Gestiunea rețelei</li> +<li>Virtualizare</li> +<li>Kernel profiling</li> +</ul> +</td></tr></table> +</div> +<div class="section" id="despre-laborator"> +<h2>Despre laborator<a class="headerlink" href="#despre-laborator" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-despre-laborator simple"> +<li>Kernel Modules and Device Drivers</li> +<li>15 min prezentare / 80 de minute lucru</li> +<li>se punctează activitatea</li> +<li>learn by doing</li> +</ul> +</div> +<div class="section" id="despre-teme"> +<h2>Despre teme<a class="headerlink" href="#despre-teme" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-despre-teme simple"> +<li>necesare: aprofundare API (laborator) și concepte (curs)</li> +<li>teste publice</li> +<li>suport de testare (vmchecker)</li> +<li>relativ puţin cod de scris dar relativ dificile</li> +<li>dificultatea constă în acomodarea cu noul mediu</li> +</ul> +</div> +<div class="section" id="lista-teme"> +<h2>Lista teme<a class="headerlink" href="#lista-teme" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-lista-teme simple"> +<li>Tema 0 - Kernel API</li> +<li>Kprobe based tracer</li> +<li>Driver pentru portul serial</li> +<li>Software RAID</li> +<li>SO2 Transport Protocol</li> +</ul> +</div> +<div class="section" id="bibliografie-curs"> +<h2>Bibliografie curs<a class="headerlink" href="#bibliografie-curs" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-bibliografie-curs simple"> +<li>Linux Kernel Development, 3rd edition, Robert Love, Addison +Wesley, 2010</li> +<li>Understanding the Linux Kernel, 3rd edition, Daniel P. Bovet & +Marco Cesati, O'Reilly 2005</li> +<li>Linux Networking Architecture, Klaus Wehrle, Frank Pahlke, +Hartmut Ritter, Daniel Muller, Marc Bechler, Prentice Hall 2004</li> +<li>Understanding Linux Network Internals, Christian Benvenuti, O'Reilly 2005</li> +</ul> +</div> +<div class="section" id="bibliografie-laborator"> +<h2>Bibliografie laborator<a class="headerlink" href="#bibliografie-laborator" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-bibliografie-laborator simple"> +<li>Linux Device Drivers, 3nd edition, Alessandro Rubini & Jonathan +Corbet, O'Reilly 2006</li> +<li>Linux Kernel in a Nutshell, Greg Kroah-Hartman, O'Reilly 2005</li> +</ul> +</div> +<div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-introduction simple"> +<li>Basic operating systems terms and concepts</li> +<li>Overview of the Linux kernel</li> +</ul> +</div> +<div class="section" id="basic-operating-systems-terms-and-concepts"> +<h2>Basic operating systems terms and concepts<a class="headerlink" href="#basic-operating-systems-terms-and-concepts" title="Permalink to this headline">¶</a></h2> +<div class="section" id="user-vs-kernel"> +<h3>User vs Kernel<a class="headerlink" href="#user-vs-kernel" title="Permalink to this headline">¶</a></h3> +<span class="admonition-user-vs-kernel"></span><p>Kernel and user are two terms that are often used in operating +systems. Their definition is pretty straight forward: The kernel is +the part of the operating system that runs with higher privileges +while user (space) usually means by applications running with low +privileges.</p> +<p>However these terms are heavily overloaded and might have very +specific meanings in some contexts.</p> +<p>User mode and kernel mode are terms that may refer specifically to the +processor execution mode. Code that runs in kernel mode can fully +<a class="footnote-reference" href="#hypervisor" id="footnote-reference-1">[1]</a> control the CPU while code that runs in user mode has +certain limitations. For example, local CPU interrupts can only be +disabled or enable while running in kernel mode. If such an operation +is attempted while running in user mode an exception will be generated +and the kernel will take over to handle it.</p> +<table class="docutils footnote" frame="void" id="hypervisor" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#footnote-reference-1">[1]</a></td><td>some processors may have even higher privileges than +kernel mode, e.g. a hypervisor mode, that is only +accessible to code running in a hypervisor (virtual +machine monitor)</td></tr> +</tbody> +</table> +<p>User space and kernel space may refer specifically to memory +protection or to virtual address spaces associated with either the +kernel or user applications.</p> +<p>Grossly simplifying, the kernel space is the memory area that is +reserved to the kernel while user space is the memory area reserved to +a particular user process. The kernel space is accessed protected so +that user applications can not access it directly, while user space +can be directly accessed from code running in kernel mode.</p> +</div> +<div class="section" id="typical-operating-system-architecture"> +<h3>Typical operating system architecture<a class="headerlink" href="#typical-operating-system-architecture" title="Permalink to this headline">¶</a></h3> +<p>In the typical operating system architecture (see the figure below) +the operating system kernel is responsible for access and sharing the +hardware in a secure and fair manner with multiple applications.</p> +<img alt="../_images/ditaa-48374873962ca32ada36c14ab9a83b60f112a1e0.png" class="admonition-typical-operating-system-architecture" src="../_images/ditaa-48374873962ca32ada36c14ab9a83b60f112a1e0.png" /> +<p>The kernel offers a set of APIs that applications issue which are +generally referred to as "System Calls". These APIs are different from +regular library APIs because they are the boundary at which the +execution mode switch from user mode to kernel mode.</p> +<p>In order to provide application compatibility, system calls are rarely +changed. Linux particularly enforces this (as opposed to in kernel +APIs that can change as needed).</p> +<p>The kernel code itself can be logically separated in core kernel +code and device drivers code. Device drivers code is responsible of +accessing particular devices while the core kernel code is +generic. The core kernel can be further divided into multiple logical +subsystems (e.g. file access, networking, process management, etc.)</p> +</div> +<div class="section" id="monolithic-kernel"> +<h3>Monolithic kernel<a class="headerlink" href="#monolithic-kernel" title="Permalink to this headline">¶</a></h3> +<p>A monolithic kernel is one where there is no access protection between +the various kernel subsystems and where public functions can be +directly called between various subsystems.</p> +<img alt="../_images/ditaa-3dc899167df5e16a230c434cf5d6964cb5868482.png" class="admonition-monolithic-kernel" src="../_images/ditaa-3dc899167df5e16a230c434cf5d6964cb5868482.png" /> +<p>However, most monolithic kernels do enforce a logical separation +between subsystems especially between the core kernel and device +drivers with relatively strict APIs (but not necessarily fixed in +stone) that must be used to access services offered by one subsystem +or device drivers. This, of course, depends on the particular kernel +implementation and the kernel's architecture.</p> +</div> +<div class="section" id="micro-kernel"> +<h3>Micro kernel<a class="headerlink" href="#micro-kernel" title="Permalink to this headline">¶</a></h3> +<p>A micro-kernel is one where large parts of the kernel are protected +from each-other, usually running as services in user space. Because +significant parts of the kernel are now running in user mode, the +remaining code that runs in kernel mode is significantly smaller, hence +micro-kernel term.</p> +<img alt="../_images/ditaa-c8a3d93d0109b7be6f608871d16adff4aaa933da.png" class="admonition-micro-kernel" src="../_images/ditaa-c8a3d93d0109b7be6f608871d16adff4aaa933da.png" /> +<p>In a micro-kernel architecture the kernel contains just enough code +that allows for message passing between different running +processes. Practically that means implement the scheduler and an IPC +mechanism in the kernel, as well as basic memory management to setup +the protection between applications and services.</p> +<p>One of the advantages of this architecture is that the services are +isolated and hence bugs in one service won't impact other services.</p> +<p>As such, if a service crashes we can just restart it without affecting +the whole system. However, in practice this is difficult to achieve +since restarting a service may affect all applications that depend on +that service (e.g. if the file server crashes all applications with +opened file descriptors would encounter errors when accessing them).</p> +<p>This architecture imposes a modular approach to the kernel and offers +memory protection between services but at a cost of performance. What +is a simple function call between two services on monolithic kernels +now requires going through IPC and scheduling which will incur a +performance penalty <a class="footnote-reference" href="#minix-vs-linux" id="footnote-reference-2">[2]</a>.</p> +<table class="docutils footnote" frame="void" id="minix-vs-linux" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#footnote-reference-2">[2]</a></td><td><a class="reference external" href="https://lwn.net/Articles/220255/">https://lwn.net/Articles/220255/</a></td></tr> +</tbody> +</table> +</div> +<div class="section" id="micro-kernels-vs-monolithic-kernels"> +<h3>Micro-kernels vs monolithic kernels<a class="headerlink" href="#micro-kernels-vs-monolithic-kernels" title="Permalink to this headline">¶</a></h3> +<p>Advocates of micro-kernels often suggest that micro-kernel are +superior because of the modular design a micro-kernel +enforces. However, monolithic kernels can also be modular and there +are several approaches that modern monolithic kernels use toward this +goal:</p> +<ul class="admonition-monolithic-kernels-can-be-modular simple"> +<li>Components can enabled or disabled at compile time</li> +<li>Support of loadable kernel modules (at runtime)</li> +<li>Organize the kernel in logical, independent subsystems</li> +<li>Strict interfaces but with low performance overhead: macros, +inline functions, function pointers</li> +</ul> +<p>There is a class of operating systems that (used to) claim to be +hybrid kernels, in between monolithic and micro-kernels (e.g. Windows, +Mac OS X). However, since all of the typical monolithic services run +in kernel-mode in these operating systems, there is little merit to +qualify them other then monolithic kernels.</p> +<p class="admonition-hybrid-kernels">Many operating systems and kernel experts have dismissed the label +as meaningless, and just marketing. Linus Torvalds said of this +issue:</p> +<p>"As to the whole 'hybrid kernel' thing - it's just marketing. It's +'oh, those microkernels had good PR, how can we try to get good PR +for our working kernel? Oh, I know, let's use a cool name and try +to imply that it has all the PR advantages that that other system +has'."</p> +</div> +<div class="section" id="address-space"> +<h3>Address space<a class="headerlink" href="#address-space" title="Permalink to this headline">¶</a></h3> +<span class="admonition-address-space"></span><p>The address space term is an overload term that can have different +meanings in different contexts.</p> +<p>The physical address space refers to the way the RAM and device +memories are visible on the memory bus. For example, on 32bit Intel +architecture, it is common to have the RAM mapped into the lower +physical address space while the graphics card memory is mapped high +in the physical address space.</p> +<p>The virtual address space (or sometimes just address space) refers to +the way the CPU sees the memory when the virtual memory module is +activated (sometime called protected mode or paging enabled). The +kernel is responsible of setting up a mapping that creates a virtual +address space in which areas of this space are mapped to certain +physical memory areas.</p> +<p>Related to the virtual address space there are two other terms that +are often used: process (address) space and kernel (address) space.</p> +<p>The process space is (part of) the virtual address space associated +with a process. It is the "memory view" of processes. It is a +continuous area that starts at zero. Where the process's address space +ends depends on the implementation and architecture.</p> +<p>The kernel space is the "memory view" of the code that runs in kernel +mode.</p> +</div> +<div class="section" id="user-and-kernel-sharing-the-virtual-address-space"> +<h3>User and kernel sharing the virtual address space<a class="headerlink" href="#user-and-kernel-sharing-the-virtual-address-space" title="Permalink to this headline">¶</a></h3> +<p>A typical implementation for user and kernel spaces is one where the +virtual address space is shared between user processes and the kernel.</p> +<p>In this case kernel space is located at the top of the address space, +while user space at the bottom. In order to prevent the user processes +from accessing kernel space, the kernel creates mappings that prevent +access to the kernel space from user mode.</p> +<img alt="../_images/ditaa-a5f93e0d17ccdc2ba24828b620d7227f7fc75e33.png" class="admonition-user-and-kernel-sharing-the-virtual-address-space" src="../_images/ditaa-a5f93e0d17ccdc2ba24828b620d7227f7fc75e33.png" /> +</div> +<div class="section" id="execution-contexts"> +<h3>Execution contexts<a class="headerlink" href="#execution-contexts" title="Permalink to this headline">¶</a></h3> +<span class="admonition-execution-contexts"></span><p>One of the most important jobs of the kernel is to service interrupts +and to service them efficiently. This is so important that a special +execution context is associated with it.</p> +<p>The kernel executes in interrupt context when it runs as a result of +an interrupt. This includes the interrupt handler, but it is not +limited to it, there are other special (software) constructs that run +in interrupt mode.</p> +<p>Code running in interrupt context always runs in kernel mode and there +are certain limitations that the kernel programmer has to be aware of +(e.g. not calling blocking functions or accessing user space).</p> +<p>Opposed to interrupt context there is process context. Code that runs +in process context can do so in user mode (executing application code) +or in kernel mode (executing a system call).</p> +</div> +<div class="section" id="multi-tasking"> +<h3>Multi-tasking<a class="headerlink" href="#multi-tasking" title="Permalink to this headline">¶</a></h3> +<span class="admonition-multi-tasking"></span><p>Multitasking is the ability of the operating system to +"simultaneously" execute multiple programs. It does so by quickly +switching between running processes.</p> +<p>Cooperative multitasking requires the programs to cooperate to achieve +multitasking. A program will run and relinquish CPU control back +to the OS, which will then schedule another program.</p> +<p>With preemptive multitasking the kernel will enforce strict limits for +each process, so that all processes have a fair chance of +running. Each process is allowed to run a time slice (e.g. 100ms) +after which, if it is still running, it is forcefully preempted and +another task is scheduled.</p> +</div> +<div class="section" id="preemptive-kernel"> +<h3>Preemptive kernel<a class="headerlink" href="#preemptive-kernel" title="Permalink to this headline">¶</a></h3> +<p class="admonition-preemptive-kernel">Preemptive multitasking and preemptive kernels are different terms.</p> +<p>A kernel is preemptive if a process can be preempted while running +in kernel mode.</p> +<p>However, note that non-preemptive kernels may support preemptive +multitasking.</p> +</div> +<div class="section" id="pageable-kernel-memory"> +<h3>Pageable kernel memory<a class="headerlink" href="#pageable-kernel-memory" title="Permalink to this headline">¶</a></h3> +<p class="admonition-pageable-kernel-memory">A kernel supports pageable kernel memory if parts of kernel memory +(code, data, stack or dynamically allocated memory) can be swapped +to disk.</p> +</div> +<div class="section" id="kernel-stack"> +<h3>Kernel stack<a class="headerlink" href="#kernel-stack" title="Permalink to this headline">¶</a></h3> +<p class="admonition-kernel-stack">Each process has a kernel stack that is used to maintain the +function call chain and local variables state while it is executing +in kernel mode, as a result of a system call.</p> +<p>The kernel stack is small (4KB - 12 KB) so the kernel developer has +to avoid allocating large structures on stack or recursive calls +that are not properly bounded.</p> +</div> +<div class="section" id="portability"> +<h3>Portability<a class="headerlink" href="#portability" title="Permalink to this headline">¶</a></h3> +<p>In order to increase portability across various architectures and +hardware configurations, modern kernels are organized as follows at the +top level:</p> +<ul class="admonition-portability simple"> +<li>Architecture and machine specific code (C & ASM)</li> +<li>Independent architecture code (C):<ul> +<li>kernel core (further split in multiple subsystems)</li> +<li>device drivers</li> +</ul> +</li> +</ul> +<p>This makes it easier to reuse code as much as possible between +different architectures and machine configurations.</p> +</div> +<div class="section" id="asymmetric-multiprocessing-asmp"> +<h3>Asymmetric MultiProcessing (ASMP)<a class="headerlink" href="#asymmetric-multiprocessing-asmp" title="Permalink to this headline">¶</a></h3> +<p>Asymmetric MultiProcessing (ASMP) is a way of supporting multiple +processors (cores) by a kernel, where a processor is dedicated to the +kernel and all other processors run user space programs.</p> +<p>The disadvantage of this approach is that the kernel throughput +(e.g. system calls, interrupt handling, etc.) does not scale with the +number of processors and hence typical processes frequently use system +calls. The scalability of the approach is limited to very specific +systems (e.g. scientific applications).</p> +<img alt="../_images/ditaa-cb16db58a2489307b74d4f70256a48c81c65f6c6.png" class="admonition-asymmetric-multiprocessing-asmp" src="../_images/ditaa-cb16db58a2489307b74d4f70256a48c81c65f6c6.png" /> +</div> +<div class="section" id="symmetric-multiprocessing-smp"> +<h3>Symmetric MultiProcessing (SMP)<a class="headerlink" href="#symmetric-multiprocessing-smp" title="Permalink to this headline">¶</a></h3> +<p>As opposed to ASMP, in SMP mode the kernel can run on any of the +existing processors, just as user processes. This approach is more +difficult to implement, because it creates race conditions in the +kernel if two processes run kernel functions that access the same +memory locations.</p> +<p>In order to support SMP the kernel must implement synchronization +primitives (e.g. spin locks) to guarantee that only one processor is +executing a critical section.</p> +<img alt="../_images/ditaa-08aff771b3ff7a5525df7b0c090e28c836502788.png" class="admonition-symmetric-multiprocessing-smp" src="../_images/ditaa-08aff771b3ff7a5525df7b0c090e28c836502788.png" /> +</div> +<div class="section" id="cpu-scalability"> +<h3>CPU Scalability<a class="headerlink" href="#cpu-scalability" title="Permalink to this headline">¶</a></h3> +<p>CPU scalability refers to how well the performance scales with +the number of cores. There are a few things that the kernel developer +should keep in mind with regard to CPU scalability:</p> +<ul class="admonition-cpu-scalability simple"> +<li>Use lock free algorithms when possible</li> +<li>Use fine grained locking for high contention areas</li> +<li>Pay attention to algorithm complexity</li> +</ul> +</div> +</div> +<div class="section" id="overview-of-the-linux-kernel"> +<h2>Overview of the Linux kernel<a class="headerlink" href="#overview-of-the-linux-kernel" title="Permalink to this headline">¶</a></h2> +<div class="section" id="linux-development-model"> +<h3>Linux development model<a class="headerlink" href="#linux-development-model" title="Permalink to this headline">¶</a></h3> +<span class="admonition-linux-development-model"></span><p>The Linux kernel is one the largest open source projects in the world +with thousands of developers contributing code and millions of lines of +code changed for each release.</p> +<p>It is distributed under the GPLv2 license, which simply put, +requires that any modification of the kernel done on software that is +shipped to customer should be made available to them (the customers), +although in practice most companies make the source code publicly +available.</p> +<p>There are many companies (often competing) that contribute code to the +Linux kernel as well as people from academia and independent +developers.</p> +<p>The current development model is based on doing releases at fixed +intervals of time (usually 3 - 4 months). New features are merged into +the kernel during a one or two week merge window. After the merge +window, a release candidate is done on a weekly basis (rc1, rc2, etc.)</p> +</div> +<div class="section" id="maintainer-hierarchy"> +<h3>Maintainer hierarchy<a class="headerlink" href="#maintainer-hierarchy" title="Permalink to this headline">¶</a></h3> +<p>In order to scale the development process, Linux uses a hierarchical +maintainership model:</p> +<ul class="admonition-maintainer-hierarchy simple"> +<li>Linus Torvalds is the maintainer of the Linux kernel and merges pull +requests from subsystem maintainers</li> +<li>Each subsystem has one or more maintainers that accept patches or +pull requests from developers or device driver maintainers</li> +<li>Each maintainer has its own git tree, e.g.:<ul> +<li>Linux Torvalds: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git</li> +<li>David Miller (networking): git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git/</li> +</ul> +</li> +<li>Each subsystem may maintain a -next tree where developers can submit +patches for the next merge window</li> +</ul> +<p>Since the merge window is only a maximum of two weeks, most of the +maintainers have a -next tree where they accept new features from +developers or maintainers downstream while even when the merge window +is closed.</p> +<p>Note that bug fixes are accepted even outside merge window in the +maintainer's tree from where they are periodically pulled by the +upstream maintainer regularly, for every release candidate.</p> +</div> +<div class="section" id="linux-source-code-layout"> +<h3>Linux source code layout<a class="headerlink" href="#linux-source-code-layout" title="Permalink to this headline">¶</a></h3> +<img alt="../_images/ditaa-f45246aade5ecc7cfb71f7f103a57f95fc7c2b9e.png" class="admonition-linux-source-code-layout" src="../_images/ditaa-f45246aade5ecc7cfb71f7f103a57f95fc7c2b9e.png" /> +<p>These are the top level of the Linux source code folders:</p> +<ul class="simple"> +<li>arch - contains architecture specific code; each architecture is +implemented in a specific sub-folder (e.g. arm, arm64, x86)</li> +<li>block - contains the block subsystem code that deals with reading +and writing data from block devices: creating block I/O requests, +scheduling them (there are several I/O schedulers available), +merging requests, and passing them down through the I/O stack to the +block device drivers</li> +<li>certs - implements support for signature checking using certificates</li> +<li>crypto - software implementation of various cryptography algorithms +as well as a framework that allows offloading such algorithms in +hardware</li> +<li>Documentation - documentation for various subsystems, Linux kernel +command line options, description for sysfs files and format, device +tree bindings (supported device tree nodes and format)</li> +<li>drivers - driver for various devices as well as the Linux driver +model implementation (an abstraction that describes drivers, devices +buses and the way they are connected)</li> +<li>firmware - binary or hex firmware files that are used by various +device drivers</li> +<li>fs - home of the Virtual Filesystem Switch (generic filesystem code) +and of various filesystem drivers</li> +<li>include - header files</li> +<li>init - the generic (as opposed to architecture specific) +initialization code that runs during boot</li> +<li>ipc - implementation for various Inter Process Communication system +calls such as message queue, semaphores, shared memory</li> +<li>kernel - process management code (including support for kernel +thread, workqueues), scheduler, tracing, time management, generic +irq code, locking</li> +<li>lib - various generic functions such as sorting, checksums, +compression and decompression, bitmap manipulation, etc.</li> +<li>mm - memory management code, for both physical and virtual memory, +including the page, SL*B and CMA allocators, swapping, virtual memory +mapping, process address space manipulation, etc.</li> +<li>net - implementation for various network stacks including IPv4 and +IPv6; BSD socket implementation, routing, filtering, packet +scheduling, bridging, etc.</li> +<li>samples - various driver samples</li> +<li>scripts - parts the build system, scripts used for building modules, +kconfig the Linux kernel configurator, as well as various other +scripts (e.g. checkpatch.pl that checks if a patch is conform with +the Linux kernel coding style)</li> +<li>security - home of the Linux Security Module framework that allows +extending the default (Unix) security model as well as +implementation for multiple such extensions such as SELinux, smack, +apparmor, tomoyo, etc.</li> +<li>sound - home of ALSA (Advanced Linux Sound System) as well as the +old Linux sound framework (OSS)</li> +<li>tools - various user space tools for testing or interacting with +Linux kernel subsystems</li> +<li>usr - support for embedding an initrd file in the kernel image</li> +<li>virt - home of the KVM (Kernel Virtual Machine) hypervisor</li> +</ul> +</div> +<div class="section" id="linux-kernel-architecture"> +<h3>Linux kernel architecture<a class="headerlink" href="#linux-kernel-architecture" title="Permalink to this headline">¶</a></h3> +<a class="admonition-linux-kernel-architecture reference internal image-reference" href="../_images/ditaa-b9ffae65be16d30be11b5eca188a7a143b1b8227.png"><img alt="../_images/ditaa-b9ffae65be16d30be11b5eca188a7a143b1b8227.png" class="admonition-linux-kernel-architecture" src="../_images/ditaa-b9ffae65be16d30be11b5eca188a7a143b1b8227.png" style="height: 100%;" /></a> +<div class="section" id="arch"> +<h4>arch<a class="headerlink" href="#arch" title="Permalink to this headline">¶</a></h4> +<ul class="admonition-arch simple"> +<li>Architecture specific code</li> +<li>May be further sub-divided in machine specific code</li> +<li>Interfacing with the boot loader and architecture specific +initialization</li> +<li>Access to various hardware bits that are architecture or machine +specific such as interrupt controller, SMP controllers, BUS +controllers, exceptions and interrupt setup, virtual memory handling</li> +<li>Architecture optimized functions (e.g. memcpy, string operations, +etc.)</li> +</ul> +<p>This part of the Linux kernel contains architecture specific code and +may be further sub-divided in machine specific code for certain +architectures (e.g. arm).</p> +<p>"Linux was first developed for 32-bit x86-based PCs (386 or +higher). These days it also runs on (at least) the Compaq Alpha AXP, +Sun SPARC and UltraSPARC, Motorola 68000, PowerPC, PowerPC64, ARM, +Hitachi SuperH, IBM S/390, MIPS, HP PA-RISC, Intel IA-64, DEC VAX, AMD +x86-64 and CRIS architectures.”</p> +<p>It implements access to various hardware bits that are architecture or +machine specific such as interrupt controller, SMP controllers, BUS +controllers, exceptions and interrupt setup, virtual memory handling.</p> +<p>It also implements architecture optimized functions (e.g. memcpy, +string operations, etc.)</p> +</div> +<div class="section" id="device-drivers"> +<h4>Device drivers<a class="headerlink" href="#device-drivers" title="Permalink to this headline">¶</a></h4> +<span class="admonition-device-drivers"></span><p>The Linux kernel uses a unified device model whose purpose is to +maintain internal data structures that reflect the state and structure +of the system. Such information includes what devices are present, +what is their status, what bus they are attached to, to what driver +they are attached, etc. This information is essential for implementing +system wide power management, as well as device discovery and dynamic +device removal.</p> +<p>Each subsystem has its own specific driver interface that is tailored +to the devices it represents in order to make it easier to write +correct drivers and to reduce code duplication.</p> +<p>Linux supports one of the most diverse set of device drivers type, +some examples are: TTY, serial, SCSI, fileystem, ethernet, USB, +framebuffer, input, sound, etc.</p> +</div> +<div class="section" id="process-management"> +<h4>Process management<a class="headerlink" href="#process-management" title="Permalink to this headline">¶</a></h4> +<span class="admonition-process-management"></span><p>Linux implements the standard Unix process management APIs such as +fork(), exec(), wait(), as well as standard POSIX threads.</p> +<p>However, Linux processes and threads are implemented particularly +different than other kernels. There are no internal structures +implementing processes or threads, instead there is a <code class="xref c c-type docutils literal"><span class="pre">struct</span> +<span class="pre">task_struct</span></code> that describe an abstract scheduling unit called task.</p> +<p>A task has pointers to resources, such as address space, file +descriptors, IPC ids, etc. The resource pointers for tasks that are +part of the same process point to the same resources, while resources +of tasks of different processes will point to different resources.</p> +<p>This peculiarity, together with the <cite>clone()</cite> and <cite>unshare()</cite> system +call allows for implementing new features such as namespaces.</p> +<p>Namespaces are used together with control groups (cgroup) to implement +operating system virtualization in Linux.</p> +<p>cgroup is a mechanism to organize processes hierarchically and +distribute system resources along the hierarchy in a controlled and +configurable manner.</p> +</div> +<div class="section" id="memory-management"> +<h4>Memory management<a class="headerlink" href="#memory-management" title="Permalink to this headline">¶</a></h4> +<p>Linux memory management is a complex subsystem that deals with:</p> +<ul class="admonition-memory-management simple"> +<li>Management of the physical memory: allocating and freeing memory</li> +<li>Management of the virtual memory: paging, swapping, demand +paging, copy on write</li> +<li>User services: user address space management (e.g. mmap(), brk(), +shared memory)</li> +<li>Kernel services: SL*B allocators, vmalloc</li> +</ul> +</div> +<div class="section" id="block-i-o-management"> +<h4>Block I/O management<a class="headerlink" href="#block-i-o-management" title="Permalink to this headline">¶</a></h4> +<p>The Linux Block I/O subsystem deals with reading and writing data from +or to block devices: creating block I/O requests, transforming block I/O +requests (e.g. for software RAID or LVM), merging and sorting the +requests and scheduling them via various I/O schedulers to the block +device drivers.</p> +<a class="admonition-block-i-o-management reference internal image-reference" href="../_images/ditaa-0a96997f269a7a9cd0cdc9c9125f6e62e549be94.png"><img alt="../_images/ditaa-0a96997f269a7a9cd0cdc9c9125f6e62e549be94.png" class="admonition-block-i-o-management" src="../_images/ditaa-0a96997f269a7a9cd0cdc9c9125f6e62e549be94.png" style="height: 100%;" /></a> +</div> +<div class="section" id="virtual-filesystem-switch"> +<h4>Virtual Filesystem Switch<a class="headerlink" href="#virtual-filesystem-switch" title="Permalink to this headline">¶</a></h4> +<p>The Linux Virtual Filesystem Switch implements common / generic +filesystem code to reduce duplication in filesystem drivers. It +introduces certain filesystem abstractions such as:</p> +<ul class="simple"> +<li>inode - describes the file on disk (attributes, location of data +blocks on disk)</li> +<li>dentry - links an inode to a name</li> +<li>file - describes the properties of an opened file (e.g. file +pointer)</li> +<li>superblock - describes the properties of a formatted filesystem +(e.g. number of blocks, block size, location of root directory on +disk, encryption, etc.)</li> +</ul> +<a class="admonition-virtual-filesystem-switch reference internal image-reference" href="../_images/ditaa-afa57a07e21b1b842554278abe30fea575278452.png"><img alt="../_images/ditaa-afa57a07e21b1b842554278abe30fea575278452.png" class="admonition-virtual-filesystem-switch" src="../_images/ditaa-afa57a07e21b1b842554278abe30fea575278452.png" style="height: 100%;" /></a> +<p>The Linux VFS also implements a complex caching mechanism which +includes the following:</p> +<ul class="simple"> +<li>the inode cache - caches the file attributes and internal file +metadata</li> +<li>the dentry cache - caches the directory hierarchy of a filesystem</li> +<li>the page cache - caches file data blocks in memory</li> +</ul> +</div> +<div class="section" id="networking-stack"> +<h4>Networking stack<a class="headerlink" href="#networking-stack" title="Permalink to this headline">¶</a></h4> +<a class="admonition-networking-stack reference internal image-reference" href="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png"><img alt="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png" class="admonition-networking-stack" src="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png" style="height: 100%;" /></a> +</div> +<div class="section" id="linux-security-modules"> +<h4>Linux Security Modules<a class="headerlink" href="#linux-security-modules" title="Permalink to this headline">¶</a></h4> +<ul class="admonition-linux-security-modules simple"> +<li>Hooks to extend the default Linux security model</li> +<li>Used by several Linux security extensions:<ul> +<li>Security Enhancened Linux</li> +<li>AppArmor</li> +<li>Tomoyo</li> +<li>Smack</li> +</ul> +</li> +</ul> +</div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="grading.html" class="btn btn-neutral float-left" title="SO2 - General Rules and Grading" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lec2-syscalls.html" class="btn btn-neutral float-right" title="SO2 Lecture 02 - System calls" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec10-networking-slides.html b/refs/pull/405/merge/so2/lec10-networking-slides.html new file mode 100644 index 00000000..8bca6f1a --- /dev/null +++ b/refs/pull/405/merge/so2/lec10-networking-slides.html @@ -0,0 +1,524 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>SO2 Lecture 10 - Networking — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="up" title="Operating Systems 2" href="index.html" /> + <link rel="next" title="SO2 Lecture 11 - Architecture Layer" href="lec11-arch.html" /> + <link rel="prev" title="SO2 Lecture 09 - Kernel debugging" href="lec9-debugging.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-so2-lecture-10-networking slide level-1"> + +<h1>SO2 Lecture 10 - Networking</h1> + + + + + +</article> +<article class="admonition-network-management slide level-2"> + +<h2>Network Management</h2> + +<ul class="simple"> +<li>Socket implementation</li> +<li>Routing implementation</li> +<li>Network Device Interface</li> +<li>Hardware and Software Acceleration Techniques</li> +</ul> + + + + +</article> +<article class="admonition-network-management-overview slide level-2"> + +<h2>Network Management Overview</h2> + +<a class="reference internal image-reference" href="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png"><img alt="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png" src="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png" style="height: 100%;" /></a> + + + + +</article> +<article class="admonition-sockets-implementation-overview slide level-2"> + +<h2>Sockets Implementation Overview</h2> + +<a class="reference internal image-reference" href="../_images/ditaa-79e3734c36891f6c04d684aa5caa39f76915dbaf.png"><img alt="../_images/ditaa-79e3734c36891f6c04d684aa5caa39f76915dbaf.png" src="../_images/ditaa-79e3734c36891f6c04d684aa5caa39f76915dbaf.png" style="height: 100%;" /></a> + + + + +</article> +<article class="admonition-sockets-families-and-protocols slide level-2"> + +<h2>Sockets Families and Protocols</h2> + +<a class="reference internal image-reference" href="../_images/ditaa-bf1244d1a5c3d99bd8d40148d81cb3e5748c0b94.png"><img alt="../_images/ditaa-bf1244d1a5c3d99bd8d40148d81cb3e5748c0b94.png" src="../_images/ditaa-bf1244d1a5c3d99bd8d40148d81cb3e5748c0b94.png" style="height: 100%;" /></a> + + + + +</article> +<article class="admonition-example-udp-send slide level-2"> + +<h2>Example: UDP send</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">char</span> <span class="n">c</span><span class="p">;</span> +<span class="k">struct</span> <span class="n">sockaddr_in</span> <span class="n">addr</span><span class="p">;</span> +<span class="kt">int</span> <span class="n">s</span><span class="p">;</span> + +<span class="n">s</span> <span class="o">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_DGRAM</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> +<span class="n">connect</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span><span class="o">*</span><span class="p">)</span><span class="o">&</span><span class="n">addr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">addr</span><span class="p">));</span> +<span class="n">write</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="o">&</span><span class="n">c</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> +<span class="n">close</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-example-udp-send slide level-2"> + +<h2>Example: UDP send</h2> + +<img alt="../_images/ditaa-ee04e3e544de75375b914f7645c79d5ae46fe6f3.png" src="../_images/ditaa-ee04e3e544de75375b914f7645c79d5ae46fe6f3.png" /> + + + + +</article> +<article class="admonition-network-processing-phases slide level-2"> + +<h2>Network processing phases</h2> + +<ul class="simple"> +<li>Interrupt handler - device driver fetches data from the RX ring, +creates a network packet and queues it to the network stack for +processing</li> +<li>NET_SOFTIRQ - packet goes through the stack layer and it is +processed: decapsulate Ethernet frame, check IP packet and route +it, if local packet decapsulate protocol packet (e.g. TCP) and +queues it to a socket</li> +<li>Process context - application fetches data from the socket queue +or pushes data to the socket queue</li> +</ul> + + + + +</article> +<article class="admonition-packet-routing slide level-2"> + +<h2>Packet Routing</h2> + +<img alt="../_images/ditaa-528948c80a3fd78b89fb6f7bd69503a58b93a4ae.png" src="../_images/ditaa-528948c80a3fd78b89fb6f7bd69503a58b93a4ae.png" /> + + + + +</article> +<article class="admonition-routing-table slide level-2"> + +<h2>Routing Table</h2> + +<div class="highlight-shell"><div class="highlight"><pre><span></span>tavi@desktop-tavi:~/src/linux$ ip route list table main +default via <span class="m">172</span>.30.240.1 dev eth0 +<span class="m">172</span>.30.240.0/20 dev eth0 proto kernel scope link src <span class="m">172</span>.30.249.241 + +tavi@desktop-tavi:~/src/linux$ ip route list table <span class="nb">local</span> +broadcast <span class="m">127</span>.0.0.0 dev lo proto kernel scope link src <span class="m">127</span>.0.0.1 +<span class="nb">local</span> <span class="m">127</span>.0.0.0/8 dev lo proto kernel scope host src <span class="m">127</span>.0.0.1 +<span class="nb">local</span> <span class="m">127</span>.0.0.1 dev lo proto kernel scope host src <span class="m">127</span>.0.0.1 +broadcast <span class="m">127</span>.255.255.255 dev lo proto kernel scope link src <span class="m">127</span>.0.0.1 +broadcast <span class="m">172</span>.30.240.0 dev eth0 proto kernel scope link src <span class="m">172</span>.30.249.241 +<span class="nb">local</span> <span class="m">172</span>.30.249.241 dev eth0 proto kernel scope host src <span class="m">172</span>.30.249.241 +broadcast <span class="m">172</span>.30.255.255 dev eth0 proto kernel scope link src <span class="m">172</span>.30.249.241 + +tavi@desktop-tavi:~/src/linux$ ip rule list +<span class="m">0</span>: from all lookup <span class="nb">local</span> +<span class="m">32766</span>: from all lookup main +<span class="m">32767</span>: from all lookup default +</pre></div> +</div> + + + + +</article> +<article class="admonition-routing-policy-database slide level-2"> + +<h2>Routing Policy Database</h2> + +<ul class="simple"> +<li>"Regular" routing only uses the destination address</li> +<li>To increase flexibility a "Routing Policy Database" is used that +allows different routing based on other fields such as the source +address, protocol type, transport ports, etc.</li> +<li>This is encoded as a list of rules that are evaluated based on +their priority (priority 0 is the highest)</li> +<li>Each rule has a selector (how to match the packet) and an +action (what action to take if the packet matches)</li> +<li>Selectors: source address, destination address, type of service (TOS), +input interface, output interface, etc.</li> +<li>Action: lookup / unicast - use given routing table, blackhole - +drop packet, unreachable - send ICMP unreachable message and drop +packet, etc.</li> +</ul> + + + + +</article> +<article class="admonition-routing-table-processing slide level-2"> + +<h2>Routing table processing</h2> + +<ul class="simple"> +<li>Special table for local addreses -> route packets to sockets +based on family, type, ports</li> +<li>Check every routing entry for starting with the most specific +routes (e.g. 192.168.0.0/24 is checked before 192.168.0.0/16)</li> +<li>A route matches if the packet destination addreess logical ORed +with the subnet mask equals the subnet address</li> +<li>Once a route matches the following information is retrieved: +interface, link layer next-hop address, network next host address</li> +</ul> + + + + +</article> +<article class="admonition-forward-information-database-removed-in-3-6 slide level-2"> + +<h2>Forward Information Database (removed in 3.6)</h2> + +<p> </p> +<img alt="../_images/fidb-overview1.png" src="../_images/fidb-overview1.png" /> + + + + +</article> +<article class="admonition-forward-information-database-removed-in-3-6 slide level-2"> + +<h2>Forward Information Database (removed in 3.6)</h2> + +<img alt="../_images/fidb-details1.png" src="../_images/fidb-details1.png" /> + + + + +</article> +<article class="admonition-routing-cache-removed-in-3-6 slide level-2"> + +<h2>Routing Cache (removed in 3.6)</h2> + +<p> </p> +<img alt="../_images/routing-cache1.png" src="../_images/routing-cache1.png" /> + + + + +</article> +<article class="admonition-fib-trie slide level-2"> + +<h2>FIB TRIE</h2> + +<p> </p> +<img alt="../_images/fib-trie1.png" src="../_images/fib-trie1.png" /> + + + + +</article> +<article class="admonition-compressed-trie slide level-2"> + +<h2>Compressed Trie</h2> + +<p> </p> +<img alt="../_images/fib-trie-compressed1.png" src="../_images/fib-trie-compressed1.png" /> + + + + +</article> +<article class="admonition-netfilter slide level-2"> + +<h2>Netfilter</h2> + +<ul class="simple"> +<li>Framework that implements packet filtering and NAT</li> +<li>It uses hooks inserted in key places in the packet flow:<ul> +<li>NF_IP_PRE_ROUTING</li> +<li>NF_IP_LOCAL_IN</li> +<li>NF_IP_FORWARD</li> +<li>NF_IP_LOCAL_OUT</li> +<li>NF_IP_POST_ROUTING</li> +<li>NF_IP_NUMHOOKS</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-network-packets-skbs slide level-2"> + +<h2>Network packets (skbs)</h2> + +<img alt="../_images/skb1.png" src="../_images/skb1.png" /> + + + + +</article> +<article class="admonition-struct-sk-buff slide level-2"> + +<h2>struct sk_buff</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">prev</span><span class="p">;</span> + + <span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">;</span> + <span class="n">ktime_t</span> <span class="n">tstamp</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">net_device</span> <span class="o">*</span><span class="n">dev</span><span class="p">;</span> + <span class="kt">char</span> <span class="n">cb</span><span class="p">[</span><span class="mi">48</span><span class="p">];</span> + + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">,</span> + <span class="n">data_len</span><span class="p">;</span> + <span class="n">__u16</span> <span class="n">mac_len</span><span class="p">,</span> + <span class="n">hdr_len</span><span class="p">;</span> + + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">destructor</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + + <span class="n">sk_buff_data_t</span> <span class="n">transport_header</span><span class="p">;</span> + <span class="n">sk_buff_data_t</span> <span class="n">network_header</span><span class="p">;</span> + <span class="n">sk_buff_data_t</span> <span class="n">mac_header</span><span class="p">;</span> + <span class="n">sk_buff_data_t</span> <span class="n">tail</span><span class="p">;</span> + <span class="n">sk_buff_data_t</span> <span class="n">end</span><span class="p">;</span> + + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">head</span><span class="p">,</span> + <span class="o">*</span><span class="n">data</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">truesize</span><span class="p">;</span> + <span class="n">atomic_t</span> <span class="n">users</span><span class="p">;</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-skb-apis slide level-2"> + +<h2>skb APIs</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* reserve head room */</span> +<span class="kt">void</span> <span class="nf">skb_reserve</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="cm">/* add data to the end */</span> +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_put</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="cm">/* add data to the top */</span> +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_push</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="cm">/* discard data at the top */</span> +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_pull</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="cm">/* discard data at the end */</span> +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_trim</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_transport_header</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_reset_transport_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_set_transport_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">offset</span><span class="p">);</span> + +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_network_header</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_reset_network_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_set_network_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">offset</span><span class="p">);</span> + +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_mac_header</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">skb_mac_header_was_set</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_reset_mac_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_set_mac_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">offset</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-skb-data-management slide level-2"> + +<h2>skb data management</h2> + +<p> </p> +<a class="reference internal image-reference" href="../_images/ditaa-91073cb05a3f537eb54ab10745c307531e6795a0.png"><img alt="../_images/ditaa-91073cb05a3f537eb54ab10745c307531e6795a0.png" src="../_images/ditaa-91073cb05a3f537eb54ab10745c307531e6795a0.png" style="height: 50%;" /></a> + + + + +</article> +<article class="admonition-network-device-interface slide level-2"> + +<h2>Network Device Interface</h2> + +<img alt="../_images/net-dev-hw1.png" src="../_images/net-dev-hw1.png" /> + + + + +</article> +<article class="admonition-advanced-features slide level-2"> + +<h2>Advanced features</h2> + +<ul class="simple"> +<li>Scatter-Gather</li> +<li>Checksum offloading: Ethernet, IP, UDP, TCP</li> +<li>Adaptive interrupt handling (coalescence, adaptive)</li> +</ul> + + + + +</article> +<article class="admonition-tcp-offload slide level-2"> + +<h2>TCP offload</h2> + +<ul class="simple"> +<li>Full offload - Implement TCP/IP stack in hardware</li> +<li>Issues:<ul> +<li>Scaling number of connections</li> +<li>Security</li> +<li>Conformance</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-performance-observation slide level-2"> + +<h2>Performance observation</h2> + +<ul class="simple"> +<li>Performance is proportional with the number of packets to be +processed</li> +<li>Example: if an end-point can process 60K pps<ul> +<li>1538 MSS -> 738Mbps</li> +<li>2038 MSS -> 978Mbps</li> +<li>9038 MSS -> 4.3Gbps</li> +<li>20738 MSS -> 9.9Gbps</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-stateless-offload slide level-2"> + +<h2>Stateless offload</h2> + +<ul class="simple"> +<li>The networking stack processes large packets</li> +<li>TX path: the hardware splits large packets in smaller packets +(TCP Segmentation Offload)</li> +<li>RX path: the hardware aggregates small packets into larger +packets (Large Receive Offload - LRO)</li> +</ul> + + + + +</article> +<article class="admonition-tcp-segmentation-offload slide level-2"> + +<h2>TCP Segmentation Offload</h2> + +<img alt="../_images/tso1.png" src="../_images/tso1.png" /> + + + + +</article> +<article class="admonition-large-receive-offload slide level-2"> + +<h2>Large Receive Offload</h2> + +<img alt="../_images/lro1.png" src="../_images/lro1.png" /> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec10-networking.html b/refs/pull/405/merge/so2/lec10-networking.html new file mode 100644 index 00000000..fc62e945 --- /dev/null +++ b/refs/pull/405/merge/so2/lec10-networking.html @@ -0,0 +1,462 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lecture 10 - Networking — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lecture 11 - Architecture Layer" href="lec11-arch.html" /> + <link rel="prev" title="SO2 Lecture 09 - Kernel debugging" href="lec9-debugging.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lecture 10 - Networking</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="#network-management-overview">Network Management Overview</a></li> +<li class="toctree-l3"><a class="reference internal" href="#sockets-implementation-overview">Sockets Implementation Overview</a></li> +<li class="toctree-l3"><a class="reference internal" href="#sockets-families-and-protocols">Sockets Families and Protocols</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#example-udp-send">Example: UDP send</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#network-processing-phases">Network processing phases</a></li> +<li class="toctree-l3"><a class="reference internal" href="#packet-routing">Packet Routing</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#routing-table-s">Routing Table(s)</a></li> +<li class="toctree-l4"><a class="reference internal" href="#routing-policy-database">Routing Policy Database</a></li> +<li class="toctree-l4"><a class="reference internal" href="#routing-table-processing">Routing table processing</a></li> +<li class="toctree-l4"><a class="reference internal" href="#forwarding-information-database">Forwarding Information Database</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#netfilter">Netfilter</a></li> +<li class="toctree-l3"><a class="reference internal" href="#network-packets-skbs-struct-sk-buff">Network packets / skbs (struct sk_buff)</a></li> +<li class="toctree-l3"><a class="reference internal" href="#network-device">Network Device</a></li> +<li class="toctree-l3"><a class="reference internal" href="#hardware-and-software-acceleration-techniques">Hardware and Software Acceleration Techniques</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lecture 10 - Networking</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lec10-networking.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lecture-10-networking"> +<h1>SO2 Lecture 10 - Networking<a class="headerlink" href="#so2-lecture-10-networking" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="lec10-networking-slides.html">View slides</a></p> +<span class="admonition-so2-lecture-10-networking"></span><div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-network-management simple"> +<li>Socket implementation</li> +<li>Routing implementation</li> +<li>Network Device Interface</li> +<li>Hardware and Software Acceleration Techniques</li> +</ul> +</div> +<div class="section" id="network-management-overview"> +<h2>Network Management Overview<a class="headerlink" href="#network-management-overview" title="Permalink to this headline">¶</a></h2> +<a class="admonition-network-management-overview reference internal image-reference" href="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png"><img alt="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png" class="admonition-network-management-overview" src="../_images/ditaa-a2ded49c8b739635d6742479583443fb10ad120a.png" style="height: 100%;" /></a> +</div> +<div class="section" id="sockets-implementation-overview"> +<h2>Sockets Implementation Overview<a class="headerlink" href="#sockets-implementation-overview" title="Permalink to this headline">¶</a></h2> +<a class="admonition-sockets-implementation-overview reference internal image-reference" href="../_images/ditaa-79e3734c36891f6c04d684aa5caa39f76915dbaf.png"><img alt="../_images/ditaa-79e3734c36891f6c04d684aa5caa39f76915dbaf.png" class="admonition-sockets-implementation-overview" src="../_images/ditaa-79e3734c36891f6c04d684aa5caa39f76915dbaf.png" style="height: 100%;" /></a> +</div> +<div class="section" id="sockets-families-and-protocols"> +<h2>Sockets Families and Protocols<a class="headerlink" href="#sockets-families-and-protocols" title="Permalink to this headline">¶</a></h2> +<a class="admonition-sockets-families-and-protocols reference internal image-reference" href="../_images/ditaa-bf1244d1a5c3d99bd8d40148d81cb3e5748c0b94.png"><img alt="../_images/ditaa-bf1244d1a5c3d99bd8d40148d81cb3e5748c0b94.png" class="admonition-sockets-families-and-protocols" src="../_images/ditaa-bf1244d1a5c3d99bd8d40148d81cb3e5748c0b94.png" style="height: 100%;" /></a> +<div class="section" id="example-udp-send"> +<h3>Example: UDP send<a class="headerlink" href="#example-udp-send" title="Permalink to this headline">¶</a></h3> +<div class="admonition-example-udp-send highlight-c"><div class="highlight"><pre><span></span><span class="kt">char</span> <span class="n">c</span><span class="p">;</span> +<span class="k">struct</span> <span class="n">sockaddr_in</span> <span class="n">addr</span><span class="p">;</span> +<span class="kt">int</span> <span class="n">s</span><span class="p">;</span> + +<span class="n">s</span> <span class="o">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_DGRAM</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> +<span class="n">connect</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span><span class="o">*</span><span class="p">)</span><span class="o">&</span><span class="n">addr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">addr</span><span class="p">));</span> +<span class="n">write</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="o">&</span><span class="n">c</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> +<span class="n">close</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> +</pre></div> +</div> +<img alt="../_images/ditaa-ee04e3e544de75375b914f7645c79d5ae46fe6f3.png" class="admonition-example-udp-send" src="../_images/ditaa-ee04e3e544de75375b914f7645c79d5ae46fe6f3.png" /> +</div> +</div> +<div class="section" id="network-processing-phases"> +<h2>Network processing phases<a class="headerlink" href="#network-processing-phases" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-network-processing-phases simple"> +<li>Interrupt handler - device driver fetches data from the RX ring, +creates a network packet and queues it to the network stack for +processing</li> +<li>NET_SOFTIRQ - packet goes through the stack layer and it is +processed: decapsulate Ethernet frame, check IP packet and route +it, if local packet decapsulate protocol packet (e.g. TCP) and +queues it to a socket</li> +<li>Process context - application fetches data from the socket queue +or pushes data to the socket queue</li> +</ul> +</div> +<div class="section" id="packet-routing"> +<h2>Packet Routing<a class="headerlink" href="#packet-routing" title="Permalink to this headline">¶</a></h2> +<img alt="../_images/ditaa-528948c80a3fd78b89fb6f7bd69503a58b93a4ae.png" class="admonition-packet-routing" src="../_images/ditaa-528948c80a3fd78b89fb6f7bd69503a58b93a4ae.png" /> +<div class="section" id="routing-table-s"> +<h3>Routing Table(s)<a class="headerlink" href="#routing-table-s" title="Permalink to this headline">¶</a></h3> +<div class="admonition-routing-table highlight-shell"><div class="highlight"><pre><span></span>tavi@desktop-tavi:~/src/linux$ ip route list table main +default via <span class="m">172</span>.30.240.1 dev eth0 +<span class="m">172</span>.30.240.0/20 dev eth0 proto kernel scope link src <span class="m">172</span>.30.249.241 + +tavi@desktop-tavi:~/src/linux$ ip route list table <span class="nb">local</span> +broadcast <span class="m">127</span>.0.0.0 dev lo proto kernel scope link src <span class="m">127</span>.0.0.1 +<span class="nb">local</span> <span class="m">127</span>.0.0.0/8 dev lo proto kernel scope host src <span class="m">127</span>.0.0.1 +<span class="nb">local</span> <span class="m">127</span>.0.0.1 dev lo proto kernel scope host src <span class="m">127</span>.0.0.1 +broadcast <span class="m">127</span>.255.255.255 dev lo proto kernel scope link src <span class="m">127</span>.0.0.1 +broadcast <span class="m">172</span>.30.240.0 dev eth0 proto kernel scope link src <span class="m">172</span>.30.249.241 +<span class="nb">local</span> <span class="m">172</span>.30.249.241 dev eth0 proto kernel scope host src <span class="m">172</span>.30.249.241 +broadcast <span class="m">172</span>.30.255.255 dev eth0 proto kernel scope link src <span class="m">172</span>.30.249.241 + +tavi@desktop-tavi:~/src/linux$ ip rule list +<span class="m">0</span>: from all lookup <span class="nb">local</span> +<span class="m">32766</span>: from all lookup main +<span class="m">32767</span>: from all lookup default +</pre></div> +</div> +</div> +<div class="section" id="routing-policy-database"> +<h3>Routing Policy Database<a class="headerlink" href="#routing-policy-database" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-routing-policy-database simple"> +<li>"Regular" routing only uses the destination address</li> +<li>To increase flexibility a "Routing Policy Database" is used that +allows different routing based on other fields such as the source +address, protocol type, transport ports, etc.</li> +<li>This is encoded as a list of rules that are evaluated based on +their priority (priority 0 is the highest)</li> +<li>Each rule has a selector (how to match the packet) and an +action (what action to take if the packet matches)</li> +<li>Selectors: source address, destination address, type of service (TOS), +input interface, output interface, etc.</li> +<li>Action: lookup / unicast - use given routing table, blackhole - +drop packet, unreachable - send ICMP unreachable message and drop +packet, etc.</li> +</ul> +</div> +<div class="section" id="routing-table-processing"> +<h3>Routing table processing<a class="headerlink" href="#routing-table-processing" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-routing-table-processing simple"> +<li>Special table for local addreses -> route packets to sockets +based on family, type, ports</li> +<li>Check every routing entry for starting with the most specific +routes (e.g. 192.168.0.0/24 is checked before 192.168.0.0/16)</li> +<li>A route matches if the packet destination addreess logical ORed +with the subnet mask equals the subnet address</li> +<li>Once a route matches the following information is retrieved: +interface, link layer next-hop address, network next host address</li> +</ul> +</div> +<div class="section" id="forwarding-information-database"> +<h3>Forwarding Information Database<a class="headerlink" href="#forwarding-information-database" title="Permalink to this headline">¶</a></h3> +<p class="admonition-forward-information-database-removed-in-3-6"> </p> +<img alt="../_images/fidb-overview1.png" src="../_images/fidb-overview1.png" /> +<img alt="../_images/fidb-details1.png" class="admonition-forward-information-database-removed-in-3-6" src="../_images/fidb-details1.png" /> +<p class="admonition-routing-cache-removed-in-3-6"> </p> +<img alt="../_images/routing-cache1.png" src="../_images/routing-cache1.png" /> +<p class="admonition-fib-trie"> </p> +<img alt="../_images/fib-trie1.png" src="../_images/fib-trie1.png" /> +<p class="admonition-compressed-trie"> </p> +<img alt="../_images/fib-trie-compressed1.png" src="../_images/fib-trie-compressed1.png" /> +</div> +</div> +<div class="section" id="netfilter"> +<h2>Netfilter<a class="headerlink" href="#netfilter" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-netfilter simple"> +<li>Framework that implements packet filtering and NAT</li> +<li>It uses hooks inserted in key places in the packet flow:<ul> +<li>NF_IP_PRE_ROUTING</li> +<li>NF_IP_LOCAL_IN</li> +<li>NF_IP_FORWARD</li> +<li>NF_IP_LOCAL_OUT</li> +<li>NF_IP_POST_ROUTING</li> +<li>NF_IP_NUMHOOKS</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="network-packets-skbs-struct-sk-buff"> +<h2>Network packets / skbs (struct sk_buff)<a class="headerlink" href="#network-packets-skbs-struct-sk-buff" title="Permalink to this headline">¶</a></h2> +<img alt="../_images/skb1.png" class="admonition-network-packets-skbs" src="../_images/skb1.png" /> +<div class="admonition-struct-sk-buff highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">prev</span><span class="p">;</span> + + <span class="k">struct</span> <span class="n">sock</span> <span class="o">*</span><span class="n">sk</span><span class="p">;</span> + <span class="n">ktime_t</span> <span class="n">tstamp</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">net_device</span> <span class="o">*</span><span class="n">dev</span><span class="p">;</span> + <span class="kt">char</span> <span class="n">cb</span><span class="p">[</span><span class="mi">48</span><span class="p">];</span> + + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">,</span> + <span class="n">data_len</span><span class="p">;</span> + <span class="n">__u16</span> <span class="n">mac_len</span><span class="p">,</span> + <span class="n">hdr_len</span><span class="p">;</span> + + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">destructor</span><span class="p">)(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + + <span class="n">sk_buff_data_t</span> <span class="n">transport_header</span><span class="p">;</span> + <span class="n">sk_buff_data_t</span> <span class="n">network_header</span><span class="p">;</span> + <span class="n">sk_buff_data_t</span> <span class="n">mac_header</span><span class="p">;</span> + <span class="n">sk_buff_data_t</span> <span class="n">tail</span><span class="p">;</span> + <span class="n">sk_buff_data_t</span> <span class="n">end</span><span class="p">;</span> + + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">head</span><span class="p">,</span> + <span class="o">*</span><span class="n">data</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">truesize</span><span class="p">;</span> + <span class="n">atomic_t</span> <span class="n">users</span><span class="p">;</span> +</pre></div> +</div> +<div class="admonition-skb-apis highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* reserve head room */</span> +<span class="kt">void</span> <span class="nf">skb_reserve</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="cm">/* add data to the end */</span> +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_put</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="cm">/* add data to the top */</span> +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_push</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="cm">/* discard data at the top */</span> +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_pull</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="cm">/* discard data at the end */</span> +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_trim</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">len</span><span class="p">);</span> + +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_transport_header</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_reset_transport_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_set_transport_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">offset</span><span class="p">);</span> + +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_network_header</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_reset_network_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_set_network_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">offset</span><span class="p">);</span> + +<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">skb_mac_header</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">skb_mac_header_was_set</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_reset_mac_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">);</span> + +<span class="kt">void</span> <span class="nf">skb_set_mac_header</span><span class="p">(</span><span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">offset</span><span class="p">);</span> +</pre></div> +</div> +<p class="admonition-skb-data-management"> </p> +<a class="reference internal image-reference" href="../_images/ditaa-91073cb05a3f537eb54ab10745c307531e6795a0.png"><img alt="../_images/ditaa-91073cb05a3f537eb54ab10745c307531e6795a0.png" src="../_images/ditaa-91073cb05a3f537eb54ab10745c307531e6795a0.png" style="height: 50%;" /></a> +</div> +<div class="section" id="network-device"> +<h2>Network Device<a class="headerlink" href="#network-device" title="Permalink to this headline">¶</a></h2> +<img alt="../_images/net-dev-hw1.png" class="admonition-network-device-interface" src="../_images/net-dev-hw1.png" /> +<ul class="admonition-advanced-features simple"> +<li>Scatter-Gather</li> +<li>Checksum offloading: Ethernet, IP, UDP, TCP</li> +<li>Adaptive interrupt handling (coalescence, adaptive)</li> +</ul> +</div> +<div class="section" id="hardware-and-software-acceleration-techniques"> +<h2>Hardware and Software Acceleration Techniques<a class="headerlink" href="#hardware-and-software-acceleration-techniques" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-tcp-offload simple"> +<li>Full offload - Implement TCP/IP stack in hardware</li> +<li>Issues:<ul> +<li>Scaling number of connections</li> +<li>Security</li> +<li>Conformance</li> +</ul> +</li> +</ul> +<ul class="admonition-performance-observation simple"> +<li>Performance is proportional with the number of packets to be +processed</li> +<li>Example: if an end-point can process 60K pps<ul> +<li>1538 MSS -> 738Mbps</li> +<li>2038 MSS -> 978Mbps</li> +<li>9038 MSS -> 4.3Gbps</li> +<li>20738 MSS -> 9.9Gbps</li> +</ul> +</li> +</ul> +<ul class="admonition-stateless-offload simple"> +<li>The networking stack processes large packets</li> +<li>TX path: the hardware splits large packets in smaller packets +(TCP Segmentation Offload)</li> +<li>RX path: the hardware aggregates small packets into larger +packets (Large Receive Offload - LRO)</li> +</ul> +<img alt="../_images/tso1.png" class="admonition-tcp-segmentation-offload" src="../_images/tso1.png" /> +<img alt="../_images/lro1.png" class="admonition-large-receive-offload" src="../_images/lro1.png" /> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lec9-debugging.html" class="btn btn-neutral float-left" title="SO2 Lecture 09 - Kernel debugging" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lec11-arch.html" class="btn btn-neutral float-right" title="SO2 Lecture 11 - Architecture Layer" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec11-arch-slides.html b/refs/pull/405/merge/so2/lec11-arch-slides.html new file mode 100644 index 00000000..374b61eb --- /dev/null +++ b/refs/pull/405/merge/so2/lec11-arch-slides.html @@ -0,0 +1,254 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>SO2 Lecture 11 - Architecture Layer — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="up" title="Operating Systems 2" href="index.html" /> + <link rel="next" title="SO2 Lecture 12 - Virtualization" href="lec12-virtualization.html" /> + <link rel="prev" title="SO2 Lecture 10 - Networking" href="lec10-networking.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-so2-lecture-11-architecture-layer slide level-1"> + +<h1>SO2 Lecture 11 - Architecture Layer</h1> + + + + + +</article> +<article class="admonition-introduction slide level-2"> + +<h2>Introduction</h2> + +<ul class="simple"> +<li>Overview of the arch layer</li> +<li>Overview of the boot process</li> +</ul> + + + + +</article> +<article class="admonition-overview-of-the-arch-layer slide level-2"> + +<h2>Overview of the arch layer</h2> + +<a class="reference internal image-reference" href="../_images/ditaa-ae895f3a8e26b92bf6c6ecbbd71e2c88912d5607.png"><img alt="../_images/ditaa-ae895f3a8e26b92bf6c6ecbbd71e2c88912d5607.png" src="../_images/ditaa-ae895f3a8e26b92bf6c6ecbbd71e2c88912d5607.png" style="height: 100%;" /></a> + + + + +</article> +<article class="admonition-bootstrap slide level-2"> + +<h2>Bootstrap</h2> + +<ul class="simple"> +<li>The first kernel code that runs</li> +<li>Typically runs with the MMU disabled</li> +<li>Move / Relocate kernel code</li> +</ul> + + + + +</article> +<article class="admonition-bootstrap slide level-2"> + +<h2>Bootstrap</h2> + +<ul class="simple"> +<li>The first kernel code that runs</li> +<li>Typically runs with the MMU disabled</li> +<li>Copy bootloader arguments and determine kernel run location</li> +<li>Move / relocate kernel code to final location</li> +<li>Initial MMU setup - map the kernel</li> +</ul> + + + + +</article> +<article class="admonition-memory-setup slide level-2"> + +<h2>Memory Setup</h2> + +<ul class="simple"> +<li>Determine available memory and setup the boot memory allocator</li> +<li>Manages memory regions before the page allocator is setup</li> +<li>Bootmem - used a bitmap to track free blocks</li> +<li>Memblock - deprecates bootmem and adds support for memory ranges<ul> +<li>Supports both physical and virtual addresses</li> +<li>support NUMA architectures</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-mmu-management slide level-2"> + +<h2>MMU management</h2> + +<ul class="simple"> +<li>Implements the generic page table manipulation APIs: types, +accessors, flags</li> +<li>Implement TLB management APIs: flush, invalidate</li> +</ul> + + + + +</article> +<article class="admonition-thread-management slide level-2"> + +<h2>Thread Management</h2> + +<ul class="simple"> +<li>Defines the thread type (struct thread_info) and implements +functions for allocating threads (if needed)</li> +<li>Implement <code class="xref c c-func docutils literal"><span class="pre">copy_thread()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">switch_context()</span></code></li> +</ul> + + + + +</article> +<article class="admonition-timer-management slide level-2"> + +<h2>Timer Management</h2> + +<ul class="simple"> +<li>Setup the timer tick and provide a time source</li> +<li>Mostly transitioned to platform drivers<ul> +<li>clock_event_device - for scheduling timers</li> +<li>clocksource - for reading the time</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-irqs-and-exception-management slide level-2"> + +<h2>IRQs and exception management</h2> + +<ul class="simple"> +<li>Define interrupt and exception handlers / entry points</li> +<li>Setup priorities</li> +<li>Platform drivers for interrupt controllers</li> +</ul> + + + + +</article> +<article class="admonition-system-calls slide level-2"> + +<h2>System calls</h2> + +<ul class="simple"> +<li>Define system call entry point(s)</li> +<li>Implement user-space access primitives (e.g. copy_to_user)</li> +</ul> + + + + +</article> +<article class="admonition-platform-drivers slide level-2"> + +<h2>Platform Drivers</h2> + +<ul class="simple"> +<li>Platform and architecture specific drivers</li> +<li>Bindings to platform device enumeration methods (e.g. device tree +or ACPI)</li> +</ul> + + + + +</article> +<article class="admonition-machine-specific-code slide level-2"> + +<h2>Machine specific code</h2> + +<ul class="simple"> +<li>Some architectures use a "machine" / "platform" abstraction</li> +<li>Typical for architecture used in embedded systems with a lot of +variety (e.g. ARM, powerPC)</li> +</ul> + + + + +</article> +<article class="admonition-boot-flow-inspection slide level-2"> + +<h2>Boot flow inspection</h2> + +<asciinema-player src="../_images/boot.cast"></asciinema-player> + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec11-arch.html b/refs/pull/405/merge/so2/lec11-arch.html new file mode 100644 index 00000000..7cbf7cb3 --- /dev/null +++ b/refs/pull/405/merge/so2/lec11-arch.html @@ -0,0 +1,317 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lecture 11 - Architecture Layer — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lecture 12 - Virtualization" href="lec12-virtualization.html" /> + <link rel="prev" title="SO2 Lecture 10 - Networking" href="lec10-networking.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lecture 11 - Architecture Layer</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="#overview-of-the-arch-layer">Overview of the arch layer</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#boot-strap">Boot strap</a></li> +<li class="toctree-l4"><a class="reference internal" href="#boot-strap-1">Boot strap</a></li> +<li class="toctree-l4"><a class="reference internal" href="#memory-setup">Memory setup</a></li> +<li class="toctree-l4"><a class="reference internal" href="#mmu-management">MMU management</a></li> +<li class="toctree-l4"><a class="reference internal" href="#thread-management">Thread Management</a></li> +<li class="toctree-l4"><a class="reference internal" href="#time-management">Time Management</a></li> +<li class="toctree-l4"><a class="reference internal" href="#irqs-and-exception-management">IRQs and exception management</a></li> +<li class="toctree-l4"><a class="reference internal" href="#system-calls">System calls</a></li> +<li class="toctree-l4"><a class="reference internal" href="#platform-drivers">Platform Drivers</a></li> +<li class="toctree-l4"><a class="reference internal" href="#machine-specific-code">Machine specific code</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#overview-of-the-boot-process">Overview of the boot process</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lecture 11 - Architecture Layer</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lec11-arch.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lecture-11-architecture-layer"> +<h1>SO2 Lecture 11 - Architecture Layer<a class="headerlink" href="#so2-lecture-11-architecture-layer" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="lec11-arch-slides.html">View slides</a></p> +<span class="admonition-so2-lecture-11-architecture-layer"></span><div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-introduction simple"> +<li>Overview of the arch layer</li> +<li>Overview of the boot process</li> +</ul> +</div> +<div class="section" id="overview-of-the-arch-layer"> +<h2>Overview of the arch layer<a class="headerlink" href="#overview-of-the-arch-layer" title="Permalink to this headline">¶</a></h2> +<a class="admonition-overview-of-the-arch-layer reference internal image-reference" href="../_images/ditaa-ae895f3a8e26b92bf6c6ecbbd71e2c88912d5607.png"><img alt="../_images/ditaa-ae895f3a8e26b92bf6c6ecbbd71e2c88912d5607.png" class="admonition-overview-of-the-arch-layer" src="../_images/ditaa-ae895f3a8e26b92bf6c6ecbbd71e2c88912d5607.png" style="height: 100%;" /></a> +<div class="section" id="boot-strap"> +<h3>Boot strap<a class="headerlink" href="#boot-strap" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-bootstrap simple"> +<li>The first kernel code that runs</li> +<li>Typically runs with the MMU disabled</li> +<li>Move / Relocate kernel code</li> +</ul> +</div> +<div class="section" id="boot-strap-1"> +<h3>Boot strap<a class="headerlink" href="#boot-strap-1" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-bootstrap simple"> +<li>The first kernel code that runs</li> +<li>Typically runs with the MMU disabled</li> +<li>Copy bootloader arguments and determine kernel run location</li> +<li>Move / relocate kernel code to final location</li> +<li>Initial MMU setup - map the kernel</li> +</ul> +</div> +<div class="section" id="memory-setup"> +<h3>Memory setup<a class="headerlink" href="#memory-setup" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-memory-setup simple"> +<li>Determine available memory and setup the boot memory allocator</li> +<li>Manages memory regions before the page allocator is setup</li> +<li>Bootmem - used a bitmap to track free blocks</li> +<li>Memblock - deprecates bootmem and adds support for memory ranges<ul> +<li>Supports both physical and virtual addresses</li> +<li>support NUMA architectures</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="mmu-management"> +<h3>MMU management<a class="headerlink" href="#mmu-management" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-mmu-management simple"> +<li>Implements the generic page table manipulation APIs: types, +accessors, flags</li> +<li>Implement TLB management APIs: flush, invalidate</li> +</ul> +</div> +<div class="section" id="thread-management"> +<h3>Thread Management<a class="headerlink" href="#thread-management" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-thread-management simple"> +<li>Defines the thread type (struct thread_info) and implements +functions for allocating threads (if needed)</li> +<li>Implement <code class="xref c c-func docutils literal"><span class="pre">copy_thread()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">switch_context()</span></code></li> +</ul> +</div> +<div class="section" id="time-management"> +<h3>Time Management<a class="headerlink" href="#time-management" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-timer-management simple"> +<li>Setup the timer tick and provide a time source</li> +<li>Mostly transitioned to platform drivers<ul> +<li>clock_event_device - for scheduling timers</li> +<li>clocksource - for reading the time</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="irqs-and-exception-management"> +<h3>IRQs and exception management<a class="headerlink" href="#irqs-and-exception-management" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-irqs-and-exception-management simple"> +<li>Define interrupt and exception handlers / entry points</li> +<li>Setup priorities</li> +<li>Platform drivers for interrupt controllers</li> +</ul> +</div> +<div class="section" id="system-calls"> +<h3>System calls<a class="headerlink" href="#system-calls" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-system-calls simple"> +<li>Define system call entry point(s)</li> +<li>Implement user-space access primitives (e.g. copy_to_user)</li> +</ul> +</div> +<div class="section" id="platform-drivers"> +<h3>Platform Drivers<a class="headerlink" href="#platform-drivers" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-platform-drivers simple"> +<li>Platform and architecture specific drivers</li> +<li>Bindings to platform device enumeration methods (e.g. device tree +or ACPI)</li> +</ul> +</div> +<div class="section" id="machine-specific-code"> +<h3>Machine specific code<a class="headerlink" href="#machine-specific-code" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-machine-specific-code simple"> +<li>Some architectures use a "machine" / "platform" abstraction</li> +<li>Typical for architecture used in embedded systems with a lot of +variety (e.g. ARM, powerPC)</li> +</ul> +</div> +</div> +<div class="section" id="overview-of-the-boot-process"> +<h2>Overview of the boot process<a class="headerlink" href="#overview-of-the-boot-process" title="Permalink to this headline">¶</a></h2> +<asciinema-player src="../_images/boot.cast"></asciinema-player></div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lec10-networking.html" class="btn btn-neutral float-left" title="SO2 Lecture 10 - Networking" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lec12-virtualization.html" class="btn btn-neutral float-right" title="SO2 Lecture 12 - Virtualization" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec12-profiling-slides.html b/refs/pull/405/merge/so2/lec12-profiling-slides.html new file mode 100644 index 00000000..a3c2d027 --- /dev/null +++ b/refs/pull/405/merge/so2/lec12-profiling-slides.html @@ -0,0 +1,70 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>SO2 Lecture 12 - Profiling — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-so2-lecture-12-profiling slide level-1"> + +<h1>SO2 Lecture 12 - Profiling</h1> + + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec12-profiling.html b/refs/pull/405/merge/so2/lec12-profiling.html new file mode 100644 index 00000000..d28a2221 --- /dev/null +++ b/refs/pull/405/merge/so2/lec12-profiling.html @@ -0,0 +1,157 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lecture 12 - Profiling — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul> +<li class="toctree-l1"><a class="reference internal" href="index.html">Operating Systems 2</a></li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item active">SO2 Lecture 12 - Profiling</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lec12-profiling.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lecture-12-profiling"> +<h1>SO2 Lecture 12 - Profiling<a class="headerlink" href="#so2-lecture-12-profiling" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="lec12-profiling-slides.html">View slides</a></p> +<span class="admonition-so2-lecture-12-profiling"></span></div> + + + </div> + </div> + <footer> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec12-virtualization-slides.html b/refs/pull/405/merge/so2/lec12-virtualization-slides.html new file mode 100644 index 00000000..fb844dfd --- /dev/null +++ b/refs/pull/405/merge/so2/lec12-virtualization-slides.html @@ -0,0 +1,709 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>SO2 Lecture 12 - Virtualization — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="up" title="Operating Systems 2" href="index.html" /> + <link rel="next" title="SO2 Lab 01 - Introduction" href="lab1-intro.html" /> + <link rel="prev" title="SO2 Lecture 11 - Architecture Layer" href="lec11-arch.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-so2-lecture-12-virtualization slide level-1"> + +<h1>SO2 Lecture 12 - Virtualization</h1> + + + + + +</article> +<article class="admonition-virtualization slide level-2"> + +<h2>Virtualization</h2> + +<ul class="simple"> +<li>Emulation basics</li> +<li>Virtualization basics</li> +<li>Paravirtualization basics</li> +<li>Hardware support for virtualization</li> +<li>Overview of the Xen hypervisor</li> +<li>Overview of the KVM hypervisor</li> +</ul> + + + + +</article> +<article class="admonition-emulation-basics slide level-2"> + +<h2>Emulation basics</h2> + +<ul class="simple"> +<li>Instructions are emulated (each time they are executed)</li> +<li>The other system components are also emulated:<ul> +<li>MMU</li> +<li>Physical memory access</li> +<li>Peripherals</li> +</ul> +</li> +<li>Target architecture - the architecture that it is emulated</li> +<li>Host architecture - the architecture that the emulator runs on</li> +<li>For emulation target and host architectures can be different</li> +</ul> + + + + +</article> +<article class="admonition-virtualization-basics slide level-2"> + +<h2>Virtualization basics</h2> + +<ul class="simple"> +<li>Defined in a paper by Popek & Goldberg in 1974</li> +<li>Fidelity</li> +<li>Performance</li> +<li>Security</li> +</ul> +<img alt="../_images/ditaa-91f08f7db4b54069e16694eab8d75c06400fc47b.png" src="../_images/ditaa-91f08f7db4b54069e16694eab8d75c06400fc47b.png" /> + + + + +</article> +<article class="admonition-classic-virtualization slide level-2"> + +<h2>Classic virtualization</h2> + +<ul class="simple"> +<li>Trap & Emulate</li> +<li>Same architecture for host and target</li> +<li>Most of the target instructions are natively executed</li> +<li>Target OS runs in non-privilege mode on the host</li> +<li>Privileged instructions are trapped and emulated</li> +<li>Two machine states: host and guest</li> +</ul> + + + + +</article> +<article class="admonition-software-virtualization slide level-2"> + +<h2>Software virtualization</h2> + +<ul class="simple"> +<li>Not all architecture can be virtualized; e.g. x86:<ul> +<li>CS register encodes the CPL</li> +<li>Some instructions don't generate a trap (e.g. popf)</li> +</ul> +</li> +<li>Solution: emulate instructions using binary translation</li> +</ul> + + + + +</article> +<article class="admonition-mmu-virtualization slide level-2"> + +<h2>MMU virtualization</h2> + +<ul class="simple"> +<li>"Fake" VM physical addresses are translated by the host to actual +physical addresses</li> +<li>Guest virtual address -> Guest physical address -> Host Physical Address</li> +<li>The guest page tables are not directly used by the host hardware</li> +<li>VM page tables are verified then translated into a new set of page +tables on the host (shadow page tables)</li> +</ul> + + + + +</article> +<article class="admonition-shadow-page-tables slide level-2"> + +<h2>Shadow page tables</h2> + +<p> </p> +<img alt="../_images/ditaa-8632e22c6d89bd18f97c9cef127444486b5077df.png" src="../_images/ditaa-8632e22c6d89bd18f97c9cef127444486b5077df.png" /> + + + + +</article> +<article class="admonition-lazy-shadow-sync slide level-2"> + +<h2>Lazy shadow sync</h2> + +<ul class="simple"> +<li>Guest page tables changes are typically batched</li> +<li>To avoid repeated traps, checks and transformations map guest +page table entries with write access</li> +<li>Update the shadow page table when<ul> +<li>The TLB is flushed</li> +<li>In the host page fault handler</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-i-o-emulation slide level-2"> + +<h2>I/O emulation</h2> + +<p> </p> +<img alt="../_images/ditaa-bb69666d75b9670e542682753fb8cc9b77ff8894.png" src="../_images/ditaa-bb69666d75b9670e542682753fb8cc9b77ff8894.png" /> + + + + +</article> +<article class="admonition-example-qemu-sifive-uart-emulation slide level-2"> + +<h2>Example: qemu SiFive UART emulation</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/*</span> +<span class="cm"> * QEMU model of the UART on the SiFive E300 and U500 series SOCs.</span> +<span class="cm"> *</span> +<span class="cm"> * Copyright (c) 2016 Stefan O'Rear</span> +<span class="cm"> *</span> +<span class="cm"> * This program is free software; you can redistribute it and/or modify it</span> +<span class="cm"> * under the terms and conditions of the GNU General Public License,</span> +<span class="cm"> * version 2 or later, as published by the Free Software Foundation.</span> +<span class="cm"> *</span> +<span class="cm"> * This program is distributed in the hope it will be useful, but WITHOUT</span> +<span class="cm"> * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or</span> +<span class="cm"> * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for</span> +<span class="cm"> * more details.</span> +<span class="cm"> *</span> +<span class="cm"> * You should have received a copy of the GNU General Public License along with</span> +<span class="cm"> * this program. If not, see <http://www.gnu.org/licenses/>.</span> +<span class="cm"> */</span> + +<span class="cp">#include</span> <span class="cpf">"qemu/osdep.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"qapi/error.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"qemu/log.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"chardev/char.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"chardev/char-fe.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"hw/irq.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"hw/char/sifive_uart.h"</span><span class="cp"></span> + +<span class="cm">/*</span> +<span class="cm"> * Not yet implemented:</span> +<span class="cm"> *</span> +<span class="cm"> * Transmit FIFO using "qemu/fifo8.h"</span> +<span class="cm"> */</span> + +<span class="cm">/* Returns the state of the IP (interrupt pending) register */</span> +<span class="k">static</span> <span class="kt">uint64_t</span> <span class="nf">uart_ip</span><span class="p">(</span><span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">uint64_t</span> <span class="n">ret</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + + <span class="kt">uint64_t</span> <span class="n">txcnt</span> <span class="o">=</span> <span class="n">SIFIVE_UART_GET_TXCNT</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">txctrl</span><span class="p">);</span> + <span class="kt">uint64_t</span> <span class="n">rxcnt</span> <span class="o">=</span> <span class="n">SIFIVE_UART_GET_RXCNT</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rxctrl</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">txcnt</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="n">ret</span> <span class="o">|=</span> <span class="n">SIFIVE_UART_IP_TXWM</span><span class="p">;</span> + <span class="p">}</span> + <span class="k">if</span> <span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span> <span class="o">></span> <span class="n">rxcnt</span><span class="p">)</span> <span class="p">{</span> + <span class="n">ret</span> <span class="o">|=</span> <span class="n">SIFIVE_UART_IP_RXWM</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="n">ret</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">update_irq</span><span class="p">(</span><span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">cond</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="k">if</span> <span class="p">((</span><span class="n">s</span><span class="o">-></span><span class="n">ie</span> <span class="o">&</span> <span class="n">SIFIVE_UART_IE_TXWM</span><span class="p">)</span> <span class="o">||</span> + <span class="p">((</span><span class="n">s</span><span class="o">-></span><span class="n">ie</span> <span class="o">&</span> <span class="n">SIFIVE_UART_IE_RXWM</span><span class="p">)</span> <span class="o">&&</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span><span class="p">))</span> <span class="p">{</span> + <span class="n">cond</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> + <span class="p">}</span> + <span class="k">if</span> <span class="p">(</span><span class="n">cond</span><span class="p">)</span> <span class="p">{</span> + <span class="n">qemu_irq_raise</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">irq</span><span class="p">);</span> + <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> + <span class="n">qemu_irq_lower</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">irq</span><span class="p">);</span> + <span class="p">}</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">uint64_t</span> +<span class="nf">uart_read</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">,</span> <span class="n">hwaddr</span> <span class="n">addr</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">size</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">r</span><span class="p">;</span> + <span class="k">switch</span> <span class="p">(</span><span class="n">addr</span><span class="p">)</span> <span class="p">{</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_RXFIFO</span><span class="p">:</span> + <span class="k">if</span> <span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span><span class="p">)</span> <span class="p">{</span> + <span class="n">r</span> <span class="o">=</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> + <span class="n">memmove</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">,</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span> + <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span><span class="o">--</span><span class="p">;</span> + <span class="n">qemu_chr_fe_accept_input</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">);</span> + <span class="n">update_irq</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> + <span class="k">return</span> <span class="n">r</span><span class="p">;</span> + <span class="p">}</span> + <span class="k">return</span> <span class="mh">0x80000000</span><span class="p">;</span> + + <span class="k">case</span> <span class="nl">SIFIVE_UART_TXFIFO</span><span class="p">:</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="cm">/* Should check tx fifo */</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_IE</span><span class="p">:</span> + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">ie</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_IP</span><span class="p">:</span> + <span class="k">return</span> <span class="n">uart_ip</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_TXCTRL</span><span class="p">:</span> + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">txctrl</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_RXCTRL</span><span class="p">:</span> + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">rxctrl</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_DIV</span><span class="p">:</span> + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">div</span><span class="p">;</span> + <span class="p">}</span> + + <span class="n">qemu_log_mask</span><span class="p">(</span><span class="n">LOG_GUEST_ERROR</span><span class="p">,</span> <span class="s">"%s: bad read: addr=0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> + <span class="n">__func__</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">addr</span><span class="p">);</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> +<span class="nf">uart_write</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">,</span> <span class="n">hwaddr</span> <span class="n">addr</span><span class="p">,</span> + <span class="kt">uint64_t</span> <span class="n">val64</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">size</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + <span class="kt">uint32_t</span> <span class="n">value</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">ch</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span> + + <span class="k">switch</span> <span class="p">(</span><span class="n">addr</span><span class="p">)</span> <span class="p">{</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_TXFIFO</span><span class="p">:</span> + <span class="n">qemu_chr_fe_write</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">,</span> <span class="o">&</span><span class="n">ch</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> + <span class="n">update_irq</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> + <span class="k">return</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_IE</span><span class="p">:</span> + <span class="n">s</span><span class="o">-></span><span class="n">ie</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="n">update_irq</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> + <span class="k">return</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_TXCTRL</span><span class="p">:</span> + <span class="n">s</span><span class="o">-></span><span class="n">txctrl</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="k">return</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_RXCTRL</span><span class="p">:</span> + <span class="n">s</span><span class="o">-></span><span class="n">rxctrl</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="k">return</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_DIV</span><span class="p">:</span> + <span class="n">s</span><span class="o">-></span><span class="n">div</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="k">return</span><span class="p">;</span> + <span class="p">}</span> + <span class="n">qemu_log_mask</span><span class="p">(</span><span class="n">LOG_GUEST_ERROR</span><span class="p">,</span> <span class="s">"%s: bad write: addr=0x%x v=0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> + <span class="n">__func__</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">addr</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">value</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="k">const</span> <span class="n">MemoryRegionOps</span> <span class="n">uart_ops</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">read</span> <span class="o">=</span> <span class="n">uart_read</span><span class="p">,</span> + <span class="p">.</span><span class="n">write</span> <span class="o">=</span> <span class="n">uart_write</span><span class="p">,</span> + <span class="p">.</span><span class="n">endianness</span> <span class="o">=</span> <span class="n">DEVICE_NATIVE_ENDIAN</span><span class="p">,</span> + <span class="p">.</span><span class="n">valid</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">min_access_size</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span> + <span class="p">.</span><span class="n">max_access_size</span> <span class="o">=</span> <span class="mi">4</span> + <span class="p">}</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">uart_rx</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">,</span> <span class="k">const</span> <span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buf</span><span class="p">,</span> <span class="kt">int</span> <span class="n">size</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + + <span class="cm">/* Got a byte. */</span> + <span class="k">if</span> <span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span> <span class="o">>=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">))</span> <span class="p">{</span> + <span class="n">printf</span><span class="p">(</span><span class="s">"WARNING: UART dropped char.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="k">return</span><span class="p">;</span> + <span class="p">}</span> + <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">[</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="o">*</span><span class="n">buf</span><span class="p">;</span> + + <span class="n">update_irq</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">uart_can_rx</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span> <span class="o"><</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">uart_event</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">,</span> <span class="n">QEMUChrEvent</span> <span class="n">event</span><span class="p">)</span> +<span class="p">{</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">uart_be_change</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + + <span class="n">qemu_chr_fe_set_handlers</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">,</span> <span class="n">uart_can_rx</span><span class="p">,</span> <span class="n">uart_rx</span><span class="p">,</span> <span class="n">uart_event</span><span class="p">,</span> + <span class="n">uart_be_change</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">true</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="cm">/*</span> +<span class="cm"> * Create UART device.</span> +<span class="cm"> */</span> +<span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="nf">sifive_uart_create</span><span class="p">(</span><span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">address_space</span><span class="p">,</span> <span class="n">hwaddr</span> <span class="n">base</span><span class="p">,</span> + <span class="n">Chardev</span> <span class="o">*</span><span class="n">chr</span><span class="p">,</span> <span class="n">qemu_irq</span> <span class="n">irq</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">g_malloc0</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">SiFiveUARTState</span><span class="p">));</span> + <span class="n">s</span><span class="o">-></span><span class="n">irq</span> <span class="o">=</span> <span class="n">irq</span><span class="p">;</span> + <span class="n">qemu_chr_fe_init</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">,</span> <span class="n">chr</span><span class="p">,</span> <span class="o">&</span><span class="n">error_abort</span><span class="p">);</span> + <span class="n">qemu_chr_fe_set_handlers</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">,</span> <span class="n">uart_can_rx</span><span class="p">,</span> <span class="n">uart_rx</span><span class="p">,</span> <span class="n">uart_event</span><span class="p">,</span> + <span class="n">uart_be_change</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">true</span><span class="p">);</span> + <span class="n">memory_region_init_io</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">mmio</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">&</span><span class="n">uart_ops</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> + <span class="n">TYPE_SIFIVE_UART</span><span class="p">,</span> <span class="n">SIFIVE_UART_MAX</span><span class="p">);</span> + <span class="n">memory_region_add_subregion</span><span class="p">(</span><span class="n">address_space</span><span class="p">,</span> <span class="n">base</span><span class="p">,</span> <span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">mmio</span><span class="p">);</span> + <span class="k">return</span> <span class="n">s</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-paravirtualization slide level-2"> + +<h2>Paravirtualization</h2> + +<ul class="simple"> +<li>Change the guest OS so that it cooperates with the VMM<ul> +<li>CPU paravirtualization</li> +<li>MMU paravirtualization</li> +<li>I/O paravirtualization</li> +</ul> +</li> +<li>VMM exposes hypercalls for:<ul> +<li>activate / deactivate the interrupts</li> +<li>changing page tables</li> +<li>accessing virtualized peripherals</li> +</ul> +</li> +<li>VMM uses events to trigger interrupts in the VM</li> +</ul> + + + + +</article> +<article class="admonition-intel-vt-x slide level-2"> + +<h2>Intel VT-x</h2> + +<ul class="simple"> +<li>Hardware extension to transform x86 to the point it can be +virtualized "classically"</li> +<li>New execution mode: non-root mode</li> +<li>Each non-root mode instance uses a Virtual Machine Control +Structure (VMCS) to store its state</li> +<li>VMM runs in root mode</li> +<li>VM-entry and VM-exit are used to transition between the two modes</li> +</ul> + + + + +</article> +<article class="admonition-virtual-machine-control-structure slide level-2"> + +<h2>Virtual Machine Control Structure</h2> + +<ul class="simple"> +<li>Guest information: state of the virtual CPU</li> +<li>Host information: state of the physical CPU</li> +<li>Saved information:<ul> +<li>visible state: segment registers, CR3, IDTR, etc.</li> +<li>internal state</li> +</ul> +</li> +<li>VMCS can not be accessed directly but certain information can be +accessed with special instructions</li> +</ul> + + + + +</article> +<article class="admonition-vm-entry-exit slide level-2"> + +<h2>VM entry & exit</h2> + +<ul class="simple"> +<li>VM entry - new instructions that switches the CPU in non-root +mode and loads the VM state from a VMCS; host state is saved in +VMCS</li> +<li>Allows injecting interrupts and exceptions in the guest</li> +<li>VM exit will be automatically triggered based on the VMCS +configuration</li> +<li>When VM exit occurs host state is loaded from VMCS, guest state +is saved in VMCS</li> +</ul> + + + + +</article> +<article class="admonition-vm-execution-control-fields slide level-2"> + +<h2>VM execution control fields</h2> + +<ul class="simple"> +<li>Selects conditions which triggers a VM exit; examples:<ul> +<li>If an external interrupt is generated</li> +<li>If an external interrupt is generated and EFLAGS.IF is set</li> +<li>If CR0-CR4 registers are modified</li> +</ul> +</li> +<li>Exception bitmap - selects which exceptions will generate a VM +exit</li> +<li>IO bitmap - selects which I/O addresses (IN/OUT accesses) +generates a VM exit</li> +<li>MSR bitmaps - selects which RDMSR or WRMSR instructions will +generate a VM exit</li> +</ul> + + + + +</article> +<article class="admonition-extend-page-tables slide level-2"> + +<h2>Extend Page Tables</h2> + +<ul class="simple"> +<li>Reduces the complexity of MMU virtualization and improves +performance</li> +<li>Access to CR3, INVLPG and page faults do not require VM exit +anymore</li> +<li>The EPT page table is controlled by the VMM</li> +</ul> +<img alt="../_images/ditaa-cc9a2e995be74ee99646ea4bf0e551d766fa92ef.png" src="../_images/ditaa-cc9a2e995be74ee99646ea4bf0e551d766fa92ef.png" /> + + + + +</article> +<article class="admonition-vpid slide level-2"> + +<h2>VPID</h2> + +<ul class="simple"> +<li>VM entry and VM exit forces a TLB flush - loses VMM / VM translations</li> +<li>To avoid this issue a VPID (Virtual Processor ID) tag is +associated with each VM (VPID 0 is reserved for the VMM)</li> +<li>All TLB entries are tagged</li> +<li>At VM entry and exit just the entries associated with the tags +are flushed</li> +<li>When searching the TLB just the current VPID is used</li> +</ul> + + + + +</article> +<article class="admonition-i-o-virtualization slide level-2"> + +<h2>I/O virtualization</h2> + +<img alt="../_images/ditaa-3901edd823cdc7a6f429ebc37cbc541e650abc96.png" src="../_images/ditaa-3901edd823cdc7a6f429ebc37cbc541e650abc96.png" /> + + + + +</article> +<article class="admonition-i-o-mmu slide level-2"> + +<h2>I/O MMU</h2> + +<p>VT-d protects and translates VM physical addresses using an I/O +MMU (DMA remaping)</p> +<img alt="../_images/ditaa-d880751969de8642b2613caaca345d71acea4500.png" src="../_images/ditaa-d880751969de8642b2613caaca345d71acea4500.png" /> + + + + +</article> +<article class="admonition-interrupt-posting slide level-2"> + +<h2>Interrupt posting</h2> + +<ul class="simple"> +<li>Messsage Signaled Interrupts (MSI) = DMA writes to the host +address range of the IRQ controller (e.g. 0xFEExxxxx)</li> +<li>Low bits of the address and the data indicate which interrupt +vector to deliver to which CPU</li> +<li>Interrupt remapping table points to the virtual CPU (VMCS) that +should receive the interrupt</li> +<li>I/O MMU will trap the IRQ controller write and look it up in the +interrupt remmaping table<ul> +<li>if that virtual CPU is currently running it will take the +interrupt directly</li> +<li>otherwise a bit is set in a table (Posted Interrupt Descriptor +table) and the interrupt will be inject next time that vCPU is +run</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-i-o-virtualization slide level-2"> + +<h2>I/O virtualization</h2> + +<img alt="../_images/ditaa-2cb0eb0056bb775d1446843d62241fd660662c96.png" src="../_images/ditaa-2cb0eb0056bb775d1446843d62241fd660662c96.png" /> + + + + +</article> +<article class="admonition-sr-iov slide level-2"> + +<h2>SR-IOV</h2> + +<ul class="simple"> +<li>Single Root - Input Output Virtualization</li> +<li>Physical device with multiple Ethernet ports will be shown as +multiple device on the PCI bus</li> +<li>Physical Function is used for the control and can be configured<ul> +<li>to present itself as a new PCI device</li> +<li>which VLAN to use</li> +</ul> +</li> +<li>The new virtual function is enumerated on the bus and can be +assigned to a particular guest</li> +</ul> + + + + +</article> +<article class="admonition-qemu slide level-2"> + +<h2>qemu</h2> + +<ul class="simple"> +<li>Uses binary translation via Tiny Code Generator (TCG) for +efficient emulation</li> +<li>Supports different target and host architectures (e.g. running +ARM VMs on x86)</li> +<li>Both process and full system level emulation</li> +<li>MMU emulation</li> +<li>I/O emulation</li> +<li>Can be used with KVM for accelerated virtualization</li> +</ul> + + + + +</article> +<article class="admonition-kvm slide level-2"> + +<h2>KVM</h2> + +<img alt="../_images/ditaa-f8fcc760ef5dad50d1038ed3426d0fcce12fd3e6.png" src="../_images/ditaa-f8fcc760ef5dad50d1038ed3426d0fcce12fd3e6.png" /> + + + + +</article> +<article class="admonition-kvm slide level-2"> + +<h2>KVM</h2> + +<ul class="simple"> +<li>Linux device driver for hardware virtualization (e.g. Intel VT-x, SVM)</li> +<li>IOCTL based interface for managing and running virtual CPUs</li> +<li>VMM components implemented inside the Linux kernel +(e.g. interrupt controller, timers)</li> +<li>Shadow page tables or EPT if present</li> +<li>Uses qemu or virtio for I/O virtualization</li> +</ul> + + + + +</article> +<article class="admonition-xen slide level-2"> + +<h2>Xen</h2> + +<ul class="simple"> +<li>Type 1 = Bare Metal Hypervisor</li> +<li>Type 2 = Hypervisor embedded in an exist kernel / OS</li> +</ul> + + + + +</article> +<article class="admonition-xen slide level-2"> + +<h2>Xen</h2> + +<img alt="../_images/xen-overview1.png" src="../_images/xen-overview1.png" /> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec12-virtualization.html b/refs/pull/405/merge/so2/lec12-virtualization.html new file mode 100644 index 00000000..f752ebc5 --- /dev/null +++ b/refs/pull/405/merge/so2/lec12-virtualization.html @@ -0,0 +1,696 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lecture 12 - Virtualization — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lab 01 - Introduction" href="lab1-intro.html" /> + <link rel="prev" title="SO2 Lecture 11 - Architecture Layer" href="lec11-arch.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lecture 12 - Virtualization</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="#emulation-basics">Emulation basics</a></li> +<li class="toctree-l3"><a class="reference internal" href="#virtualization-basics">Virtualization basics</a></li> +<li class="toctree-l3"><a class="reference internal" href="#classic-virtualization">Classic virtualization</a></li> +<li class="toctree-l3"><a class="reference internal" href="#software-virtualization">Software virtualization</a></li> +<li class="toctree-l3"><a class="reference internal" href="#mmu-virtualization">MMU virtualization</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#shadow-page-tables">Shadow page tables</a></li> +<li class="toctree-l4"><a class="reference internal" href="#lazy-shadow-sync">Lazy shadow sync</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#i-o-emulation">I/O emulation</a></li> +<li class="toctree-l3"><a class="reference internal" href="#paravirtualization">Paravirtualization</a></li> +<li class="toctree-l3"><a class="reference internal" href="#intel-vt-x">Intel VT-x</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#virtual-machine-control-structure">Virtual Machine Control Structure</a></li> +<li class="toctree-l4"><a class="reference internal" href="#vm-entry-exit">VM entry & exit</a></li> +<li class="toctree-l4"><a class="reference internal" href="#vm-execution-control-fields">VM execution control fields</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#extend-page-tables">Extend Page Tables</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#vpid">VPID</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#i-o-virtualization">I/O virtualization</a></li> +<li class="toctree-l3"><a class="reference internal" href="#qemu">qemu</a></li> +<li class="toctree-l3"><a class="reference internal" href="#kvm">KVM</a></li> +<li class="toctree-l3"><a class="reference internal" href="#type-1-vs-type-2-hypervisors">Type 1 vs Type 2 Hypervisors</a></li> +<li class="toctree-l3"><a class="reference internal" href="#xen">Xen</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lecture 12 - Virtualization</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lec12-virtualization.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lecture-12-virtualization"> +<h1>SO2 Lecture 12 - Virtualization<a class="headerlink" href="#so2-lecture-12-virtualization" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="lec12-virtualization-slides.html">View slides</a></p> +<span class="admonition-so2-lecture-12-virtualization"></span><div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-virtualization simple"> +<li>Emulation basics</li> +<li>Virtualization basics</li> +<li>Paravirtualization basics</li> +<li>Hardware support for virtualization</li> +<li>Overview of the Xen hypervisor</li> +<li>Overview of the KVM hypervisor</li> +</ul> +</div> +<div class="section" id="emulation-basics"> +<h2>Emulation basics<a class="headerlink" href="#emulation-basics" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-emulation-basics simple"> +<li>Instructions are emulated (each time they are executed)</li> +<li>The other system components are also emulated:<ul> +<li>MMU</li> +<li>Physical memory access</li> +<li>Peripherals</li> +</ul> +</li> +<li>Target architecture - the architecture that it is emulated</li> +<li>Host architecture - the architecture that the emulator runs on</li> +<li>For emulation target and host architectures can be different</li> +</ul> +</div> +<div class="section" id="virtualization-basics"> +<h2>Virtualization basics<a class="headerlink" href="#virtualization-basics" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-virtualization-basics simple"> +<li>Defined in a paper by Popek & Goldberg in 1974</li> +<li>Fidelity</li> +<li>Performance</li> +<li>Security</li> +</ul> +<img alt="../_images/ditaa-91f08f7db4b54069e16694eab8d75c06400fc47b.png" src="../_images/ditaa-91f08f7db4b54069e16694eab8d75c06400fc47b.png" /> +</div> +<div class="section" id="classic-virtualization"> +<h2>Classic virtualization<a class="headerlink" href="#classic-virtualization" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-classic-virtualization simple"> +<li>Trap & Emulate</li> +<li>Same architecture for host and target</li> +<li>Most of the target instructions are natively executed</li> +<li>Target OS runs in non-privilege mode on the host</li> +<li>Privileged instructions are trapped and emulated</li> +<li>Two machine states: host and guest</li> +</ul> +</div> +<div class="section" id="software-virtualization"> +<h2>Software virtualization<a class="headerlink" href="#software-virtualization" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-software-virtualization simple"> +<li>Not all architecture can be virtualized; e.g. x86:<ul> +<li>CS register encodes the CPL</li> +<li>Some instructions don't generate a trap (e.g. popf)</li> +</ul> +</li> +<li>Solution: emulate instructions using binary translation</li> +</ul> +</div> +<div class="section" id="mmu-virtualization"> +<h2>MMU virtualization<a class="headerlink" href="#mmu-virtualization" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-mmu-virtualization simple"> +<li>"Fake" VM physical addresses are translated by the host to actual +physical addresses</li> +<li>Guest virtual address -> Guest physical address -> Host Physical Address</li> +<li>The guest page tables are not directly used by the host hardware</li> +<li>VM page tables are verified then translated into a new set of page +tables on the host (shadow page tables)</li> +</ul> +<div class="section" id="shadow-page-tables"> +<h3>Shadow page tables<a class="headerlink" href="#shadow-page-tables" title="Permalink to this headline">¶</a></h3> +<p class="admonition-shadow-page-tables"> </p> +<img alt="../_images/ditaa-8632e22c6d89bd18f97c9cef127444486b5077df.png" src="../_images/ditaa-8632e22c6d89bd18f97c9cef127444486b5077df.png" /> +</div> +<div class="section" id="lazy-shadow-sync"> +<h3>Lazy shadow sync<a class="headerlink" href="#lazy-shadow-sync" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-lazy-shadow-sync simple"> +<li>Guest page tables changes are typically batched</li> +<li>To avoid repeated traps, checks and transformations map guest +page table entries with write access</li> +<li>Update the shadow page table when<ul> +<li>The TLB is flushed</li> +<li>In the host page fault handler</li> +</ul> +</li> +</ul> +</div> +</div> +<div class="section" id="i-o-emulation"> +<h2>I/O emulation<a class="headerlink" href="#i-o-emulation" title="Permalink to this headline">¶</a></h2> +<p class="admonition-i-o-emulation"> </p> +<img alt="../_images/ditaa-bb69666d75b9670e542682753fb8cc9b77ff8894.png" src="../_images/ditaa-bb69666d75b9670e542682753fb8cc9b77ff8894.png" /> +<div class="admonition-example-qemu-sifive-uart-emulation highlight-c"><div class="highlight"><pre><span></span><span class="cm">/*</span> +<span class="cm"> * QEMU model of the UART on the SiFive E300 and U500 series SOCs.</span> +<span class="cm"> *</span> +<span class="cm"> * Copyright (c) 2016 Stefan O'Rear</span> +<span class="cm"> *</span> +<span class="cm"> * This program is free software; you can redistribute it and/or modify it</span> +<span class="cm"> * under the terms and conditions of the GNU General Public License,</span> +<span class="cm"> * version 2 or later, as published by the Free Software Foundation.</span> +<span class="cm"> *</span> +<span class="cm"> * This program is distributed in the hope it will be useful, but WITHOUT</span> +<span class="cm"> * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or</span> +<span class="cm"> * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for</span> +<span class="cm"> * more details.</span> +<span class="cm"> *</span> +<span class="cm"> * You should have received a copy of the GNU General Public License along with</span> +<span class="cm"> * this program. If not, see <http://www.gnu.org/licenses/>.</span> +<span class="cm"> */</span> + +<span class="cp">#include</span> <span class="cpf">"qemu/osdep.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"qapi/error.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"qemu/log.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"chardev/char.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"chardev/char-fe.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"hw/irq.h"</span><span class="cp"></span> +<span class="cp">#include</span> <span class="cpf">"hw/char/sifive_uart.h"</span><span class="cp"></span> + +<span class="cm">/*</span> +<span class="cm"> * Not yet implemented:</span> +<span class="cm"> *</span> +<span class="cm"> * Transmit FIFO using "qemu/fifo8.h"</span> +<span class="cm"> */</span> + +<span class="cm">/* Returns the state of the IP (interrupt pending) register */</span> +<span class="k">static</span> <span class="kt">uint64_t</span> <span class="nf">uart_ip</span><span class="p">(</span><span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">uint64_t</span> <span class="n">ret</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + + <span class="kt">uint64_t</span> <span class="n">txcnt</span> <span class="o">=</span> <span class="n">SIFIVE_UART_GET_TXCNT</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">txctrl</span><span class="p">);</span> + <span class="kt">uint64_t</span> <span class="n">rxcnt</span> <span class="o">=</span> <span class="n">SIFIVE_UART_GET_RXCNT</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rxctrl</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">txcnt</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> + <span class="n">ret</span> <span class="o">|=</span> <span class="n">SIFIVE_UART_IP_TXWM</span><span class="p">;</span> + <span class="p">}</span> + <span class="k">if</span> <span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span> <span class="o">></span> <span class="n">rxcnt</span><span class="p">)</span> <span class="p">{</span> + <span class="n">ret</span> <span class="o">|=</span> <span class="n">SIFIVE_UART_IP_RXWM</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="n">ret</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">update_irq</span><span class="p">(</span><span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">cond</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="k">if</span> <span class="p">((</span><span class="n">s</span><span class="o">-></span><span class="n">ie</span> <span class="o">&</span> <span class="n">SIFIVE_UART_IE_TXWM</span><span class="p">)</span> <span class="o">||</span> + <span class="p">((</span><span class="n">s</span><span class="o">-></span><span class="n">ie</span> <span class="o">&</span> <span class="n">SIFIVE_UART_IE_RXWM</span><span class="p">)</span> <span class="o">&&</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span><span class="p">))</span> <span class="p">{</span> + <span class="n">cond</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> + <span class="p">}</span> + <span class="k">if</span> <span class="p">(</span><span class="n">cond</span><span class="p">)</span> <span class="p">{</span> + <span class="n">qemu_irq_raise</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">irq</span><span class="p">);</span> + <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> + <span class="n">qemu_irq_lower</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">irq</span><span class="p">);</span> + <span class="p">}</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">uint64_t</span> +<span class="nf">uart_read</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">,</span> <span class="n">hwaddr</span> <span class="n">addr</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">size</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">r</span><span class="p">;</span> + <span class="k">switch</span> <span class="p">(</span><span class="n">addr</span><span class="p">)</span> <span class="p">{</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_RXFIFO</span><span class="p">:</span> + <span class="k">if</span> <span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span><span class="p">)</span> <span class="p">{</span> + <span class="n">r</span> <span class="o">=</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> + <span class="n">memmove</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">,</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span> + <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span><span class="o">--</span><span class="p">;</span> + <span class="n">qemu_chr_fe_accept_input</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">);</span> + <span class="n">update_irq</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> + <span class="k">return</span> <span class="n">r</span><span class="p">;</span> + <span class="p">}</span> + <span class="k">return</span> <span class="mh">0x80000000</span><span class="p">;</span> + + <span class="k">case</span> <span class="nl">SIFIVE_UART_TXFIFO</span><span class="p">:</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="cm">/* Should check tx fifo */</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_IE</span><span class="p">:</span> + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">ie</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_IP</span><span class="p">:</span> + <span class="k">return</span> <span class="n">uart_ip</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_TXCTRL</span><span class="p">:</span> + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">txctrl</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_RXCTRL</span><span class="p">:</span> + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">rxctrl</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_DIV</span><span class="p">:</span> + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">div</span><span class="p">;</span> + <span class="p">}</span> + + <span class="n">qemu_log_mask</span><span class="p">(</span><span class="n">LOG_GUEST_ERROR</span><span class="p">,</span> <span class="s">"%s: bad read: addr=0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> + <span class="n">__func__</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">addr</span><span class="p">);</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> +<span class="nf">uart_write</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">,</span> <span class="n">hwaddr</span> <span class="n">addr</span><span class="p">,</span> + <span class="kt">uint64_t</span> <span class="n">val64</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">size</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + <span class="kt">uint32_t</span> <span class="n">value</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">ch</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span> + + <span class="k">switch</span> <span class="p">(</span><span class="n">addr</span><span class="p">)</span> <span class="p">{</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_TXFIFO</span><span class="p">:</span> + <span class="n">qemu_chr_fe_write</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">,</span> <span class="o">&</span><span class="n">ch</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> + <span class="n">update_irq</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> + <span class="k">return</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_IE</span><span class="p">:</span> + <span class="n">s</span><span class="o">-></span><span class="n">ie</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="n">update_irq</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> + <span class="k">return</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_TXCTRL</span><span class="p">:</span> + <span class="n">s</span><span class="o">-></span><span class="n">txctrl</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="k">return</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_RXCTRL</span><span class="p">:</span> + <span class="n">s</span><span class="o">-></span><span class="n">rxctrl</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="k">return</span><span class="p">;</span> + <span class="k">case</span> <span class="nl">SIFIVE_UART_DIV</span><span class="p">:</span> + <span class="n">s</span><span class="o">-></span><span class="n">div</span> <span class="o">=</span> <span class="n">val64</span><span class="p">;</span> + <span class="k">return</span><span class="p">;</span> + <span class="p">}</span> + <span class="n">qemu_log_mask</span><span class="p">(</span><span class="n">LOG_GUEST_ERROR</span><span class="p">,</span> <span class="s">"%s: bad write: addr=0x%x v=0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> + <span class="n">__func__</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">addr</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">value</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="k">const</span> <span class="n">MemoryRegionOps</span> <span class="n">uart_ops</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">read</span> <span class="o">=</span> <span class="n">uart_read</span><span class="p">,</span> + <span class="p">.</span><span class="n">write</span> <span class="o">=</span> <span class="n">uart_write</span><span class="p">,</span> + <span class="p">.</span><span class="n">endianness</span> <span class="o">=</span> <span class="n">DEVICE_NATIVE_ENDIAN</span><span class="p">,</span> + <span class="p">.</span><span class="n">valid</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">.</span><span class="n">min_access_size</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span> + <span class="p">.</span><span class="n">max_access_size</span> <span class="o">=</span> <span class="mi">4</span> + <span class="p">}</span> +<span class="p">};</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">uart_rx</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">,</span> <span class="k">const</span> <span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buf</span><span class="p">,</span> <span class="kt">int</span> <span class="n">size</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + + <span class="cm">/* Got a byte. */</span> + <span class="k">if</span> <span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span> <span class="o">>=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">))</span> <span class="p">{</span> + <span class="n">printf</span><span class="p">(</span><span class="s">"WARNING: UART dropped char.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="k">return</span><span class="p">;</span> + <span class="p">}</span> + <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">[</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="o">*</span><span class="n">buf</span><span class="p">;</span> + + <span class="n">update_irq</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">uart_can_rx</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + + <span class="k">return</span> <span class="n">s</span><span class="o">-></span><span class="n">rx_fifo_len</span> <span class="o"><</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">s</span><span class="o">-></span><span class="n">rx_fifo</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">uart_event</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">,</span> <span class="n">QEMUChrEvent</span> <span class="n">event</span><span class="p">)</span> +<span class="p">{</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">uart_be_change</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span> + + <span class="n">qemu_chr_fe_set_handlers</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">,</span> <span class="n">uart_can_rx</span><span class="p">,</span> <span class="n">uart_rx</span><span class="p">,</span> <span class="n">uart_event</span><span class="p">,</span> + <span class="n">uart_be_change</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">true</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="cm">/*</span> +<span class="cm"> * Create UART device.</span> +<span class="cm"> */</span> +<span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="nf">sifive_uart_create</span><span class="p">(</span><span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">address_space</span><span class="p">,</span> <span class="n">hwaddr</span> <span class="n">base</span><span class="p">,</span> + <span class="n">Chardev</span> <span class="o">*</span><span class="n">chr</span><span class="p">,</span> <span class="n">qemu_irq</span> <span class="n">irq</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">SiFiveUARTState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">g_malloc0</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">SiFiveUARTState</span><span class="p">));</span> + <span class="n">s</span><span class="o">-></span><span class="n">irq</span> <span class="o">=</span> <span class="n">irq</span><span class="p">;</span> + <span class="n">qemu_chr_fe_init</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">,</span> <span class="n">chr</span><span class="p">,</span> <span class="o">&</span><span class="n">error_abort</span><span class="p">);</span> + <span class="n">qemu_chr_fe_set_handlers</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">chr</span><span class="p">,</span> <span class="n">uart_can_rx</span><span class="p">,</span> <span class="n">uart_rx</span><span class="p">,</span> <span class="n">uart_event</span><span class="p">,</span> + <span class="n">uart_be_change</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">true</span><span class="p">);</span> + <span class="n">memory_region_init_io</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">mmio</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">&</span><span class="n">uart_ops</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> + <span class="n">TYPE_SIFIVE_UART</span><span class="p">,</span> <span class="n">SIFIVE_UART_MAX</span><span class="p">);</span> + <span class="n">memory_region_add_subregion</span><span class="p">(</span><span class="n">address_space</span><span class="p">,</span> <span class="n">base</span><span class="p">,</span> <span class="o">&</span><span class="n">s</span><span class="o">-></span><span class="n">mmio</span><span class="p">);</span> + <span class="k">return</span> <span class="n">s</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="paravirtualization"> +<h2>Paravirtualization<a class="headerlink" href="#paravirtualization" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-paravirtualization simple"> +<li>Change the guest OS so that it cooperates with the VMM<ul> +<li>CPU paravirtualization</li> +<li>MMU paravirtualization</li> +<li>I/O paravirtualization</li> +</ul> +</li> +<li>VMM exposes hypercalls for:<ul> +<li>activate / deactivate the interrupts</li> +<li>changing page tables</li> +<li>accessing virtualized peripherals</li> +</ul> +</li> +<li>VMM uses events to trigger interrupts in the VM</li> +</ul> +</div> +<div class="section" id="intel-vt-x"> +<h2>Intel VT-x<a class="headerlink" href="#intel-vt-x" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-intel-vt-x simple"> +<li>Hardware extension to transform x86 to the point it can be +virtualized "classically"</li> +<li>New execution mode: non-root mode</li> +<li>Each non-root mode instance uses a Virtual Machine Control +Structure (VMCS) to store its state</li> +<li>VMM runs in root mode</li> +<li>VM-entry and VM-exit are used to transition between the two modes</li> +</ul> +<div class="section" id="virtual-machine-control-structure"> +<h3>Virtual Machine Control Structure<a class="headerlink" href="#virtual-machine-control-structure" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-virtual-machine-control-structure simple"> +<li>Guest information: state of the virtual CPU</li> +<li>Host information: state of the physical CPU</li> +<li>Saved information:<ul> +<li>visible state: segment registers, CR3, IDTR, etc.</li> +<li>internal state</li> +</ul> +</li> +<li>VMCS can not be accessed directly but certain information can be +accessed with special instructions</li> +</ul> +</div> +<div class="section" id="vm-entry-exit"> +<h3>VM entry & exit<a class="headerlink" href="#vm-entry-exit" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-vm-entry-exit simple"> +<li>VM entry - new instructions that switches the CPU in non-root +mode and loads the VM state from a VMCS; host state is saved in +VMCS</li> +<li>Allows injecting interrupts and exceptions in the guest</li> +<li>VM exit will be automatically triggered based on the VMCS +configuration</li> +<li>When VM exit occurs host state is loaded from VMCS, guest state +is saved in VMCS</li> +</ul> +</div> +<div class="section" id="vm-execution-control-fields"> +<h3>VM execution control fields<a class="headerlink" href="#vm-execution-control-fields" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-vm-execution-control-fields simple"> +<li>Selects conditions which triggers a VM exit; examples:<ul> +<li>If an external interrupt is generated</li> +<li>If an external interrupt is generated and EFLAGS.IF is set</li> +<li>If CR0-CR4 registers are modified</li> +</ul> +</li> +<li>Exception bitmap - selects which exceptions will generate a VM +exit</li> +<li>IO bitmap - selects which I/O addresses (IN/OUT accesses) +generates a VM exit</li> +<li>MSR bitmaps - selects which RDMSR or WRMSR instructions will +generate a VM exit</li> +</ul> +</div> +</div> +<div class="section" id="extend-page-tables"> +<h2>Extend Page Tables<a class="headerlink" href="#extend-page-tables" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-extend-page-tables simple"> +<li>Reduces the complexity of MMU virtualization and improves +performance</li> +<li>Access to CR3, INVLPG and page faults do not require VM exit +anymore</li> +<li>The EPT page table is controlled by the VMM</li> +</ul> +<img alt="../_images/ditaa-cc9a2e995be74ee99646ea4bf0e551d766fa92ef.png" src="../_images/ditaa-cc9a2e995be74ee99646ea4bf0e551d766fa92ef.png" /> +<div class="section" id="vpid"> +<h3>VPID<a class="headerlink" href="#vpid" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-vpid simple"> +<li>VM entry and VM exit forces a TLB flush - loses VMM / VM translations</li> +<li>To avoid this issue a VPID (Virtual Processor ID) tag is +associated with each VM (VPID 0 is reserved for the VMM)</li> +<li>All TLB entries are tagged</li> +<li>At VM entry and exit just the entries associated with the tags +are flushed</li> +<li>When searching the TLB just the current VPID is used</li> +</ul> +</div> +</div> +<div class="section" id="i-o-virtualization"> +<h2>I/O virtualization<a class="headerlink" href="#i-o-virtualization" title="Permalink to this headline">¶</a></h2> +<blockquote> +<div><ul class="simple"> +<li>Direct access to hardware from a VM - in a controlled fashion<ul> +<li>Map the MMIO host directly to the guest</li> +<li>Forward interrupts</li> +</ul> +</li> +</ul> +</div></blockquote> +<img alt="../_images/ditaa-3901edd823cdc7a6f429ebc37cbc541e650abc96.png" class="admonition-i-o-virtualization" src="../_images/ditaa-3901edd823cdc7a6f429ebc37cbc541e650abc96.png" /> +<p>Instead of trapping MMIO as with emulated devices we can allow the +guest to access the MMIO directly by mapping through its page tables.</p> +<p>Interrupts from the device are handled by the host kernel and a signal +is send to the VMM which injects the interrupt to the guest just as +for the emulated devices.</p> +<p class="admonition-i-o-mmu">VT-d protects and translates VM physical addresses using an I/O +MMU (DMA remaping)</p> +<img alt="../_images/ditaa-d880751969de8642b2613caaca345d71acea4500.png" src="../_images/ditaa-d880751969de8642b2613caaca345d71acea4500.png" /> +<ul class="admonition-interrupt-posting simple"> +<li>Messsage Signaled Interrupts (MSI) = DMA writes to the host +address range of the IRQ controller (e.g. 0xFEExxxxx)</li> +<li>Low bits of the address and the data indicate which interrupt +vector to deliver to which CPU</li> +<li>Interrupt remapping table points to the virtual CPU (VMCS) that +should receive the interrupt</li> +<li>I/O MMU will trap the IRQ controller write and look it up in the +interrupt remmaping table<ul> +<li>if that virtual CPU is currently running it will take the +interrupt directly</li> +<li>otherwise a bit is set in a table (Posted Interrupt Descriptor +table) and the interrupt will be inject next time that vCPU is +run</li> +</ul> +</li> +</ul> +<img alt="../_images/ditaa-2cb0eb0056bb775d1446843d62241fd660662c96.png" class="admonition-i-o-virtualization" src="../_images/ditaa-2cb0eb0056bb775d1446843d62241fd660662c96.png" /> +<ul class="admonition-sr-iov simple"> +<li>Single Root - Input Output Virtualization</li> +<li>Physical device with multiple Ethernet ports will be shown as +multiple device on the PCI bus</li> +<li>Physical Function is used for the control and can be configured<ul> +<li>to present itself as a new PCI device</li> +<li>which VLAN to use</li> +</ul> +</li> +<li>The new virtual function is enumerated on the bus and can be +assigned to a particular guest</li> +</ul> +</div> +<div class="section" id="qemu"> +<h2>qemu<a class="headerlink" href="#qemu" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-qemu simple"> +<li>Uses binary translation via Tiny Code Generator (TCG) for +efficient emulation</li> +<li>Supports different target and host architectures (e.g. running +ARM VMs on x86)</li> +<li>Both process and full system level emulation</li> +<li>MMU emulation</li> +<li>I/O emulation</li> +<li>Can be used with KVM for accelerated virtualization</li> +</ul> +</div> +<div class="section" id="kvm"> +<h2>KVM<a class="headerlink" href="#kvm" title="Permalink to this headline">¶</a></h2> +<img alt="../_images/ditaa-f8fcc760ef5dad50d1038ed3426d0fcce12fd3e6.png" class="admonition-kvm" src="../_images/ditaa-f8fcc760ef5dad50d1038ed3426d0fcce12fd3e6.png" /> +<ul class="admonition-kvm simple"> +<li>Linux device driver for hardware virtualization (e.g. Intel VT-x, SVM)</li> +<li>IOCTL based interface for managing and running virtual CPUs</li> +<li>VMM components implemented inside the Linux kernel +(e.g. interrupt controller, timers)</li> +<li>Shadow page tables or EPT if present</li> +<li>Uses qemu or virtio for I/O virtualization</li> +</ul> +</div> +<div class="section" id="type-1-vs-type-2-hypervisors"> +<h2>Type 1 vs Type 2 Hypervisors<a class="headerlink" href="#type-1-vs-type-2-hypervisors" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-xen simple"> +<li>Type 1 = Bare Metal Hypervisor</li> +<li>Type 2 = Hypervisor embedded in an exist kernel / OS</li> +</ul> +</div> +<div class="section" id="xen"> +<h2>Xen<a class="headerlink" href="#xen" title="Permalink to this headline">¶</a></h2> +<img alt="../_images/xen-overview1.png" class="admonition-xen" src="../_images/xen-overview1.png" /> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lec11-arch.html" class="btn btn-neutral float-left" title="SO2 Lecture 11 - Architecture Layer" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lab1-intro.html" class="btn btn-neutral float-right" title="SO2 Lab 01 - Introduction" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec2-syscalls-slides.html b/refs/pull/405/merge/so2/lec2-syscalls-slides.html new file mode 100644 index 00000000..93ccc076 --- /dev/null +++ b/refs/pull/405/merge/so2/lec2-syscalls-slides.html @@ -0,0 +1,540 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>SO2 Lecture 02 - System calls — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="up" title="Operating Systems 2" href="index.html" /> + <link rel="next" title="SO2 Lecture 03 - Processes" href="lec3-processes.html" /> + <link rel="prev" title="SO2 Lecture 01 - Course overview and Linux kernel introduction" href="lec1-intro.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-so2-lecture-02-system-calls slide level-1"> + +<h1>SO2 Lecture 02 - System calls</h1> + + + + + +</article> +<article class="admonition-system-calls slide level-2"> + +<h2>System Calls</h2> + +<ul class="simple"> +<li>Linux system calls implementation</li> +<li>VDSO and virtual syscalls</li> +<li>Accessing user space from system calls</li> +</ul> + + + + +</article> +<article class="admonition-system-calls-as-kernel-services slide level-2"> + +<h2>System Calls as Kernel services</h2> + +<p> </p> +<img alt="../_images/ditaa-e76e44cad2e92f2134ab77f6a09605b29524d039.png" src="../_images/ditaa-e76e44cad2e92f2134ab77f6a09605b29524d039.png" /> + + + + +</article> +<article class="admonition-system-call-setup slide level-2"> + +<h2>System Call Setup</h2> + +<ul class="simple"> +<li>setup information to identify the system call and its parameters</li> +<li>trigger a kernel mode switch</li> +<li>retrieve the result of the system call</li> +</ul> + + + + +</article> +<article class="admonition-linux-system-call-setup slide level-2"> + +<h2>Linux system call setup</h2> + +<ul class="simple"> +<li>System calls are identified by numbers</li> +<li>The parameters for system calls are machine word sized (32 or 64 +bit) and they are limited to a maximum of 6</li> +<li>Uses registers to store them both (e.g. for 32bit x86: EAX for +system call and EBX, ECX, EDX, ESI, EDI, EBP for parameters)</li> +</ul> + + + + +</article> +<article class="admonition-example-of-linux-system-call-setup-and-handling slide level-2"> + +<h2>Example of Linux system call setup and handling</h2> + +<img alt="../_images/ditaa-eeb919cd078d0ba5021028fa628bb47d7d6866e2.png" src="../_images/ditaa-eeb919cd078d0ba5021028fa628bb47d7d6866e2.png" /> + + + + +</article> +<article class="admonition-linux-system-call-dispatcher slide level-2"> + +<h2>Linux System Call Dispatcher</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* Handles int $0x80 */</span> +<span class="n">__visible</span> <span class="kt">void</span> <span class="nf">do_int80_syscall_32</span><span class="p">(</span><span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">enter_from_user_mode</span><span class="p">();</span> + <span class="n">local_irq_enable</span><span class="p">();</span> + <span class="n">do_syscall_32_irqs_on</span><span class="p">(</span><span class="n">regs</span><span class="p">);</span> +<span class="p">}</span> + +<span class="cm">/* simplified version of the Linux x86 32bit System Call Dispatcher */</span> +<span class="k">static</span> <span class="n">__always_inline</span> <span class="kt">void</span> <span class="nf">do_syscall_32_irqs_on</span><span class="p">(</span><span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">nr</span> <span class="o">=</span> <span class="n">regs</span><span class="o">-></span><span class="n">orig_ax</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">nr</span> <span class="o"><</span> <span class="n">IA32_NR_syscalls</span><span class="p">)</span> + <span class="n">regs</span><span class="o">-></span><span class="n">ax</span> <span class="o">=</span> <span class="n">ia32_sys_call_table</span><span class="p">[</span><span class="n">nr</span><span class="p">](</span><span class="n">regs</span><span class="o">-></span><span class="n">bx</span><span class="p">,</span> <span class="n">regs</span><span class="o">-></span><span class="n">cx</span><span class="p">,</span> + <span class="n">regs</span><span class="o">-></span><span class="n">dx</span><span class="p">,</span> <span class="n">regs</span><span class="o">-></span><span class="n">si</span><span class="p">,</span> + <span class="n">regs</span><span class="o">-></span><span class="n">di</span><span class="p">,</span> <span class="n">regs</span><span class="o">-></span><span class="n">bp</span><span class="p">);</span> + <span class="n">syscall_return_slowpath</span><span class="p">(</span><span class="n">regs</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-inspecting-dup2-system-call slide level-2"> + +<h2>Inspecting dup2 system call</h2> + +<p> </p> +<asciinema-player src="../_images/syscalls-inspection.cast"></asciinema-player> + + + +</article> +<article class="admonition-system-call-flow-summary slide level-2"> + +<h2>System Call Flow Summary</h2> + +<ul class="simple"> +<li>The application is setting up the system call number and +parameters and it issues a trap instruction</li> +<li>The execution mode switches from user to kernel; the CPU switches +to a kernel stack; the user stack and the return address to user +space is saved on the kernel stack</li> +<li>The kernel entry point saves registers on the kernel stack</li> +<li>The system call dispatcher identifies the system call function +and runs it</li> +<li>The user space registers are restored and execution is switched +back to user (e.g. calling IRET)</li> +<li>The user space application resumes</li> +</ul> + + + + +</article> +<article class="admonition-system-call-table slide level-2"> + +<h2>System Call Table</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define __SYSCALL_I386(nr, sym, qual) [nr] = sym,</span> + +<span class="k">const</span> <span class="n">sys_call_ptr_t</span> <span class="n">ia32_sys_call_table</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">[</span><span class="mi">0</span> <span class="p">...</span> <span class="n">__NR_syscall_compat_max</span><span class="p">]</span> <span class="o">=</span> <span class="o">&</span><span class="n">sys_ni_syscall</span><span class="p">,</span> + <span class="cp">#include</span> <span class="cpf"><asm/syscalls_32.h></span><span class="cp"></span> +<span class="p">};</span> +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">sys_restart_syscall</span><span class="p">)</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">sys_exit</span><span class="p">)</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">sys_fork</span><span class="p">)</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">sys_read</span><span class="p">)</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="n">sys_write</span><span class="p">)</span> +<span class="cp">#ifdef CONFIG_X86_32</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">sys_open</span><span class="p">)</span> +<span class="cp">#else</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">compat_sys_open</span><span class="p">)</span> +<span class="cp">#endif</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">6</span><span class="p">,</span> <span class="n">sys_close</span><span class="p">)</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-system-calls-pointer-parameters slide level-2"> + +<h2>System Calls Pointer Parameters</h2> + +<ul class="simple"> +<li>Never allow pointers to kernel-space</li> +<li>Check for invalid pointers</li> +</ul> + + + + +</article> +<article class="admonition-pointers-to-kernel-space slide level-2"> + +<h2>Pointers to Kernel Space</h2> + +<ul class="simple"> +<li>User access to kernel data if allowed in a write system call</li> +<li>User corrupting kernel data if allowed in a read system call</li> +</ul> + + + + +</article> +<article class="admonition-invalid-pointers-handling-approaches slide level-2"> + +<h2>Invalid pointers handling approaches</h2> + +<ul class="simple"> +<li>Check the pointer against the user address space before using it, +or</li> +<li>Avoid checking the pointer and rely on the MMU to detect when the +pointer is invalid and use the page fault handler to determine +that the pointer was invalid</li> +</ul> + + + + +</article> +<article class="admonition-page-fault-handling slide level-2"> + +<h2>Page fault handling</h2> + +<blockquote> +<div><ul class="simple"> +<li>Copy on write, demand paging, swapping: both the fault and +faulting addresses are in user space; the fault address is +valid (checked against the user address space)</li> +<li>Invalid pointer used in system call: the faulting address is +in kernel space; the fault address is in user space and it is +invalid</li> +<li>Kernel bug (kernel accesses invalid pointer): same as above</li> +</ul> +</div></blockquote> + + + + +</article> +<article class="admonition-marking-kernel-code-that-accesses-user-space slide level-2"> + +<h2>Marking kernel code that accesses user space</h2> + +<ul class="simple"> +<li>The exact instructions that access user space are recorded in a +table (exception table)</li> +<li>When a page fault occurs the faulting address is checked against +this table</li> +</ul> + + + + +</article> +<article class="admonition-cost-analysis-for-pointer-checks-vs-fault-handling slide level-2"> + +<h2>Cost analysis for pointer checks vs fault handling</h2> + +<table border="1" class="docutils"> +<colgroup> +<col width="28%" /> +<col width="35%" /> +<col width="37%" /> +</colgroup> +<thead valign="bottom"> +<tr class="row-odd"><th class="head">Cost</th> +<th class="head">Pointer checks</th> +<th class="head">Fault handling</th> +</tr> +</thead> +<tbody valign="top"> +<tr class="row-even"><td>Valid address</td> +<td>address space search</td> +<td>negligible</td> +</tr> +<tr class="row-odd"><td>Invalid address</td> +<td>address space search</td> +<td>exception table search</td> +</tr> +</tbody> +</table> + + + + +</article> +<article class="admonition-virtual-dynamic-shared-object-vdso slide level-2"> + +<h2>Virtual Dynamic Shared Object (VDSO)</h2> + +<ul class="simple"> +<li>a stream of instructions to issue the system call is generated by +the kernel in a special memory area (formatted as an ELF shared +object)</li> +<li>that memory area is mapped towards the end of the user address +space</li> +<li>libc searches for VDSO and if present will use it to issue the +system call</li> +</ul> + + + + +</article> +<article class="admonition-inspecting-vdso slide level-2"> + +<h2>Inspecting VDSO</h2> + +<p> </p> +<asciinema-player src="../_images/syscalls-vdso.cast"></asciinema-player> + + + +</article> +<article class="admonition-virtual-system-calls-vsyscalls slide level-2"> + +<h2>Virtual System Calls (vsyscalls)</h2> + +<ul class="simple"> +<li>"System calls" that run directly from user space, part of the VDSO</li> +<li>Static data (e.g. getpid())</li> +<li>Dynamic data update by the kernel a in RW map of the VDSO +(e.g. gettimeofday(), time(), )</li> +</ul> + + + + +</article> +<article class="admonition-accessing-user-space-from-system-calls slide level-2"> + +<h2>Accessing user space from system calls</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* OK: return -EFAULT if user_ptr is invalid */</span> +<span class="k">if</span> <span class="p">(</span><span class="n">copy_from_user</span><span class="p">(</span><span class="o">&</span><span class="n">kernel_buffer</span><span class="p">,</span> <span class="n">user_ptr</span><span class="p">,</span> <span class="n">size</span><span class="p">))</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EFAULT</span><span class="p">;</span> + +<span class="cm">/* NOK: only works if user_ptr is valid otherwise crashes kernel */</span> +<span class="n">memcpy</span><span class="p">(</span><span class="o">&</span><span class="n">kernel_buffer</span><span class="p">,</span> <span class="n">user_ptr</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-get-user-implementation slide level-2"> + +<h2>get_user implementation</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define get_user(x, ptr) \</span> +<span class="cp">({ \</span> +<span class="cp"> int __ret_gu; \</span> +<span class="cp"> register __inttype(*(ptr)) __val_gu asm("%"_ASM_DX); \</span> +<span class="cp"> __chk_user_ptr(ptr); \</span> +<span class="cp"> might_fault(); \</span> +<span class="cp"> asm volatile("call __get_user_%P4" \</span> +<span class="cp"> : "=a" (__ret_gu), "=r" (__val_gu), \</span> +<span class="cp"> ASM_CALL_CONSTRAINT \</span> +<span class="cp"> : "0" (ptr), "i" (sizeof(*(ptr)))); \</span> +<span class="cp"> (x) = (__force __typeof__(*(ptr))) __val_gu; \</span> +<span class="cp"> __builtin_expect(__ret_gu, 0); \</span> +<span class="cp">})</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-get-user-pseudo-code slide level-2"> + +<h2>get_user pseudo code</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define get_user(x, ptr) \</span> +<span class="cp"> movl ptr, %eax \</span> +<span class="cp"> call __get_user_1 \</span> +<span class="cp"> movl %edx, x \</span> +<span class="cp"> movl %eax, result \</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-get-user-1-implementation slide level-2"> + +<h2>get_user_1 implementation</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>.text +ENTRY(__get_user_1) + mov PER_CPU_VAR(current_task), %_ASM_DX + cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX + jae bad_get_user + ASM_STAC +1: movzbl (%_ASM_AX),%edx + xor %eax,%eax + ASM_CLAC + ret +ENDPROC(__get_user_1) + +bad_get_user: + xor %edx,%edx + mov $(-EFAULT),%_ASM_AX + ASM_CLAC + ret +END(bad_get_user) + +_ASM_EXTABLE(1b,bad_get_user) +</pre></div> +</div> + + + + +</article> +<article class="admonition-exception-table-entry slide level-2"> + +<h2>Exception table entry</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* Exception table entry */</span> +<span class="cp"># define _ASM_EXTABLE_HANDLE(from, to, handler) \</span> +<span class="cp"> .pushsection "__ex_table","a" ; \</span> +<span class="cp"> .balign 4 ; \</span> +<span class="cp"> .long (from) - . ; \</span> +<span class="cp"> .long (to) - . ; \</span> +<span class="cp"> .long (handler) - . ; \</span> +<span class="cp"> .popsection</span> + +<span class="cp"># define _ASM_EXTABLE(from, to) \</span> +<span class="cp"> _ASM_EXTABLE_HANDLE(from, to, ex_handler_default)</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-exception-table-building slide level-2"> + +<h2>Exception table building</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define EXCEPTION_TABLE(align) \</span> +<span class="cp"> . = ALIGN(align); \</span> +<span class="cp"> __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { \</span> +<span class="cp"> VMLINUX_SYMBOL(__start___ex_table) = .; \</span> +<span class="cp"> KEEP(*(__ex_table)) \</span> +<span class="cp"> VMLINUX_SYMBOL(__stop___ex_table) = .; \</span> +<span class="cp"> }</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-exception-table-handling slide level-2"> + +<h2>Exception table handling</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">bool</span> <span class="nf">ex_handler_default</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">exception_table_entry</span> <span class="o">*</span><span class="n">fixup</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">,</span> <span class="kt">int</span> <span class="n">trapnr</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">regs</span><span class="o">-></span><span class="n">ip</span> <span class="o">=</span> <span class="n">ex_fixup_addr</span><span class="p">(</span><span class="n">fixup</span><span class="p">);</span> + <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">int</span> <span class="nf">fixup_exception</span><span class="p">(</span><span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">,</span> <span class="kt">int</span> <span class="n">trapnr</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">exception_table_entry</span> <span class="o">*</span><span class="n">e</span><span class="p">;</span> + <span class="n">ex_handler_t</span> <span class="n">handler</span><span class="p">;</span> + + <span class="n">e</span> <span class="o">=</span> <span class="n">search_exception_tables</span><span class="p">(</span><span class="n">regs</span><span class="o">-></span><span class="n">ip</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">e</span><span class="p">)</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> + + <span class="n">handler</span> <span class="o">=</span> <span class="n">ex_fixup_handler</span><span class="p">(</span><span class="n">e</span><span class="p">);</span> + <span class="k">return</span> <span class="n">handler</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">regs</span><span class="p">,</span> <span class="n">trapnr</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec2-syscalls.html b/refs/pull/405/merge/so2/lec2-syscalls.html new file mode 100644 index 00000000..ededaa78 --- /dev/null +++ b/refs/pull/405/merge/so2/lec2-syscalls.html @@ -0,0 +1,577 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lecture 02 - System calls — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lecture 03 - Processes" href="lec3-processes.html" /> + <link rel="prev" title="SO2 Lecture 01 - Course overview and Linux kernel introduction" href="lec1-intro.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lecture 02 - System calls</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="#linux-system-calls-implementation">Linux system calls implementation</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#system-call-table">System call table</a></li> +<li class="toctree-l4"><a class="reference internal" href="#system-call-parameters-handling">System call parameters handling</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#virtual-dynamic-shared-object-vdso">Virtual Dynamic Shared Object (VDSO)</a></li> +<li class="toctree-l3"><a class="reference internal" href="#accessing-user-space-from-system-calls">Accessing user space from system calls</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lecture 02 - System calls</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lec2-syscalls.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lecture-02-system-calls"> +<h1>SO2 Lecture 02 - System calls<a class="headerlink" href="#so2-lecture-02-system-calls" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="lec2-syscalls-slides.html">View slides</a></p> +<span class="admonition-so2-lecture-02-system-calls"></span><div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-system-calls simple"> +<li>Linux system calls implementation</li> +<li>VDSO and virtual syscalls</li> +<li>Accessing user space from system calls</li> +</ul> +</div> +<div class="section" id="linux-system-calls-implementation"> +<h2>Linux system calls implementation<a class="headerlink" href="#linux-system-calls-implementation" title="Permalink to this headline">¶</a></h2> +<p>At a high level system calls are "services" offered by the kernel to +user applications and they resemble library APIs in that they are +described as a function call with a name, parameters, and return value.</p> +<p class="admonition-system-calls-as-kernel-services"> </p> +<img alt="../_images/ditaa-e76e44cad2e92f2134ab77f6a09605b29524d039.png" src="../_images/ditaa-e76e44cad2e92f2134ab77f6a09605b29524d039.png" /> +<p>However, on a closer look, we can see that system calls are actually +not function calls, but specific assembly instructions (architecture +and kernel specific) that do the following:</p> +<ul class="admonition-system-call-setup simple"> +<li>setup information to identify the system call and its parameters</li> +<li>trigger a kernel mode switch</li> +<li>retrieve the result of the system call</li> +</ul> +<p>In Linux, system calls are identified by numbers and the parameters +for system calls are machine word sized (32 or 64 bit). There can be a +maximum of 6 system call parameters. Both the system call number and +the parameters are stored in certain registers.</p> +<p>For example, on 32bit x86 architecture, the system call identifier is +stored in the EAX register, while parameters in registers EBX, ECX, +EDX, ESI, EDI, EBP.</p> +<span class="admonition-linux-system-call-setup"></span><p>System libraries (e.g. libc) offers functions that implement the +actual system calls in order to make it easier for applications to use +them.</p> +<p>When a user to kernel mode transition occurs, the execution flow is +interrupted and it is transferred to a kernel entry point. This is +similar to how interrupts and exceptions are handled (in fact on some +architectures this transition happens as a result of an exception).</p> +<p>The system call entry point will save registers (which contains values +from user space, including system call number and system call +parameters) on stack and then it will continue with executing the +system call dispatcher.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">During the user - kernel mode transition the stack is also +switched from the user stack to the kernel stack. This is +explained in more details in the interrupts lecture.</p> +</div> +<img alt="../_images/ditaa-eeb919cd078d0ba5021028fa628bb47d7d6866e2.png" class="admonition-example-of-linux-system-call-setup-and-handling" src="../_images/ditaa-eeb919cd078d0ba5021028fa628bb47d7d6866e2.png" /> +<p>The purpose of the system call dispatcher is to verify the system call +number and run the kernel function associated with the system call.</p> +<div class="admonition-linux-system-call-dispatcher highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* Handles int $0x80 */</span> +<span class="n">__visible</span> <span class="kt">void</span> <span class="nf">do_int80_syscall_32</span><span class="p">(</span><span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">enter_from_user_mode</span><span class="p">();</span> + <span class="n">local_irq_enable</span><span class="p">();</span> + <span class="n">do_syscall_32_irqs_on</span><span class="p">(</span><span class="n">regs</span><span class="p">);</span> +<span class="p">}</span> + +<span class="cm">/* simplified version of the Linux x86 32bit System Call Dispatcher */</span> +<span class="k">static</span> <span class="n">__always_inline</span> <span class="kt">void</span> <span class="nf">do_syscall_32_irqs_on</span><span class="p">(</span><span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">nr</span> <span class="o">=</span> <span class="n">regs</span><span class="o">-></span><span class="n">orig_ax</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">nr</span> <span class="o"><</span> <span class="n">IA32_NR_syscalls</span><span class="p">)</span> + <span class="n">regs</span><span class="o">-></span><span class="n">ax</span> <span class="o">=</span> <span class="n">ia32_sys_call_table</span><span class="p">[</span><span class="n">nr</span><span class="p">](</span><span class="n">regs</span><span class="o">-></span><span class="n">bx</span><span class="p">,</span> <span class="n">regs</span><span class="o">-></span><span class="n">cx</span><span class="p">,</span> + <span class="n">regs</span><span class="o">-></span><span class="n">dx</span><span class="p">,</span> <span class="n">regs</span><span class="o">-></span><span class="n">si</span><span class="p">,</span> + <span class="n">regs</span><span class="o">-></span><span class="n">di</span><span class="p">,</span> <span class="n">regs</span><span class="o">-></span><span class="n">bp</span><span class="p">);</span> + <span class="n">syscall_return_slowpath</span><span class="p">(</span><span class="n">regs</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<p>To demonstrate the system call flow we are going to use the virtual +machine setup, attach gdb to a running kernel, add a breakpoint to the +dup2 system call and inspect the state.</p> +<p class="admonition-inspecting-dup2-system-call"> </p> +<asciinema-player src="../_images/syscalls-inspection.cast"></asciinema-player><p>In summary, this is what happens during a system call:</p> +<ul class="admonition-system-call-flow-summary simple"> +<li>The application is setting up the system call number and +parameters and it issues a trap instruction</li> +<li>The execution mode switches from user to kernel; the CPU switches +to a kernel stack; the user stack and the return address to user +space is saved on the kernel stack</li> +<li>The kernel entry point saves registers on the kernel stack</li> +<li>The system call dispatcher identifies the system call function +and runs it</li> +<li>The user space registers are restored and execution is switched +back to user (e.g. calling IRET)</li> +<li>The user space application resumes</li> +</ul> +<div class="section" id="system-call-table"> +<h3>System call table<a class="headerlink" href="#system-call-table" title="Permalink to this headline">¶</a></h3> +<p>The system call table is what the system call dispatcher uses to map +system call numbers to kernel functions:</p> +<div class="admonition-system-call-table highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define __SYSCALL_I386(nr, sym, qual) [nr] = sym,</span> + +<span class="k">const</span> <span class="n">sys_call_ptr_t</span> <span class="n">ia32_sys_call_table</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> + <span class="p">[</span><span class="mi">0</span> <span class="p">...</span> <span class="n">__NR_syscall_compat_max</span><span class="p">]</span> <span class="o">=</span> <span class="o">&</span><span class="n">sys_ni_syscall</span><span class="p">,</span> + <span class="cp">#include</span> <span class="cpf"><asm/syscalls_32.h></span><span class="cp"></span> +<span class="p">};</span> +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">sys_restart_syscall</span><span class="p">)</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">sys_exit</span><span class="p">)</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">sys_fork</span><span class="p">)</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">sys_read</span><span class="p">)</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="n">sys_write</span><span class="p">)</span> +<span class="cp">#ifdef CONFIG_X86_32</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">sys_open</span><span class="p">)</span> +<span class="cp">#else</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">compat_sys_open</span><span class="p">)</span> +<span class="cp">#endif</span> +<span class="n">__SYSCALL_I386</span><span class="p">(</span><span class="mi">6</span><span class="p">,</span> <span class="n">sys_close</span><span class="p">)</span> +</pre></div> +</div> +</div> +<div class="section" id="system-call-parameters-handling"> +<h3>System call parameters handling<a class="headerlink" href="#system-call-parameters-handling" title="Permalink to this headline">¶</a></h3> +<p>Handling system call parameters is tricky. Since these values are +setup by user space, the kernel can not assume correctness and must +always verify them thoroughly.</p> +<p>Pointers have a few important special cases that must be checked:</p> +<ul class="admonition-system-calls-pointer-parameters simple"> +<li>Never allow pointers to kernel-space</li> +<li>Check for invalid pointers</li> +</ul> +<p>Since system calls are executed in kernel mode, they have access to +kernel space and if pointers are not properly checked user +applications might get read or write access to kernel space.</p> +<p>For example, let's consider the case where such a check is not made for +the read or write system calls. If the user passes a kernel-space +pointer to a write system call then it can get access to kernel data +by later reading the file. If it passes a kernel-space pointer to a +read system call then it can corrupt kernel memory.</p> +<span class="admonition-pointers-to-kernel-space"></span><p>Likewise, if a pointer passed by the application is invalid +(e.g. unmapped, read-only for cases where it is used for writing), it +could "crash" the kernel. Two approaches could be used:</p> +<ul class="admonition-invalid-pointers-handling-approaches simple"> +<li>Check the pointer against the user address space before using it, +or</li> +<li>Avoid checking the pointer and rely on the MMU to detect when the +pointer is invalid and use the page fault handler to determine +that the pointer was invalid</li> +</ul> +<p>Although it sounds tempting, the second approach is not that easy to +implement. The page fault handler uses the fault address (the address +that was accessed), the faulting address (the address of the +instruction that did the access) and information from the user address +space to determine the cause:</p> +<blockquote class="admonition-page-fault-handling"> +<div><ul class="simple"> +<li>Copy on write, demand paging, swapping: both the fault and +faulting addresses are in user space; the fault address is +valid (checked against the user address space)</li> +<li>Invalid pointer used in system call: the faulting address is +in kernel space; the fault address is in user space and it is +invalid</li> +<li>Kernel bug (kernel accesses invalid pointer): same as above</li> +</ul> +</div></blockquote> +<p>But in the last two cases we don't have enough information to +determine the cause of the fault.</p> +<p>In order to solve this issue, Linux uses special APIs (e.g +<code class="xref c c-func docutils literal"><span class="pre">copy_to_user()</span></code>) to accesses user space that are specially +crafted:</p> +<ul class="admonition-marking-kernel-code-that-accesses-user-space simple"> +<li>The exact instructions that access user space are recorded in a +table (exception table)</li> +<li>When a page fault occurs the faulting address is checked against +this table</li> +</ul> +<p>Although the fault handling case may be more costly overall depending +on the address space vs exception table size, and it is more complex, +it is optimized for the common case and that is why it is preferred +and used in Linux.</p> +<table border="1" class="admonition-cost-analysis-for-pointer-checks-vs-fault-handling docutils"> +<colgroup> +<col width="28%" /> +<col width="35%" /> +<col width="37%" /> +</colgroup> +<thead valign="bottom"> +<tr class="row-odd"><th class="head">Cost</th> +<th class="head">Pointer checks</th> +<th class="head">Fault handling</th> +</tr> +</thead> +<tbody valign="top"> +<tr class="row-even"><td>Valid address</td> +<td>address space search</td> +<td>negligible</td> +</tr> +<tr class="row-odd"><td>Invalid address</td> +<td>address space search</td> +<td>exception table search</td> +</tr> +</tbody> +</table> +</div> +</div> +<div class="section" id="virtual-dynamic-shared-object-vdso"> +<h2>Virtual Dynamic Shared Object (VDSO)<a class="headerlink" href="#virtual-dynamic-shared-object-vdso" title="Permalink to this headline">¶</a></h2> +<p>The VDSO mechanism was born out of the necessity of optimizing the +system call implementation, in a way that does not impact libc with +having to track the CPU capabilities in conjunction with the kernel +version.</p> +<p>For example, x86 has two ways of issuing system calls: int 0x80 and +sysenter. The latter is significantly faster so it should be used when +available. However, it is only available for processors newer than +Pentium II and only for kernel versions greater than 2.6.</p> +<p>With VDSO the system call interface is decided by the kernel:</p> +<ul class="admonition-virtual-dynamic-shared-object-vdso simple"> +<li>a stream of instructions to issue the system call is generated by +the kernel in a special memory area (formatted as an ELF shared +object)</li> +<li>that memory area is mapped towards the end of the user address +space</li> +<li>libc searches for VDSO and if present will use it to issue the +system call</li> +</ul> +<p class="admonition-inspecting-vdso"> </p> +<asciinema-player src="../_images/syscalls-vdso.cast"></asciinema-player><p>An interesting development of the VDSO is the virtual system calls +(vsyscalls) which run directly from user space. These vsyscalls are +also part of VDSO and they are accessing data from the VDSO page that +is either static or modified by the kernel in a separate read-write +map of the VDSO page. Examples of system calls that can be implemented +as vsyscalls are: getpid or gettimeofday.</p> +<ul class="admonition-virtual-system-calls-vsyscalls simple"> +<li>"System calls" that run directly from user space, part of the VDSO</li> +<li>Static data (e.g. getpid())</li> +<li>Dynamic data update by the kernel a in RW map of the VDSO +(e.g. gettimeofday(), time(), )</li> +</ul> +</div> +<div class="section" id="accessing-user-space-from-system-calls"> +<h2>Accessing user space from system calls<a class="headerlink" href="#accessing-user-space-from-system-calls" title="Permalink to this headline">¶</a></h2> +<p>As we mentioned earlier, user space must be accessed with special APIs +(<code class="xref c c-func docutils literal"><span class="pre">get_user()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">put_user()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">copy_from_user()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">copy_to_user()</span></code>) that check whether the pointer is in user space +and also handle the fault if the pointer is invalid. In case of invalid +pointers, they return a non-zero value.</p> +<div class="admonition-accessing-user-space-from-system-calls highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* OK: return -EFAULT if user_ptr is invalid */</span> +<span class="k">if</span> <span class="p">(</span><span class="n">copy_from_user</span><span class="p">(</span><span class="o">&</span><span class="n">kernel_buffer</span><span class="p">,</span> <span class="n">user_ptr</span><span class="p">,</span> <span class="n">size</span><span class="p">))</span> + <span class="k">return</span> <span class="o">-</span><span class="n">EFAULT</span><span class="p">;</span> + +<span class="cm">/* NOK: only works if user_ptr is valid otherwise crashes kernel */</span> +<span class="n">memcpy</span><span class="p">(</span><span class="o">&</span><span class="n">kernel_buffer</span><span class="p">,</span> <span class="n">user_ptr</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span> +</pre></div> +</div> +<p>Let's examine the simplest API, get_user, as implemented for x86:</p> +<div class="admonition-get-user-implementation highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define get_user(x, ptr) \</span> +<span class="cp">({ \</span> +<span class="cp"> int __ret_gu; \</span> +<span class="cp"> register __inttype(*(ptr)) __val_gu asm("%"_ASM_DX); \</span> +<span class="cp"> __chk_user_ptr(ptr); \</span> +<span class="cp"> might_fault(); \</span> +<span class="cp"> asm volatile("call __get_user_%P4" \</span> +<span class="cp"> : "=a" (__ret_gu), "=r" (__val_gu), \</span> +<span class="cp"> ASM_CALL_CONSTRAINT \</span> +<span class="cp"> : "0" (ptr), "i" (sizeof(*(ptr)))); \</span> +<span class="cp"> (x) = (__force __typeof__(*(ptr))) __val_gu; \</span> +<span class="cp"> __builtin_expect(__ret_gu, 0); \</span> +<span class="cp">})</span> +</pre></div> +</div> +<p>The implementation uses inline assembly, which allows inserting ASM +sequences in C code and also handles access to/from variables in the +ASM code.</p> +<p>Based on the type size of the x variable, one of __get_user_1, +__get_user_2 or __get_user_4 will be called. Also, before executing +the assembly call, ptr will be moved to the first register EAX while +after the completion of assembly part the value of EAX will be moved +to __ret_gu and the EDX register will be moved to __val_gu.</p> +<p>It is equivalent to the following pseudo code:</p> +<div class="admonition-get-user-pseudo-code highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define get_user(x, ptr) \</span> +<span class="cp"> movl ptr, %eax \</span> +<span class="cp"> call __get_user_1 \</span> +<span class="cp"> movl %edx, x \</span> +<span class="cp"> movl %eax, result \</span> +</pre></div> +</div> +<p>The __get_user_1 implementation for x86 is the following:</p> +<div class="admonition-get-user-1-implementation highlight-none"><div class="highlight"><pre><span></span>.text +ENTRY(__get_user_1) + mov PER_CPU_VAR(current_task), %_ASM_DX + cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX + jae bad_get_user + ASM_STAC +1: movzbl (%_ASM_AX),%edx + xor %eax,%eax + ASM_CLAC + ret +ENDPROC(__get_user_1) + +bad_get_user: + xor %edx,%edx + mov $(-EFAULT),%_ASM_AX + ASM_CLAC + ret +END(bad_get_user) + +_ASM_EXTABLE(1b,bad_get_user) +</pre></div> +</div> +<p>The first two statements check the pointer (which is stored in EDX) +with the addr_limit field of the current task (process) descriptor to +make sure that we don't have a pointer to kernel space.</p> +<p>Then, SMAP is disabled, to allow access to user from kernel, and the +access to user space is done with the instruction at the 1: label. EAX +is then zeroed to mark success, SMAP is enabled, and the call returns.</p> +<p>The movzbl instruction is the one that does the access to user space +and its address is captured with the 1: label and stored in a special +section:</p> +<div class="admonition-exception-table-entry highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* Exception table entry */</span> +<span class="cp"># define _ASM_EXTABLE_HANDLE(from, to, handler) \</span> +<span class="cp"> .pushsection "__ex_table","a" ; \</span> +<span class="cp"> .balign 4 ; \</span> +<span class="cp"> .long (from) - . ; \</span> +<span class="cp"> .long (to) - . ; \</span> +<span class="cp"> .long (handler) - . ; \</span> +<span class="cp"> .popsection</span> + +<span class="cp"># define _ASM_EXTABLE(from, to) \</span> +<span class="cp"> _ASM_EXTABLE_HANDLE(from, to, ex_handler_default)</span> +</pre></div> +</div> +<p>For each address that accesses user space we have an entry in the +exception table, that is made up of: the faulting address(from), where +to jump to in case of a fault, and a handler function (that implements +the jump logic). All of these addresses are stored on 32bit in +relative format to the exception table, so that they work for both 32 +and 64 bit kernels.</p> +<p>All of the exception table entries are then collected in the +__ex_table section by the linker script:</p> +<div class="admonition-exception-table-building highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define EXCEPTION_TABLE(align) \</span> +<span class="cp"> . = ALIGN(align); \</span> +<span class="cp"> __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { \</span> +<span class="cp"> VMLINUX_SYMBOL(__start___ex_table) = .; \</span> +<span class="cp"> KEEP(*(__ex_table)) \</span> +<span class="cp"> VMLINUX_SYMBOL(__stop___ex_table) = .; \</span> +<span class="cp"> }</span> +</pre></div> +</div> +<p>The section is guarded with __start___ex_table and __stop___ex_table +symbols, so that it is easy to find the data from C code. This table +is accessed by the fault handler:</p> +<div class="admonition-exception-table-handling highlight-c"><div class="highlight"><pre><span></span><span class="kt">bool</span> <span class="nf">ex_handler_default</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">exception_table_entry</span> <span class="o">*</span><span class="n">fixup</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">,</span> <span class="kt">int</span> <span class="n">trapnr</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">regs</span><span class="o">-></span><span class="n">ip</span> <span class="o">=</span> <span class="n">ex_fixup_addr</span><span class="p">(</span><span class="n">fixup</span><span class="p">);</span> + <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">int</span> <span class="nf">fixup_exception</span><span class="p">(</span><span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">,</span> <span class="kt">int</span> <span class="n">trapnr</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">exception_table_entry</span> <span class="o">*</span><span class="n">e</span><span class="p">;</span> + <span class="n">ex_handler_t</span> <span class="n">handler</span><span class="p">;</span> + + <span class="n">e</span> <span class="o">=</span> <span class="n">search_exception_tables</span><span class="p">(</span><span class="n">regs</span><span class="o">-></span><span class="n">ip</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">e</span><span class="p">)</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> + + <span class="n">handler</span> <span class="o">=</span> <span class="n">ex_fixup_handler</span><span class="p">(</span><span class="n">e</span><span class="p">);</span> + <span class="k">return</span> <span class="n">handler</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">regs</span><span class="p">,</span> <span class="n">trapnr</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<p>All it does is to set the return address to the one in the field of +the exception table entry which, in case of the get_user exception +table entry, is bad_get_user which return -EFAULT to the caller.</p> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lec1-intro.html" class="btn btn-neutral float-left" title="SO2 Lecture 01 - Course overview and Linux kernel introduction" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lec3-processes.html" class="btn btn-neutral float-right" title="SO2 Lecture 03 - Processes" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec3-processes-slides.html b/refs/pull/405/merge/so2/lec3-processes-slides.html new file mode 100644 index 00000000..5f8f3870 --- /dev/null +++ b/refs/pull/405/merge/so2/lec3-processes-slides.html @@ -0,0 +1,996 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>SO2 Lecture 03 - Processes — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="up" title="Operating Systems 2" href="index.html" /> + <link rel="next" title="SO2 Lecture 04 - Interrupts" href="lec4-interrupts.html" /> + <link rel="prev" title="SO2 Lecture 02 - System calls" href="lec2-syscalls.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-so2-lecture-03-processes slide level-1"> + +<h1>SO2 Lecture 03 - Processes</h1> + + + + + +</article> +<article class="admonition-processes-and-threads slide level-2"> + +<h2>Processes and threads</h2> + +<ul class="simple"> +<li>Process and threads</li> +<li>Context switching</li> +<li>Blocking and waking up</li> +<li>Process context</li> +</ul> + + + + +</article> +<article class="admonition-what-is-a-process slide level-2"> + +<h2>What is a process?</h2> + +<table class="hlist"><tr><td><ul class="simple"> +<li>An address space</li> +<li>One or more threads</li> +<li>Opened files</li> +<li>Sockets</li> +<li>Semaphores</li> +</ul> +</td><td><ul class="simple"> +<li>Shared memory regions</li> +<li>Timers</li> +<li>Signal handlers</li> +<li>Many other resources and status information</li> +</ul> +</td></tr></table> +<p>All this information is grouped in the Process Control Group +(PCB). In Linux this is <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>.</p> + + + + +</article> +<article class="admonition-overview-of-process-resources slide level-2"> + +<h2>Overview of process resources</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span> +-------------------------------------------------------------------+ + | dr-x------ 2 tavi tavi 0 2021 03 14 12:34 . | + | dr-xr-xr-x 6 tavi tavi 0 2021 03 14 12:34 .. | + | lrwx------ 1 tavi tavi 64 2021 03 14 12:34 0 -> /dev/pts/4 | + +--->| lrwx------ 1 tavi tavi 64 2021 03 14 12:34 1 -> /dev/pts/4 | + | | lrwx------ 1 tavi tavi 64 2021 03 14 12:34 2 -> /dev/pts/4 | + | | lr-x------ 1 tavi tavi 64 2021 03 14 12:34 3 -> /proc/18312/fd | + | +-------------------------------------------------------------------+ + | +----------------------------------------------------------------+ + | | 08048000-0804c000 r-xp 00000000 08:02 16875609 /bin/cat | +$ ls -1 /proc/self/ | 0804c000-0804d000 rw-p 00003000 08:02 16875609 /bin/cat | +cmdline | | 0804d000-0806e000 rw-p 0804d000 00:00 0 [heap] | +cwd | | ... | +environ | +----------->| b7f46000-b7f49000 rw-p b7f46000 00:00 0 | +exe | | | b7f59000-b7f5b000 rw-p b7f59000 00:00 0 | +fd --------+ | | b7f5b000-b7f77000 r-xp 00000000 08:02 11601524 /lib/ld-2.7.so | +fdinfo | | b7f77000-b7f79000 rw-p 0001b000 08:02 11601524 /lib/ld-2.7.so | +maps -----------+ | bfa05000-bfa1a000 rw-p bffeb000 00:00 0 [stack] | +mem | ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso] | +root +----------------------------------------------------------------+ +stat +----------------------------+ +statm | Name: cat | +status ------+ | State: R (running) | +task | | Tgid: 18205 | +wchan +------>| Pid: 18205 | + | PPid: 18133 | + | Uid: 1000 1000 1000 1000 | + | Gid: 1000 1000 1000 1000 | + +----------------------------+ +</pre></div> +</div> + + + + +</article> +<article class="admonition-struct-task-struct slide level-2"> + +<h2>struct task_struct</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span>$ pahole -C task_struct vmlinux + +struct task_struct { + struct thread_info thread_info; /* 0 8 */ + volatile long int state; /* 8 4 */ + void * stack; /* 12 4 */ + + ... + + /* --- cacheline 45 boundary (2880 bytes) --- */ + struct thread_struct thread __attribute__((__aligned__(64))); /* 2880 4288 */ + + /* size: 7168, cachelines: 112, members: 155 */ + /* sum members: 7148, holes: 2, sum holes: 12 */ + /* sum bitfield members: 7 bits, bit holes: 2, sum bit holes: 57 bits */ + /* paddings: 1, sum paddings: 2 */ + /* forced alignments: 6, forced holes: 2, sum forced holes: 12 */ +} __attribute__((__aligned__(64))); +</pre></div> +</div> + + + + +</article> +<article class="admonition-inspecting-task-struct slide level-2"> + +<h2>Inspecting task_struct</h2> + +<p> </p> +<asciinema-player src="../_images/inspect_task_struct.cast"></asciinema-player> + + + +</article> +<article class="admonition-quiz-inspect-opened-files slide level-2"> + +<h2>Quiz: Inspect opened files</h2> + +<p>Use the debugger to inspect the process named syslogd.</p> +<ul class="simple"> +<li>What command should we use to list the opened file descriptors?</li> +<li>How many file descriptors are opened?</li> +<li>What command should we use the determine the file name for opened file descriptor 3?</li> +<li>What is the filename for file descriptor 3?</li> +</ul> + + + + +</article> +<article class="admonition-threads slide level-2"> + +<h2>Threads</h2> + +<ul class="simple"> +<li>Each thread has its own stack and together with the register +values it determines the thread execution state</li> +<li>A thread runs in the context of a process and all threads in the +same process share the resources</li> +<li>The kernel schedules threads not processes and user-level threads +(e.g. fibers, coroutines, etc.) are not visible at the kernel level</li> +</ul> + + + + +</article> +<article class="admonition-classic-implementation-windows slide level-2"> + +<h2>Classic implementation (Windows)</h2> + +<p> </p> +<img alt="../_images/ditaa-4b5c1874d3924d9716f26d4893a3e4f313bf1c43.png" src="../_images/ditaa-4b5c1874d3924d9716f26d4893a3e4f313bf1c43.png" /> + + + + +</article> +<article class="admonition-linux-implementation slide level-2"> + +<h2>Linux implementation</h2> + +<p> </p> +<img alt="../_images/ditaa-fd771038e88b95def30ae9bd4df0b7bd6b7b3503.png" src="../_images/ditaa-fd771038e88b95def30ae9bd4df0b7bd6b7b3503.png" /> + + + + +</article> +<article class="admonition-the-clone-system-call slide level-2"> + +<h2>The clone system call</h2> + +<ul class="simple"> +<li>CLONE_FILES - shares the file descriptor table with the parent</li> +<li>CLONE_VM - shares the address space with the parent</li> +<li>CLONE_FS - shares the filesystem information (root directory, +current directory) with the parent</li> +<li>CLONE_NEWNS - does not share the mount namespace with the parent</li> +<li>CLONE_NEWIPC - does not share the IPC namespace (System V IPC +objects, POSIX message queues) with the parent</li> +<li>CLONE_NEWNET - does not share the networking namespaces (network +interfaces, routing table) with the parent</li> +</ul> + + + + +</article> +<article class="admonition-namespaces-and-containers slide level-2"> + +<h2>Namespaces and "containers"</h2> + +<ul class="simple"> +<li>Containers = a form of lightweight virtual machines</li> +<li>Container based technologies: LXC, docker</li> +<li>Containers are built of top of kernel namespaces</li> +<li>Kernel namespaces allows isolation of otherwise globally visible +resources</li> +<li><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">nsproxy</span></code> has multiple namespaces each of which +can be selectively shared between groups of processes</li> +<li>At boot initial namespaces are created (e.g. <code class="xref c c-data docutils literal"><span class="pre">init_net</span></code>) +that are by default shared between new processes (e.g. list of +available network interfaces)</li> +<li>New namespace can be created a runtime and new processes can +point to these new namespaces</li> +</ul> + + + + +</article> +<article class="admonition-accessing-the-current-process slide level-2"> + +<h2>Accessing the current process</h2> + +<p>Accessing the current process is a frequent operation:</p> +<ul class="simple"> +<li>opening a file needs access to <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>'s +file field</li> +<li>mapping a new file needs access to <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>'s +mm field</li> +<li>Over 90% of the system calls needs to access the current process +structure so it needs to be fast</li> +<li>The <code class="xref c c-macro docutils literal"><span class="pre">current</span></code> macro is available to access to current +process's <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code></li> +</ul> + + + + +</article> +<article class="admonition-accessing-the-current-process-on-x86 slide level-2"> + +<h2>Accessing the current process on x86</h2> + +<p> </p> +<img alt="../_images/ditaa-019489e686a2f60f1594e37458cfcb10320eae0f.png" src="../_images/ditaa-019489e686a2f60f1594e37458cfcb10320eae0f.png" /> + + + + +</article> +<article class="admonition-previous-implementation-for-current-x86 slide level-2"> + +<h2>Previous implementation for current (x86)</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span>/* how to get the current stack pointer from C */ +register unsigned long current_stack_pointer asm("esp") __attribute_used__; + +/* how to get the thread information struct from C */ +static inline struct thread_info *current_thread_info(void) +{ + return (struct thread_info *)(current_stack_pointer & ~(THREAD_SIZE – 1)); +} + +#define current current_thread_info()->task +</pre></div> +</div> + + + + +</article> +<article class="admonition-quiz-previous-implementation-for-current-x86 slide level-2"> + +<h2>Quiz: previous implementation for current (x86)</h2> + +<p>What is the size of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">thread_info</span></code>?</p> +<p>Which of the following are potential valid sizes for +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">thread_info</span></code>: 4095, 4096, 4097?</p> + + + + +</article> +<article class="admonition-overview-the-context-switching-processes slide level-2"> + +<h2>Overview the context switching processes</h2> + +<img alt="../_images/ditaa-f6b228332baf165f498d8a1bb0bc0bdb91ae50c5.png" src="../_images/ditaa-f6b228332baf165f498d8a1bb0bc0bdb91ae50c5.png" /> + + + + +</article> +<article class="admonition-context-switch slide level-2"> + +<h2>context_switch</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">__always_inline</span> <span class="k">struct</span> <span class="n">rq</span> <span class="o">*</span> +<span class="nf">context_switch</span><span class="p">(</span><span class="k">struct</span> <span class="n">rq</span> <span class="o">*</span><span class="n">rq</span><span class="p">,</span> <span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">prev</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">next</span><span class="p">,</span> <span class="k">struct</span> <span class="n">rq_flags</span> <span class="o">*</span><span class="n">rf</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">prepare_task_switch</span><span class="p">(</span><span class="n">rq</span><span class="p">,</span> <span class="n">prev</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span> + + <span class="cm">/*</span> +<span class="cm"> * For paravirt, this is coupled with an exit in switch_to to</span> +<span class="cm"> * combine the page table reload and the switch backend into</span> +<span class="cm"> * one hypercall.</span> +<span class="cm"> */</span> + <span class="n">arch_start_context_switch</span><span class="p">(</span><span class="n">prev</span><span class="p">);</span> + + <span class="cm">/*</span> +<span class="cm"> * kernel -> kernel lazy + transfer active</span> +<span class="cm"> * user -> kernel lazy + mmgrab() active</span> +<span class="cm"> *</span> +<span class="cm"> * kernel -> user switch + mmdrop() active</span> +<span class="cm"> * user -> user switch</span> +<span class="cm"> */</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">next</span><span class="o">-></span><span class="n">mm</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// to kernel</span> + <span class="n">enter_lazy_tlb</span><span class="p">(</span><span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span> + + <span class="n">next</span><span class="o">-></span><span class="n">active_mm</span> <span class="o">=</span> <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">;</span> + <span class="k">if</span> <span class="p">(</span><span class="n">prev</span><span class="o">-></span><span class="n">mm</span><span class="p">)</span> <span class="c1">// from user</span> + <span class="n">mmgrab</span><span class="p">(</span><span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">);</span> + <span class="k">else</span> + <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="c1">// to user</span> + <span class="n">membarrier_switch_mm</span><span class="p">(</span><span class="n">rq</span><span class="p">,</span> <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">,</span> <span class="n">next</span><span class="o">-></span><span class="n">mm</span><span class="p">);</span> + <span class="cm">/*</span> +<span class="cm"> * sys_membarrier() requires an smp_mb() between setting</span> +<span class="cm"> * rq->curr / membarrier_switch_mm() and returning to userspace.</span> +<span class="cm"> *</span> +<span class="cm"> * The below provides this either through switch_mm(), or in</span> +<span class="cm"> * case 'prev->active_mm == next->mm' through</span> +<span class="cm"> * finish_task_switch()'s mmdrop().</span> +<span class="cm"> */</span> + <span class="n">switch_mm_irqs_off</span><span class="p">(</span><span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">,</span> <span class="n">next</span><span class="o">-></span><span class="n">mm</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">prev</span><span class="o">-></span><span class="n">mm</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// from kernel</span> + <span class="cm">/* will mmdrop() in finish_task_switch(). */</span> + <span class="n">rq</span><span class="o">-></span><span class="n">prev_mm</span> <span class="o">=</span> <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">;</span> + <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="p">}</span> + <span class="p">}</span> + + <span class="n">rq</span><span class="o">-></span><span class="n">clock_update_flags</span> <span class="o">&=</span> <span class="o">~</span><span class="p">(</span><span class="n">RQCF_ACT_SKIP</span><span class="o">|</span><span class="n">RQCF_REQ_SKIP</span><span class="p">);</span> + + <span class="n">prepare_lock_switch</span><span class="p">(</span><span class="n">rq</span><span class="p">,</span> <span class="n">next</span><span class="p">,</span> <span class="n">rf</span><span class="p">);</span> + + <span class="cm">/* Here we just switch the register state and the stack. */</span> + <span class="n">switch_to</span><span class="p">(</span><span class="n">prev</span><span class="p">,</span> <span class="n">next</span><span class="p">,</span> <span class="n">prev</span><span class="p">);</span> + <span class="n">barrier</span><span class="p">();</span> + + <span class="k">return</span> <span class="n">finish_task_switch</span><span class="p">(</span><span class="n">prev</span><span class="p">);</span> + <span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-switch-to slide level-2"> + +<h2>switch_to</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define switch_to(prev, next, last) \</span> +<span class="cp">do { \</span> +<span class="cp"> ((last) = __switch_to_asm((prev), (next))); \</span> +<span class="cp">} while (0)</span> + + +<span class="cm">/*</span> +<span class="cm"> * %eax: prev task</span> +<span class="cm"> * %edx: next task</span> +<span class="cm"> */</span> +<span class="p">.</span><span class="n">pushsection</span> <span class="p">.</span><span class="n">text</span><span class="p">,</span> <span class="s">"ax"</span> +<span class="n">SYM_CODE_START</span><span class="p">(</span><span class="n">__switch_to_asm</span><span class="p">)</span> + <span class="cm">/*</span> +<span class="cm"> * Save callee-saved registers</span> +<span class="cm"> * This must match the order in struct inactive_task_frame</span> +<span class="cm"> */</span> + <span class="n">pushl</span> <span class="o">%</span><span class="n">ebp</span> + <span class="n">pushl</span> <span class="o">%</span><span class="n">ebx</span> + <span class="n">pushl</span> <span class="o">%</span><span class="n">edi</span> + <span class="n">pushl</span> <span class="o">%</span><span class="n">esi</span> + <span class="cm">/*</span> +<span class="cm"> * Flags are saved to prevent AC leakage. This could go</span> +<span class="cm"> * away if objtool would have 32bit support to verify</span> +<span class="cm"> * the STAC/CLAC correctness.</span> +<span class="cm"> */</span> + <span class="n">pushfl</span> + +<span class="hll"> <span class="cm">/* switch stack */</span> +</span><span class="hll"> <span class="n">movl</span> <span class="o">%</span><span class="n">esp</span><span class="p">,</span> <span class="n">TASK_threadsp</span><span class="p">(</span><span class="o">%</span><span class="n">eax</span><span class="p">)</span> +</span><span class="hll"> <span class="n">movl</span> <span class="n">TASK_threadsp</span><span class="p">(</span><span class="o">%</span><span class="n">edx</span><span class="p">),</span> <span class="o">%</span><span class="n">esp</span> +</span> + <span class="cp">#ifdef CONFIG_STACKPROTECTOR</span> + <span class="n">movl</span> <span class="n">TASK_stack_canary</span><span class="p">(</span><span class="o">%</span><span class="n">edx</span><span class="p">),</span> <span class="o">%</span><span class="n">ebx</span> + <span class="n">movl</span> <span class="o">%</span><span class="n">ebx</span><span class="p">,</span> <span class="n">PER_CPU_VAR</span><span class="p">(</span><span class="n">stack_canary</span><span class="p">)</span><span class="o">+</span><span class="n">stack_canary_offset</span> + <span class="cp">#endif</span> + + <span class="cp">#ifdef CONFIG_RETPOLINE</span> + <span class="cm">/*</span> +<span class="cm"> * When switching from a shallower to a deeper call stack</span> +<span class="cm"> * the RSB may either underflow or use entries populated</span> +<span class="cm"> * with userspace addresses. On CPUs where those concerns</span> +<span class="cm"> * exist, overwrite the RSB with entries which capture</span> +<span class="cm"> * speculative execution to prevent attack.</span> +<span class="cm"> */</span> + <span class="n">FILL_RETURN_BUFFER</span> <span class="o">%</span><span class="n">ebx</span><span class="p">,</span> <span class="n">RSB_CLEAR_LOOPS</span><span class="p">,</span> <span class="n">X86_FEATURE_RSB_CTXSW</span> + <span class="cp">#endif</span> + + <span class="cm">/* Restore flags or the incoming task to restore AC state. */</span> + <span class="n">popfl</span> + <span class="cm">/* restore callee-saved registers */</span> + <span class="n">popl</span> <span class="o">%</span><span class="n">esi</span> + <span class="n">popl</span> <span class="o">%</span><span class="n">edi</span> + <span class="n">popl</span> <span class="o">%</span><span class="n">ebx</span> + <span class="n">popl</span> <span class="o">%</span><span class="n">ebp</span> + +<span class="hll"> <span class="n">jmp</span> <span class="n">__switch_to</span> +</span> <span class="n">SYM_CODE_END</span><span class="p">(</span><span class="n">__switch_to_asm</span><span class="p">)</span> + <span class="p">.</span><span class="n">popsection</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-inspecting-task-struct slide level-2"> + +<h2>Inspecting task_struct</h2> + +<p> </p> +<asciinema-player src="../_images/context_switch.cast"></asciinema-player> + + + +</article> +<article class="admonition-quiz-context-switch slide level-2"> + +<h2>Quiz: context switch</h2> + +<p>We are executing a context switch. Select all of the statements that are true.</p> +<ul class="simple"> +<li>the ESP register is saved in the task structure</li> +<li>the EIP register is saved in the task structure</li> +<li>general registers are saved in the task structure</li> +<li>the ESP register is saved on the stack</li> +<li>the EIP register is saved on the stack</li> +<li>general registers are saved on the stack</li> +</ul> + + + + +</article> +<article class="admonition-task-states slide level-2"> + +<h2>Task states</h2> + +<img alt="../_images/ditaa-0b8cde2be9bbd195ac9dcaeac978a8bbe0d3b805.png" src="../_images/ditaa-0b8cde2be9bbd195ac9dcaeac978a8bbe0d3b805.png" /> + + + + +</article> +<article class="admonition-blocking-the-current-thread slide level-2"> + +<h2>Blocking the current thread</h2> + +<ul class="simple"> +<li>Set the current thread state to TASK_UINTERRUPTIBLE or +TASK_INTERRUPTIBLE</li> +<li>Add the task to a waiting queue</li> +<li>Call the scheduler which will pick up a new task from the READY +queue</li> +<li>Do the context switch to the new task</li> +</ul> + + + + +</article> +<article class="admonition-wait-event slide level-2"> + +<h2>wait_event</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/**</span> +<span class="cm"> * wait_event - sleep until a condition gets true</span> +<span class="cm"> * @wq_head: the waitqueue to wait on</span> +<span class="cm"> * @condition: a C expression for the event to wait for</span> +<span class="cm"> *</span> +<span class="cm"> * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the</span> +<span class="cm"> * @condition evaluates to true. The @condition is checked each time</span> +<span class="cm"> * the waitqueue @wq_head is woken up.</span> +<span class="cm"> *</span> +<span class="cm"> * wake_up() has to be called after changing any variable that could</span> +<span class="cm"> * change the result of the wait condition.</span> +<span class="cm"> */</span> +<span class="cp">#define wait_event(wq_head, condition) \</span> +<span class="cp">do { \</span> +<span class="cp"> might_sleep(); \</span> +<span class="cp"> if (condition) \</span> +<span class="cp"> break; \</span> +<span class="cp"> __wait_event(wq_head, condition); \</span> +<span class="cp">} while (0)</span> + +<span class="cp">#define __wait_event(wq_head, condition) \</span> +<span class="cp"> (void)___wait_event(wq_head, condition, TASK_UNINTERRUPTIBLE, 0, 0, \</span> +<span class="cp"> schedule())</span> + +<span class="cm">/*</span> +<span class="cm"> * The below macro ___wait_event() has an explicit shadow of the __ret</span> +<span class="cm"> * variable when used from the wait_event_*() macros.</span> +<span class="cm"> *</span> +<span class="cm"> * This is so that both can use the ___wait_cond_timeout() construct</span> +<span class="cm"> * to wrap the condition.</span> +<span class="cm"> *</span> +<span class="cm"> * The type inconsistency of the wait_event_*() __ret variable is also</span> +<span class="cm"> * on purpose; we use long where we can return timeout values and int</span> +<span class="cm"> * otherwise.</span> +<span class="cm"> */</span> +<span class="cp">#define ___wait_event(wq_head, condition, state, exclusive, ret, cmd) \</span> +<span class="cp">({ \</span> +<span class="cp"> __label__ __out; \</span> +<span class="cp"> struct wait_queue_entry __wq_entry; \</span> +<span class="cp"> long __ret = ret; </span><span class="cm">/* explicit shadow */</span><span class="cp"> \</span> +<span class="cp"> \</span> +<span class="cp"> init_wait_entry(&__wq_entry, exclusive ? WQ_FLAG_EXCLUSIVE : 0); \</span> +<span class="cp"> for (;;) { \</span> +<span class="cp"> long __int = prepare_to_wait_event(&wq_head, &__wq_entry, state);\</span> +<span class="cp"> \</span> +<span class="cp"> if (condition) \</span> +<span class="cp"> break; \</span> +<span class="cp"> \</span> +<span class="cp"> if (___wait_is_interruptible(state) && __int) { \</span> +<span class="cp"> __ret = __int; \</span> +<span class="cp"> goto __out; \</span> +<span class="cp"> } \</span> +<span class="cp"> \</span> +<span class="cp"> cmd; \</span> +<span class="cp"> } \</span> +<span class="cp"> finish_wait(&wq_head, &__wq_entry); \</span> +<span class="cp"> __out: __ret; \</span> +<span class="cp"> })</span> + + <span class="kt">void</span> <span class="nf">init_wait_entry</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">,</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">wq_entry</span><span class="o">-></span><span class="n">flags</span> <span class="o">=</span> <span class="n">flags</span><span class="p">;</span> + <span class="n">wq_entry</span><span class="o">-></span><span class="n">private</span> <span class="o">=</span> <span class="n">current</span><span class="p">;</span> + <span class="n">wq_entry</span><span class="o">-></span><span class="n">func</span> <span class="o">=</span> <span class="n">autoremove_wake_function</span><span class="p">;</span> + <span class="n">INIT_LIST_HEAD</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="p">}</span> + + <span class="kt">long</span> <span class="nf">prepare_to_wait_event</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">,</span> <span class="kt">int</span> <span class="n">state</span><span class="p">)</span> + <span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + <span class="kt">long</span> <span class="n">ret</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + + <span class="n">spin_lock_irqsave</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">signal_pending_state</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">current</span><span class="p">))</span> <span class="p">{</span> + <span class="cm">/*</span> +<span class="cm"> * Exclusive waiter must not fail if it was selected by wakeup,</span> +<span class="cm"> * it should "consume" the condition we were waiting for.</span> +<span class="cm"> *</span> +<span class="cm"> * The caller will recheck the condition and return success if</span> +<span class="cm"> * we were already woken up, we can not miss the event because</span> +<span class="cm"> * wakeup locks/unlocks the same wq_head->lock.</span> +<span class="cm"> *</span> +<span class="cm"> * But we need to ensure that set-condition + wakeup after that</span> +<span class="cm"> * can't see us, it should wake up another exclusive waiter if</span> +<span class="cm"> * we fail.</span> +<span class="cm"> */</span> + <span class="n">list_del_init</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="n">ret</span> <span class="o">=</span> <span class="o">-</span><span class="n">ERESTARTSYS</span><span class="p">;</span> + <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">list_empty</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">))</span> <span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_EXCLUSIVE</span><span class="p">)</span> + <span class="n">__add_wait_queue_entry_tail</span><span class="p">(</span><span class="n">wq_head</span><span class="p">,</span> <span class="n">wq_entry</span><span class="p">);</span> + <span class="k">else</span> + <span class="n">__add_wait_queue</span><span class="p">(</span><span class="n">wq_head</span><span class="p">,</span> <span class="n">wq_entry</span><span class="p">);</span> + <span class="p">}</span> + <span class="n">set_current_state</span><span class="p">(</span><span class="n">state</span><span class="p">);</span> + <span class="p">}</span> + <span class="n">spin_unlock_irqrestore</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + + <span class="k">return</span> <span class="n">ret</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">static</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="nf">__add_wait_queue</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">list_add</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">,</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">);</span> + <span class="p">}</span> + + <span class="k">static</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="nf">__add_wait_queue_entry_tail</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">list_add_tail</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">,</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">);</span> + <span class="p">}</span> + + <span class="cm">/**</span> +<span class="cm"> * finish_wait - clean up after waiting in a queue</span> +<span class="cm"> * @wq_head: waitqueue waited on</span> +<span class="cm"> * @wq_entry: wait descriptor</span> +<span class="cm"> *</span> +<span class="cm"> * Sets current thread back to running state and removes</span> +<span class="cm"> * the wait descriptor from the given waitqueue if still</span> +<span class="cm"> * queued.</span> +<span class="cm"> */</span> + <span class="kt">void</span> <span class="nf">finish_wait</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">)</span> + <span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + + <span class="n">__set_current_state</span><span class="p">(</span><span class="n">TASK_RUNNING</span><span class="p">);</span> + <span class="cm">/*</span> +<span class="cm"> * We can check for list emptiness outside the lock</span> +<span class="cm"> * IFF:</span> +<span class="cm"> * - we use the "careful" check that verifies both</span> +<span class="cm"> * the next and prev pointers, so that there cannot</span> +<span class="cm"> * be any half-pending updates in progress on other</span> +<span class="cm"> * CPU's that we haven't seen yet (and that might</span> +<span class="cm"> * still change the stack area.</span> +<span class="cm"> * and</span> +<span class="cm"> * - all other users take the lock (ie we can only</span> +<span class="cm"> * have _one_ other CPU that looks at or modifies</span> +<span class="cm"> * the list).</span> +<span class="cm"> */</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">list_empty_careful</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">))</span> <span class="p">{</span> + <span class="n">spin_lock_irqsave</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="n">list_del_init</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="n">spin_unlock_irqrestore</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="p">}</span> + <span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-waking-up-a-task slide level-2"> + +<h2>Waking up a task</h2> + +<ul class="simple"> +<li>Select a task from the waiting queue</li> +<li>Set the task state to TASK_READY</li> +<li>Insert the task into the scheduler's READY queue</li> +<li>On SMP system this is a complex operation: each processor has its +own queue, queues need to be balanced, CPUs needs to be signaled</li> +</ul> + + + + +</article> +<article class="admonition-wake-up slide level-2"> + +<h2>wake_up</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)</span> + +<span class="cm">/**</span> +<span class="cm"> * __wake_up - wake up threads blocked on a waitqueue.</span> +<span class="cm"> * @wq_head: the waitqueue</span> +<span class="cm"> * @mode: which threads</span> +<span class="cm"> * @nr_exclusive: how many wake-one or wake-many threads to wake up</span> +<span class="cm"> * @key: is directly passed to the wakeup function</span> +<span class="cm"> *</span> +<span class="cm"> * If this function wakes up a task, it executes a full memory barrier before</span> +<span class="cm"> * accessing the task state.</span> +<span class="cm"> */</span> +<span class="kt">void</span> <span class="nf">__wake_up</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">mode</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">nr_exclusive</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">__wake_up_common_lock</span><span class="p">(</span><span class="n">wq_head</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">nr_exclusive</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">key</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">__wake_up_common_lock</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">mode</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">nr_exclusive</span><span class="p">,</span> <span class="kt">int</span> <span class="n">wake_flags</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + <span class="n">wait_queue_entry_t</span> <span class="n">bookmark</span><span class="p">;</span> + + <span class="n">bookmark</span><span class="p">.</span><span class="n">flags</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="n">bookmark</span><span class="p">.</span><span class="n">private</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="n">bookmark</span><span class="p">.</span><span class="n">func</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="n">INIT_LIST_HEAD</span><span class="p">(</span><span class="o">&</span><span class="n">bookmark</span><span class="p">.</span><span class="n">entry</span><span class="p">);</span> + + <span class="k">do</span> <span class="p">{</span> + <span class="n">spin_lock_irqsave</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="n">nr_exclusive</span> <span class="o">=</span> <span class="n">__wake_up_common</span><span class="p">(</span><span class="n">wq_head</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">nr_exclusive</span><span class="p">,</span> + <span class="n">wake_flags</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="o">&</span><span class="n">bookmark</span><span class="p">);</span> + <span class="n">spin_unlock_irqrestore</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="n">bookmark</span><span class="p">.</span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_BOOKMARK</span><span class="p">);</span> +<span class="p">}</span> + +<span class="cm">/*</span> +<span class="cm"> * The core wakeup function. Non-exclusive wakeups (nr_exclusive == 0) just</span> +<span class="cm"> * wake everything up. If it's an exclusive wakeup (nr_exclusive == small +ve</span> +<span class="cm"> * number) then we wake all the non-exclusive tasks and one exclusive task.</span> +<span class="cm"> *</span> +<span class="cm"> * There are circumstances in which we can try to wake a task which has already</span> +<span class="cm"> * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns</span> +<span class="cm"> * zero in this (rare) case, and we handle it by continuing to scan the queue.</span> +<span class="cm"> */</span> +<span class="k">static</span> <span class="kt">int</span> <span class="nf">__wake_up_common</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">mode</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">nr_exclusive</span><span class="p">,</span> <span class="kt">int</span> <span class="n">wake_flags</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">,</span> + <span class="n">wait_queue_entry_t</span> <span class="o">*</span><span class="n">bookmark</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">wait_queue_entry_t</span> <span class="o">*</span><span class="n">curr</span><span class="p">,</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">cnt</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + + <span class="n">lockdep_assert_held</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">bookmark</span> <span class="o">&&</span> <span class="p">(</span><span class="n">bookmark</span><span class="o">-></span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_BOOKMARK</span><span class="p">))</span> <span class="p">{</span> + <span class="n">curr</span> <span class="o">=</span> <span class="n">list_next_entry</span><span class="p">(</span><span class="n">bookmark</span><span class="p">,</span> <span class="n">entry</span><span class="p">);</span> + + <span class="n">list_del</span><span class="p">(</span><span class="o">&</span><span class="n">bookmark</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="n">bookmark</span><span class="o">-></span><span class="n">flags</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="p">}</span> <span class="k">else</span> + <span class="n">curr</span> <span class="o">=</span> <span class="n">list_first_entry</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">,</span> <span class="n">wait_queue_entry_t</span><span class="p">,</span> <span class="n">entry</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">&</span><span class="n">curr</span><span class="o">-></span><span class="n">entry</span> <span class="o">==</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">)</span> + <span class="k">return</span> <span class="n">nr_exclusive</span><span class="p">;</span> + + <span class="n">list_for_each_entry_safe_from</span><span class="p">(</span><span class="n">curr</span><span class="p">,</span> <span class="n">next</span><span class="p">,</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">,</span> <span class="n">entry</span><span class="p">)</span> <span class="p">{</span> + <span class="kt">unsigned</span> <span class="n">flags</span> <span class="o">=</span> <span class="n">curr</span><span class="o">-></span><span class="n">flags</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">ret</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_BOOKMARK</span><span class="p">)</span> + <span class="k">continue</span><span class="p">;</span> + + <span class="n">ret</span> <span class="o">=</span> <span class="n">curr</span><span class="o">-></span><span class="n">func</span><span class="p">(</span><span class="n">curr</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">wake_flags</span><span class="p">,</span> <span class="n">key</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">ret</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">break</span><span class="p">;</span> + <span class="k">if</span> <span class="p">(</span><span class="n">ret</span> <span class="o">&&</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_EXCLUSIVE</span><span class="p">)</span> <span class="o">&&</span> <span class="o">!--</span><span class="n">nr_exclusive</span><span class="p">)</span> + <span class="k">break</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">bookmark</span> <span class="o">&&</span> <span class="p">(</span><span class="o">++</span><span class="n">cnt</span> <span class="o">></span> <span class="n">WAITQUEUE_WALK_BREAK_CNT</span><span class="p">)</span> <span class="o">&&</span> + <span class="p">(</span><span class="o">&</span><span class="n">next</span><span class="o">-></span><span class="n">entry</span> <span class="o">!=</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">))</span> <span class="p">{</span> + <span class="n">bookmark</span><span class="o">-></span><span class="n">flags</span> <span class="o">=</span> <span class="n">WQ_FLAG_BOOKMARK</span><span class="p">;</span> + <span class="n">list_add_tail</span><span class="p">(</span><span class="o">&</span><span class="n">bookmark</span><span class="o">-></span><span class="n">entry</span><span class="p">,</span> <span class="o">&</span><span class="n">next</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="k">break</span><span class="p">;</span> + <span class="p">}</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="n">nr_exclusive</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">int</span> <span class="nf">autoremove_wake_function</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">mode</span><span class="p">,</span> <span class="kt">int</span> <span class="n">sync</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">default_wake_function</span><span class="p">(</span><span class="n">wq_entry</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">sync</span><span class="p">,</span> <span class="n">key</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">ret</span><span class="p">)</span> + <span class="n">list_del_init_careful</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + + <span class="k">return</span> <span class="n">ret</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">int</span> <span class="nf">default_wake_function</span><span class="p">(</span><span class="n">wait_queue_entry_t</span> <span class="o">*</span><span class="n">curr</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">mode</span><span class="p">,</span> <span class="kt">int</span> <span class="n">wake_flags</span><span class="p">,</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">WARN_ON_ONCE</span><span class="p">(</span><span class="n">IS_ENABLED</span><span class="p">(</span><span class="n">CONFIG_SCHED_DEBUG</span><span class="p">)</span> <span class="o">&&</span> <span class="n">wake_flags</span> <span class="o">&</span> <span class="o">~</span><span class="n">WF_SYNC</span><span class="p">);</span> + <span class="k">return</span> <span class="n">try_to_wake_up</span><span class="p">(</span><span class="n">curr</span><span class="o">-></span><span class="n">private</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">wake_flags</span><span class="p">);</span> +<span class="p">}</span> + +<span class="cm">/**</span> +<span class="cm"> * try_to_wake_up - wake up a thread</span> +<span class="cm"> * @p: the thread to be awakened</span> +<span class="cm"> * @state: the mask of task states that can be woken</span> +<span class="cm"> * @wake_flags: wake modifier flags (WF_*)</span> +<span class="cm"> *</span> +<span class="cm"> * Conceptually does:</span> +<span class="cm"> *</span> +<span class="cm"> * If (@state & @p->state) @p->state = TASK_RUNNING.</span> +<span class="cm"> *</span> +<span class="cm"> * If the task was not queued/runnable, also place it back on a runqueue.</span> +<span class="cm"> *</span> +<span class="cm"> * This function is atomic against schedule() which would dequeue the task.</span> +<span class="cm"> *</span> +<span class="cm"> * It issues a full memory barrier before accessing @p->state, see the comment</span> +<span class="cm"> * with set_current_state().</span> +<span class="cm"> *</span> +<span class="cm"> * Uses p->pi_lock to serialize against concurrent wake-ups.</span> +<span class="cm"> *</span> +<span class="cm"> * Relies on p->pi_lock stabilizing:</span> +<span class="cm"> * - p->sched_class</span> +<span class="cm"> * - p->cpus_ptr</span> +<span class="cm"> * - p->sched_task_group</span> +<span class="cm"> * in order to do migration, see its use of select_task_rq()/set_task_cpu().</span> +<span class="cm"> *</span> +<span class="cm"> * Tries really hard to only take one task_rq(p)->lock for performance.</span> +<span class="cm"> * Takes rq->lock in:</span> +<span class="cm"> * - ttwu_runnable() -- old rq, unavoidable, see comment there;</span> +<span class="cm"> * - ttwu_queue() -- new rq, for enqueue of the task;</span> +<span class="cm"> * - psi_ttwu_dequeue() -- much sadness :-( accounting will kill us.</span> +<span class="cm"> *</span> +<span class="cm"> * As a consequence we race really badly with just about everything. See the</span> +<span class="cm"> * many memory barriers and their comments for details.</span> +<span class="cm"> *</span> +<span class="cm"> * Return: %true if @p->state changes (an actual wakeup was done),</span> +<span class="cm"> * %false otherwise.</span> +<span class="cm"> */</span> + <span class="k">static</span> <span class="kt">int</span> + <span class="nf">try_to_wake_up</span><span class="p">(</span><span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">p</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">state</span><span class="p">,</span> <span class="kt">int</span> <span class="n">wake_flags</span><span class="p">)</span> + <span class="p">{</span> + <span class="p">...</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-non-preemptive-kernel slide level-2"> + +<h2>Non preemptive kernel</h2> + +<ul class="simple"> +<li>At every tick the kernel checks to see if the current process has +its time slice consumed</li> +<li>If that happens a flag is set in interrupt context</li> +<li>Before returning to userspace the kernel checks this flag and +calls <code class="xref c c-func docutils literal"><span class="pre">schedule()</span></code> if needed</li> +<li>In this case tasks are not preempted while running in kernel mode +(e.g. system call) so there are no synchronization issues</li> +</ul> + + + + +</article> +<article class="admonition-preemptive-kernel slide level-2"> + +<h2>Preemptive kernel</h2> + +<ul class="simple"> +<li>Tasks can be preempted even when running in kernel mode</li> +<li>It requires new synchronization primitives to be used in critical +sections: <code class="xref c c-macro docutils literal"><span class="pre">preempt_disable</span></code> and +<code class="xref c c-macro docutils literal"><span class="pre">preempt_enable</span></code></li> +<li>Spinlocks also disable preemption</li> +<li>When a thread needs to be preempted a flag is set and action is +taken (e.g. scheduler is called) when preemption is reactivated</li> +</ul> + + + + +</article> +<article class="admonition-process-context slide level-2"> + +<h2>Process context</h2> + +<p>The kernel is executing in process context when it is running a +system call.</p> +<p>In process context there is a well defined context and we can +access the current process data with <code class="xref c c-macro docutils literal"><span class="pre">current</span></code></p> +<p>In process context we can sleep (wait on a condition).</p> +<p>In process context we can access the user-space (unless we are +running in a kernel thread context).</p> + + + + +</article> +<article class="admonition-kernel-threads slide level-2"> + +<h2>Kernel threads</h2> + +<p>Sometimes the kernel core or device drivers need to perform blocking +operations and thus they need to run in process context.</p> +<p>Kernel threads are used exactly for this and are a special class of +tasks that don't "userspace" resources (e.g. no address space or +opened files).</p> + + + + +</article> +<article class="admonition-inspecting-kernel-threads slide level-2"> + +<h2>Inspecting kernel threads</h2> + +<p> </p> +<asciinema-player src="../_images/kernel_threads.cast"></asciinema-player> + + + +</article> +<article class="admonition-quiz-kernel-gdb-scripts slide level-2"> + +<h2>Quiz: Kernel gdb scripts</h2> + +<p>What is the following change of the lx-ps script trying to +accomplish?</p> +<div class="highlight-diff"><div class="highlight"><pre><span></span><span class="gh">diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py</span> +<span class="gh">index 17ec19e9b5bf..7e43c163832f 100644</span> +<span class="gd">--- a/scripts/gdb/linux/tasks.py</span> +<span class="gi">+++ b/scripts/gdb/linux/tasks.py</span> +<span class="gu">@@ -75,10 +75,13 @@ class LxPs(gdb.Command):</span> + def invoke(self, arg, from_tty): + gdb.write("{:>10} {:>12} {:>7}\n".format("TASK", "PID", "COMM")) + for task in task_lists(): +<span class="gd">- gdb.write("{} {:^5} {}\n".format(</span> +<span class="gi">+ check = task["mm"].format_string() == "0x0"</span> +<span class="gi">+ gdb.write("{} {:^5} {}{}{}\n".format(</span> + task.format_string().split()[0], + task["pid"].format_string(), +<span class="gd">- task["comm"].string()))</span> +<span class="gi">+ "[" if check else "",</span> +<span class="gi">+ task["comm"].string(),</span> +<span class="gi">+ "]" if check else ""))</span> + + + LxPs() +</pre></div> +</div> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec3-processes.html b/refs/pull/405/merge/so2/lec3-processes.html new file mode 100644 index 00000000..dd483dbb --- /dev/null +++ b/refs/pull/405/merge/so2/lec3-processes.html @@ -0,0 +1,1119 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lecture 03 - Processes — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lecture 04 - Interrupts" href="lec4-interrupts.html" /> + <link rel="prev" title="SO2 Lecture 02 - System calls" href="lec2-syscalls.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lecture 03 - Processes</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lecture-objectives">Lecture objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#processes-and-threads">Processes and threads</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#overview-of-process-resources">Overview of process resources</a></li> +<li class="toctree-l4"><a class="reference internal" href="#struct-task-struct"><code class="docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code></a></li> +<li class="toctree-l4"><a class="reference internal" href="#inspecting-task-struct">Inspecting task_struct</a></li> +<li class="toctree-l4"><a class="reference internal" href="#quiz-inspect-a-task-to-determine-opened-files">Quiz: Inspect a task to determine opened files</a></li> +<li class="toctree-l4"><a class="reference internal" href="#threads">Threads</a></li> +<li class="toctree-l4"><a class="reference internal" href="#the-clone-system-call">The clone system call</a></li> +<li class="toctree-l4"><a class="reference internal" href="#namespaces-and-containers">Namespaces and "containers"</a></li> +<li class="toctree-l4"><a class="reference internal" href="#accessing-the-current-process">Accessing the current process</a></li> +<li class="toctree-l4"><a class="reference internal" href="#quiz-previous-implementation-for-current-x86">Quiz: previous implementation for current (x86)</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#context-switching">Context switching</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#quiz-context-switch">Quiz: context switch</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#blocking-and-waking-up-tasks">Blocking and waking up tasks</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#task-states">Task states</a></li> +<li class="toctree-l4"><a class="reference internal" href="#blocking-the-current-thread">Blocking the current thread</a></li> +<li class="toctree-l4"><a class="reference internal" href="#waking-up-a-task">Waking up a task</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#preempting-tasks">Preempting tasks</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#non-preemptive-kernel">Non preemptive kernel</a></li> +<li class="toctree-l4"><a class="reference internal" href="#preemptive-kernel">Preemptive kernel</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#process-context">Process context</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#kernel-threads">Kernel threads</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#using-gdb-scripts-for-kernel-inspection">Using gdb scripts for kernel inspection</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#quiz-kernel-gdb-scripts">Quiz: Kernel gdb scripts</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lecture 03 - Processes</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lec3-processes.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lecture-03-processes"> +<h1>SO2 Lecture 03 - Processes<a class="headerlink" href="#so2-lecture-03-processes" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="lec3-processes-slides.html">View slides</a></p> +<span class="admonition-so2-lecture-03-processes"></span><div class="section" id="lecture-objectives"> +<h2>Lecture objectives<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-processes-and-threads simple"> +<li>Process and threads</li> +<li>Context switching</li> +<li>Blocking and waking up</li> +<li>Process context</li> +</ul> +</div> +<div class="section" id="processes-and-threads"> +<h2>Processes and threads<a class="headerlink" href="#processes-and-threads" title="Permalink to this headline">¶</a></h2> +<p>A process is an operating system abstraction that groups together +multiple resources:</p> +<table class="hlist"><tr><td><ul class="simple"> +<li>An address space</li> +<li>One or more threads</li> +<li>Opened files</li> +<li>Sockets</li> +<li>Semaphores</li> +</ul> +</td><td><ul class="simple"> +<li>Shared memory regions</li> +<li>Timers</li> +<li>Signal handlers</li> +<li>Many other resources and status information</li> +</ul> +</td></tr></table> +<p>All this information is grouped in the Process Control Group +(PCB). In Linux this is <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>.</p> +<div class="section" id="overview-of-process-resources"> +<h3>Overview of process resources<a class="headerlink" href="#overview-of-process-resources" title="Permalink to this headline">¶</a></h3> +<p>A summary of the resources a process has can be obtain from the +<cite>/proc/<pid></cite> directory, where <cite><pid></cite> is the process id for the +process we want to look at.</p> +<div class="highlight-none"><div class="highlight"><pre><span></span> +-------------------------------------------------------------------+ + | dr-x------ 2 tavi tavi 0 2021 03 14 12:34 . | + | dr-xr-xr-x 6 tavi tavi 0 2021 03 14 12:34 .. | + | lrwx------ 1 tavi tavi 64 2021 03 14 12:34 0 -> /dev/pts/4 | + +--->| lrwx------ 1 tavi tavi 64 2021 03 14 12:34 1 -> /dev/pts/4 | + | | lrwx------ 1 tavi tavi 64 2021 03 14 12:34 2 -> /dev/pts/4 | + | | lr-x------ 1 tavi tavi 64 2021 03 14 12:34 3 -> /proc/18312/fd | + | +-------------------------------------------------------------------+ + | +----------------------------------------------------------------+ + | | 08048000-0804c000 r-xp 00000000 08:02 16875609 /bin/cat | +$ ls -1 /proc/self/ | 0804c000-0804d000 rw-p 00003000 08:02 16875609 /bin/cat | +cmdline | | 0804d000-0806e000 rw-p 0804d000 00:00 0 [heap] | +cwd | | ... | +environ | +----------->| b7f46000-b7f49000 rw-p b7f46000 00:00 0 | +exe | | | b7f59000-b7f5b000 rw-p b7f59000 00:00 0 | +fd --------+ | | b7f5b000-b7f77000 r-xp 00000000 08:02 11601524 /lib/ld-2.7.so | +fdinfo | | b7f77000-b7f79000 rw-p 0001b000 08:02 11601524 /lib/ld-2.7.so | +maps -----------+ | bfa05000-bfa1a000 rw-p bffeb000 00:00 0 [stack] | +mem | ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso] | +root +----------------------------------------------------------------+ +stat +----------------------------+ +statm | Name: cat | +status ------+ | State: R (running) | +task | | Tgid: 18205 | +wchan +------>| Pid: 18205 | + | PPid: 18133 | + | Uid: 1000 1000 1000 1000 | + | Gid: 1000 1000 1000 1000 | + +----------------------------+ +</pre></div> +</div> +</div> +<div class="section" id="struct-task-struct"> +<h3><code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code><a class="headerlink" href="#struct-task-struct" title="Permalink to this headline">¶</a></h3> +<p>Lets take a close look at <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>. For that we +could just look at the source code, but here we will use a tool called +<cite>pahole</cite> (part of the dwarves install package) in order to get +some insights about this structure:</p> +<div class="admonition-struct-task-struct highlight-c"><div class="highlight"><pre><span></span>$ pahole -C task_struct vmlinux + +struct task_struct { + struct thread_info thread_info; /* 0 8 */ + volatile long int state; /* 8 4 */ + void * stack; /* 12 4 */ + + ... + + /* --- cacheline 45 boundary (2880 bytes) --- */ + struct thread_struct thread __attribute__((__aligned__(64))); /* 2880 4288 */ + + /* size: 7168, cachelines: 112, members: 155 */ + /* sum members: 7148, holes: 2, sum holes: 12 */ + /* sum bitfield members: 7 bits, bit holes: 2, sum bit holes: 57 bits */ + /* paddings: 1, sum paddings: 2 */ + /* forced alignments: 6, forced holes: 2, sum forced holes: 12 */ +} __attribute__((__aligned__(64))); +</pre></div> +</div> +<p>As you can see it is a pretty large data structure: almost 8KB in size +and 155 fields.</p> +</div> +<div class="section" id="inspecting-task-struct"> +<h3>Inspecting task_struct<a class="headerlink" href="#inspecting-task-struct" title="Permalink to this headline">¶</a></h3> +<p>The following screencast is going to demonstrate how we can inspect +the process control block (<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>) by connecting +the debugger to the running virtual machine. We are going to use a +helper gdb command <cite>lx-ps</cite> to list the processes and the address of +the task_struct for each process.</p> +<p class="admonition-inspecting-task-struct"> </p> +<asciinema-player src="../_images/inspect_task_struct.cast"></asciinema-player></div> +<div class="section" id="quiz-inspect-a-task-to-determine-opened-files"> +<h3>Quiz: Inspect a task to determine opened files<a class="headerlink" href="#quiz-inspect-a-task-to-determine-opened-files" title="Permalink to this headline">¶</a></h3> +<p class="admonition-quiz-inspect-opened-files">Use the debugger to inspect the process named syslogd.</p> +<ul class="simple"> +<li>What command should we use to list the opened file descriptors?</li> +<li>How many file descriptors are opened?</li> +<li>What command should we use the determine the file name for opened file descriptor 3?</li> +<li>What is the filename for file descriptor 3?</li> +</ul> +</div> +<div class="section" id="threads"> +<h3>Threads<a class="headerlink" href="#threads" title="Permalink to this headline">¶</a></h3> +<p>A thread is the basic unit that the kernel process scheduler uses to +allow applications to run the CPU. A thread has the following +characteristics:</p> +<ul class="admonition-threads simple"> +<li>Each thread has its own stack and together with the register +values it determines the thread execution state</li> +<li>A thread runs in the context of a process and all threads in the +same process share the resources</li> +<li>The kernel schedules threads not processes and user-level threads +(e.g. fibers, coroutines, etc.) are not visible at the kernel level</li> +</ul> +<p>The typical thread implementation is one where the threads is +implemented as a separate data structure which is then linked to the +process data structure. For example, the Windows kernel uses such an +implementation:</p> +<p class="admonition-classic-implementation-windows"> </p> +<img alt="../_images/ditaa-4b5c1874d3924d9716f26d4893a3e4f313bf1c43.png" src="../_images/ditaa-4b5c1874d3924d9716f26d4893a3e4f313bf1c43.png" /> +<p>Linux uses a different implementation for threads. The basic unit is +called a task (hence the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>) and it is used +for both threads and processes. Instead of embedding resources in the +task structure it has pointers to these resources.</p> +<p>Thus, if two threads are the same process will point to the same +resource structure instance. If two threads are in different processes +they will point to different resource structure instances.</p> +<p class="admonition-linux-implementation"> </p> +<img alt="../_images/ditaa-fd771038e88b95def30ae9bd4df0b7bd6b7b3503.png" src="../_images/ditaa-fd771038e88b95def30ae9bd4df0b7bd6b7b3503.png" /> +</div> +<div class="section" id="the-clone-system-call"> +<h3>The clone system call<a class="headerlink" href="#the-clone-system-call" title="Permalink to this headline">¶</a></h3> +<p>In Linux a new thread or process is create with the <code class="xref c c-func docutils literal"><span class="pre">clone()</span></code> +system call. Both the <code class="xref c c-func docutils literal"><span class="pre">fork()</span></code> system call and the +<code class="xref c c-func docutils literal"><span class="pre">pthread_create()</span></code> function uses the <code class="xref c c-func docutils literal"><span class="pre">clone()</span></code> +implementation.</p> +<p>It allows the caller to decide what resources should be shared with +the parent and which should be copied or isolated:</p> +<ul class="admonition-the-clone-system-call simple"> +<li>CLONE_FILES - shares the file descriptor table with the parent</li> +<li>CLONE_VM - shares the address space with the parent</li> +<li>CLONE_FS - shares the filesystem information (root directory, +current directory) with the parent</li> +<li>CLONE_NEWNS - does not share the mount namespace with the parent</li> +<li>CLONE_NEWIPC - does not share the IPC namespace (System V IPC +objects, POSIX message queues) with the parent</li> +<li>CLONE_NEWNET - does not share the networking namespaces (network +interfaces, routing table) with the parent</li> +</ul> +<p>For example, if <cite>CLONE_FILES | CLONE_VM | CLONE_FS</cite> is used by the +caller then effectively a new thread is created. If these flags are +not used then a new process is created.</p> +</div> +<div class="section" id="namespaces-and-containers"> +<h3>Namespaces and "containers"<a class="headerlink" href="#namespaces-and-containers" title="Permalink to this headline">¶</a></h3> +<p>"Containers" are a form of lightweight virtual machines that share the +same kernel instance, as opposed to normal virtualization where a +hypervisor runs multiple VMs, each with its one kernel +instance.</p> +<p>Examples of container technologies are LXC - that allows running +lightweight "VM" and docker - a specialized container for running a +single application.</p> +<p>Containers are built on top of a few kernel features, one of which is +namespaces. They allow isolation of different resources that would +otherwise be globally visible. For example, without containers, all +processes would be visible in /proc. With containers, processes in one +container will not be visible (in /proc or be killable) to other +containers.</p> +<p>To achieve this partitioning, the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">nsproxy</span></code> structure +is used to group types of resources that we want to partition. It +currently supports IPC, networking, cgroup, mount, networking, PID, +time namespaces. For example, instead of having a global list for +networking interfaces, the list is part of a <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">net</span></code>. The +system initializes with a default namespace (<code class="xref c c-data docutils literal"><span class="pre">init_net</span></code>) and by +default all processes will share this namespace. When a new namespace +is created a new net namespace is created and then new processes can +point to that new namespace instead of the default one.</p> +<span class="admonition-namespaces-and-containers"></span></div> +<div class="section" id="accessing-the-current-process"> +<h3>Accessing the current process<a class="headerlink" href="#accessing-the-current-process" title="Permalink to this headline">¶</a></h3> +<p class="admonition-accessing-the-current-process">Accessing the current process is a frequent operation:</p> +<ul class="simple"> +<li>opening a file needs access to <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>'s +file field</li> +<li>mapping a new file needs access to <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>'s +mm field</li> +<li>Over 90% of the system calls needs to access the current process +structure so it needs to be fast</li> +<li>The <code class="xref c c-macro docutils literal"><span class="pre">current</span></code> macro is available to access to current +process's <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code></li> +</ul> +<p>In order to support fast access in multi processor configurations a +per CPU variable is used to store and retrieve the pointer to the +current <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code>:</p> +<p class="admonition-accessing-the-current-process-on-x86"> </p> +<img alt="../_images/ditaa-019489e686a2f60f1594e37458cfcb10320eae0f.png" src="../_images/ditaa-019489e686a2f60f1594e37458cfcb10320eae0f.png" /> +<p>Previously the following sequence was used as the implementation for +the <code class="xref c c-macro docutils literal"><span class="pre">current</span></code> macro:</p> +<div class="admonition-previous-implementation-for-current-x86 highlight-c"><div class="highlight"><pre><span></span>/* how to get the current stack pointer from C */ +register unsigned long current_stack_pointer asm("esp") __attribute_used__; + +/* how to get the thread information struct from C */ +static inline struct thread_info *current_thread_info(void) +{ + return (struct thread_info *)(current_stack_pointer & ~(THREAD_SIZE – 1)); +} + +#define current current_thread_info()->task +</pre></div> +</div> +</div> +<div class="section" id="quiz-previous-implementation-for-current-x86"> +<h3>Quiz: previous implementation for current (x86)<a class="headerlink" href="#quiz-previous-implementation-for-current-x86" title="Permalink to this headline">¶</a></h3> +<p class="admonition-quiz-previous-implementation-for-current-x86">What is the size of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">thread_info</span></code>?</p> +<p>Which of the following are potential valid sizes for +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">thread_info</span></code>: 4095, 4096, 4097?</p> +</div> +</div> +<div class="section" id="context-switching"> +<h2>Context switching<a class="headerlink" href="#context-switching" title="Permalink to this headline">¶</a></h2> +<p>The following diagram shows an overview of the Linux kernel context +switch process:</p> +<img alt="../_images/ditaa-f6b228332baf165f498d8a1bb0bc0bdb91ae50c5.png" class="admonition-overview-the-context-switching-processes" src="../_images/ditaa-f6b228332baf165f498d8a1bb0bc0bdb91ae50c5.png" /> +<p>Note that before a context switch can occur we must do a kernel +transition, either with a system call or with an interrupt. At that +point the user space registers are saved on the kernel stack. At some +point the <code class="xref c c-func docutils literal"><span class="pre">schedule()</span></code> function will be called which can decide +that a context switch must occur from T0 to T1 (e.g. because the +current thread is blocking waiting for an I/O operation to complete or +because it's allocated time slice has expired).</p> +<p>At that point <code class="xref c c-func docutils literal"><span class="pre">context_switch()</span></code> will perform architecture +specific operations and will switch the address space if needed:</p> +<div class="admonition-context-switch highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">__always_inline</span> <span class="k">struct</span> <span class="n">rq</span> <span class="o">*</span> +<span class="nf">context_switch</span><span class="p">(</span><span class="k">struct</span> <span class="n">rq</span> <span class="o">*</span><span class="n">rq</span><span class="p">,</span> <span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">prev</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">next</span><span class="p">,</span> <span class="k">struct</span> <span class="n">rq_flags</span> <span class="o">*</span><span class="n">rf</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">prepare_task_switch</span><span class="p">(</span><span class="n">rq</span><span class="p">,</span> <span class="n">prev</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span> + + <span class="cm">/*</span> +<span class="cm"> * For paravirt, this is coupled with an exit in switch_to to</span> +<span class="cm"> * combine the page table reload and the switch backend into</span> +<span class="cm"> * one hypercall.</span> +<span class="cm"> */</span> + <span class="n">arch_start_context_switch</span><span class="p">(</span><span class="n">prev</span><span class="p">);</span> + + <span class="cm">/*</span> +<span class="cm"> * kernel -> kernel lazy + transfer active</span> +<span class="cm"> * user -> kernel lazy + mmgrab() active</span> +<span class="cm"> *</span> +<span class="cm"> * kernel -> user switch + mmdrop() active</span> +<span class="cm"> * user -> user switch</span> +<span class="cm"> */</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">next</span><span class="o">-></span><span class="n">mm</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// to kernel</span> + <span class="n">enter_lazy_tlb</span><span class="p">(</span><span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span> + + <span class="n">next</span><span class="o">-></span><span class="n">active_mm</span> <span class="o">=</span> <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">;</span> + <span class="k">if</span> <span class="p">(</span><span class="n">prev</span><span class="o">-></span><span class="n">mm</span><span class="p">)</span> <span class="c1">// from user</span> + <span class="n">mmgrab</span><span class="p">(</span><span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">);</span> + <span class="k">else</span> + <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="c1">// to user</span> + <span class="n">membarrier_switch_mm</span><span class="p">(</span><span class="n">rq</span><span class="p">,</span> <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">,</span> <span class="n">next</span><span class="o">-></span><span class="n">mm</span><span class="p">);</span> + <span class="cm">/*</span> +<span class="cm"> * sys_membarrier() requires an smp_mb() between setting</span> +<span class="cm"> * rq->curr / membarrier_switch_mm() and returning to userspace.</span> +<span class="cm"> *</span> +<span class="cm"> * The below provides this either through switch_mm(), or in</span> +<span class="cm"> * case 'prev->active_mm == next->mm' through</span> +<span class="cm"> * finish_task_switch()'s mmdrop().</span> +<span class="cm"> */</span> + <span class="n">switch_mm_irqs_off</span><span class="p">(</span><span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">,</span> <span class="n">next</span><span class="o">-></span><span class="n">mm</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">prev</span><span class="o">-></span><span class="n">mm</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// from kernel</span> + <span class="cm">/* will mmdrop() in finish_task_switch(). */</span> + <span class="n">rq</span><span class="o">-></span><span class="n">prev_mm</span> <span class="o">=</span> <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span><span class="p">;</span> + <span class="n">prev</span><span class="o">-></span><span class="n">active_mm</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="p">}</span> + <span class="p">}</span> + + <span class="n">rq</span><span class="o">-></span><span class="n">clock_update_flags</span> <span class="o">&=</span> <span class="o">~</span><span class="p">(</span><span class="n">RQCF_ACT_SKIP</span><span class="o">|</span><span class="n">RQCF_REQ_SKIP</span><span class="p">);</span> + + <span class="n">prepare_lock_switch</span><span class="p">(</span><span class="n">rq</span><span class="p">,</span> <span class="n">next</span><span class="p">,</span> <span class="n">rf</span><span class="p">);</span> + + <span class="cm">/* Here we just switch the register state and the stack. */</span> + <span class="n">switch_to</span><span class="p">(</span><span class="n">prev</span><span class="p">,</span> <span class="n">next</span><span class="p">,</span> <span class="n">prev</span><span class="p">);</span> + <span class="n">barrier</span><span class="p">();</span> + + <span class="k">return</span> <span class="n">finish_task_switch</span><span class="p">(</span><span class="n">prev</span><span class="p">);</span> + <span class="p">}</span> +</pre></div> +</div> +<p>Then it will call the architecture specific <code class="xref c c-macro docutils literal"><span class="pre">switch_to</span></code> +implementation to switch the registers state and kernel stack. Note +that registers are saved on stack and that the stack pointer is saved +in the task structure:</p> +<div class="admonition-switch-to highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define switch_to(prev, next, last) \</span> +<span class="cp">do { \</span> +<span class="cp"> ((last) = __switch_to_asm((prev), (next))); \</span> +<span class="cp">} while (0)</span> + + +<span class="cm">/*</span> +<span class="cm"> * %eax: prev task</span> +<span class="cm"> * %edx: next task</span> +<span class="cm"> */</span> +<span class="p">.</span><span class="n">pushsection</span> <span class="p">.</span><span class="n">text</span><span class="p">,</span> <span class="s">"ax"</span> +<span class="n">SYM_CODE_START</span><span class="p">(</span><span class="n">__switch_to_asm</span><span class="p">)</span> + <span class="cm">/*</span> +<span class="cm"> * Save callee-saved registers</span> +<span class="cm"> * This must match the order in struct inactive_task_frame</span> +<span class="cm"> */</span> + <span class="n">pushl</span> <span class="o">%</span><span class="n">ebp</span> + <span class="n">pushl</span> <span class="o">%</span><span class="n">ebx</span> + <span class="n">pushl</span> <span class="o">%</span><span class="n">edi</span> + <span class="n">pushl</span> <span class="o">%</span><span class="n">esi</span> + <span class="cm">/*</span> +<span class="cm"> * Flags are saved to prevent AC leakage. This could go</span> +<span class="cm"> * away if objtool would have 32bit support to verify</span> +<span class="cm"> * the STAC/CLAC correctness.</span> +<span class="cm"> */</span> + <span class="n">pushfl</span> + +<span class="hll"> <span class="cm">/* switch stack */</span> +</span><span class="hll"> <span class="n">movl</span> <span class="o">%</span><span class="n">esp</span><span class="p">,</span> <span class="n">TASK_threadsp</span><span class="p">(</span><span class="o">%</span><span class="n">eax</span><span class="p">)</span> +</span><span class="hll"> <span class="n">movl</span> <span class="n">TASK_threadsp</span><span class="p">(</span><span class="o">%</span><span class="n">edx</span><span class="p">),</span> <span class="o">%</span><span class="n">esp</span> +</span> + <span class="cp">#ifdef CONFIG_STACKPROTECTOR</span> + <span class="n">movl</span> <span class="n">TASK_stack_canary</span><span class="p">(</span><span class="o">%</span><span class="n">edx</span><span class="p">),</span> <span class="o">%</span><span class="n">ebx</span> + <span class="n">movl</span> <span class="o">%</span><span class="n">ebx</span><span class="p">,</span> <span class="n">PER_CPU_VAR</span><span class="p">(</span><span class="n">stack_canary</span><span class="p">)</span><span class="o">+</span><span class="n">stack_canary_offset</span> + <span class="cp">#endif</span> + + <span class="cp">#ifdef CONFIG_RETPOLINE</span> + <span class="cm">/*</span> +<span class="cm"> * When switching from a shallower to a deeper call stack</span> +<span class="cm"> * the RSB may either underflow or use entries populated</span> +<span class="cm"> * with userspace addresses. On CPUs where those concerns</span> +<span class="cm"> * exist, overwrite the RSB with entries which capture</span> +<span class="cm"> * speculative execution to prevent attack.</span> +<span class="cm"> */</span> + <span class="n">FILL_RETURN_BUFFER</span> <span class="o">%</span><span class="n">ebx</span><span class="p">,</span> <span class="n">RSB_CLEAR_LOOPS</span><span class="p">,</span> <span class="n">X86_FEATURE_RSB_CTXSW</span> + <span class="cp">#endif</span> + + <span class="cm">/* Restore flags or the incoming task to restore AC state. */</span> + <span class="n">popfl</span> + <span class="cm">/* restore callee-saved registers */</span> + <span class="n">popl</span> <span class="o">%</span><span class="n">esi</span> + <span class="n">popl</span> <span class="o">%</span><span class="n">edi</span> + <span class="n">popl</span> <span class="o">%</span><span class="n">ebx</span> + <span class="n">popl</span> <span class="o">%</span><span class="n">ebp</span> + +<span class="hll"> <span class="n">jmp</span> <span class="n">__switch_to</span> +</span> <span class="n">SYM_CODE_END</span><span class="p">(</span><span class="n">__switch_to_asm</span><span class="p">)</span> + <span class="p">.</span><span class="n">popsection</span> +</pre></div> +</div> +<p>You can notice that the instruction pointer is not explicitly +saved. It is not needed because:</p> +<blockquote> +<div><ul class="simple"> +<li>a task will always resume in this function</li> +<li>the <code class="xref c c-func docutils literal"><span class="pre">schedule()</span></code> (<code class="xref c c-func docutils literal"><span class="pre">context_switch()</span></code> is always +inlined) caller's return address is saved on the kernel stack</li> +<li>a jmp is used to execute <code class="xref c c-func docutils literal"><span class="pre">__switch_to()</span></code> which is a function +and when it returns it will pop the original (next task) return +address from the stack</li> +</ul> +</div></blockquote> +<p>The following screencast uses the debugger to setup a breaking in +__switch_to_asm and examine the stack during the context switch:</p> +<p class="admonition-inspecting-task-struct"> </p> +<asciinema-player src="../_images/context_switch.cast"></asciinema-player><div class="section" id="quiz-context-switch"> +<h3>Quiz: context switch<a class="headerlink" href="#quiz-context-switch" title="Permalink to this headline">¶</a></h3> +<p class="admonition-quiz-context-switch">We are executing a context switch. Select all of the statements that are true.</p> +<ul class="simple"> +<li>the ESP register is saved in the task structure</li> +<li>the EIP register is saved in the task structure</li> +<li>general registers are saved in the task structure</li> +<li>the ESP register is saved on the stack</li> +<li>the EIP register is saved on the stack</li> +<li>general registers are saved on the stack</li> +</ul> +</div> +</div> +<div class="section" id="blocking-and-waking-up-tasks"> +<h2>Blocking and waking up tasks<a class="headerlink" href="#blocking-and-waking-up-tasks" title="Permalink to this headline">¶</a></h2> +<div class="section" id="task-states"> +<h3>Task states<a class="headerlink" href="#task-states" title="Permalink to this headline">¶</a></h3> +<p>The following diagram shows to the task (threads) states and the +possible transitions between them:</p> +<img alt="../_images/ditaa-0b8cde2be9bbd195ac9dcaeac978a8bbe0d3b805.png" class="admonition-task-states" src="../_images/ditaa-0b8cde2be9bbd195ac9dcaeac978a8bbe0d3b805.png" /> +</div> +<div class="section" id="blocking-the-current-thread"> +<h3>Blocking the current thread<a class="headerlink" href="#blocking-the-current-thread" title="Permalink to this headline">¶</a></h3> +<p>Blocking the current thread is an important operation we need to +perform to implement efficient task scheduling - we want to run other +threads while I/O operations complete.</p> +<p>In order to accomplish this the following operations take place:</p> +<ul class="admonition-blocking-the-current-thread simple"> +<li>Set the current thread state to TASK_UINTERRUPTIBLE or +TASK_INTERRUPTIBLE</li> +<li>Add the task to a waiting queue</li> +<li>Call the scheduler which will pick up a new task from the READY +queue</li> +<li>Do the context switch to the new task</li> +</ul> +<p>Below are some snippets for the <code class="xref c c-macro docutils literal"><span class="pre">wait_event</span></code> +implementation. Note that the waiting queue is a list with some extra +information like a pointer to the task struct.</p> +<p>Also note that a lot of effort is put into making sure no deadlock can +occur between <code class="xref c c-macro docutils literal"><span class="pre">wait_event</span></code> and <code class="xref c c-macro docutils literal"><span class="pre">wake_up</span></code>: the task +is added to the list before checking <code class="xref c c-data docutils literal"><span class="pre">condition</span></code>, signals are +checked before calling <code class="xref c c-func docutils literal"><span class="pre">schedule()</span></code>.</p> +<div class="admonition-wait-event highlight-c"><div class="highlight"><pre><span></span><span class="cm">/**</span> +<span class="cm"> * wait_event - sleep until a condition gets true</span> +<span class="cm"> * @wq_head: the waitqueue to wait on</span> +<span class="cm"> * @condition: a C expression for the event to wait for</span> +<span class="cm"> *</span> +<span class="cm"> * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the</span> +<span class="cm"> * @condition evaluates to true. The @condition is checked each time</span> +<span class="cm"> * the waitqueue @wq_head is woken up.</span> +<span class="cm"> *</span> +<span class="cm"> * wake_up() has to be called after changing any variable that could</span> +<span class="cm"> * change the result of the wait condition.</span> +<span class="cm"> */</span> +<span class="cp">#define wait_event(wq_head, condition) \</span> +<span class="cp">do { \</span> +<span class="cp"> might_sleep(); \</span> +<span class="cp"> if (condition) \</span> +<span class="cp"> break; \</span> +<span class="cp"> __wait_event(wq_head, condition); \</span> +<span class="cp">} while (0)</span> + +<span class="cp">#define __wait_event(wq_head, condition) \</span> +<span class="cp"> (void)___wait_event(wq_head, condition, TASK_UNINTERRUPTIBLE, 0, 0, \</span> +<span class="cp"> schedule())</span> + +<span class="cm">/*</span> +<span class="cm"> * The below macro ___wait_event() has an explicit shadow of the __ret</span> +<span class="cm"> * variable when used from the wait_event_*() macros.</span> +<span class="cm"> *</span> +<span class="cm"> * This is so that both can use the ___wait_cond_timeout() construct</span> +<span class="cm"> * to wrap the condition.</span> +<span class="cm"> *</span> +<span class="cm"> * The type inconsistency of the wait_event_*() __ret variable is also</span> +<span class="cm"> * on purpose; we use long where we can return timeout values and int</span> +<span class="cm"> * otherwise.</span> +<span class="cm"> */</span> +<span class="cp">#define ___wait_event(wq_head, condition, state, exclusive, ret, cmd) \</span> +<span class="cp">({ \</span> +<span class="cp"> __label__ __out; \</span> +<span class="cp"> struct wait_queue_entry __wq_entry; \</span> +<span class="cp"> long __ret = ret; </span><span class="cm">/* explicit shadow */</span><span class="cp"> \</span> +<span class="cp"> \</span> +<span class="cp"> init_wait_entry(&__wq_entry, exclusive ? WQ_FLAG_EXCLUSIVE : 0); \</span> +<span class="cp"> for (;;) { \</span> +<span class="cp"> long __int = prepare_to_wait_event(&wq_head, &__wq_entry, state);\</span> +<span class="cp"> \</span> +<span class="cp"> if (condition) \</span> +<span class="cp"> break; \</span> +<span class="cp"> \</span> +<span class="cp"> if (___wait_is_interruptible(state) && __int) { \</span> +<span class="cp"> __ret = __int; \</span> +<span class="cp"> goto __out; \</span> +<span class="cp"> } \</span> +<span class="cp"> \</span> +<span class="cp"> cmd; \</span> +<span class="cp"> } \</span> +<span class="cp"> finish_wait(&wq_head, &__wq_entry); \</span> +<span class="cp"> __out: __ret; \</span> +<span class="cp"> })</span> + + <span class="kt">void</span> <span class="nf">init_wait_entry</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">,</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">wq_entry</span><span class="o">-></span><span class="n">flags</span> <span class="o">=</span> <span class="n">flags</span><span class="p">;</span> + <span class="n">wq_entry</span><span class="o">-></span><span class="n">private</span> <span class="o">=</span> <span class="n">current</span><span class="p">;</span> + <span class="n">wq_entry</span><span class="o">-></span><span class="n">func</span> <span class="o">=</span> <span class="n">autoremove_wake_function</span><span class="p">;</span> + <span class="n">INIT_LIST_HEAD</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="p">}</span> + + <span class="kt">long</span> <span class="nf">prepare_to_wait_event</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">,</span> <span class="kt">int</span> <span class="n">state</span><span class="p">)</span> + <span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + <span class="kt">long</span> <span class="n">ret</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + + <span class="n">spin_lock_irqsave</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">signal_pending_state</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">current</span><span class="p">))</span> <span class="p">{</span> + <span class="cm">/*</span> +<span class="cm"> * Exclusive waiter must not fail if it was selected by wakeup,</span> +<span class="cm"> * it should "consume" the condition we were waiting for.</span> +<span class="cm"> *</span> +<span class="cm"> * The caller will recheck the condition and return success if</span> +<span class="cm"> * we were already woken up, we can not miss the event because</span> +<span class="cm"> * wakeup locks/unlocks the same wq_head->lock.</span> +<span class="cm"> *</span> +<span class="cm"> * But we need to ensure that set-condition + wakeup after that</span> +<span class="cm"> * can't see us, it should wake up another exclusive waiter if</span> +<span class="cm"> * we fail.</span> +<span class="cm"> */</span> + <span class="n">list_del_init</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="n">ret</span> <span class="o">=</span> <span class="o">-</span><span class="n">ERESTARTSYS</span><span class="p">;</span> + <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">list_empty</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">))</span> <span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_EXCLUSIVE</span><span class="p">)</span> + <span class="n">__add_wait_queue_entry_tail</span><span class="p">(</span><span class="n">wq_head</span><span class="p">,</span> <span class="n">wq_entry</span><span class="p">);</span> + <span class="k">else</span> + <span class="n">__add_wait_queue</span><span class="p">(</span><span class="n">wq_head</span><span class="p">,</span> <span class="n">wq_entry</span><span class="p">);</span> + <span class="p">}</span> + <span class="n">set_current_state</span><span class="p">(</span><span class="n">state</span><span class="p">);</span> + <span class="p">}</span> + <span class="n">spin_unlock_irqrestore</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + + <span class="k">return</span> <span class="n">ret</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">static</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="nf">__add_wait_queue</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">list_add</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">,</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">);</span> + <span class="p">}</span> + + <span class="k">static</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="nf">__add_wait_queue_entry_tail</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">list_add_tail</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">,</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">);</span> + <span class="p">}</span> + + <span class="cm">/**</span> +<span class="cm"> * finish_wait - clean up after waiting in a queue</span> +<span class="cm"> * @wq_head: waitqueue waited on</span> +<span class="cm"> * @wq_entry: wait descriptor</span> +<span class="cm"> *</span> +<span class="cm"> * Sets current thread back to running state and removes</span> +<span class="cm"> * the wait descriptor from the given waitqueue if still</span> +<span class="cm"> * queued.</span> +<span class="cm"> */</span> + <span class="kt">void</span> <span class="nf">finish_wait</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">)</span> + <span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + + <span class="n">__set_current_state</span><span class="p">(</span><span class="n">TASK_RUNNING</span><span class="p">);</span> + <span class="cm">/*</span> +<span class="cm"> * We can check for list emptiness outside the lock</span> +<span class="cm"> * IFF:</span> +<span class="cm"> * - we use the "careful" check that verifies both</span> +<span class="cm"> * the next and prev pointers, so that there cannot</span> +<span class="cm"> * be any half-pending updates in progress on other</span> +<span class="cm"> * CPU's that we haven't seen yet (and that might</span> +<span class="cm"> * still change the stack area.</span> +<span class="cm"> * and</span> +<span class="cm"> * - all other users take the lock (ie we can only</span> +<span class="cm"> * have _one_ other CPU that looks at or modifies</span> +<span class="cm"> * the list).</span> +<span class="cm"> */</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">list_empty_careful</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">))</span> <span class="p">{</span> + <span class="n">spin_lock_irqsave</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="n">list_del_init</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="n">spin_unlock_irqrestore</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="p">}</span> + <span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="waking-up-a-task"> +<h3>Waking up a task<a class="headerlink" href="#waking-up-a-task" title="Permalink to this headline">¶</a></h3> +<p>We can wake-up tasks by using the <code class="xref c c-macro docutils literal"><span class="pre">wake_up</span></code> primitive. The +following high level operations are performed to wake up a task:</p> +<ul class="admonition-waking-up-a-task simple"> +<li>Select a task from the waiting queue</li> +<li>Set the task state to TASK_READY</li> +<li>Insert the task into the scheduler's READY queue</li> +<li>On SMP system this is a complex operation: each processor has its +own queue, queues need to be balanced, CPUs needs to be signaled</li> +</ul> +<div class="admonition-wake-up highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)</span> + +<span class="cm">/**</span> +<span class="cm"> * __wake_up - wake up threads blocked on a waitqueue.</span> +<span class="cm"> * @wq_head: the waitqueue</span> +<span class="cm"> * @mode: which threads</span> +<span class="cm"> * @nr_exclusive: how many wake-one or wake-many threads to wake up</span> +<span class="cm"> * @key: is directly passed to the wakeup function</span> +<span class="cm"> *</span> +<span class="cm"> * If this function wakes up a task, it executes a full memory barrier before</span> +<span class="cm"> * accessing the task state.</span> +<span class="cm"> */</span> +<span class="kt">void</span> <span class="nf">__wake_up</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">mode</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">nr_exclusive</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">__wake_up_common_lock</span><span class="p">(</span><span class="n">wq_head</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">nr_exclusive</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">key</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">__wake_up_common_lock</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">mode</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">nr_exclusive</span><span class="p">,</span> <span class="kt">int</span> <span class="n">wake_flags</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + <span class="n">wait_queue_entry_t</span> <span class="n">bookmark</span><span class="p">;</span> + + <span class="n">bookmark</span><span class="p">.</span><span class="n">flags</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="n">bookmark</span><span class="p">.</span><span class="n">private</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="n">bookmark</span><span class="p">.</span><span class="n">func</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> + <span class="n">INIT_LIST_HEAD</span><span class="p">(</span><span class="o">&</span><span class="n">bookmark</span><span class="p">.</span><span class="n">entry</span><span class="p">);</span> + + <span class="k">do</span> <span class="p">{</span> + <span class="n">spin_lock_irqsave</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="n">nr_exclusive</span> <span class="o">=</span> <span class="n">__wake_up_common</span><span class="p">(</span><span class="n">wq_head</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">nr_exclusive</span><span class="p">,</span> + <span class="n">wake_flags</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="o">&</span><span class="n">bookmark</span><span class="p">);</span> + <span class="n">spin_unlock_irqrestore</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span> + <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="n">bookmark</span><span class="p">.</span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_BOOKMARK</span><span class="p">);</span> +<span class="p">}</span> + +<span class="cm">/*</span> +<span class="cm"> * The core wakeup function. Non-exclusive wakeups (nr_exclusive == 0) just</span> +<span class="cm"> * wake everything up. If it's an exclusive wakeup (nr_exclusive == small +ve</span> +<span class="cm"> * number) then we wake all the non-exclusive tasks and one exclusive task.</span> +<span class="cm"> *</span> +<span class="cm"> * There are circumstances in which we can try to wake a task which has already</span> +<span class="cm"> * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns</span> +<span class="cm"> * zero in this (rare) case, and we handle it by continuing to scan the queue.</span> +<span class="cm"> */</span> +<span class="k">static</span> <span class="kt">int</span> <span class="nf">__wake_up_common</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_head</span> <span class="o">*</span><span class="n">wq_head</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">mode</span><span class="p">,</span> + <span class="kt">int</span> <span class="n">nr_exclusive</span><span class="p">,</span> <span class="kt">int</span> <span class="n">wake_flags</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">,</span> + <span class="n">wait_queue_entry_t</span> <span class="o">*</span><span class="n">bookmark</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">wait_queue_entry_t</span> <span class="o">*</span><span class="n">curr</span><span class="p">,</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">cnt</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + + <span class="n">lockdep_assert_held</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">lock</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">bookmark</span> <span class="o">&&</span> <span class="p">(</span><span class="n">bookmark</span><span class="o">-></span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_BOOKMARK</span><span class="p">))</span> <span class="p">{</span> + <span class="n">curr</span> <span class="o">=</span> <span class="n">list_next_entry</span><span class="p">(</span><span class="n">bookmark</span><span class="p">,</span> <span class="n">entry</span><span class="p">);</span> + + <span class="n">list_del</span><span class="p">(</span><span class="o">&</span><span class="n">bookmark</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="n">bookmark</span><span class="o">-></span><span class="n">flags</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + <span class="p">}</span> <span class="k">else</span> + <span class="n">curr</span> <span class="o">=</span> <span class="n">list_first_entry</span><span class="p">(</span><span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">,</span> <span class="n">wait_queue_entry_t</span><span class="p">,</span> <span class="n">entry</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">&</span><span class="n">curr</span><span class="o">-></span><span class="n">entry</span> <span class="o">==</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">)</span> + <span class="k">return</span> <span class="n">nr_exclusive</span><span class="p">;</span> + + <span class="n">list_for_each_entry_safe_from</span><span class="p">(</span><span class="n">curr</span><span class="p">,</span> <span class="n">next</span><span class="p">,</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">,</span> <span class="n">entry</span><span class="p">)</span> <span class="p">{</span> + <span class="kt">unsigned</span> <span class="n">flags</span> <span class="o">=</span> <span class="n">curr</span><span class="o">-></span><span class="n">flags</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">ret</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_BOOKMARK</span><span class="p">)</span> + <span class="k">continue</span><span class="p">;</span> + + <span class="n">ret</span> <span class="o">=</span> <span class="n">curr</span><span class="o">-></span><span class="n">func</span><span class="p">(</span><span class="n">curr</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">wake_flags</span><span class="p">,</span> <span class="n">key</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="n">ret</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> + <span class="k">break</span><span class="p">;</span> + <span class="k">if</span> <span class="p">(</span><span class="n">ret</span> <span class="o">&&</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&</span> <span class="n">WQ_FLAG_EXCLUSIVE</span><span class="p">)</span> <span class="o">&&</span> <span class="o">!--</span><span class="n">nr_exclusive</span><span class="p">)</span> + <span class="k">break</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">bookmark</span> <span class="o">&&</span> <span class="p">(</span><span class="o">++</span><span class="n">cnt</span> <span class="o">></span> <span class="n">WAITQUEUE_WALK_BREAK_CNT</span><span class="p">)</span> <span class="o">&&</span> + <span class="p">(</span><span class="o">&</span><span class="n">next</span><span class="o">-></span><span class="n">entry</span> <span class="o">!=</span> <span class="o">&</span><span class="n">wq_head</span><span class="o">-></span><span class="n">head</span><span class="p">))</span> <span class="p">{</span> + <span class="n">bookmark</span><span class="o">-></span><span class="n">flags</span> <span class="o">=</span> <span class="n">WQ_FLAG_BOOKMARK</span><span class="p">;</span> + <span class="n">list_add_tail</span><span class="p">(</span><span class="o">&</span><span class="n">bookmark</span><span class="o">-></span><span class="n">entry</span><span class="p">,</span> <span class="o">&</span><span class="n">next</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + <span class="k">break</span><span class="p">;</span> + <span class="p">}</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="n">nr_exclusive</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">int</span> <span class="nf">autoremove_wake_function</span><span class="p">(</span><span class="k">struct</span> <span class="n">wait_queue_entry</span> <span class="o">*</span><span class="n">wq_entry</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">mode</span><span class="p">,</span> <span class="kt">int</span> <span class="n">sync</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">default_wake_function</span><span class="p">(</span><span class="n">wq_entry</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">sync</span><span class="p">,</span> <span class="n">key</span><span class="p">);</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">ret</span><span class="p">)</span> + <span class="n">list_del_init_careful</span><span class="p">(</span><span class="o">&</span><span class="n">wq_entry</span><span class="o">-></span><span class="n">entry</span><span class="p">);</span> + + <span class="k">return</span> <span class="n">ret</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">int</span> <span class="nf">default_wake_function</span><span class="p">(</span><span class="n">wait_queue_entry_t</span> <span class="o">*</span><span class="n">curr</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">mode</span><span class="p">,</span> <span class="kt">int</span> <span class="n">wake_flags</span><span class="p">,</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">key</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">WARN_ON_ONCE</span><span class="p">(</span><span class="n">IS_ENABLED</span><span class="p">(</span><span class="n">CONFIG_SCHED_DEBUG</span><span class="p">)</span> <span class="o">&&</span> <span class="n">wake_flags</span> <span class="o">&</span> <span class="o">~</span><span class="n">WF_SYNC</span><span class="p">);</span> + <span class="k">return</span> <span class="n">try_to_wake_up</span><span class="p">(</span><span class="n">curr</span><span class="o">-></span><span class="n">private</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">wake_flags</span><span class="p">);</span> +<span class="p">}</span> + +<span class="cm">/**</span> +<span class="cm"> * try_to_wake_up - wake up a thread</span> +<span class="cm"> * @p: the thread to be awakened</span> +<span class="cm"> * @state: the mask of task states that can be woken</span> +<span class="cm"> * @wake_flags: wake modifier flags (WF_*)</span> +<span class="cm"> *</span> +<span class="cm"> * Conceptually does:</span> +<span class="cm"> *</span> +<span class="cm"> * If (@state & @p->state) @p->state = TASK_RUNNING.</span> +<span class="cm"> *</span> +<span class="cm"> * If the task was not queued/runnable, also place it back on a runqueue.</span> +<span class="cm"> *</span> +<span class="cm"> * This function is atomic against schedule() which would dequeue the task.</span> +<span class="cm"> *</span> +<span class="cm"> * It issues a full memory barrier before accessing @p->state, see the comment</span> +<span class="cm"> * with set_current_state().</span> +<span class="cm"> *</span> +<span class="cm"> * Uses p->pi_lock to serialize against concurrent wake-ups.</span> +<span class="cm"> *</span> +<span class="cm"> * Relies on p->pi_lock stabilizing:</span> +<span class="cm"> * - p->sched_class</span> +<span class="cm"> * - p->cpus_ptr</span> +<span class="cm"> * - p->sched_task_group</span> +<span class="cm"> * in order to do migration, see its use of select_task_rq()/set_task_cpu().</span> +<span class="cm"> *</span> +<span class="cm"> * Tries really hard to only take one task_rq(p)->lock for performance.</span> +<span class="cm"> * Takes rq->lock in:</span> +<span class="cm"> * - ttwu_runnable() -- old rq, unavoidable, see comment there;</span> +<span class="cm"> * - ttwu_queue() -- new rq, for enqueue of the task;</span> +<span class="cm"> * - psi_ttwu_dequeue() -- much sadness :-( accounting will kill us.</span> +<span class="cm"> *</span> +<span class="cm"> * As a consequence we race really badly with just about everything. See the</span> +<span class="cm"> * many memory barriers and their comments for details.</span> +<span class="cm"> *</span> +<span class="cm"> * Return: %true if @p->state changes (an actual wakeup was done),</span> +<span class="cm"> * %false otherwise.</span> +<span class="cm"> */</span> + <span class="k">static</span> <span class="kt">int</span> + <span class="nf">try_to_wake_up</span><span class="p">(</span><span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">p</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">state</span><span class="p">,</span> <span class="kt">int</span> <span class="n">wake_flags</span><span class="p">)</span> + <span class="p">{</span> + <span class="p">...</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="preempting-tasks"> +<h2>Preempting tasks<a class="headerlink" href="#preempting-tasks" title="Permalink to this headline">¶</a></h2> +<p>Up until this point we look at how context switches occurs voluntary +between threads. Next we will look at how preemption is handled. We +will start wight the simpler case where the kernel is configured as +non preemptive and then we will move to the preemptive kernel case.</p> +<div class="section" id="non-preemptive-kernel"> +<h3>Non preemptive kernel<a class="headerlink" href="#non-preemptive-kernel" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-non-preemptive-kernel simple"> +<li>At every tick the kernel checks to see if the current process has +its time slice consumed</li> +<li>If that happens a flag is set in interrupt context</li> +<li>Before returning to userspace the kernel checks this flag and +calls <code class="xref c c-func docutils literal"><span class="pre">schedule()</span></code> if needed</li> +<li>In this case tasks are not preempted while running in kernel mode +(e.g. system call) so there are no synchronization issues</li> +</ul> +</div> +<div class="section" id="preemptive-kernel"> +<h3>Preemptive kernel<a class="headerlink" href="#preemptive-kernel" title="Permalink to this headline">¶</a></h3> +<p>In this case the current task can be preempted even if we are running +in kernel mode and executing a system call. This requires using a +special synchronization primitives: <code class="xref c c-macro docutils literal"><span class="pre">preempt_disable</span></code> and +<code class="xref c c-macro docutils literal"><span class="pre">preempt_enable</span></code>.</p> +<p>In order to simplify handling for preemptive kernels and since +synchronization primitives are needed for the SMP case anyway, +preemption is disabled automatically when a spinlock is used.</p> +<p>As before, if we run into a condition that requires the preemption of +the current task (its time slices has expired) a flag is set. This +flag is checked whenever the preemption is reactivated, e.g. when +exiting a critical section through a <code class="xref c c-func docutils literal"><span class="pre">spin_unlock()</span></code> and if +needed the scheduler is called to select a new task.</p> +<span class="admonition-preemptive-kernel"></span></div> +</div> +<div class="section" id="process-context"> +<h2>Process context<a class="headerlink" href="#process-context" title="Permalink to this headline">¶</a></h2> +<p>Now that we have examined the implementation of processes and threads +(tasks), how context switching occurs, how we can block, wake-up and +preempt tasks, we can finally define what the process context is what +are its properties:</p> +<p class="admonition-process-context">The kernel is executing in process context when it is running a +system call.</p> +<p>In process context there is a well defined context and we can +access the current process data with <code class="xref c c-macro docutils literal"><span class="pre">current</span></code></p> +<p>In process context we can sleep (wait on a condition).</p> +<p>In process context we can access the user-space (unless we are +running in a kernel thread context).</p> +<div class="section" id="kernel-threads"> +<h3>Kernel threads<a class="headerlink" href="#kernel-threads" title="Permalink to this headline">¶</a></h3> +<p class="admonition-kernel-threads">Sometimes the kernel core or device drivers need to perform blocking +operations and thus they need to run in process context.</p> +<p>Kernel threads are used exactly for this and are a special class of +tasks that don't "userspace" resources (e.g. no address space or +opened files).</p> +<p>The following screencast takes a closer look at kernel threads:</p> +<p class="admonition-inspecting-kernel-threads"> </p> +<asciinema-player src="../_images/kernel_threads.cast"></asciinema-player></div> +</div> +<div class="section" id="using-gdb-scripts-for-kernel-inspection"> +<h2>Using gdb scripts for kernel inspection<a class="headerlink" href="#using-gdb-scripts-for-kernel-inspection" title="Permalink to this headline">¶</a></h2> +<p>The Linux kernel comes with a predefined set of gdb extra commands we +can use to inspect the kernel during debugging. They will +automatically be loaded as long gdbinit is properly setup</p> +<div class="highlight-sh"><div class="highlight"><pre><span></span>ubuntu@so2:/linux/tools/labs$ cat ~/.gdbinit +add-auto-load-safe-path /linux/scripts/gdb/vmlinux-gdb.py +</pre></div> +</div> +<p>All of the kernel specific commands are prefixed with lx-. You can use +TAB in gdb to list all of them:</p> +<div class="highlight-sh"><div class="highlight"><pre><span></span><span class="o">(</span>gdb<span class="o">)</span> lx- +lx-clk-summary lx-dmesg lx-mounts +lx-cmdline lx-fdtdump lx-ps +lx-configdump lx-genpd-summary lx-symbols +lx-cpus lx-iomem lx-timerlist +lx-device-list-bus lx-ioports lx-version +lx-device-list-class lx-list-check +lx-device-list-tree lx-lsmod +</pre></div> +</div> +<p>The implementation of the commands can be found at +<cite>script/gdb/linux</cite>. Lets take a closer look at the lx-ps +implementation:</p> +<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">task_type</span> <span class="o">=</span> <span class="n">utils</span><span class="o">.</span><span class="n">CachedType</span><span class="p">(</span><span class="s2">"struct task_struct"</span><span class="p">)</span> + + +<span class="k">def</span> <span class="nf">task_lists</span><span class="p">():</span> + <span class="n">task_ptr_type</span> <span class="o">=</span> <span class="n">task_type</span><span class="o">.</span><span class="n">get_type</span><span class="p">()</span><span class="o">.</span><span class="n">pointer</span><span class="p">()</span> + <span class="n">init_task</span> <span class="o">=</span> <span class="n">gdb</span><span class="o">.</span><span class="n">parse_and_eval</span><span class="p">(</span><span class="s2">"init_task"</span><span class="p">)</span><span class="o">.</span><span class="n">address</span> + <span class="n">t</span> <span class="o">=</span> <span class="n">g</span> <span class="o">=</span> <span class="n">init_task</span> + + <span class="k">while</span> <span class="bp">True</span><span class="p">:</span> + <span class="k">while</span> <span class="bp">True</span><span class="p">:</span> + <span class="k">yield</span> <span class="n">t</span> + + <span class="n">t</span> <span class="o">=</span> <span class="n">utils</span><span class="o">.</span><span class="n">container_of</span><span class="p">(</span><span class="n">t</span><span class="p">[</span><span class="s1">'thread_group'</span><span class="p">][</span><span class="s1">'next'</span><span class="p">],</span> + <span class="n">task_ptr_type</span><span class="p">,</span> <span class="s2">"thread_group"</span><span class="p">)</span> + <span class="k">if</span> <span class="n">t</span> <span class="o">==</span> <span class="n">g</span><span class="p">:</span> + <span class="k">break</span> + + <span class="n">t</span> <span class="o">=</span> <span class="n">g</span> <span class="o">=</span> <span class="n">utils</span><span class="o">.</span><span class="n">container_of</span><span class="p">(</span><span class="n">g</span><span class="p">[</span><span class="s1">'tasks'</span><span class="p">][</span><span class="s1">'next'</span><span class="p">],</span> + <span class="n">task_ptr_type</span><span class="p">,</span> <span class="s2">"tasks"</span><span class="p">)</span> + <span class="k">if</span> <span class="n">t</span> <span class="o">==</span> <span class="n">init_task</span><span class="p">:</span> + <span class="k">return</span> + + + <span class="k">class</span> <span class="nc">LxPs</span><span class="p">(</span><span class="n">gdb</span><span class="o">.</span><span class="n">Command</span><span class="p">):</span> + <span class="sd">"""Dump Linux tasks."""</span> + + <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="nb">super</span><span class="p">(</span><span class="n">LxPs</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="s2">"lx-ps"</span><span class="p">,</span> <span class="n">gdb</span><span class="o">.</span><span class="n">COMMAND_DATA</span><span class="p">)</span> + + <span class="k">def</span> <span class="nf">invoke</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">arg</span><span class="p">,</span> <span class="n">from_tty</span><span class="p">):</span> + <span class="n">gdb</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">"{:>10} {:>12} {:>7}</span><span class="se">\n</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">"TASK"</span><span class="p">,</span> <span class="s2">"PID"</span><span class="p">,</span> <span class="s2">"COMM"</span><span class="p">))</span> + <span class="k">for</span> <span class="n">task</span> <span class="ow">in</span> <span class="n">task_lists</span><span class="p">():</span> + <span class="n">gdb</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">"{} {:^5} {}</span><span class="se">\n</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span> + <span class="n">task</span><span class="o">.</span><span class="n">format_string</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">()[</span><span class="mi">0</span><span class="p">],</span> + <span class="n">task</span><span class="p">[</span><span class="s2">"pid"</span><span class="p">]</span><span class="o">.</span><span class="n">format_string</span><span class="p">(),</span> + <span class="n">task</span><span class="p">[</span><span class="s2">"comm"</span><span class="p">]</span><span class="o">.</span><span class="n">string</span><span class="p">()))</span> +</pre></div> +</div> +<div class="section" id="quiz-kernel-gdb-scripts"> +<h3>Quiz: Kernel gdb scripts<a class="headerlink" href="#quiz-kernel-gdb-scripts" title="Permalink to this headline">¶</a></h3> +<p class="admonition-quiz-kernel-gdb-scripts">What is the following change of the lx-ps script trying to +accomplish?</p> +<div class="highlight-diff"><div class="highlight"><pre><span></span><span class="gh">diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py</span> +<span class="gh">index 17ec19e9b5bf..7e43c163832f 100644</span> +<span class="gd">--- a/scripts/gdb/linux/tasks.py</span> +<span class="gi">+++ b/scripts/gdb/linux/tasks.py</span> +<span class="gu">@@ -75,10 +75,13 @@ class LxPs(gdb.Command):</span> + def invoke(self, arg, from_tty): + gdb.write("{:>10} {:>12} {:>7}\n".format("TASK", "PID", "COMM")) + for task in task_lists(): +<span class="gd">- gdb.write("{} {:^5} {}\n".format(</span> +<span class="gi">+ check = task["mm"].format_string() == "0x0"</span> +<span class="gi">+ gdb.write("{} {:^5} {}{}{}\n".format(</span> + task.format_string().split()[0], + task["pid"].format_string(), +<span class="gd">- task["comm"].string()))</span> +<span class="gi">+ "[" if check else "",</span> +<span class="gi">+ task["comm"].string(),</span> +<span class="gi">+ "]" if check else ""))</span> + + + LxPs() +</pre></div> +</div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lec2-syscalls.html" class="btn btn-neutral float-left" title="SO2 Lecture 02 - System calls" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lec4-interrupts.html" class="btn btn-neutral float-right" title="SO2 Lecture 04 - Interrupts" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec4-interrupts-slides.html b/refs/pull/405/merge/so2/lec4-interrupts-slides.html new file mode 100644 index 00000000..0d2932d8 --- /dev/null +++ b/refs/pull/405/merge/so2/lec4-interrupts-slides.html @@ -0,0 +1,638 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>SO2 Lecture 04 - Interrupts — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="up" title="Operating Systems 2" href="index.html" /> + <link rel="next" title="SO2 Lecture 05 - Symmetric Multi-Processing" href="lec5-smp.html" /> + <link rel="prev" title="SO2 Lecture 03 - Processes" href="lec3-processes.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-so2-lecture-04-interrupts slide level-1"> + +<h1>SO2 Lecture 04 - Interrupts</h1> + + + + + +</article> +<article class="admonition-interrupts slide level-2"> + +<h2>Interrupts</h2> + +<ul class="simple"> +<li>Interrupts and exceptions (x86)</li> +<li>Interrupts and exceptions (Linux)</li> +<li>Deferrable work</li> +<li>Timers</li> +</ul> + + + + +</article> +<article class="admonition-interrupts slide level-2"> + +<h2>Interrupts</h2> + +<ul class="simple"> +<li><strong>synchronous</strong>, generated by executing an instruction</li> +<li><strong>asynchronous</strong>, generated by an external event</li> +<li><strong>maskable</strong><ul> +<li>can be ignored</li> +<li>signaled via INT pin</li> +</ul> +</li> +<li><strong>non-maskable</strong><ul> +<li>cannot be ignored</li> +<li>signaled via NMI pin</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-exceptions slide level-2"> + +<h2>Exceptions</h2> + +<ul class="simple"> +<li>processor detected<ul> +<li><strong>faults</strong></li> +<li><strong>traps</strong></li> +<li><strong>aborts</strong></li> +</ul> +</li> +<li>programmed<ul> +<li><strong>int n</strong></li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-quiz-interrupt-terminology slide level-2"> + +<h2>Quiz: interrupt terminology</h2> + +<p>For each of the following terms on the left select all the terms +from right that best describe them.</p> +<table class="hlist"><tr><td><ul class="simple"> +<li>Watchdog</li> +<li>Demand paging</li> +<li>Division by zero</li> +<li>Timer</li> +<li>System call</li> +<li>Breakpoint</li> +</ul> +</td><td><ul class="simple"> +<li>Exception</li> +<li>Interrupt</li> +<li>Maskable</li> +<li>Nonmaskable</li> +<li>Trap</li> +<li>Fault</li> +</ul> +</td></tr></table> + + + + +</article> +<article class="admonition-programmable-interrupt-controller slide level-2"> + +<h2>Programmable Interrupt Controller</h2> + +<p> </p> +<img alt="../_images/ditaa-5db1739b80a83b12505e4ff749b5e69fccd01f1b.png" src="../_images/ditaa-5db1739b80a83b12505e4ff749b5e69fccd01f1b.png" /> + + + + +</article> +<article class="admonition-interrupt-controllers-in-smp-systems slide level-2"> + +<h2>Interrupt controllers in SMP systems</h2> + +<p> </p> +<img alt="../_images/ditaa-9d23d02ebdff6eeb6bec8044480f055de9852ecc.png" src="../_images/ditaa-9d23d02ebdff6eeb6bec8044480f055de9852ecc.png" /> + + + + +</article> +<article class="admonition-enabling-disabling-the-interrupts slide level-2"> + +<h2>Enabling/disabling the interrupts</h2> + +<ul class="simple"> +<li>at the device level<ul> +<li>by programming the device control registers</li> +</ul> +</li> +<li>at the PIC level<ul> +<li>PIC can be programmed to disable a given IRQ line</li> +</ul> +</li> +<li>at the CPU level; for example, on x86 one can use the following +instructions:</li> +</ul> +<blockquote> +<div><ul class="simple"> +<li>cli (CLear Interrupt flag)</li> +<li>sti (SeT Interrupt flag)</li> +</ul> +</div></blockquote> + + + + +</article> +<article class="admonition-interrupt-priorities slide level-2"> + +<h2>Interrupt priorities</h2> + +<p> </p> +<img alt="../_images/ditaa-8b00a68b494f72d54b5fad38c88f7265aadaaa0e.png" src="../_images/ditaa-8b00a68b494f72d54b5fad38c88f7265aadaaa0e.png" /> + + + + +</article> +<article class="admonition-quiz-hardware-concepts slide level-2"> + +<h2>Quiz: hardware concepts</h2> + +<p>Which of the following statements are true?</p> +<ul class="simple"> +<li>The CPU can start processing a new interrupt before the current +one is finished</li> +<li>Interrupts can be disabled at the device level</li> +<li>Lower priority interrupts can not preempt handlers for higher +priority interrupts</li> +<li>Interrupts can be disabled at the interrupt controller level</li> +<li>On SMP systems the same interrupt can be routed to different CPUs</li> +<li>Interrupts can be disabled at the CPU level</li> +</ul> + + + + +</article> +<article class="admonition-interrupt-descriptor-table slide level-2"> + +<h2>Interrupt Descriptor Table</h2> + +<ul class="simple"> +<li>it is used as a jump table by the CPU when a given vector is triggered</li> +<li>it is an array of 256 x 8 bytes entries</li> +<li>may reside anywhere in physical memory</li> +<li>processor locates IDT by the means of IDTR</li> +</ul> + + + + +</article> +<article class="admonition-linux-irq-vector-layout slide level-2"> + +<h2>Linux IRQ vector layout</h2> + +<p> </p> +<img alt="../_images/ditaa-5b3c93f6e612d0cc0e4d4837d92a443627405262.png" src="../_images/ditaa-5b3c93f6e612d0cc0e4d4837d92a443627405262.png" /> + + + + +</article> +<article class="admonition-interrupt-descriptor-table-entry-gate slide level-2"> + +<h2>Interrupt descriptor table entry (gate)</h2> + +<p> </p> +<img alt="../_images/ditaa-eff5e0e3b58ce239d5310b22b89c0927be5853bd.png" src="../_images/ditaa-eff5e0e3b58ce239d5310b22b89c0927be5853bd.png" /> + + + + +</article> +<article class="admonition-interrupt-handler-address slide level-2"> + +<h2>Interrupt handler address</h2> + +<p> </p> +<img alt="../_images/ditaa-b2023fce22479e20bbe08fd76eed87e9a0527688.png" src="../_images/ditaa-b2023fce22479e20bbe08fd76eed87e9a0527688.png" /> + + + + +</article> +<article class="admonition-interrupt-handler-stack slide level-2"> + +<h2>Interrupt handler stack</h2> + +<p> </p> +<img alt="../_images/ditaa-85b69602726fa6143fc3ba0ffdb492454864aacf.png" src="../_images/ditaa-85b69602726fa6143fc3ba0ffdb492454864aacf.png" /> + + + + +</article> +<article class="admonition-handling-an-interrupt-request slide level-2"> + +<h2>Handling an interrupt request</h2> + +<ul> +<li><p class="first">CPU checks the current privilege level</p> +</li> +<li><p class="first">if need to change privilege level</p> +<blockquote> +<div><ul class="simple"> +<li>change stack with the one associated with new privilege</li> +<li>save old stack information on the new stack</li> +</ul> +</div></blockquote> +</li> +<li><p class="first">save EFLAGS, CS, EIP on stack</p> +</li> +<li><p class="first">save error code on stack in case of an abort</p> +</li> +<li><p class="first">execute the kernel interrupt handler</p> +</li> +</ul> + + + + +</article> +<article class="admonition-returning-from-an-interrupt slide level-2"> + +<h2>Returning from an interrupt</h2> + +<ul class="simple"> +<li>pop the error code (in case of an abort)</li> +<li>call IRET<ul> +<li>pops values from the stack and restore the following register: CS, EIP, EFLAGS</li> +<li>if privilege level changed returns to the old stack and old privilege level</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-inspecting-the-x86-interrupt-handling slide level-2"> + +<h2>Inspecting the x86 interrupt handling</h2> + +<p> </p> +<asciinema-player src="../_images/intr_x86.cast"></asciinema-player> + + + +</article> +<article class="admonition-quiz-x86-interrupt-handling slide level-2"> + +<h2>Quiz: x86 interrupt handling</h2> + +<p>The following gdb commands are used to determine the handler for +the int80 based system call exception. Select and arrange the +commands or output of the commands in the correct order.</p> +<div class="highlight-gdb"><div class="highlight"><pre><span></span>(void *) 0xc15de780 <entry_SYSENTER_32> + +set $idtr_addr=($idtr_entry>>48<<16)|($idtr_entry&0xffff) + +print (void*)$idtr_addr + +set $idtr = 0xff800000 + +(void *) 0xc15de874 <entry_INT80_32> + +set $idtr = 0xff801000 + +set $idtr_entry = *(uint64_t*)($idtr + 8 * 128) + +monitor info registers +</pre></div> +</div> + + + + +</article> +<article class="admonition-interrupt-handling-in-linux slide level-2"> + +<h2>Interrupt handling in Linux</h2> + +<p> </p> +<img alt="../_images/ditaa-da31e3d17a4d55e5c3dbc0bd5903306418a896ca.png" src="../_images/ditaa-da31e3d17a4d55e5c3dbc0bd5903306418a896ca.png" /> + + + + +</article> +<article class="admonition-irq-and-exception-nesting-in-linux slide level-2"> + +<h2>IRQ and exception nesting in Linux</h2> + +<ul class="simple"> +<li>an exception (e.g. page fault, system call) can not preempt an interrupt; +if that occurs it is considered a bug</li> +<li>an interrupt can preempt an exception</li> +<li>an interrupt can not preempt another interrupt (it used to be possible)</li> +</ul> + + + + +</article> +<article class="admonition-interrupt-exception-nesting slide level-2"> + +<h2>Interrupt/Exception nesting</h2> + +<p> </p> +<img alt="../_images/ditaa-2e49ca6ac606dab4b2b53231cfbe85ff06312d36.png" src="../_images/ditaa-2e49ca6ac606dab4b2b53231cfbe85ff06312d36.png" /> + + + + +</article> +<article class="admonition-interrupt-context slide level-2"> + +<h2>Interrupt context</h2> + +<blockquote> +<div><ul class="simple"> +<li>it runs as a result of an IRQ (not of an exception)</li> +<li>there is no well defined process context associated</li> +<li>not allowed to trigger a context switch (no sleep, schedule, or user memory access)</li> +</ul> +</div></blockquote> + + + + +</article> +<article class="admonition-deferrable-actions slide level-2"> + +<h2>Deferrable actions</h2> + +<blockquote> +<div><ul class="simple"> +<li>Schedule callback functions to run at a later time</li> +<li>Interrupt context deferrable actions</li> +<li>Process context deferrable actions</li> +<li>APIs for initialization, scheduling, and masking</li> +</ul> +</div></blockquote> + + + + +</article> +<article class="admonition-soft-irqs slide level-2"> + +<h2>Soft IRQs</h2> + +<blockquote> +<div><p>Soft IRQ APIs:</p> +<blockquote> +<div><ul class="simple"> +<li>initialize: <code class="xref c c-func docutils literal"><span class="pre">open_softirq()</span></code></li> +<li>activation: <code class="xref c c-func docutils literal"><span class="pre">raise_softirq()</span></code></li> +<li>masking: <code class="xref c c-func docutils literal"><span class="pre">local_bh_disable()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">local_bh_enable()</span></code></li> +</ul> +</div></blockquote> +<p>Once activated, the callback function <code class="xref c c-func docutils literal"><span class="pre">do_softirq()</span></code> runs either:</p> +<blockquote> +<div><ul class="simple"> +<li>after an interrupt handler or</li> +<li>from the ksoftirqd kernel thread</li> +</ul> +</div></blockquote> +</div></blockquote> + + + + +</article> +<article class="admonition-ksoftirqd slide level-2"> + +<h2>ksoftirqd</h2> + +<blockquote> +<div><ul class="simple"> +<li>minimum priority kernel thread</li> +<li>runs softirqs after certain limits are reached</li> +<li>tries to achieve good latency and avoid process starvation</li> +</ul> +</div></blockquote> + + + + +</article> +<article class="admonition-types-of-soft-irqs slide level-2"> + +<h2>Types of soft IRQs</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* PLEASE, avoid to allocate new softirqs, if you need not _really_ high</span> +<span class="cm"> frequency threaded job scheduling. For almost all the purposes</span> +<span class="cm"> tasklets are more than enough. F.e. all serial device BHs et</span> +<span class="cm"> al. should be converted to tasklets, not to softirqs.</span> +<span class="cm">*/</span> + +<span class="k">enum</span> +<span class="p">{</span> + <span class="n">HI_SOFTIRQ</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> + <span class="n">TIMER_SOFTIRQ</span><span class="p">,</span> + <span class="n">NET_TX_SOFTIRQ</span><span class="p">,</span> + <span class="n">NET_RX_SOFTIRQ</span><span class="p">,</span> + <span class="n">BLOCK_SOFTIRQ</span><span class="p">,</span> + <span class="n">IRQ_POLL_SOFTIRQ</span><span class="p">,</span> + <span class="n">TASKLET_SOFTIRQ</span><span class="p">,</span> + <span class="n">SCHED_SOFTIRQ</span><span class="p">,</span> + <span class="n">HRTIMER_SOFTIRQ</span><span class="p">,</span> + <span class="n">RCU_SOFTIRQ</span><span class="p">,</span> <span class="cm">/* Preferable RCU should always be the last softirq */</span> + + <span class="n">NR_SOFTIRQS</span> +<span class="p">};</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-packet-flood-example slide level-2"> + +<h2>Packet flood example</h2> + +<p> </p> +<asciinema-player src="../_images/ksoftirqd-packet-flood.cast"></asciinema-player> + + + +</article> +<article class="admonition-tasklets slide level-2"> + +<h2>Tasklets</h2> + +<p>Tasklets are a dynamic type (not limited to a fixed number) of +deferred work running in interrupt context.</p> +<p>Tasklets API:</p> +<blockquote> +<div><ul class="simple"> +<li>initialization: <code class="xref c c-func docutils literal"><span class="pre">tasklet_init()</span></code></li> +<li>activation: <code class="xref c c-func docutils literal"><span class="pre">tasklet_schedule()</span></code></li> +<li>masking: <code class="xref c c-func docutils literal"><span class="pre">tasklet_disable()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">tasklet_enable()</span></code></li> +</ul> +</div></blockquote> +<p>Tasklets are implemented on top of two dedicated softirqs: +<code class="xref c c-macro docutils literal"><span class="pre">TASKLET_SOFITIRQ</span></code> and <code class="xref c c-macro docutils literal"><span class="pre">HI_SOFTIRQ</span></code></p> +<p>Tasklets are also serialized, i.e. the same tasklet can only execute on one processor.</p> + + + + +</article> +<article class="admonition-workqueues slide level-2"> + +<h2>Workqueues</h2> + +<p>Workqueues are a type of deferred work that runs in process context.</p> +<p>They are implemented on top of kernel threads.</p> +<p>Workqueues API:</p> +<blockquote> +<div><ul class="simple"> +<li>init: <code class="xref c c-macro docutils literal"><span class="pre">INIT_WORK</span></code></li> +<li>activation: <code class="xref c c-func docutils literal"><span class="pre">schedule_work()</span></code></li> +</ul> +</div></blockquote> + + + + +</article> +<article class="admonition-timers slide level-2"> + +<h2>Timers</h2> + +<blockquote> +<div><p>Timers are implemented on top of the <code class="xref c c-macro docutils literal"><span class="pre">TIMER_SOFTIRQ</span></code></p> +<p>Timer API:</p> +<ul class="simple"> +<li>initialization: <code class="xref c c-func docutils literal"><span class="pre">setup_timer()</span></code></li> +<li>activation: <code class="xref c c-func docutils literal"><span class="pre">mod_timer()</span></code></li> +</ul> +</div></blockquote> + + + + +</article> +<article class="admonition-deferrable-actions-summary slide level-2"> + +<h2>Deferrable actions summary</h2> + +<blockquote> +<div><ul class="simple"> +<li>softIRQ<ul> +<li>runs in interrupt context</li> +<li>statically allocated</li> +<li>same handler may run in parallel on multiple cores</li> +</ul> +</li> +<li>tasklet<ul> +<li>runs in interrupt context</li> +<li>can be dynamically allocated</li> +<li>same handler runs are serialized</li> +</ul> +</li> +<li>workqueues<ul> +<li>run in process context</li> +</ul> +</li> +</ul> +</div></blockquote> + + + + +</article> +<article class="admonition-quiz-linux-interrupt-handling slide level-2"> + +<h2>Quiz: Linux interrupt handling</h2> + +<p>Which of the following phases of interrupt handling runs with +interrupts disabled at the CPU level?</p> +<ul class="simple"> +<li>Critical</li> +<li>Immediate</li> +<li>Deferred</li> +</ul> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec4-interrupts.html b/refs/pull/405/merge/so2/lec4-interrupts.html new file mode 100644 index 00000000..f9ab1e6f --- /dev/null +++ b/refs/pull/405/merge/so2/lec4-interrupts.html @@ -0,0 +1,790 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lecture 04 - Interrupts — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lecture 05 - Symmetric Multi-Processing" href="lec5-smp.html" /> + <link rel="prev" title="SO2 Lecture 03 - Processes" href="lec3-processes.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lecture 04 - Interrupts</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lecture-objectives">Lecture objectives</a></li> +<li class="toctree-l3"><a class="reference internal" href="#what-is-an-interrupt">What is an interrupt?</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#exceptions">Exceptions</a></li> +<li class="toctree-l4"><a class="reference internal" href="#quiz-interrupt-terminology">Quiz: interrupt terminology</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#hardware-concepts">Hardware Concepts</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#programmable-interrupt-controller">Programmable Interrupt Controller</a></li> +<li class="toctree-l4"><a class="reference internal" href="#interrupt-controllers-in-smp-systems">Interrupt controllers in SMP systems</a></li> +<li class="toctree-l4"><a class="reference internal" href="#interrupt-control">Interrupt Control</a></li> +<li class="toctree-l4"><a class="reference internal" href="#interrupt-priorities">Interrupt priorities</a></li> +<li class="toctree-l4"><a class="reference internal" href="#quiz-hardware-concepts">Quiz: hardware concepts</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#interrupt-handling-on-the-x86-architecture">Interrupt handling on the x86 architecture</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#interrupt-descriptor-table">Interrupt Descriptor Table</a></li> +<li class="toctree-l4"><a class="reference internal" href="#interrupt-handler-address">Interrupt handler address</a></li> +<li class="toctree-l4"><a class="reference internal" href="#stack-of-interrupt-handler">Stack of interrupt handler</a></li> +<li class="toctree-l4"><a class="reference internal" href="#handling-an-interrupt-request">Handling an interrupt request</a></li> +<li class="toctree-l4"><a class="reference internal" href="#returning-from-an-interrupt-handler">Returning from an interrupt handler</a></li> +<li class="toctree-l4"><a class="reference internal" href="#inspecting-the-x86-interrupt-handling">Inspecting the x86 interrupt handling</a></li> +<li class="toctree-l4"><a class="reference internal" href="#quiz-x86-interrupt-handling">Quiz: x86 interrupt handling</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#interrupt-handling-in-linux">Interrupt handling in Linux</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#nested-interrupts-and-exceptions">Nested interrupts and exceptions</a></li> +<li class="toctree-l4"><a class="reference internal" href="#interrupt-context">Interrupt context</a></li> +<li class="toctree-l4"><a class="reference internal" href="#deferrable-actions">Deferrable actions</a></li> +<li class="toctree-l4"><a class="reference internal" href="#soft-irqs">Soft IRQs</a></li> +<li class="toctree-l4"><a class="reference internal" href="#packet-flood-example">Packet flood example</a></li> +<li class="toctree-l4"><a class="reference internal" href="#tasklets">Tasklets</a></li> +<li class="toctree-l4"><a class="reference internal" href="#workqueues">Workqueues</a></li> +<li class="toctree-l4"><a class="reference internal" href="#timers">Timers</a></li> +<li class="toctree-l4"><a class="reference internal" href="#deferrable-actions-summary">Deferrable actions summary</a></li> +<li class="toctree-l4"><a class="reference internal" href="#quiz-linux-interrupt-handling">Quiz: Linux interrupt handling</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lecture 04 - Interrupts</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lec4-interrupts.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lecture-04-interrupts"> +<h1>SO2 Lecture 04 - Interrupts<a class="headerlink" href="#so2-lecture-04-interrupts" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="lec4-interrupts-slides.html">View slides</a></p> +<span class="admonition-so2-lecture-04-interrupts"></span><div class="section" id="lecture-objectives"> +<h2>Lecture objectives<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-interrupts simple"> +<li>Interrupts and exceptions (x86)</li> +<li>Interrupts and exceptions (Linux)</li> +<li>Deferrable work</li> +<li>Timers</li> +</ul> +</div> +<div class="section" id="what-is-an-interrupt"> +<h2>What is an interrupt?<a class="headerlink" href="#what-is-an-interrupt" title="Permalink to this headline">¶</a></h2> +<p>An interrupt is an event that alters the normal execution flow of a +program and can be generated by hardware devices or even by the CPU +itself. When an interrupt occurs the current flow of execution is +suspended and interrupt handler runs. After the interrupt handler runs +the previous execution flow is resumed.</p> +<p>Interrupts can be grouped into two categories based on the source of +the interrupt. They can also be grouped into two other categories based +on the ability to postpone or temporarily disable the interrupt:</p> +<ul class="admonition-interrupts simple"> +<li><strong>synchronous</strong>, generated by executing an instruction</li> +<li><strong>asynchronous</strong>, generated by an external event</li> +<li><strong>maskable</strong><ul> +<li>can be ignored</li> +<li>signaled via INT pin</li> +</ul> +</li> +<li><strong>non-maskable</strong><ul> +<li>cannot be ignored</li> +<li>signaled via NMI pin</li> +</ul> +</li> +</ul> +<p>Synchronous interrupts, usually named exceptions, handle conditions detected by the +processor itself in the course of executing an instruction. Divide by zero or +a system call are examples of exceptions.</p> +<p>Asynchronous interrupts, usually named interrupts, are external events generated +by I/O devices. For example a network card generates an interrupts to signal +that a packet has arrived.</p> +<p>Most interrupts are maskable, which means we can temporarily postpone +running the interrupt handler when we disable the interrupt until the +time the interrupt is re-enabled. However, there are a few critical +interrupts that can not be disabled/postponed.</p> +<div class="section" id="exceptions"> +<h3>Exceptions<a class="headerlink" href="#exceptions" title="Permalink to this headline">¶</a></h3> +<p>There are two sources for exceptions:</p> +<ul class="admonition-exceptions simple"> +<li>processor detected<ul> +<li><strong>faults</strong></li> +<li><strong>traps</strong></li> +<li><strong>aborts</strong></li> +</ul> +</li> +<li>programmed<ul> +<li><strong>int n</strong></li> +</ul> +</li> +</ul> +<p>Processor detected exceptions are raised when an abnormal condition is +detected while executing an instruction.</p> +<p>A fault is a type of exception that is reported before the execution of the +instruction and can be usually corrected. The saved EIP is the address of +the instruction that caused the fault, so after the fault is corrected +the program can re-execute the faulty instruction. (e.g page fault).</p> +<p>A trap is a type of exception that is reported after the execution of the +instruction in which the exception was detected. The saved EIP is the address +of the instruction after the instruction that caused the trap. (e.g debug trap).</p> +</div> +<div class="section" id="quiz-interrupt-terminology"> +<h3>Quiz: interrupt terminology<a class="headerlink" href="#quiz-interrupt-terminology" title="Permalink to this headline">¶</a></h3> +<p class="admonition-quiz-interrupt-terminology">For each of the following terms on the left select all the terms +from right that best describe them.</p> +<table class="hlist"><tr><td><ul class="simple"> +<li>Watchdog</li> +<li>Demand paging</li> +<li>Division by zero</li> +<li>Timer</li> +<li>System call</li> +<li>Breakpoint</li> +</ul> +</td><td><ul class="simple"> +<li>Exception</li> +<li>Interrupt</li> +<li>Maskable</li> +<li>Nonmaskable</li> +<li>Trap</li> +<li>Fault</li> +</ul> +</td></tr></table> +</div> +</div> +<div class="section" id="hardware-concepts"> +<h2>Hardware Concepts<a class="headerlink" href="#hardware-concepts" title="Permalink to this headline">¶</a></h2> +<div class="section" id="programmable-interrupt-controller"> +<h3>Programmable Interrupt Controller<a class="headerlink" href="#programmable-interrupt-controller" title="Permalink to this headline">¶</a></h3> +<p class="admonition-programmable-interrupt-controller"> </p> +<img alt="../_images/ditaa-5db1739b80a83b12505e4ff749b5e69fccd01f1b.png" src="../_images/ditaa-5db1739b80a83b12505e4ff749b5e69fccd01f1b.png" /> +<p>A device supporting interrupts has an output pin used for signaling an Interrupt ReQuest. IRQ +pins are connected to a device named Programmable Interrupt Controller (PIC) which is connected +to CPU's INTR pin.</p> +<p>A PIC usually has a set of ports used to exchange information with the CPU. When a device +connected to one of the PIC's IRQ lines needs CPU attention the following flow happens:</p> +<blockquote> +<div><ul class="simple"> +<li>device raises an interrupt on the corresponding IRQn pin</li> +<li>PIC converts the IRQ into a vector number and writes it to a port for CPU to read</li> +<li>PIC raises an interrupt on CPU INTR pin</li> +<li>PIC waits for CPU to acknowledge an interrupt before raising another interrupt</li> +<li>CPU acknowledges the interrupt then it starts handling the interrupt</li> +</ul> +</div></blockquote> +<p>Will see later how the CPU handles the interrupt. Notice that by +design PIC won't raise another interrupt until the CPU acknowledged +the current interrupt.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Once the interrupt is acknowledged by the CPU the interrupt +controller can request another interrupt, regardless if the CPU +finished handled the previous interrupt or not. Thus, depending on +how the OS controls the CPU it is possible to have nested +interrupts.</p> +</div> +<p>The interrupt controller allows each IRQ line to be individually +disabled. This allows simplifying design by making sure that interrupt +handlers are always executed serially.</p> +</div> +<div class="section" id="interrupt-controllers-in-smp-systems"> +<h3>Interrupt controllers in SMP systems<a class="headerlink" href="#interrupt-controllers-in-smp-systems" title="Permalink to this headline">¶</a></h3> +<p>In SMP systems we may have multiple interrupt controllers in the +systems.</p> +<p>For example, on the x86 architecture each core has a local APIC used +to process interrupts from locally connected devices like timers or +thermals sensors. Then there is an I/O APIC is used to distribute IRQ +from external devices to CPU cores.</p> +<p class="admonition-interrupt-controllers-in-smp-systems"> </p> +<img alt="../_images/ditaa-9d23d02ebdff6eeb6bec8044480f055de9852ecc.png" src="../_images/ditaa-9d23d02ebdff6eeb6bec8044480f055de9852ecc.png" /> +</div> +<div class="section" id="interrupt-control"> +<h3>Interrupt Control<a class="headerlink" href="#interrupt-control" title="Permalink to this headline">¶</a></h3> +<p>In order to synchronize access to shared data between the interrupt handler +and other potential concurrent activities such as driver initialization or +driver data processing, it is often required to enable and disable interrupts in +a controlled fashion.</p> +<p>This can be accomplished at several levels:</p> +<ul class="admonition-enabling-disabling-the-interrupts simple"> +<li>at the device level<ul> +<li>by programming the device control registers</li> +</ul> +</li> +<li>at the PIC level<ul> +<li>PIC can be programmed to disable a given IRQ line</li> +</ul> +</li> +<li>at the CPU level; for example, on x86 one can use the following +instructions:</li> +</ul> +<blockquote> +<div><ul class="simple"> +<li>cli (CLear Interrupt flag)</li> +<li>sti (SeT Interrupt flag)</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="interrupt-priorities"> +<h3>Interrupt priorities<a class="headerlink" href="#interrupt-priorities" title="Permalink to this headline">¶</a></h3> +<p>Most architectures also support interrupt priorities. When this is +enabled, it permits interrupt nesting only for those interrupts that +have a higher priority than the current priority level.</p> +<p class="admonition-interrupt-priorities"> </p> +<img alt="../_images/ditaa-8b00a68b494f72d54b5fad38c88f7265aadaaa0e.png" src="../_images/ditaa-8b00a68b494f72d54b5fad38c88f7265aadaaa0e.png" /> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Not all architectures support interrupt priorities. It is also +difficult to support defining a generic scheme for interrupt +priorities for general use OSes and some kernels (Linux included) +do not use interrupt priorities. On the other hand most RTOS use +interrupt priorities since they are typically used in more +constraint use-cases where it is easier to define interrupt +priorities.</p> +</div> +</div> +<div class="section" id="quiz-hardware-concepts"> +<h3>Quiz: hardware concepts<a class="headerlink" href="#quiz-hardware-concepts" title="Permalink to this headline">¶</a></h3> +<p class="admonition-quiz-hardware-concepts">Which of the following statements are true?</p> +<ul class="simple"> +<li>The CPU can start processing a new interrupt before the current +one is finished</li> +<li>Interrupts can be disabled at the device level</li> +<li>Lower priority interrupts can not preempt handlers for higher +priority interrupts</li> +<li>Interrupts can be disabled at the interrupt controller level</li> +<li>On SMP systems the same interrupt can be routed to different CPUs</li> +<li>Interrupts can be disabled at the CPU level</li> +</ul> +</div> +</div> +<div class="section" id="interrupt-handling-on-the-x86-architecture"> +<h2>Interrupt handling on the x86 architecture<a class="headerlink" href="#interrupt-handling-on-the-x86-architecture" title="Permalink to this headline">¶</a></h2> +<p>This section will examine how interrupts are handled by the CPU on the +x86 architecture.</p> +<div class="section" id="interrupt-descriptor-table"> +<h3>Interrupt Descriptor Table<a class="headerlink" href="#interrupt-descriptor-table" title="Permalink to this headline">¶</a></h3> +<p>The interrupt descriptor table (IDT) associates each interrupt or exception +identifier with a descriptor for the instructions that service the associated +event. We will name the identifier as vector number and the associated +instructions as interrupt/exception handler.</p> +<p>An IDT has the following characteristics:</p> +<ul class="admonition-interrupt-descriptor-table simple"> +<li>it is used as a jump table by the CPU when a given vector is triggered</li> +<li>it is an array of 256 x 8 bytes entries</li> +<li>may reside anywhere in physical memory</li> +<li>processor locates IDT by the means of IDTR</li> +</ul> +<p>Below we can find Linux IRQ vector layout. The first 32 entries are reserved +for exceptions, vector 128 is used for syscall interface and the rest are +used mostly for hardware interrupts handlers.</p> +<p class="admonition-linux-irq-vector-layout"> </p> +<img alt="../_images/ditaa-5b3c93f6e612d0cc0e4d4837d92a443627405262.png" src="../_images/ditaa-5b3c93f6e612d0cc0e4d4837d92a443627405262.png" /> +<p>On x86 an IDT entry has 8 bytes and it is named gate. There can be 3 types of gates:</p> +<blockquote> +<div><ul class="simple"> +<li>interrupt gate, holds the address of an interrupt or exception handler. +Jumping to the handler disables maskable interrupts (IF flag is cleared).</li> +<li>trap gates, similar to an interrupt gate but it does not disable maskable +interrupts while jumping to interrupt/exception handler.</li> +<li>task gates (not used in Linux)</li> +</ul> +</div></blockquote> +<p>Let's have a look at several fields of an IDT entry:</p> +<blockquote> +<div><ul class="simple"> +<li>segment selector, index into GDT/LDT to find the start of the code segment where +the interrupt handlers reside</li> +<li>offset, offset inside the code segment</li> +<li>T, represents the type of gate</li> +<li>DPL, minimum privilege required for using the segments content.</li> +</ul> +</div></blockquote> +<p class="admonition-interrupt-descriptor-table-entry-gate"> </p> +<img alt="../_images/ditaa-eff5e0e3b58ce239d5310b22b89c0927be5853bd.png" src="../_images/ditaa-eff5e0e3b58ce239d5310b22b89c0927be5853bd.png" /> +</div> +<div class="section" id="interrupt-handler-address"> +<h3>Interrupt handler address<a class="headerlink" href="#interrupt-handler-address" title="Permalink to this headline">¶</a></h3> +<p>In order to find the interrupt handler address we first need to find the start +address of the code segment where interrupt handler resides. For this we +use the segment selector to index into GDT/LDT where we can find the corresponding +segment descriptor. This will provide the start address kept in the 'base' field. +Using base address and the offset we can now go to the start of the interrupt handler.</p> +<p class="admonition-interrupt-handler-address"> </p> +<img alt="../_images/ditaa-b2023fce22479e20bbe08fd76eed87e9a0527688.png" src="../_images/ditaa-b2023fce22479e20bbe08fd76eed87e9a0527688.png" /> +</div> +<div class="section" id="stack-of-interrupt-handler"> +<h3>Stack of interrupt handler<a class="headerlink" href="#stack-of-interrupt-handler" title="Permalink to this headline">¶</a></h3> +<p>Similar to control transfer to a normal function, a control transfer +to an interrupt or exception handler uses the stack to store the +information needed for returning to the interrupted code.</p> +<p>As can be seen in the figure below, an interrupt pushes the EFLAGS register +before saving the address of the interrupted instruction. Certain types +of exceptions also cause an error code to be pushed on the stack to help +debug the exception.</p> +<p class="admonition-interrupt-handler-stack"> </p> +<img alt="../_images/ditaa-85b69602726fa6143fc3ba0ffdb492454864aacf.png" src="../_images/ditaa-85b69602726fa6143fc3ba0ffdb492454864aacf.png" /> +</div> +<div class="section" id="handling-an-interrupt-request"> +<h3>Handling an interrupt request<a class="headerlink" href="#handling-an-interrupt-request" title="Permalink to this headline">¶</a></h3> +<p>After an interrupt request has been generated the processor runs a sequence of +events that eventually end up with running the kernel interrupt handler:</p> +<ul class="admonition-handling-an-interrupt-request"> +<li><p class="first">CPU checks the current privilege level</p> +</li> +<li><p class="first">if need to change privilege level</p> +<blockquote> +<div><ul class="simple"> +<li>change stack with the one associated with new privilege</li> +<li>save old stack information on the new stack</li> +</ul> +</div></blockquote> +</li> +<li><p class="first">save EFLAGS, CS, EIP on stack</p> +</li> +<li><p class="first">save error code on stack in case of an abort</p> +</li> +<li><p class="first">execute the kernel interrupt handler</p> +</li> +</ul> +</div> +<div class="section" id="returning-from-an-interrupt-handler"> +<h3>Returning from an interrupt handler<a class="headerlink" href="#returning-from-an-interrupt-handler" title="Permalink to this headline">¶</a></h3> +<p>Most architectures offer special instructions to clean up the stack and resume +the execution after the interrupt handler has been executed. On x86 IRET is used +to return from an interrupt handler. IRET is similar to RET except that IRET +increments ESP by extra four bytes (because of the flags on stack) and moves the +saved flags into EFLAGS register.</p> +<p>To resume the execution after an interrupt the following sequence is used (x86):</p> +<ul class="admonition-returning-from-an-interrupt simple"> +<li>pop the error code (in case of an abort)</li> +<li>call IRET<ul> +<li>pops values from the stack and restore the following register: CS, EIP, EFLAGS</li> +<li>if privilege level changed returns to the old stack and old privilege level</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="inspecting-the-x86-interrupt-handling"> +<h3>Inspecting the x86 interrupt handling<a class="headerlink" href="#inspecting-the-x86-interrupt-handling" title="Permalink to this headline">¶</a></h3> +<p class="admonition-inspecting-the-x86-interrupt-handling"> </p> +<asciinema-player src="../_images/intr_x86.cast"></asciinema-player></div> +<div class="section" id="quiz-x86-interrupt-handling"> +<h3>Quiz: x86 interrupt handling<a class="headerlink" href="#quiz-x86-interrupt-handling" title="Permalink to this headline">¶</a></h3> +<p class="admonition-quiz-x86-interrupt-handling">The following gdb commands are used to determine the handler for +the int80 based system call exception. Select and arrange the +commands or output of the commands in the correct order.</p> +<div class="highlight-gdb"><div class="highlight"><pre><span></span>(void *) 0xc15de780 <entry_SYSENTER_32> + +set $idtr_addr=($idtr_entry>>48<<16)|($idtr_entry&0xffff) + +print (void*)$idtr_addr + +set $idtr = 0xff800000 + +(void *) 0xc15de874 <entry_INT80_32> + +set $idtr = 0xff801000 + +set $idtr_entry = *(uint64_t*)($idtr + 8 * 128) + +monitor info registers +</pre></div> +</div> +</div> +</div> +<div class="section" id="interrupt-handling-in-linux"> +<h2>Interrupt handling in Linux<a class="headerlink" href="#interrupt-handling-in-linux" title="Permalink to this headline">¶</a></h2> +<p>In Linux the interrupt handling is done in three phases: critical, immediate and +deferred.</p> +<p>In the first phase the kernel will run the generic interrupt handler that +determines the interrupt number, the interrupt handler for this particular +interrupt and the interrupt controller. At this point any timing critical +actions will also be performed (e.g. acknowledge the interrupt at the interrupt +controller level). Local processor interrupts are disabled for the duration of +this phase and continue to be disabled in the next phase.</p> +<p>In the second phase, all of the device driver's handlers associated with this +interrupt will be executed. At the end of this phase, the interrupt controller's +"end of interrupt" method is called to allow the interrupt controller to +reassert this interrupt. The local processor interrupts are enabled at this +point.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">It is possible that one interrupt is associated with multiple +devices and in this case it is said that the interrupt is +shared. Usually, when using shared interrupts it is the +responsibility of the device driver to determine if the interrupt +is target to its device or not.</p> +</div> +<p>Finally, in the last phase of interrupt handling interrupt context deferrable +actions will be run. These are also sometimes known as "bottom half" of the +interrupt (the upper half being the part of the interrupt handling that runs +with interrupts disabled). At this point, interrupts are enabled on the local +processor.</p> +<p class="admonition-interrupt-handling-in-linux"> </p> +<img alt="../_images/ditaa-da31e3d17a4d55e5c3dbc0bd5903306418a896ca.png" src="../_images/ditaa-da31e3d17a4d55e5c3dbc0bd5903306418a896ca.png" /> +<div class="section" id="nested-interrupts-and-exceptions"> +<h3>Nested interrupts and exceptions<a class="headerlink" href="#nested-interrupts-and-exceptions" title="Permalink to this headline">¶</a></h3> +<p>Linux used to support nested interrupts but this was removed some time +ago in order to avoid increasingly complex solutions to stack +overflows issues - allow just one level of nesting, allow multiple +levels of nesting up to a certain kernel stack depth, etc.</p> +<p>However, it is still possible to have nesting between exceptions and +interrupts but the rules are fairly restrictive:</p> +<ul class="admonition-irq-and-exception-nesting-in-linux simple"> +<li>an exception (e.g. page fault, system call) can not preempt an interrupt; +if that occurs it is considered a bug</li> +<li>an interrupt can preempt an exception</li> +<li>an interrupt can not preempt another interrupt (it used to be possible)</li> +</ul> +<p>The diagram below shows the possible nesting scenarios:</p> +<p class="admonition-interrupt-exception-nesting"> </p> +<img alt="../_images/ditaa-2e49ca6ac606dab4b2b53231cfbe85ff06312d36.png" src="../_images/ditaa-2e49ca6ac606dab4b2b53231cfbe85ff06312d36.png" /> +</div> +<div class="section" id="interrupt-context"> +<h3>Interrupt context<a class="headerlink" href="#interrupt-context" title="Permalink to this headline">¶</a></h3> +<p>While an interrupt is handled (from the time the CPU jumps to the interrupt +handler until the interrupt handler returns - e.g. IRET is issued) it is said +that code runs in "interrupt context".</p> +<p>Code that runs in interrupt context has the following properties:</p> +<blockquote class="admonition-interrupt-context"> +<div><ul class="simple"> +<li>it runs as a result of an IRQ (not of an exception)</li> +<li>there is no well defined process context associated</li> +<li>not allowed to trigger a context switch (no sleep, schedule, or user memory access)</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="deferrable-actions"> +<h3>Deferrable actions<a class="headerlink" href="#deferrable-actions" title="Permalink to this headline">¶</a></h3> +<p>Deferrable actions are used to run callback functions at a later time. If +deferrable actions scheduled from an interrupt handler, the associated callback +function will run after the interrupt handler has completed.</p> +<p>There are two large categories of deferrable actions: those that run in +interrupt context and those that run in process context.</p> +<p>The purpose of interrupt context deferrable actions is to avoid doing too much +work in the interrupt handler function. Running for too long with interrupts +disabled can have undesired effects such as increased latency or poor system +performance due to missing other interrupts (e.g. dropping network packets +because the CPU did not react in time to dequeue packets from the network +interface and the network card buffer is full).</p> +<p>Deferrable actions have APIs to: <strong>initialize</strong> an instance, <strong>activate</strong> or +<strong>schedule</strong> the action and <strong>mask/disable</strong> and <strong>unmask/enable</strong> the execution +of the callback function. The latter is used for synchronization purposes between +the callback function and other contexts.</p> +<p>Typically the device driver will initialize the deferrable action +structure during the device instance initialization and will activate +/ schedule the deferrable action from the interrupt handler.</p> +<span class="admonition-deferrable-actions"></span></div> +<div class="section" id="soft-irqs"> +<h3>Soft IRQs<a class="headerlink" href="#soft-irqs" title="Permalink to this headline">¶</a></h3> +<p>Soft IRQs is the term used for the low-level mechanism that implements deferring +work from interrupt handlers but that still runs in interrupt context.</p> +<blockquote class="admonition-soft-irqs"> +<div><p>Soft IRQ APIs:</p> +<blockquote> +<div><ul class="simple"> +<li>initialize: <code class="xref c c-func docutils literal"><span class="pre">open_softirq()</span></code></li> +<li>activation: <code class="xref c c-func docutils literal"><span class="pre">raise_softirq()</span></code></li> +<li>masking: <code class="xref c c-func docutils literal"><span class="pre">local_bh_disable()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">local_bh_enable()</span></code></li> +</ul> +</div></blockquote> +<p>Once activated, the callback function <code class="xref c c-func docutils literal"><span class="pre">do_softirq()</span></code> runs either:</p> +<blockquote> +<div><ul class="simple"> +<li>after an interrupt handler or</li> +<li>from the ksoftirqd kernel thread</li> +</ul> +</div></blockquote> +</div></blockquote> +<p>Since softirqs can reschedule themselves or other interrupts can occur that +reschedules them, they can potentially lead to (temporary) process starvation if +checks are not put into place. Currently, the Linux kernel does not allow +running soft irqs for more than <code class="xref c c-macro docutils literal"><span class="pre">MAX_SOFTIRQ_TIME</span></code> or rescheduling for +more than <code class="xref c c-macro docutils literal"><span class="pre">MAX_SOFTIRQ_RESTART</span></code> consecutive times.</p> +<p>Once these limits are reached a special kernel thread, <strong>ksoftirqd</strong> is woken up +and all of the rest of pending soft irqs will be run from the context of this +kernel thread.</p> +<span class="admonition-ksoftirqd"></span><p>Soft irqs usage is restricted, they are use by a handful of subsystems that have +low latency requirements and high frequency:</p> +<div class="admonition-types-of-soft-irqs highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* PLEASE, avoid to allocate new softirqs, if you need not _really_ high</span> +<span class="cm"> frequency threaded job scheduling. For almost all the purposes</span> +<span class="cm"> tasklets are more than enough. F.e. all serial device BHs et</span> +<span class="cm"> al. should be converted to tasklets, not to softirqs.</span> +<span class="cm">*/</span> + +<span class="k">enum</span> +<span class="p">{</span> + <span class="n">HI_SOFTIRQ</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> + <span class="n">TIMER_SOFTIRQ</span><span class="p">,</span> + <span class="n">NET_TX_SOFTIRQ</span><span class="p">,</span> + <span class="n">NET_RX_SOFTIRQ</span><span class="p">,</span> + <span class="n">BLOCK_SOFTIRQ</span><span class="p">,</span> + <span class="n">IRQ_POLL_SOFTIRQ</span><span class="p">,</span> + <span class="n">TASKLET_SOFTIRQ</span><span class="p">,</span> + <span class="n">SCHED_SOFTIRQ</span><span class="p">,</span> + <span class="n">HRTIMER_SOFTIRQ</span><span class="p">,</span> + <span class="n">RCU_SOFTIRQ</span><span class="p">,</span> <span class="cm">/* Preferable RCU should always be the last softirq */</span> + + <span class="n">NR_SOFTIRQS</span> +<span class="p">};</span> +</pre></div> +</div> +</div> +<div class="section" id="packet-flood-example"> +<h3>Packet flood example<a class="headerlink" href="#packet-flood-example" title="Permalink to this headline">¶</a></h3> +<p>The following screencast will look at what happens when we flood the +system with a large number of packets. Since at least a part of the +packet processing is happening in softirq we should expect the CPU to +spend most of the time running softirqs but the majority of that +should be in the context of the <cite>ksoftirqd</cite> thread.</p> +<p class="admonition-packet-flood-example"> </p> +<asciinema-player src="../_images/ksoftirqd-packet-flood.cast"></asciinema-player></div> +<div class="section" id="tasklets"> +<h3>Tasklets<a class="headerlink" href="#tasklets" title="Permalink to this headline">¶</a></h3> +<p class="admonition-tasklets">Tasklets are a dynamic type (not limited to a fixed number) of +deferred work running in interrupt context.</p> +<p>Tasklets API:</p> +<blockquote> +<div><ul class="simple"> +<li>initialization: <code class="xref c c-func docutils literal"><span class="pre">tasklet_init()</span></code></li> +<li>activation: <code class="xref c c-func docutils literal"><span class="pre">tasklet_schedule()</span></code></li> +<li>masking: <code class="xref c c-func docutils literal"><span class="pre">tasklet_disable()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">tasklet_enable()</span></code></li> +</ul> +</div></blockquote> +<p>Tasklets are implemented on top of two dedicated softirqs: +<code class="xref c c-macro docutils literal"><span class="pre">TASKLET_SOFITIRQ</span></code> and <code class="xref c c-macro docutils literal"><span class="pre">HI_SOFTIRQ</span></code></p> +<p>Tasklets are also serialized, i.e. the same tasklet can only execute on one processor.</p> +</div> +<div class="section" id="workqueues"> +<h3>Workqueues<a class="headerlink" href="#workqueues" title="Permalink to this headline">¶</a></h3> +<blockquote> +<div><p class="admonition-workqueues">Workqueues are a type of deferred work that runs in process context.</p> +<p>They are implemented on top of kernel threads.</p> +<p>Workqueues API:</p> +<blockquote> +<div><ul class="simple"> +<li>init: <code class="xref c c-macro docutils literal"><span class="pre">INIT_WORK</span></code></li> +<li>activation: <code class="xref c c-func docutils literal"><span class="pre">schedule_work()</span></code></li> +</ul> +</div></blockquote> +</div></blockquote> +</div> +<div class="section" id="timers"> +<h3>Timers<a class="headerlink" href="#timers" title="Permalink to this headline">¶</a></h3> +<blockquote class="admonition-timers"> +<div><p>Timers are implemented on top of the <code class="xref c c-macro docutils literal"><span class="pre">TIMER_SOFTIRQ</span></code></p> +<p>Timer API:</p> +<ul class="simple"> +<li>initialization: <code class="xref c c-func docutils literal"><span class="pre">setup_timer()</span></code></li> +<li>activation: <code class="xref c c-func docutils literal"><span class="pre">mod_timer()</span></code></li> +</ul> +</div></blockquote> +</div> +<div class="section" id="deferrable-actions-summary"> +<h3>Deferrable actions summary<a class="headerlink" href="#deferrable-actions-summary" title="Permalink to this headline">¶</a></h3> +<p>Here is a cheat sheet which summarizes Linux deferrable actions:</p> +<blockquote class="admonition-deferrable-actions-summary"> +<div><ul class="simple"> +<li>softIRQ<ul> +<li>runs in interrupt context</li> +<li>statically allocated</li> +<li>same handler may run in parallel on multiple cores</li> +</ul> +</li> +<li>tasklet<ul> +<li>runs in interrupt context</li> +<li>can be dynamically allocated</li> +<li>same handler runs are serialized</li> +</ul> +</li> +<li>workqueues<ul> +<li>run in process context</li> +</ul> +</li> +</ul> +</div></blockquote> +</div> +<div class="section" id="quiz-linux-interrupt-handling"> +<h3>Quiz: Linux interrupt handling<a class="headerlink" href="#quiz-linux-interrupt-handling" title="Permalink to this headline">¶</a></h3> +<p class="admonition-quiz-linux-interrupt-handling">Which of the following phases of interrupt handling runs with +interrupts disabled at the CPU level?</p> +<ul class="simple"> +<li>Critical</li> +<li>Immediate</li> +<li>Deferred</li> +</ul> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lec3-processes.html" class="btn btn-neutral float-left" title="SO2 Lecture 03 - Processes" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lec5-smp.html" class="btn btn-neutral float-right" title="SO2 Lecture 05 - Symmetric Multi-Processing" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec5-smp-slides.html b/refs/pull/405/merge/so2/lec5-smp-slides.html new file mode 100644 index 00000000..75b38a6c --- /dev/null +++ b/refs/pull/405/merge/so2/lec5-smp-slides.html @@ -0,0 +1,821 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>SO2 Lecture 05 - Symmetric Multi-Processing — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="up" title="Operating Systems 2" href="index.html" /> + <link rel="next" title="SO2 Lecture 06 - Address Space" href="lec6-address-space.html" /> + <link rel="prev" title="SO2 Lecture 04 - Interrupts" href="lec4-interrupts.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-so2-lecture-05-symmetric-multi-processing slide level-1"> + +<h1>SO2 Lecture 05 - Symmetric Multi-Processing</h1> + + + + + +</article> +<article class="admonition-symmetric-multi-processing slide level-2"> + +<h2>Symmetric Multi-Processing</h2> + +<ul class="simple"> +<li>Kernel Concurrency</li> +<li>Atomic operations</li> +<li>Spin locks</li> +<li>Cache thrashing</li> +<li>Optimized spin locks</li> +<li>Process and Interrupt Context Synchronization</li> +<li>Mutexes</li> +<li>Per CPU data</li> +<li>Memory Ordering and Barriers</li> +<li>Read-Copy Update</li> +</ul> + + + + +</article> +<article class="admonition-race-conditions slide level-2"> + +<h2>Race conditions</h2> + +<ul class="simple"> +<li>there are at least two execution contexts that run in "parallel":<ul> +<li>truly run in parallel (e.g. two system calls running on +different processors)</li> +<li>one of the contexts can arbitrary preempt the other (e.g. an +interrupt preempts a system call)</li> +</ul> +</li> +<li>the execution contexts perform read-write accesses to shared +memory</li> +</ul> + + + + +</article> +<article class="admonition-race-condition-resource-counter-release slide level-2"> + +<h2>Race condition: resource counter release</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">release_resource</span><span class="p">()</span> +<span class="p">{</span> + <span class="n">counter</span><span class="o">--</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">counter</span><span class="p">)</span> + <span class="n">free_resource</span><span class="p">();</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-race-condition-scenario slide level-2"> + +<h2>Race condition scenario</h2> + +<p> </p> +<img alt="../_images/ditaa-35f7597b35b83bb0025ac2a5f158c9eae23050c8.png" src="../_images/ditaa-35f7597b35b83bb0025ac2a5f158c9eae23050c8.png" /> + + + + +</article> +<article class="admonition-avoiding-race-conditions slide level-2"> + +<h2>Avoiding race conditions</h2> + +<ul class="simple"> +<li>make the critical section <strong>atomic</strong> (e.g. use atomic +instructions)</li> +<li><strong>disable preemption</strong> during the critical section (e.g. disable +interrupts, bottom-half handlers, or thread preemption)</li> +<li><strong>serialize the access</strong> to the critical section (e.g. use spin +locks or mutexes to allow only one context or thread in the +critical section)</li> +</ul> + + + + +</article> +<article class="admonition-linux-kernel-concurrency-sources slide level-2"> + +<h2>Linux kernel concurrency sources</h2> + +<ul class="simple"> +<li><strong>single core systems</strong>, <strong>non-preemptive kernel</strong>: the current +process can be preempted by interrupts</li> +<li><strong>single core systems</strong>, <strong>preemptive kernel</strong>: above + the +current process can be preempted by other processes</li> +<li><strong>multi-core systems</strong>: above + the current process can run +in parallel with another process or with an interrupt running on +another processor</li> +</ul> + + + + +</article> +<article class="admonition-atomic-operations slide level-2"> + +<h2>Atomic operations</h2> + +<ul class="simple"> +<li>integer based:<ul> +<li>simple: <code class="xref c c-func docutils literal"><span class="pre">atomic_inc()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">atomic_dec()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">atomic_add()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">atomic_sub()</span></code></li> +<li>conditional: <code class="xref c c-func docutils literal"><span class="pre">atomic_dec_and_test()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">atomic_sub_and_test()</span></code></li> +</ul> +</li> +<li>bit based:<ul> +<li>simple: <code class="xref c c-func docutils literal"><span class="pre">test_bit()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">set_bit()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">change_bit()</span></code></li> +<li>conditional: <code class="xref c c-func docutils literal"><span class="pre">test_and_set_bit()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">test_and_clear_bit()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">test_and_change_bit()</span></code></li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-using-c-func-atomic-dec-and-test-to-implement-resource-counter-release slide level-2"> + +<h2>Using <code class="xref c c-func docutils literal"><span class="pre">atomic_dec_and_test()</span></code> to implement resource counter release</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">release_resource</span><span class="p">()</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">atomic_dec_and_test</span><span class="p">(</span><span class="o">&</span><span class="n">counter</span><span class="p">))</span> + <span class="n">free_resource</span><span class="p">();</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-atomic-operations-may-not-be-atomic-on-smp-systems slide level-2"> + +<h2>Atomic operations may not be atomic on SMP systems</h2> + +<p> </p> +<img alt="../_images/ditaa-ddd14be50300088958e86912bc5f396797634a3a.png" src="../_images/ditaa-ddd14be50300088958e86912bc5f396797634a3a.png" /> + + + + +</article> +<article class="admonition-fixing-atomic-operations-for-smp-systems-x86 slide level-2"> + +<h2>Fixing atomic operations for SMP systems (x86)</h2> + +<p> </p> +<img alt="../_images/ditaa-c11fccb956cdf115910f9f72e1dc14cd7ed549ff.png" src="../_images/ditaa-c11fccb956cdf115910f9f72e1dc14cd7ed549ff.png" /> + + + + +</article> +<article class="admonition-synchronization-with-interrupts-x86 slide level-2"> + +<h2>Synchronization with interrupts (x86)</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span> <span class="cp">#define local_irq_disable() \</span> +<span class="cp"> asm volatile („cli” : : : „memory”)</span> + +<span class="cp">#define local_irq_enable() \</span> +<span class="cp"> asm volatile („sti” : : : „memory”)</span> + +<span class="cp">#define local_irq_save(flags) \</span> +<span class="cp"> asm volatile ("pushf ; pop %0" :"=g" (flags)</span> + <span class="o">:</span> <span class="cm">/* no input */</span><span class="o">:</span> <span class="s">"memory"</span><span class="p">)</span> \ + <span class="k">asm</span> <span class="k">volatile</span><span class="p">(</span><span class="s">"cli"</span><span class="o">:</span> <span class="o">:</span> <span class="o">:</span><span class="s">"memory"</span><span class="p">)</span> + +<span class="cp">#define local_irq_restore(flags) \</span> +<span class="cp"> asm volatile ("push %0 ; popf"</span> + <span class="o">:</span> <span class="cm">/* no output */</span> + <span class="o">:</span> <span class="s">"g"</span> <span class="p">(</span><span class="n">flags</span><span class="p">)</span> <span class="o">:</span><span class="s">"memory"</span><span class="p">,</span> <span class="s">"cc"</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-spin-lock-implementation-example-x86 slide level-2"> + +<h2>Spin Lock Implementation Example (x86)</h2> + +<div class="highlight-asm"><div class="highlight"><pre><span></span>spin_lock: + lock bts [my_lock], 0 + jc spin_lock + +/* critical section */ + +spin_unlock: + mov [my_lock], 0 +</pre></div> +</div> +<p><strong>bts dts, src</strong> - bit test and set; it copies the src bit from the dts +memory address to the carry flag and then sets it:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">CF</span> <span class="o"><-</span> <span class="n">dts</span><span class="p">[</span><span class="n">src</span><span class="p">]</span> +<span class="n">dts</span><span class="p">[</span><span class="n">src</span><span class="p">]</span> <span class="o"><-</span> <span class="mi">1</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-lock-contention slide level-2"> + +<h2>Lock Contention</h2> + +<ul class="simple"> +<li>There is lock contention when at least one core spins trying to +enter the critical section lock</li> +<li>Lock contention grows with the critical section size, time spent +in the critical section and the number of cores in the system</li> +</ul> + + + + +</article> +<article class="admonition-cache-thrashing slide level-2"> + +<h2>Cache Thrashing</h2> + +<p>Cache thrashing occurs when multiple cores are trying to read and +write to the same memory resulting in excessive cache misses.</p> +<p>Since spin locks continuously access memory during lock contention, +cache thrashing is a common occurrence due to the way cache +coherency is implemented.</p> + + + + +</article> +<article class="admonition-synchronized-caches-and-memory slide level-2"> + +<h2>Synchronized caches and memory</h2> + +<p> </p> +<img alt="../_images/ditaa-4d63c157487ff8291f2a6e93fe680ec38c1a3212.png" src="../_images/ditaa-4d63c157487ff8291f2a6e93fe680ec38c1a3212.png" /> + + + + +</article> +<article class="admonition-unsynchronized-caches-and-memory slide level-2"> + +<h2>Unsynchronized caches and memory</h2> + +<p> </p> +<img alt="../_images/ditaa-7ee0f9bb5f5af586e043afd47cfbad0adcc34888.png" src="../_images/ditaa-7ee0f9bb5f5af586e043afd47cfbad0adcc34888.png" /> + + + + +</article> +<article class="admonition-cache-coherency-protocols slide level-2"> + +<h2>Cache Coherency Protocols</h2> + +<ul class="simple"> +<li>Bus snooping (sniffing) based: memory bus transactions are +monitored by caches and they take actions to preserve +coherency</li> +<li>Directory based: there is a separate entity (directory) that +maintains the state of caches; caches interact with directory +to preserve coherency</li> +</ul> +<p>Bus snooping is simpler but it performs poorly when the number of +cores goes beyond 32-64.</p> +<p>Directory based cache coherence protocols scale much better (up +to thousands of cores) and are usually used in NUMA systems.</p> + + + + +</article> +<article class="admonition-mesi-cache-coherence-protocol slide level-2"> + +<h2>MESI Cache Coherence Protocol</h2> + +<ul class="simple"> +<li>Caching policy: write back</li> +<li>Cache line states<ul> +<li>Modified: owned by a single core and dirty</li> +<li>Exclusive: owned by a single core and clean</li> +<li>Shared: shared between multiple cores and clean</li> +<li>Invalid : the line is not cached</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-mesi-state-transitions slide level-2"> + +<h2>MESI State Transitions</h2> + +<ul class="simple"> +<li>Invalid -> Exclusive: read request, all other cores have the line +in Invalid; line loaded from memory</li> +<li>Invalid -> Shared: read request, at least one core has the line +in Shared or Exclusive; line loaded from sibling cache</li> +<li>Invalid/Shared/Exclusive -> Modified: write request; <strong>all +other</strong> cores <strong>invalidate</strong> the line</li> +<li>Modified -> Invalid: write request from other core; line is +flushed to memory</li> +</ul> + + + + +</article> +<article class="admonition-cache-thrashing-due-to-spin-lock-contention slide level-2"> + +<h2>Cache thrashing due to spin lock contention</h2> + +<p> </p> +<img alt="../_images/ditaa-b26d802c286bda6c559b4dcfa8a7fb27f840463e.png" src="../_images/ditaa-b26d802c286bda6c559b4dcfa8a7fb27f840463e.png" /> + + + + +</article> +<article class="admonition-optimized-spin-lock-keacquirespinlock slide level-2"> + +<h2>Optimized spin lock (KeAcquireSpinLock)</h2> + +<p> </p> +<div class="highlight-asm"><div class="highlight"><pre><span></span><span class="nl">spin_lock:</span> + <span class="na">rep</span> <span class="c">; nop</span> + <span class="nf">test</span> <span class="no">lock_addr</span><span class="p">,</span> <span class="mi">1</span> + <span class="nf">jnz</span> <span class="no">spin_lock</span> + <span class="na">lock</span> <span class="nf">bts</span> <span class="no">lock_addr</span> + <span class="nf">jc</span> <span class="no">spin_lock</span> +</pre></div> +</div> +<ul class="simple"> +<li>we first test the lock read only, using a non atomic +instructions, to avoid writes and thus invalidate operations +while we spin</li> +<li>only when the lock <em>might</em> be free, we try to acquire it</li> +</ul> + + + + +</article> +<article class="admonition-queued-spin-locks slide level-2"> + +<h2>Queued Spin Locks</h2> + +<p> </p> +<img alt="../_images/ditaa-58545831034f050660727be99cede213bc4a53c7.png" src="../_images/ditaa-58545831034f050660727be99cede213bc4a53c7.png" /> + + + + +</article> +<article class="admonition-process-and-interrupt-handler-synchronization-deadlock slide level-2"> + +<h2>Process and Interrupt Handler Synchronization Deadlock</h2> + +<ul class="simple"> +<li>In the process context we take the spin lock</li> +<li>An interrupt occurs and it is scheduled on the same CPU core</li> +<li>The interrupt handler runs and tries to take the spin lock</li> +<li>The current CPU will deadlock</li> +</ul> + + + + +</article> +<article class="admonition-interrupt-synchronization-for-smp slide level-2"> + +<h2>Interrupt Synchronization for SMP</h2> + +<ul class="simple"> +<li>In process context: disable interrupts and acquire a spin lock; +this will protect both against interrupt or other CPU cores race +conditions (<code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_lock_restore()</span></code> combine the two operations)</li> +<li>In interrupt context: take a spin lock; this will will protect +against race conditions with other interrupt handlers or process +context running on different processors</li> +</ul> + + + + +</article> +<article class="admonition-bottom-half-synchronization-for-smp slide level-2"> + +<h2>Bottom-Half Synchronization for SMP</h2> + +<ul class="simple"> +<li>In process context use <code class="xref c c-func docutils literal"><span class="pre">spin_lock_bh()</span></code> (which combines +<code class="xref c c-func docutils literal"><span class="pre">local_bh_disable()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">spin_lock()</span></code>) and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock_bh()</span></code> (which combines <code class="xref c c-func docutils literal"><span class="pre">spin_unlock()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">local_bh_enable()</span></code>)</li> +<li>In bottom half context use: <code class="xref c c-func docutils literal"><span class="pre">spin_lock()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock()</span></code> (or <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqrestore()</span></code> if sharing data with interrupt +handlers)</li> +</ul> + + + + +</article> +<article class="admonition-preemption slide level-2"> + +<h2>Preemption</h2> + +<p> </p> +<p>Preemption is configurable: when active it provides better latency +and response time, while when deactivated it provides better +throughput.</p> +<p>Preemption is disabled by spin locks and mutexes but it can be +manually disabled as well (by core kernel code).</p> + + + + +</article> +<article class="admonition-preemption-and-bottom-half-masking slide level-2"> + +<h2>Preemption and Bottom-Half Masking</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define PREEMPT_BITS 8</span> +<span class="cp">#define SOFTIRQ_BITS 8</span> +<span class="cp">#define HARDIRQ_BITS 4</span> +<span class="cp">#define NMI_BITS 1</span> + +<span class="cp">#define preempt_disable() preempt_count_inc()</span> + +<span class="cp">#define local_bh_disable() add_preempt_count(SOFTIRQ_OFFSET)</span> + +<span class="cp">#define local_bh_enable() sub_preempt_count(SOFTIRQ_OFFSET)</span> + +<span class="cp">#define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK))</span> + +<span class="cp">#define in_interrupt() irq_count()</span> + +<span class="n">asmlinkage</span> <span class="kt">void</span> <span class="nf">do_softirq</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">in_interrupt</span><span class="p">())</span> <span class="k">return</span><span class="p">;</span> + <span class="p">...</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-mutexes slide level-2"> + +<h2>Mutexes</h2> + +<ul class="simple"> +<li>They don't "waste" CPU cycles; system throughput is better than +spin locks if context switch overhead is lower than medium +spinning time</li> +<li>They can't be used in interrupt context</li> +<li>They have a higher latency than spin locks</li> +</ul> + + + + +</article> +<article class="admonition-c-func-mutex-lock-fast-path slide level-2"> + +<h2><code class="xref c c-func docutils literal"><span class="pre">mutex_lock()</span></code> fast path</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="n">__sched</span> <span class="nf">mutex_lock</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">might_sleep</span><span class="p">();</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">__mutex_trylock_fast</span><span class="p">(</span><span class="n">lock</span><span class="p">))</span> + <span class="n">__mutex_lock_slowpath</span><span class="p">(</span><span class="n">lock</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="n">__always_inline</span> <span class="kt">bool</span> <span class="nf">__mutex_trylock_fast</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">curr</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)</span><span class="n">current</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">atomic_long_cmpxchg_acquire</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">owner</span><span class="p">,</span> <span class="mi">0UL</span><span class="p">,</span> <span class="n">curr</span><span class="p">))</span> + <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> + + <span class="k">return</span> <span class="nb">false</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-c-func-mutex-lock-slow-path slide level-2"> + +<h2><code class="xref c c-func docutils literal"><span class="pre">mutex_lock()</span></code> slow path</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="p">...</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="p">...</span> + <span class="cm">/* add waiting tasks to the end of the waitqueue (FIFO): */</span> + <span class="n">list_add_tail</span><span class="p">(</span><span class="o">&</span><span class="n">waiter</span><span class="p">.</span><span class="n">list</span><span class="p">,</span> <span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_list</span><span class="p">);</span> +<span class="p">...</span> + <span class="n">waiter</span><span class="p">.</span><span class="n">task</span> <span class="o">=</span> <span class="n">current</span><span class="p">;</span> +<span class="p">...</span> + <span class="k">for</span> <span class="p">(;;)</span> <span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">__mutex_trylock</span><span class="p">(</span><span class="n">lock</span><span class="p">))</span> + <span class="k">goto</span> <span class="n">acquired</span><span class="p">;</span> + <span class="p">...</span> + <span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> + <span class="p">...</span> + <span class="n">set_current_state</span><span class="p">(</span><span class="n">state</span><span class="p">);</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> + <span class="p">}</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="nl">acquired</span><span class="p">:</span> + <span class="n">__set_current_state</span><span class="p">(</span><span class="n">TASK_RUNNING</span><span class="p">);</span> + <span class="n">mutex_remove_waiter</span><span class="p">(</span><span class="n">lock</span><span class="p">,</span> <span class="o">&</span><span class="n">waiter</span><span class="p">,</span> <span class="n">current</span><span class="p">);</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="p">...</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-c-func-mutex-unlock-fast-path slide level-2"> + +<h2><code class="xref c c-func docutils literal"><span class="pre">mutex_unlock()</span></code> fast path</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="n">__sched</span> <span class="nf">mutex_unlock</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">__mutex_unlock_fast</span><span class="p">(</span><span class="n">lock</span><span class="p">))</span> + <span class="k">return</span><span class="p">;</span> + <span class="n">__mutex_unlock_slowpath</span><span class="p">(</span><span class="n">lock</span><span class="p">,</span> <span class="n">_RET_IP_</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="n">__always_inline</span> <span class="kt">bool</span> <span class="nf">__mutex_unlock_fast</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">curr</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)</span><span class="n">current</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">atomic_long_cmpxchg_release</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">owner</span><span class="p">,</span> <span class="n">curr</span><span class="p">,</span> <span class="mi">0UL</span><span class="p">)</span> <span class="o">==</span> <span class="n">curr</span><span class="p">)</span> + <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> + + <span class="k">return</span> <span class="nb">false</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">void</span> <span class="nf">__mutex_lock_slowpath</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> +<span class="p">...</span> + <span class="k">if</span> <span class="p">(</span><span class="n">__mutex_waiter_is_first</span><span class="p">(</span><span class="n">lock</span><span class="p">,</span> <span class="o">&</span><span class="n">waiter</span><span class="p">))</span> + <span class="n">__mutex_set_flag</span><span class="p">(</span><span class="n">lock</span><span class="p">,</span> <span class="n">MUTEX_FLAG_WAITERS</span><span class="p">);</span> +<span class="p">...</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-c-func-mutex-unlock-slow-path slide level-2"> + +<h2><code class="xref c c-func docutils literal"><span class="pre">mutex_unlock()</span></code> slow path</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="p">...</span> +<span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">list_empty</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_list</span><span class="p">))</span> <span class="p">{</span> + <span class="cm">/* get the first entry from the wait-list: */</span> + <span class="k">struct</span> <span class="n">mutex_waiter</span> <span class="o">*</span><span class="n">waiter</span><span class="p">;</span> + <span class="n">waiter</span> <span class="o">=</span> <span class="n">list_first_entry</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_list</span><span class="p">,</span> <span class="k">struct</span> <span class="n">mutex_waiter</span><span class="p">,</span> + <span class="n">list</span><span class="p">);</span> + <span class="n">next</span> <span class="o">=</span> <span class="n">waiter</span><span class="o">-></span><span class="n">task</span><span class="p">;</span> + <span class="n">wake_q_add</span><span class="p">(</span><span class="o">&</span><span class="n">wake_q</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span> +<span class="p">}</span> +<span class="p">...</span> +<span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="p">...</span> +<span class="n">wake_up_q</span><span class="p">(</span><span class="o">&</span><span class="n">wake_q</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-per-cpu-data slide level-2"> + +<h2>Per CPU data</h2> + +<ul class="simple"> +<li>No need to synchronize to access the data</li> +<li>No contention, no performance impact</li> +<li>Well suited for distributed processing where aggregation is only +seldom necessary (e.g. statistics counters)</li> +</ul> + + + + +</article> +<article class="admonition-out-of-order-compiler-generated-code slide level-2"> + +<h2>Out of Order Compiler Generated Code</h2> + +<table border="1" class="docutils"> +<colgroup> +<col width="43%" /> +<col width="57%" /> +</colgroup> +<tbody valign="top"> +<tr class="row-odd"><td>C code</td> +<td>Compiler generated code</td> +</tr> +<tr class="row-even"><td><div class="first last highlight-c"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> +<span class="n">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> +</pre></div> +</div> +</td> +<td><div class="first last highlight-asm"><div class="highlight"><pre><span></span><span class="nf">MOV</span> <span class="no">R10</span><span class="p">,</span> <span class="mi">1</span> +<span class="nf">MOV</span> <span class="no">R11</span><span class="p">,</span> <span class="mi">2</span> +<span class="nf">STORE</span> <span class="no">R11</span><span class="p">,</span> <span class="no">b</span> +<span class="nf">STORE</span> <span class="no">R10</span><span class="p">,</span> <span class="no">a</span> +</pre></div> +</div> +</td> +</tr> +</tbody> +</table> + + + + +</article> +<article class="admonition-barriers slide level-2"> + +<h2>Barriers</h2> + +<ul class="simple"> +<li>A read barrier (<code class="xref c c-func docutils literal"><span class="pre">rmb()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">smp_rmb()</span></code>) is used to +make sure that no read operation crosses the barrier; that is, +all read operation before the barrier are complete before +executing the first instruction after the barrier</li> +<li>A write barrier (<code class="xref c c-func docutils literal"><span class="pre">wmb()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">smp_wmb()</span></code>) is used to +make sure that no write operation crosses the barrier</li> +<li>A simple barrier (<code class="xref c c-func docutils literal"><span class="pre">mb()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">smp_mb()</span></code>) is used +to make sure that no write or read operation crosses the barrier</li> +</ul> + + + + +</article> +<article class="admonition-read-copy-update-rcu slide level-2"> + +<h2>Read Copy Update (RCU)</h2> + +<ul class="simple"> +<li><strong>Read-only</strong> lock-less access at the same time with write access</li> +<li>Write accesses still requires locks in order to avoid races +between writers</li> +<li>Requires unidirectional traversal by readers</li> +</ul> + + + + +</article> +<article class="admonition-removal-and-reclamation slide level-2"> + +<h2>Removal and Reclamation</h2> + +<ul class="simple"> +<li><strong>Removal</strong>: removes references to elements. Some old readers may +still see the old reference so we can't free the element.</li> +<li><strong>Elimination</strong>: free the element. This action is postponed until +all existing readers finish traversal (quiescent cycle). New +readers won't affect the quiescent cycle.</li> +</ul> + + + + +</article> +<article class="admonition-rcu-list-delete slide level-2"> + +<h2>RCU List Delete</h2> + +<p> </p> +<img alt="../_images/ditaa-5193a924360bebc83d2f81188cd0b0093ec01e6a.png" src="../_images/ditaa-5193a924360bebc83d2f81188cd0b0093ec01e6a.png" /> + + + + +</article> +<article class="admonition-rcu-list-apis-cheat-sheet slide level-2"> + +<h2>RCU list APIs cheat sheet</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* list traversal */</span> +<span class="n">rcu_read_lock</span><span class="p">();</span> +<span class="n">list_for_each_entry_rcu</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">head</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* no sleeping, blocking calls or context switch allowed */</span> +<span class="p">}</span> +<span class="n">rcu_read_unlock</span><span class="p">();</span> + + +<span class="cm">/* list element delete */</span> +<span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> +<span class="n">list_del_rcu</span><span class="p">(</span><span class="o">&</span><span class="n">node</span><span class="o">-></span><span class="n">list</span><span class="p">);</span> +<span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> +<span class="n">synchronize_rcu</span><span class="p">();</span> +<span class="n">kfree</span><span class="p">(</span><span class="n">node</span><span class="p">);</span> + +<span class="cm">/* list element add */</span> +<span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> +<span class="n">list_add_rcu</span><span class="p">(</span><span class="n">head</span><span class="p">,</span> <span class="o">&</span><span class="n">node</span><span class="o">-></span><span class="n">list</span><span class="p">);</span> +<span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec5-smp.html b/refs/pull/405/merge/so2/lec5-smp.html new file mode 100644 index 00000000..dc01bed9 --- /dev/null +++ b/refs/pull/405/merge/so2/lec5-smp.html @@ -0,0 +1,919 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lecture 05 - Symmetric Multi-Processing — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lecture 06 - Address Space" href="lec6-address-space.html" /> + <link rel="prev" title="SO2 Lecture 04 - Interrupts" href="lec4-interrupts.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lecture 05 - Symmetric Multi-Processing</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="#synchronization-basics">Synchronization basics</a></li> +<li class="toctree-l3"><a class="reference internal" href="#linux-kernel-concurrency-sources">Linux kernel concurrency sources</a></li> +<li class="toctree-l3"><a class="reference internal" href="#atomic-operations">Atomic operations</a></li> +<li class="toctree-l3"><a class="reference internal" href="#disabling-preemption-interrupts">Disabling preemption (interrupts)</a></li> +<li class="toctree-l3"><a class="reference internal" href="#spin-locks">Spin Locks</a></li> +<li class="toctree-l3"><a class="reference internal" href="#cache-coherency-in-multi-processor-systems">Cache coherency in multi-processor systems</a></li> +<li class="toctree-l3"><a class="reference internal" href="#optimized-spin-locks">Optimized spin locks</a></li> +<li class="toctree-l3"><a class="reference internal" href="#process-and-interrupt-context-synchronization">Process and Interrupt Context Synchronization</a></li> +<li class="toctree-l3"><a class="reference internal" href="#mutexes">Mutexes</a></li> +<li class="toctree-l3"><a class="reference internal" href="#per-cpu-data">Per CPU data</a></li> +<li class="toctree-l3"><a class="reference internal" href="#memory-ordering-and-barriers">Memory Ordering and Barriers</a></li> +<li class="toctree-l3"><a class="reference internal" href="#read-copy-update-rcu">Read Copy Update (RCU)</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lecture 05 - Symmetric Multi-Processing</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lec5-smp.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lecture-05-symmetric-multi-processing"> +<h1>SO2 Lecture 05 - Symmetric Multi-Processing<a class="headerlink" href="#so2-lecture-05-symmetric-multi-processing" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="lec5-smp-slides.html">View slides</a></p> +<span class="admonition-so2-lecture-05-symmetric-multi-processing"></span><div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-symmetric-multi-processing simple"> +<li>Kernel Concurrency</li> +<li>Atomic operations</li> +<li>Spin locks</li> +<li>Cache thrashing</li> +<li>Optimized spin locks</li> +<li>Process and Interrupt Context Synchronization</li> +<li>Mutexes</li> +<li>Per CPU data</li> +<li>Memory Ordering and Barriers</li> +<li>Read-Copy Update</li> +</ul> +</div> +<div class="section" id="synchronization-basics"> +<h2>Synchronization basics<a class="headerlink" href="#synchronization-basics" title="Permalink to this headline">¶</a></h2> +<p>Because the Linux kernel supports symmetric multi-processing (SMP) it +must use a set of synchronization mechanisms to achieve predictable +results, free of race conditions.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">We will use the terms core, CPU and processor as +interchangeable for the purpose of this lecture.</p> +</div> +<p>Race conditions can occur when the following two conditions happen +simultaneously:</p> +<ul class="admonition-race-conditions simple"> +<li>there are at least two execution contexts that run in "parallel":<ul> +<li>truly run in parallel (e.g. two system calls running on +different processors)</li> +<li>one of the contexts can arbitrary preempt the other (e.g. an +interrupt preempts a system call)</li> +</ul> +</li> +<li>the execution contexts perform read-write accesses to shared +memory</li> +</ul> +<p>Race conditions can lead to erroneous results that are hard to debug, +because they manifest only when the execution contexts are scheduled +on the CPU cores in a very specific order.</p> +<p>A classical race condition example is an incorrect implementation for +a release operation of a resource counter:</p> +<div class="admonition-race-condition-resource-counter-release highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">release_resource</span><span class="p">()</span> +<span class="p">{</span> + <span class="n">counter</span><span class="o">--</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">counter</span><span class="p">)</span> + <span class="n">free_resource</span><span class="p">();</span> +<span class="p">}</span> +</pre></div> +</div> +<p>A resource counter is used to keep a shared resource available until +the last user releases it but the above implementation has a race +condition that can cause freeing the resource twice:</p> +<p class="admonition-race-condition-scenario"> </p> +<img alt="../_images/ditaa-35f7597b35b83bb0025ac2a5f158c9eae23050c8.png" src="../_images/ditaa-35f7597b35b83bb0025ac2a5f158c9eae23050c8.png" /> +<p>In most cases the <cite>release_resource()</cite> function will only free the +resource once. However, in the scenario above, if thread A is +preempted right after decrementing <cite>counter</cite> and thread B calls +<cite>release_resource()</cite> it will cause the resource to be freed. When +resumed, thread A will also free the resource since the counter value +is 0.</p> +<p>To avoid race conditions the programmer must first identify the +critical section that can generate a race condition. The critical +section is the part of the code that reads and writes shared memory +from multiple parallel contexts.</p> +<p>In the example above, the minimal critical section is starting with +the counter decrement and ending with checking the counter's value.</p> +<p>Once the critical section has been identified race conditions can be +avoided by using one of the following approaches:</p> +<ul class="admonition-avoiding-race-conditions simple"> +<li>make the critical section <strong>atomic</strong> (e.g. use atomic +instructions)</li> +<li><strong>disable preemption</strong> during the critical section (e.g. disable +interrupts, bottom-half handlers, or thread preemption)</li> +<li><strong>serialize the access</strong> to the critical section (e.g. use spin +locks or mutexes to allow only one context or thread in the +critical section)</li> +</ul> +</div> +<div class="section" id="linux-kernel-concurrency-sources"> +<h2>Linux kernel concurrency sources<a class="headerlink" href="#linux-kernel-concurrency-sources" title="Permalink to this headline">¶</a></h2> +<p>There are multiple source of concurrency in the Linux kernel that +depend on the kernel configuration as well as the type of system it +runs on:</p> +<ul class="admonition-linux-kernel-concurrency-sources simple"> +<li><strong>single core systems</strong>, <strong>non-preemptive kernel</strong>: the current +process can be preempted by interrupts</li> +<li><strong>single core systems</strong>, <strong>preemptive kernel</strong>: above + the +current process can be preempted by other processes</li> +<li><strong>multi-core systems</strong>: above + the current process can run +in parallel with another process or with an interrupt running on +another processor</li> +</ul> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">We only discuss kernel concurrency and that is why a +non-preemptive kernel running on an single core system +has interrupts as the only source of concurrency.</p> +</div> +</div> +<div class="section" id="atomic-operations"> +<h2>Atomic operations<a class="headerlink" href="#atomic-operations" title="Permalink to this headline">¶</a></h2> +<p>In certain circumstances we can avoid race conditions by using atomic +operations that are provided by hardware. Linux provides a unified API +to access atomic operations:</p> +<ul class="admonition-atomic-operations simple"> +<li>integer based:<ul> +<li>simple: <code class="xref c c-func docutils literal"><span class="pre">atomic_inc()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">atomic_dec()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">atomic_add()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">atomic_sub()</span></code></li> +<li>conditional: <code class="xref c c-func docutils literal"><span class="pre">atomic_dec_and_test()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">atomic_sub_and_test()</span></code></li> +</ul> +</li> +<li>bit based:<ul> +<li>simple: <code class="xref c c-func docutils literal"><span class="pre">test_bit()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">set_bit()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">change_bit()</span></code></li> +<li>conditional: <code class="xref c c-func docutils literal"><span class="pre">test_and_set_bit()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">test_and_clear_bit()</span></code>, +<code class="xref c c-func docutils literal"><span class="pre">test_and_change_bit()</span></code></li> +</ul> +</li> +</ul> +<p>For example, we could use <code class="xref c c-func docutils literal"><span class="pre">atomic_dec_and_test()</span></code> to implement +the resource counter decrement and value checking atomic:</p> +<div class="admonition-using-c-func-atomic-dec-and-test-to-implement-resource-counter-release highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">release_resource</span><span class="p">()</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">atomic_dec_and_test</span><span class="p">(</span><span class="o">&</span><span class="n">counter</span><span class="p">))</span> + <span class="n">free_resource</span><span class="p">();</span> +<span class="p">}</span> +</pre></div> +</div> +<p>One complication with atomic operations is encountered in +multi-core systems, where an atomic operation is not longer +atomic at the system level (but still atomic at the core level).</p> +<p>To understand why, we need to decompose the atomic operation in memory +loads and stores. Then we can construct race condition scenarios where +the load and store operations are interleaved across CPUs, like in the +example below where incrementing a value from two processors will +produce an unexpected result:</p> +<p class="admonition-atomic-operations-may-not-be-atomic-on-smp-systems"> </p> +<img alt="../_images/ditaa-ddd14be50300088958e86912bc5f396797634a3a.png" src="../_images/ditaa-ddd14be50300088958e86912bc5f396797634a3a.png" /> +<p>In order to provide atomic operations on SMP systems different +architectures use different techniques. For example, on x86 a LOCK +prefix is used to lock the system bus while executing the prefixed +operation:</p> +<p class="admonition-fixing-atomic-operations-for-smp-systems-x86"> </p> +<img alt="../_images/ditaa-c11fccb956cdf115910f9f72e1dc14cd7ed549ff.png" src="../_images/ditaa-c11fccb956cdf115910f9f72e1dc14cd7ed549ff.png" /> +<p>On ARM the LDREX and STREX instructions are used together to guarantee +atomic access: LDREX loads a value and signals the exclusive monitor +that an atomic operation is in progress. The STREX attempts to store a +new value but only succeeds if the exclusive monitor has not detected +other exclusive operations. So, to implement atomic operations the +programmer must retry the operation (both LDREX and STREX) until the +exclusive monitor signals a success.</p> +<p>Although they are often interpreted as "light" or "efficient" +synchronization mechanisms (because they "don't require spinning or +context switches", or because they "are implemented in hardware so +they must be more efficient", or because they "are just instructions +so they must have similar efficiency as other instructions"), as seen +from the implementation details, atomic operations are actually +expensive.</p> +</div> +<div class="section" id="disabling-preemption-interrupts"> +<h2>Disabling preemption (interrupts)<a class="headerlink" href="#disabling-preemption-interrupts" title="Permalink to this headline">¶</a></h2> +<p>On single core systems and non preemptive kernels the only source of +concurrency is the preemption of the current thread by an +interrupt. To prevent concurrency is thus sufficient to disable +interrupts.</p> +<p>This is done with architecture specific instructions, but Linux offers +architecture independent APIs to disable and enable interrupts:</p> +<div class="admonition-synchronization-with-interrupts-x86 highlight-c"><div class="highlight"><pre><span></span> <span class="cp">#define local_irq_disable() \</span> +<span class="cp"> asm volatile („cli” : : : „memory”)</span> + +<span class="cp">#define local_irq_enable() \</span> +<span class="cp"> asm volatile („sti” : : : „memory”)</span> + +<span class="cp">#define local_irq_save(flags) \</span> +<span class="cp"> asm volatile ("pushf ; pop %0" :"=g" (flags)</span> + <span class="o">:</span> <span class="cm">/* no input */</span><span class="o">:</span> <span class="s">"memory"</span><span class="p">)</span> \ + <span class="k">asm</span> <span class="k">volatile</span><span class="p">(</span><span class="s">"cli"</span><span class="o">:</span> <span class="o">:</span> <span class="o">:</span><span class="s">"memory"</span><span class="p">)</span> + +<span class="cp">#define local_irq_restore(flags) \</span> +<span class="cp"> asm volatile ("push %0 ; popf"</span> + <span class="o">:</span> <span class="cm">/* no output */</span> + <span class="o">:</span> <span class="s">"g"</span> <span class="p">(</span><span class="n">flags</span><span class="p">)</span> <span class="o">:</span><span class="s">"memory"</span><span class="p">,</span> <span class="s">"cc"</span><span class="p">);</span> +</pre></div> +</div> +<p>Although the interrupts can be explicitly disabled and enable with +<code class="xref c c-func docutils literal"><span class="pre">local_irq_disable()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">local_irq_enable()</span></code> these APIs +should only be used when the current state and interrupts is +known. They are usually used in core kernel code (like interrupt +handling).</p> +<p>For typical cases where we want to avoid interrupts due to concurrency +issues it is recommended to use the <code class="xref c c-func docutils literal"><span class="pre">local_irq_save()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">local_irq_restore()</span></code> variants. They take care of saving and +restoring the interrupts states so they can be freely called from +overlapping critical sections without the risk of accidentally +enabling interrupts while still in a critical section, as long as the +calls are balanced.</p> +</div> +<div class="section" id="spin-locks"> +<h2>Spin Locks<a class="headerlink" href="#spin-locks" title="Permalink to this headline">¶</a></h2> +<p>Spin locks are used to serialize access to a critical section. They +are necessary on multi-core systems where we can have true execution +parallelism. This is a typical spin lock implementation:</p> +<div class="admonition-spin-lock-implementation-example-x86 highlight-asm"><div class="highlight"><pre><span></span>spin_lock: + lock bts [my_lock], 0 + jc spin_lock + +/* critical section */ + +spin_unlock: + mov [my_lock], 0 +</pre></div> +</div> +<p><strong>bts dts, src</strong> - bit test and set; it copies the src bit from the dts +memory address to the carry flag and then sets it:</p> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">CF</span> <span class="o"><-</span> <span class="n">dts</span><span class="p">[</span><span class="n">src</span><span class="p">]</span> +<span class="n">dts</span><span class="p">[</span><span class="n">src</span><span class="p">]</span> <span class="o"><-</span> <span class="mi">1</span> +</pre></div> +</div> +<p>As it can be seen, the spin lock uses an atomic instruction to make +sure that only one core can enter the critical section. If there are +multiple cores trying to enter they will continuously "spin" until the +lock is released.</p> +<p>While the spin lock avoids race conditions, it can have a significant +impact on the system's performance due to "lock contention":</p> +<ul class="admonition-lock-contention simple"> +<li>There is lock contention when at least one core spins trying to +enter the critical section lock</li> +<li>Lock contention grows with the critical section size, time spent +in the critical section and the number of cores in the system</li> +</ul> +<p>Another negative side effect of spin locks is cache thrashing.</p> +<p class="admonition-cache-thrashing">Cache thrashing occurs when multiple cores are trying to read and +write to the same memory resulting in excessive cache misses.</p> +<p>Since spin locks continuously access memory during lock contention, +cache thrashing is a common occurrence due to the way cache +coherency is implemented.</p> +</div> +<div class="section" id="cache-coherency-in-multi-processor-systems"> +<h2>Cache coherency in multi-processor systems<a class="headerlink" href="#cache-coherency-in-multi-processor-systems" title="Permalink to this headline">¶</a></h2> +<p>The memory hierarchy in multi-processor systems is composed of local +CPU caches (L1 caches), shared CPU caches (L2 caches) and the main +memory. To explain cache coherency we will ignore the L2 cache and +only consider the L1 caches and main memory.</p> +<p>In the figure below we present a view of the memory hierarchy with two +variables A and B that fall into different cache lines and where +caches and the main memory are synchronized:</p> +<p class="admonition-synchronized-caches-and-memory"> </p> +<img alt="../_images/ditaa-4d63c157487ff8291f2a6e93fe680ec38c1a3212.png" src="../_images/ditaa-4d63c157487ff8291f2a6e93fe680ec38c1a3212.png" /> +<p>In the absence of a synchronization mechanism between the caches and +main memory, when CPU 0 executes <cite>A = A + B</cite> and CPU 1 executes <cite>B = +A + B</cite> we will have the following memory view:</p> +<p class="admonition-unsynchronized-caches-and-memory"> </p> +<img alt="../_images/ditaa-7ee0f9bb5f5af586e043afd47cfbad0adcc34888.png" src="../_images/ditaa-7ee0f9bb5f5af586e043afd47cfbad0adcc34888.png" /> +<p>In order to avoid the situation above multi-processor systems use +cache coherency protocols. There are two main types of cache coherency +protocols:</p> +<ul class="admonition-cache-coherency-protocols simple"> +<li>Bus snooping (sniffing) based: memory bus transactions are +monitored by caches and they take actions to preserve +coherency</li> +<li>Directory based: there is a separate entity (directory) that +maintains the state of caches; caches interact with directory +to preserve coherency</li> +</ul> +<p>Bus snooping is simpler but it performs poorly when the number of +cores goes beyond 32-64.</p> +<p>Directory based cache coherence protocols scale much better (up +to thousands of cores) and are usually used in NUMA systems.</p> +<p>A simple cache coherency protocol that is commonly used in practice is +MESI (named after the acronym of the cache line states names: +<strong>Modified</strong>, <strong>Exclusive</strong>, <strong>Shared</strong> and <strong>Invalid</strong>). It's main +characteristics are:</p> +<ul class="admonition-mesi-cache-coherence-protocol simple"> +<li>Caching policy: write back</li> +<li>Cache line states<ul> +<li>Modified: owned by a single core and dirty</li> +<li>Exclusive: owned by a single core and clean</li> +<li>Shared: shared between multiple cores and clean</li> +<li>Invalid : the line is not cached</li> +</ul> +</li> +</ul> +<p>Issuing read or write requests from CPU cores will trigger state +transitions, as exemplified below:</p> +<ul class="admonition-mesi-state-transitions simple"> +<li>Invalid -> Exclusive: read request, all other cores have the line +in Invalid; line loaded from memory</li> +<li>Invalid -> Shared: read request, at least one core has the line +in Shared or Exclusive; line loaded from sibling cache</li> +<li>Invalid/Shared/Exclusive -> Modified: write request; <strong>all +other</strong> cores <strong>invalidate</strong> the line</li> +<li>Modified -> Invalid: write request from other core; line is +flushed to memory</li> +</ul> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The most important characteristic of the MESI protocol is +that it is a write-invalidate cache protocol. When writing to a +shared location all other caches are invalidated.</p> +</div> +<p>This has important performance impact in certain access patterns, and +one such pattern is contention for a simple spin lock implementation +like we discussed above.</p> +<p>To exemplify this issue lets consider a system with three CPU cores, +where the first has acquired the spin lock and it is running the +critical section while the other two are spinning waiting to enter the +critical section:</p> +<p class="admonition-cache-thrashing-due-to-spin-lock-contention"> </p> +<img alt="../_images/ditaa-b26d802c286bda6c559b4dcfa8a7fb27f840463e.png" src="../_images/ditaa-b26d802c286bda6c559b4dcfa8a7fb27f840463e.png" /> +<p>As it can be seen from the figure above due to the writes issued by +the cores spinning on the lock we see frequent cache line invalidate +operations which means that basically the two waiting cores will flush +and load the cache line while waiting for the lock, creating +unnecessary traffic on the memory bus and slowing down memory accesses +for the first core.</p> +<p>Another issue is that most likely data accessed by the first CPU +during the critical section is stored in the same cache line with the +lock (common optimization to have the data ready in the cache after +the lock is acquired). Which means that the cache invalidation +triggered by the two other spinning cores will slow down the execution +of the critical section which in turn triggers more cache invalidate +actions.</p> +</div> +<div class="section" id="optimized-spin-locks"> +<h2>Optimized spin locks<a class="headerlink" href="#optimized-spin-locks" title="Permalink to this headline">¶</a></h2> +<p>As we have seen simple spin lock implementations can have poor +performance issues due to cache thrashing, especially as the number of +cores increase. To avoid this issue there are two possible strategies:</p> +<ul class="simple"> +<li>reduce the number of writes and thus reduce the number of cache +invalidate operations</li> +<li>avoid the other processors spinning on the same cache line, and thus +avoid the cache invalidate operations</li> +</ul> +<p>An optimized spin lock implementation that uses the first approach is +presented below:</p> +<p class="admonition-optimized-spin-lock-keacquirespinlock"> </p> +<div class="highlight-asm"><div class="highlight"><pre><span></span><span class="nl">spin_lock:</span> + <span class="na">rep</span> <span class="c">; nop</span> + <span class="nf">test</span> <span class="no">lock_addr</span><span class="p">,</span> <span class="mi">1</span> + <span class="nf">jnz</span> <span class="no">spin_lock</span> + <span class="na">lock</span> <span class="nf">bts</span> <span class="no">lock_addr</span> + <span class="nf">jc</span> <span class="no">spin_lock</span> +</pre></div> +</div> +<ul class="simple"> +<li>we first test the lock read only, using a non atomic +instructions, to avoid writes and thus invalidate operations +while we spin</li> +<li>only when the lock <em>might</em> be free, we try to acquire it</li> +</ul> +<p>The implementation also use the <strong>PAUSE</strong> instruction to avoid +pipeline flushes due to (false positive) memory order violations and +to add a small delay (proportional with the memory bus frequency) to +reduce power consumption.</p> +<p>A similar implementation with support for fairness (the CPU cores are +allowed in the critical section based on the time of arrival) is used +in the Linux kernel (the <a class="reference external" href="https://lwn.net/Articles/267968/">ticket spin lock</a>) +for many architectures.</p> +<p>However, for the x86 architecture, the current spin lock +implementation uses a queued spin lock where the CPU cores spin on +different locks (hopefully distributed in different cache lines) to +avoid cache invalidation operations:</p> +<p class="admonition-queued-spin-locks"> </p> +<img alt="../_images/ditaa-58545831034f050660727be99cede213bc4a53c7.png" src="../_images/ditaa-58545831034f050660727be99cede213bc4a53c7.png" /> +<p>Conceptually, when a new CPU core tries to acquire the lock and it +fails it will add its private lock to the list of waiting CPU +cores. When the lock owner exits the critical section it unlocks the +next lock in the list, if any.</p> +<p>While a read spin optimized spin lock reduces most of the cache +invalidation operations, the lock owner can still generate cache +invalidate operations due to writes to data structures close to the +lock and thus part of the same cache line. This in turn generates +memory traffic on subsequent reads on the spinning cores.</p> +<p>Hence, queued spin locks scale much better for large number of cores +as is the case for NUMA systems. And since they have similar fairness +properties as the ticket lock it is the preferred implementation on +the x86 architecture.</p> +</div> +<div class="section" id="process-and-interrupt-context-synchronization"> +<h2>Process and Interrupt Context Synchronization<a class="headerlink" href="#process-and-interrupt-context-synchronization" title="Permalink to this headline">¶</a></h2> +<p>Accessing shared data from both process and interrupt context is a +relatively common scenario. On single core systems we can do this by +disabling interrupts, but that won't work on multi-core systems, +as we can have the process running on one CPU core and the interrupt +context running on a different CPU core.</p> +<p>Using a spin lock, which was designed for multi-processor systems, +seems like the right solution, but doing so can cause common +deadlock conditions, as detailed by the following scenario:</p> +<ul class="admonition-process-and-interrupt-handler-synchronization-deadlock simple"> +<li>In the process context we take the spin lock</li> +<li>An interrupt occurs and it is scheduled on the same CPU core</li> +<li>The interrupt handler runs and tries to take the spin lock</li> +<li>The current CPU will deadlock</li> +</ul> +<p>To avoid this issue a two fold approach is used:</p> +<ul class="admonition-interrupt-synchronization-for-smp simple"> +<li>In process context: disable interrupts and acquire a spin lock; +this will protect both against interrupt or other CPU cores race +conditions (<code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_lock_restore()</span></code> combine the two operations)</li> +<li>In interrupt context: take a spin lock; this will will protect +against race conditions with other interrupt handlers or process +context running on different processors</li> +</ul> +<p>We have the same issue for other interrupt context handlers such as +softirqs, tasklets or timers and while disabling interrupts might +work, it is recommended to use dedicated APIs:</p> +<ul class="admonition-bottom-half-synchronization-for-smp simple"> +<li>In process context use <code class="xref c c-func docutils literal"><span class="pre">spin_lock_bh()</span></code> (which combines +<code class="xref c c-func docutils literal"><span class="pre">local_bh_disable()</span></code> and <code class="xref c c-func docutils literal"><span class="pre">spin_lock()</span></code>) and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock_bh()</span></code> (which combines <code class="xref c c-func docutils literal"><span class="pre">spin_unlock()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">local_bh_enable()</span></code>)</li> +<li>In bottom half context use: <code class="xref c c-func docutils literal"><span class="pre">spin_lock()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_unlock()</span></code> (or <code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqsave()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">spin_lock_irqrestore()</span></code> if sharing data with interrupt +handlers)</li> +</ul> +<p>As mentioned before, another source of concurrency in the Linux kernel +can be other processes, due to preemption.</p> +<p class="admonition-preemption"> </p> +<p>Preemption is configurable: when active it provides better latency +and response time, while when deactivated it provides better +throughput.</p> +<p>Preemption is disabled by spin locks and mutexes but it can be +manually disabled as well (by core kernel code).</p> +<p>As for local interrupt enabling and disabling APIs, the bottom half +and preemption APIs allows them to be used in overlapping critical +sections. A counter is used to track the state of bottom half and +preemption. In fact the same counter is used, with different increment +values:</p> +<div class="admonition-preemption-and-bottom-half-masking highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define PREEMPT_BITS 8</span> +<span class="cp">#define SOFTIRQ_BITS 8</span> +<span class="cp">#define HARDIRQ_BITS 4</span> +<span class="cp">#define NMI_BITS 1</span> + +<span class="cp">#define preempt_disable() preempt_count_inc()</span> + +<span class="cp">#define local_bh_disable() add_preempt_count(SOFTIRQ_OFFSET)</span> + +<span class="cp">#define local_bh_enable() sub_preempt_count(SOFTIRQ_OFFSET)</span> + +<span class="cp">#define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK))</span> + +<span class="cp">#define in_interrupt() irq_count()</span> + +<span class="n">asmlinkage</span> <span class="kt">void</span> <span class="nf">do_softirq</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">in_interrupt</span><span class="p">())</span> <span class="k">return</span><span class="p">;</span> + <span class="p">...</span> +</pre></div> +</div> +</div> +<div class="section" id="mutexes"> +<h2>Mutexes<a class="headerlink" href="#mutexes" title="Permalink to this headline">¶</a></h2> +<p>Mutexes are used to protect against race conditions from other CPU +cores but they can only be used in <strong>process context</strong>. As opposed to +spin locks, while a thread is waiting to enter the critical section it +will not use CPU time, but instead it will be added to a waiting queue +until the critical section is vacated.</p> +<p>Since mutexes and spin locks usage intersect, it is useful to compare +the two:</p> +<ul class="admonition-mutexes simple"> +<li>They don't "waste" CPU cycles; system throughput is better than +spin locks if context switch overhead is lower than medium +spinning time</li> +<li>They can't be used in interrupt context</li> +<li>They have a higher latency than spin locks</li> +</ul> +<p>Conceptually, the <code class="xref c c-func docutils literal"><span class="pre">mutex_lock()</span></code> operation is relatively simple: +if the mutex is not acquired we can take the fast path via an atomic +exchange operation:</p> +<div class="admonition-c-func-mutex-lock-fast-path highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="n">__sched</span> <span class="nf">mutex_lock</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">might_sleep</span><span class="p">();</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">__mutex_trylock_fast</span><span class="p">(</span><span class="n">lock</span><span class="p">))</span> + <span class="n">__mutex_lock_slowpath</span><span class="p">(</span><span class="n">lock</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="n">__always_inline</span> <span class="kt">bool</span> <span class="nf">__mutex_trylock_fast</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">curr</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)</span><span class="n">current</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">atomic_long_cmpxchg_acquire</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">owner</span><span class="p">,</span> <span class="mi">0UL</span><span class="p">,</span> <span class="n">curr</span><span class="p">))</span> + <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> + + <span class="k">return</span> <span class="nb">false</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>otherwise we take the slow path where we add ourselves to the mutex +waiting list and put ourselves to sleep:</p> +<div class="admonition-c-func-mutex-lock-slow-path highlight-c"><div class="highlight"><pre><span></span><span class="p">...</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="p">...</span> + <span class="cm">/* add waiting tasks to the end of the waitqueue (FIFO): */</span> + <span class="n">list_add_tail</span><span class="p">(</span><span class="o">&</span><span class="n">waiter</span><span class="p">.</span><span class="n">list</span><span class="p">,</span> <span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_list</span><span class="p">);</span> +<span class="p">...</span> + <span class="n">waiter</span><span class="p">.</span><span class="n">task</span> <span class="o">=</span> <span class="n">current</span><span class="p">;</span> +<span class="p">...</span> + <span class="k">for</span> <span class="p">(;;)</span> <span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">__mutex_trylock</span><span class="p">(</span><span class="n">lock</span><span class="p">))</span> + <span class="k">goto</span> <span class="n">acquired</span><span class="p">;</span> + <span class="p">...</span> + <span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> + <span class="p">...</span> + <span class="n">set_current_state</span><span class="p">(</span><span class="n">state</span><span class="p">);</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> + <span class="p">}</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="nl">acquired</span><span class="p">:</span> + <span class="n">__set_current_state</span><span class="p">(</span><span class="n">TASK_RUNNING</span><span class="p">);</span> + <span class="n">mutex_remove_waiter</span><span class="p">(</span><span class="n">lock</span><span class="p">,</span> <span class="o">&</span><span class="n">waiter</span><span class="p">,</span> <span class="n">current</span><span class="p">);</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="p">...</span> +</pre></div> +</div> +<p>The full implementation is a bit more complex: instead of going to +sleep immediately it optimistic spinning if it detects that the lock +owner is currently running on a different CPU as chances are the owner +will release the lock soon. It also checks for signals and handles +mutex debugging for locking dependency engine debug feature.</p> +<p>The <code class="xref c c-func docutils literal"><span class="pre">mutex_unlock()</span></code> operation is symmetric: if there are no +waiters on the mutex then we can take the fast path via an atomic exchange +operation:</p> +<div class="admonition-c-func-mutex-unlock-fast-path highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="n">__sched</span> <span class="nf">mutex_unlock</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">__mutex_unlock_fast</span><span class="p">(</span><span class="n">lock</span><span class="p">))</span> + <span class="k">return</span><span class="p">;</span> + <span class="n">__mutex_unlock_slowpath</span><span class="p">(</span><span class="n">lock</span><span class="p">,</span> <span class="n">_RET_IP_</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="n">__always_inline</span> <span class="kt">bool</span> <span class="nf">__mutex_unlock_fast</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">curr</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)</span><span class="n">current</span><span class="p">;</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">atomic_long_cmpxchg_release</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">owner</span><span class="p">,</span> <span class="n">curr</span><span class="p">,</span> <span class="mi">0UL</span><span class="p">)</span> <span class="o">==</span> <span class="n">curr</span><span class="p">)</span> + <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> + + <span class="k">return</span> <span class="nb">false</span><span class="p">;</span> +<span class="p">}</span> + +<span class="kt">void</span> <span class="nf">__mutex_lock_slowpath</span><span class="p">(</span><span class="k">struct</span> <span class="n">mutex</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span> +<span class="p">{</span> +<span class="p">...</span> + <span class="k">if</span> <span class="p">(</span><span class="n">__mutex_waiter_is_first</span><span class="p">(</span><span class="n">lock</span><span class="p">,</span> <span class="o">&</span><span class="n">waiter</span><span class="p">))</span> + <span class="n">__mutex_set_flag</span><span class="p">(</span><span class="n">lock</span><span class="p">,</span> <span class="n">MUTEX_FLAG_WAITERS</span><span class="p">);</span> +<span class="p">...</span> +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Because <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">task_struct</span></code> is cached aligned the 7 +lower bits of the owner field can be used for various flags, +such as <code class="xref c c-type docutils literal"><span class="pre">MUTEX_FLAG_WAITERS</span></code>.</p> +</div> +<p>Otherwise we take the slow path where we pick up first waiter from the +list and wake it up:</p> +<div class="admonition-c-func-mutex-unlock-slow-path highlight-c"><div class="highlight"><pre><span></span><span class="p">...</span> +<span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">list_empty</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_list</span><span class="p">))</span> <span class="p">{</span> + <span class="cm">/* get the first entry from the wait-list: */</span> + <span class="k">struct</span> <span class="n">mutex_waiter</span> <span class="o">*</span><span class="n">waiter</span><span class="p">;</span> + <span class="n">waiter</span> <span class="o">=</span> <span class="n">list_first_entry</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_list</span><span class="p">,</span> <span class="k">struct</span> <span class="n">mutex_waiter</span><span class="p">,</span> + <span class="n">list</span><span class="p">);</span> + <span class="n">next</span> <span class="o">=</span> <span class="n">waiter</span><span class="o">-></span><span class="n">task</span><span class="p">;</span> + <span class="n">wake_q_add</span><span class="p">(</span><span class="o">&</span><span class="n">wake_q</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span> +<span class="p">}</span> +<span class="p">...</span> +<span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="o">-></span><span class="n">wait_lock</span><span class="p">);</span> +<span class="p">...</span> +<span class="n">wake_up_q</span><span class="p">(</span><span class="o">&</span><span class="n">wake_q</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="per-cpu-data"> +<h2>Per CPU data<a class="headerlink" href="#per-cpu-data" title="Permalink to this headline">¶</a></h2> +<p>Per CPU data avoids race conditions by avoiding to use shared +data. Instead, an array sized to the maximum possible CPU cores is +used and each core will use its own array entry to read and write +data. This approach certainly has advantages:</p> +<ul class="admonition-per-cpu-data simple"> +<li>No need to synchronize to access the data</li> +<li>No contention, no performance impact</li> +<li>Well suited for distributed processing where aggregation is only +seldom necessary (e.g. statistics counters)</li> +</ul> +</div> +<div class="section" id="memory-ordering-and-barriers"> +<h2>Memory Ordering and Barriers<a class="headerlink" href="#memory-ordering-and-barriers" title="Permalink to this headline">¶</a></h2> +<p>Modern processors and compilers employ out-of-order execution to +improve performance. For example, processors can execute "future" +instructions while waiting for current instruction data to be fetched +from memory.</p> +<p>Here is an example of out of order compiler generated code:</p> +<table border="1" class="admonition-out-of-order-compiler-generated-code docutils"> +<colgroup> +<col width="43%" /> +<col width="57%" /> +</colgroup> +<tbody valign="top"> +<tr class="row-odd"><td>C code</td> +<td>Compiler generated code</td> +</tr> +<tr class="row-even"><td><div class="first last highlight-c"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> +<span class="n">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> +</pre></div> +</div> +</td> +<td><div class="first last highlight-asm"><div class="highlight"><pre><span></span><span class="nf">MOV</span> <span class="no">R10</span><span class="p">,</span> <span class="mi">1</span> +<span class="nf">MOV</span> <span class="no">R11</span><span class="p">,</span> <span class="mi">2</span> +<span class="nf">STORE</span> <span class="no">R11</span><span class="p">,</span> <span class="no">b</span> +<span class="nf">STORE</span> <span class="no">R10</span><span class="p">,</span> <span class="no">a</span> +</pre></div> +</div> +</td> +</tr> +</tbody> +</table> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">When executing instructions out of order the processor makes +sure that data dependency is observed, i.e. it won't execute +instructions whose input depend on the output of a previous +instruction that has not been executed.</p> +</div> +<p>In most cases out of order execution is not an issue. However, in +certain situations (e.g. communicating via shared memory between +processors or between processors and hardware) we must issue some +instructions before others even without data dependency between them.</p> +<p>For this purpose we can use barriers to order memory operations:</p> +<ul class="admonition-barriers simple"> +<li>A read barrier (<code class="xref c c-func docutils literal"><span class="pre">rmb()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">smp_rmb()</span></code>) is used to +make sure that no read operation crosses the barrier; that is, +all read operation before the barrier are complete before +executing the first instruction after the barrier</li> +<li>A write barrier (<code class="xref c c-func docutils literal"><span class="pre">wmb()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">smp_wmb()</span></code>) is used to +make sure that no write operation crosses the barrier</li> +<li>A simple barrier (<code class="xref c c-func docutils literal"><span class="pre">mb()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">smp_mb()</span></code>) is used +to make sure that no write or read operation crosses the barrier</li> +</ul> +</div> +<div class="section" id="read-copy-update-rcu"> +<h2>Read Copy Update (RCU)<a class="headerlink" href="#read-copy-update-rcu" title="Permalink to this headline">¶</a></h2> +<p>Read Copy Update is a special synchronization mechanism similar with +read-write locks but with significant improvements over it (and some +limitations):</p> +<ul class="admonition-read-copy-update-rcu simple"> +<li><strong>Read-only</strong> lock-less access at the same time with write access</li> +<li>Write accesses still requires locks in order to avoid races +between writers</li> +<li>Requires unidirectional traversal by readers</li> +</ul> +<p>In fact, the read-write locks in the Linux kernel have been deprecated +and then removed, in favor of RCU.</p> +<p>Implementing RCU for a new data structure is difficult, but a few +common data structures (lists, queues, trees) do have RCU APIs that +can be used.</p> +<p>RCU splits removal updates to the data structures in two phases:</p> +<ul class="admonition-removal-and-reclamation simple"> +<li><strong>Removal</strong>: removes references to elements. Some old readers may +still see the old reference so we can't free the element.</li> +<li><strong>Elimination</strong>: free the element. This action is postponed until +all existing readers finish traversal (quiescent cycle). New +readers won't affect the quiescent cycle.</li> +</ul> +<p>As an example, lets take a look on how to delete an element from a +list using RCU:</p> +<p class="admonition-rcu-list-delete"> </p> +<img alt="../_images/ditaa-5193a924360bebc83d2f81188cd0b0093ec01e6a.png" src="../_images/ditaa-5193a924360bebc83d2f81188cd0b0093ec01e6a.png" /> +<p>In the first step it can be seen that while readers traverse the list +all elements are referenced. In step two a writer removes +element B. Reclamation is postponed since there are still readers that +hold references to it. In step three a quiescent cycle just expired +and it can be noticed that there are no more references to +element B. Other elements still have references from readers that +started the list traversal after the element was removed. In step 4 we +finally perform reclamation (free the element).</p> +<p>Now that we covered how RCU functions at the high level, lets looks at +the APIs for traversing the list as well as adding and removing an +element to the list:</p> +<div class="admonition-rcu-list-apis-cheat-sheet highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* list traversal */</span> +<span class="n">rcu_read_lock</span><span class="p">();</span> +<span class="n">list_for_each_entry_rcu</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">head</span><span class="p">)</span> <span class="p">{</span> + <span class="cm">/* no sleeping, blocking calls or context switch allowed */</span> +<span class="p">}</span> +<span class="n">rcu_read_unlock</span><span class="p">();</span> + + +<span class="cm">/* list element delete */</span> +<span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> +<span class="n">list_del_rcu</span><span class="p">(</span><span class="o">&</span><span class="n">node</span><span class="o">-></span><span class="n">list</span><span class="p">);</span> +<span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> +<span class="n">synchronize_rcu</span><span class="p">();</span> +<span class="n">kfree</span><span class="p">(</span><span class="n">node</span><span class="p">);</span> + +<span class="cm">/* list element add */</span> +<span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> +<span class="n">list_add_rcu</span><span class="p">(</span><span class="n">head</span><span class="p">,</span> <span class="o">&</span><span class="n">node</span><span class="o">-></span><span class="n">list</span><span class="p">);</span> +<span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> +</pre></div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lec4-interrupts.html" class="btn btn-neutral float-left" title="SO2 Lecture 04 - Interrupts" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lec6-address-space.html" class="btn btn-neutral float-right" title="SO2 Lecture 06 - Address Space" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec6-address-space-slides.html b/refs/pull/405/merge/so2/lec6-address-space-slides.html new file mode 100644 index 00000000..6d6ca403 --- /dev/null +++ b/refs/pull/405/merge/so2/lec6-address-space-slides.html @@ -0,0 +1,719 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>SO2 Lecture 06 - Address Space — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="up" title="Operating Systems 2" href="index.html" /> + <link rel="next" title="SO2 Lecture 07 - Memory Management" href="lec7-memory-management.html" /> + <link rel="prev" title="SO2 Lecture 05 - Symmetric Multi-Processing" href="lec5-smp.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-so2-lecture-06-address-space slide level-1"> + +<h1>SO2 Lecture 06 - Address Space</h1> + + + + + +</article> +<article class="admonition-address-space slide level-2"> + +<h2>Address Space</h2> + +<ul class="simple"> +<li>x86 MMU<ul> +<li>Segmentation</li> +<li>Paging</li> +<li>TLB</li> +</ul> +</li> +<li>Linux Address Space<ul> +<li>User</li> +<li>Kernel</li> +<li>High memory</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-x86-mmu slide level-2"> + +<h2>x86 MMU</h2> + +<p> </p> +<img alt="../_images/ditaa-f3703e3f627a948c59f6f960518d5f68eb7becec.png" src="../_images/ditaa-f3703e3f627a948c59f6f960518d5f68eb7becec.png" /> + + + + +</article> +<article class="admonition-selectors slide level-2"> + +<h2>Selectors</h2> + +<p> </p> +<img alt="../_images/ditaa-d6845a04f0ec792beec598d2a9f4c5b92c65529e.png" src="../_images/ditaa-d6845a04f0ec792beec598d2a9f4c5b92c65529e.png" /> +<ul class="simple"> +<li>Selectors: CS, DS, SS, ES, FS, GS</li> +<li>Index: indexes the segment descriptor table</li> +<li>TI: selects either the GDT or LDT</li> +<li>RPL: for CS only indicates the running (current) priviledge level</li> +<li>GDTR and LDTR registers points to the base of GDP and LDT</li> +</ul> + + + + +</article> +<article class="admonition-segment-descriptor slide level-2"> + +<h2>Segment descriptor</h2> + +<p> </p> +<img alt="../_images/ditaa-5cd4a8fa1ad97cff4bb1f64da13ce9ebfcfc4562.png" src="../_images/ditaa-5cd4a8fa1ad97cff4bb1f64da13ce9ebfcfc4562.png" /> +<ul class="simple"> +<li>Base: linear address for the start of the segment</li> +<li>Limit: size of the segment</li> +<li>G: granularity bit: if set the size is in bytes otherwise in 4K pages</li> +<li>B/D: data/code</li> +<li>Type: code segment, data/stack, TSS, LDT, GDT</li> +<li>Protection: the minimum priviledge level required to access the +segment (RPL is checked against DPL)</li> +</ul> + + + + +</article> +<article class="admonition-segmentation-in-linux slide level-2"> + +<h2>Segmentation in Linux</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/*</span> +<span class="cm"> * The layout of the per-CPU GDT under Linux:</span> +<span class="cm"> *</span> +<span class="cm"> * 0 - null <=== cacheline #1</span> +<span class="cm"> * 1 - reserved</span> +<span class="cm"> * 2 - reserved</span> +<span class="cm"> * 3 - reserved</span> +<span class="cm"> *</span> +<span class="cm"> * 4 - unused <=== cacheline #2</span> +<span class="cm"> * 5 - unused</span> +<span class="cm"> *</span> +<span class="cm"> * ------- start of TLS (Thread-Local Storage) segments:</span> +<span class="cm"> *</span> +<span class="cm"> * 6 - TLS segment #1 [ glibc's TLS segment ]</span> +<span class="cm"> * 7 - TLS segment #2 [ Wine's %fs Win32 segment ]</span> +<span class="cm"> * 8 - TLS segment #3 <=== cacheline #3</span> +<span class="cm"> * 9 - reserved</span> +<span class="cm"> * 10 - reserved</span> +<span class="cm"> * 11 - reserved</span> +<span class="cm"> *</span> +<span class="cm"> * ------- start of kernel segments:</span> +<span class="cm"> *</span> +<span class="cm"> * 12 - kernel code segment <=== cacheline #4</span> +<span class="cm"> * 13 - kernel data segment</span> +<span class="cm"> * 14 - default user CS</span> +<span class="cm"> * 15 - default user DS</span> +<span class="cm"> * 16 - TSS <=== cacheline #5</span> +<span class="cm"> * 17 - LDT</span> +<span class="cm"> * 18 - PNPBIOS support (16->32 gate)</span> +<span class="cm"> * 19 - PNPBIOS support</span> +<span class="cm"> * 20 - PNPBIOS support <=== cacheline #6</span> +<span class="cm"> * 21 - PNPBIOS support</span> +<span class="cm"> * 22 - PNPBIOS support</span> +<span class="cm"> * 23 - APM BIOS support</span> +<span class="cm"> * 24 - APM BIOS support <=== cacheline #7</span> +<span class="cm"> * 25 - APM BIOS support</span> +<span class="cm"> *</span> +<span class="cm"> * 26 - ESPFIX small SS</span> +<span class="cm"> * 27 - per-cpu [ offset to per-cpu data area ]</span> +<span class="cm"> * 28 - stack_canary-20 [ for stack protector ] <=== cacheline #8</span> +<span class="cm"> * 29 - unused</span> +<span class="cm"> * 30 - unused</span> +<span class="cm"> * 31 - TSS for double fault handler</span> +<span class="cm"> */</span> + + <span class="n">DEFINE_PER_CPU_PAGE_ALIGNED</span><span class="p">(</span><span class="k">struct</span> <span class="n">gdt_page</span><span class="p">,</span> <span class="n">gdt_page</span><span class="p">)</span> <span class="o">=</span> <span class="p">{</span> <span class="p">.</span><span class="n">gdt</span> <span class="o">=</span> <span class="p">{</span> + <span class="cp">#ifdef CONFIG_X86_64</span> + <span class="cm">/*</span> +<span class="cm"> * We need valid kernel segments for data and code in long mode too</span> +<span class="cm"> * IRET will check the segment types kkeil 2000/10/28</span> +<span class="cm"> * Also sysret mandates a special GDT layout</span> +<span class="cm"> *</span> +<span class="cm"> * TLS descriptors are currently at a different place compared to i386.</span> +<span class="cm"> * Hopefully nobody expects them at a fixed place (Wine?)</span> +<span class="cm"> */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL32_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc09b</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xa09b</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc093</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER32_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0fb</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0f3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xa0fb</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="cp">#else</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc09a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0fa</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0f2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="cm">/*</span> +<span class="cm"> * Segments used for calling PnP BIOS have byte granularity.</span> +<span class="cm"> * They code segments and data segments have fixed 64k limits,</span> +<span class="cm"> * the transfer segment sizes are set at run time.</span> +<span class="cm"> */</span> + <span class="cm">/* 32-bit code */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_CS32</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x409a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* 16-bit code */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_CS16</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x009a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* 16-bit data */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x0092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* 16-bit data */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_TS1</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x0092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> + <span class="cm">/* 16-bit data */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_TS2</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x0092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> + <span class="cm">/*</span> +<span class="cm"> * The APM segments have byte granularity and their bases</span> +<span class="cm"> * are set at run time. All have 64k limits.</span> +<span class="cm"> */</span> + <span class="cm">/* 32-bit code */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_APMBIOS_BASE</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x409a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* 16-bit code */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_APMBIOS_BASE</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x009a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* data */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_APMBIOS_BASE</span><span class="o">+</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x4092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + + <span class="p">[</span><span class="n">GDT_ENTRY_ESPFIX_SS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PERCPU</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="n">GDT_STACK_CANARY_INIT</span> + <span class="cp">#endif</span> + <span class="p">}</span> <span class="p">};</span> + <span class="n">EXPORT_PER_CPU_SYMBOL_GPL</span><span class="p">(</span><span class="n">gdt_page</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-inspecting-selectors-and-segments slide level-2"> + +<h2>Inspecting selectors and segments</h2> + +<p> </p> +<asciinema-player src="../_images/selectors-and-segments.cast"></asciinema-player> + + + +</article> +<article class="admonition-regular-paging slide level-2"> + +<h2>Regular paging</h2> + +<p> </p> +<img alt="../_images/ditaa-def299abebe530d760a6c8f16c791bbb016f9238.png" src="../_images/ditaa-def299abebe530d760a6c8f16c791bbb016f9238.png" /> + + + + +</article> +<article class="admonition-extended-paging slide level-2"> + +<h2>Extended paging</h2> + +<img alt="../_images/ditaa-709c2e7a68bfcdcfe9c1938d6ef2a0c9b5627931.png" src="../_images/ditaa-709c2e7a68bfcdcfe9c1938d6ef2a0c9b5627931.png" /> + + + + +</article> +<article class="admonition-page-tables slide level-2"> + +<h2>Page tables</h2> + +<ul class="simple"> +<li>Both page directory and page table have 1024 entries</li> +<li>Each entry has 4 bytes</li> +<li>The special CR3 register point to the base of the page directory</li> +<li>Page directory entries points to the base of the page table</li> +<li>All tables are stored in memory</li> +<li>All table addresses are physical addresses</li> +</ul> + + + + +</article> +<article class="admonition-page-table-entry-fields slide level-2"> + +<h2>Page table entry fields</h2> + +<ul class="simple"> +<li>Present/Absent</li> +<li>PFN (Page Frame Number): the most 20 significant bits of the physical address</li> +<li>Accessed - not updated by hardware (can be used by OS for housekeeping)</li> +<li>Dirty - not updated by hardware (can be used by OS for housekeeping)</li> +<li>Access rights: Read/Write</li> +<li>Privilege: User/Supervisor</li> +<li>Page size - only for page directory; if set extended paging is used</li> +<li>PCD (page cache disable), PWT (page write through)</li> +</ul> + + + + +</article> +<article class="admonition-linux-paging slide level-2"> + +<h2>Linux paging</h2> + +<img alt="../_images/ditaa-5e4d73e3fcb24db9d1f8c16daddf98694c063fe6.png" src="../_images/ditaa-5e4d73e3fcb24db9d1f8c16daddf98694c063fe6.png" /> + + + + +</article> +<article class="admonition-linux-apis-for-page-table-handling slide level-2"> + +<h2>Linux APIs for page table handling</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="o">*</span> <span class="n">page</span><span class="p">;</span> +<span class="n">pgd_t</span> <span class="n">pgd</span><span class="p">;</span> +<span class="n">pmd_t</span> <span class="n">pmd</span><span class="p">;</span> +<span class="n">pud_t</span> <span class="n">pud</span><span class="p">;</span> +<span class="n">pte_t</span> <span class="n">pte</span><span class="p">;</span> +<span class="kt">void</span> <span class="o">*</span><span class="n">laddr</span><span class="p">,</span> <span class="o">*</span><span class="n">paddr</span><span class="p">;</span> + +<span class="n">pgd</span> <span class="o">=</span> <span class="n">pgd_offset</span><span class="p">(</span><span class="n">mm</span><span class="p">,</span> <span class="n">vaddr</span><span class="p">);</span> +<span class="n">pud</span> <span class="o">=</span> <span class="n">pud_offet</span><span class="p">(</span><span class="n">pgd</span><span class="p">,</span> <span class="n">vaddr</span><span class="p">);</span> +<span class="n">pmd</span> <span class="o">=</span> <span class="n">pmd_offset</span><span class="p">(</span><span class="n">pud</span><span class="p">,</span> <span class="n">vaddr</span><span class="p">);</span> +<span class="n">pte</span> <span class="o">=</span> <span class="n">pte_offset</span><span class="p">(</span><span class="n">pmd</span><span class="p">,</span> <span class="n">vaddr</span><span class="p">);</span> +<span class="n">page</span> <span class="o">=</span> <span class="n">pte_page</span><span class="p">(</span><span class="n">pte</span><span class="p">);</span> +<span class="n">laddr</span> <span class="o">=</span> <span class="n">page_address</span><span class="p">(</span><span class="n">page</span><span class="p">);</span> +<span class="n">paddr</span> <span class="o">=</span> <span class="n">virt_to_phys</span><span class="p">(</span><span class="n">laddr</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-what-about-platforms-with-less-then-4-levels-of-pagination slide level-2"> + +<h2>What about platforms with less then 4 levels of pagination?</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kr">inline</span> <span class="n">pud_t</span> <span class="o">*</span> <span class="nf">pud_offset</span><span class="p">(</span><span class="n">pgd_t</span> <span class="o">*</span> <span class="n">pgd</span><span class="p">,</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">address</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="p">(</span><span class="n">pud_t</span> <span class="o">*</span><span class="p">)</span><span class="n">pgd</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kr">inline</span> <span class="n">pmd_t</span> <span class="o">*</span> <span class="nf">pmd_offset</span><span class="p">(</span><span class="n">pud_t</span> <span class="o">*</span> <span class="n">pud</span><span class="p">,</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">address</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="p">(</span><span class="n">pmd_t</span> <span class="o">*</span><span class="p">)</span><span class="n">pud</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-translation-look-aside-buffer slide level-2"> + +<h2>Translation Look-aside Buffer</h2> + +<ul class="simple"> +<li>Caches paging information (PFN, rights, privilege)</li> +<li>Content Addressable Memory / Associative Memory<ul> +<li>Very small (64-128)</li> +<li>Very fast (single cycle due to parallel search implementation)</li> +</ul> +</li> +<li>CPUs usually have two TLBs: i-TLB (code) and d-TLB (data)</li> +<li>TLB miss penalty: up hundreds of cycles</li> +</ul> + + + + +</article> +<article class="admonition-tlb-invalidation slide level-2"> + +<h2>TLB invalidation</h2> + +<p>Single address invalidation:</p> +<div class="highlight-asm"><div class="highlight"><pre><span></span>mov $addr, %eax +invlpg %(eax) +</pre></div> +</div> +<p>Full invalidation:</p> +<div class="highlight-asm"><div class="highlight"><pre><span></span><span class="nf">mov</span> <span class="nv">%cr3</span><span class="p">,</span> <span class="nv">%eax</span> +<span class="nf">mov</span> <span class="nv">%eax</span><span class="p">,</span> <span class="nv">%cr3</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-address-space-options-for-32bit-systems slide level-2"> + +<h2>Address space options for 32bit systems</h2> + +<p> </p> +<img alt="../_images/ditaa-d5d1129b0298a2ea5f116c9d4b246eb1b888db6b.png" src="../_images/ditaa-d5d1129b0298a2ea5f116c9d4b246eb1b888db6b.png" /> + + + + +</article> +<article class="admonition-advantages-and-disadvantages slide level-2"> + +<h2>Advantages and disadvantages</h2> + +<ul class="simple"> +<li>Disadvantages for dedicated kernel space:<ul> +<li>Fully invalidating the TLB for every system call</li> +</ul> +</li> +<li>Disadvantages for shared address space<ul> +<li>Less address space for both kernel and user processes</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-linux-address-space-for-32bit-systems slide level-2"> + +<h2>Linux address space for 32bit systems</h2> + +<p> </p> +<img alt="../_images/ditaa-3985c420def8f30934a72ea8c738a00ed629c298.png" src="../_images/ditaa-3985c420def8f30934a72ea8c738a00ed629c298.png" /> + + + + +</article> +<article class="admonition-virtual-to-physical-address-translations-for-i-o-transfers slide level-2"> + +<h2>Virtual to physical address translations for I/O transfers</h2> + +<ul class="simple"> +<li>Use the virtual address of a kernel buffer in order to copy to +data from from user space</li> +<li>Walk the page tables to transform the kernel buffer virtual +address to a physical address</li> +<li>Use the physical address of the kernel buffer to start a DMA +transfer</li> +</ul> + + + + +</article> +<article class="admonition-linear-mappings slide level-2"> + +<h2>Linear mappings</h2> + +<ul class="simple"> +<li>Virtual to physical address space translation is reduced to one +operation (instead of walking the page tables)</li> +<li>Less memory is used to create the page tables</li> +<li>Less TLB entries are used for the kernel memory</li> +</ul> + + + + +</article> +<article class="admonition-highmem slide level-2"> + +<h2>Highmem</h2> + +<p> </p> +<img alt="../_images/ditaa-bb8455a43088bf800eece11869f6ff857574605d.png" src="../_images/ditaa-bb8455a43088bf800eece11869f6ff857574605d.png" /> + + + + +</article> +<article class="admonition-multi-page-permanent-mappings slide level-2"> + +<h2>Multi-page permanent mappings</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="o">*</span> <span class="nf">vmalloc</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">size</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">vfree</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span> <span class="n">addr</span><span class="p">);</span> + +<span class="kt">void</span> <span class="o">*</span><span class="nf">ioremap</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">offset</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">size</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">iounmap</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span> <span class="n">addr</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-fixed-mapped-linear-addresses slide level-2"> + +<h2>Fixed-mapped linear addresses</h2> + +<ul class="simple"> +<li>Reserved virtual addresses (constants)</li> +<li>Mapped to physical addresses during boot</li> +</ul> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">set_fixmap</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="n">phys_addr</span><span class="p">)</span> +<span class="n">set_fixmap_nocache</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="n">phys_addr</span><span class="p">)</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-fixed-mapped-linear-addresses slide level-2"> + +<h2>Fixed-mapped linear addresses</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/*</span> +<span class="cm"> * Here we define all the compile-time 'special' virtual</span> +<span class="cm"> * addresses. The point is to have a constant address at</span> +<span class="cm"> * compile time, but to set the physical address only</span> +<span class="cm"> * in the boot process.</span> +<span class="cm"> * for x86_32: We allocate these special addresses</span> +<span class="cm"> * from the end of virtual memory (0xfffff000) backwards.</span> +<span class="cm"> * Also this lets us do fail-safe vmalloc(), we</span> +<span class="cm"> * can guarantee that these special addresses and</span> +<span class="cm"> * vmalloc()-ed addresses never overlap.</span> +<span class="cm"> *</span> +<span class="cm"> * These 'compile-time allocated' memory buffers are</span> +<span class="cm"> * fixed-size 4k pages (or larger if used with an increment</span> +<span class="cm"> * higher than 1). Use set_fixmap(idx,phys) to associate</span> +<span class="cm"> * physical memory with fixmap indices.</span> +<span class="cm"> *</span> +<span class="cm"> * TLB entries of such buffers will not be flushed across</span> +<span class="cm"> * task switches.</span> +<span class="cm"> */</span> + +<span class="k">enum</span> <span class="n">fixed_addresses</span> <span class="p">{</span> +<span class="cp">#ifdef CONFIG_X86_32</span> + <span class="n">FIX_HOLE</span><span class="p">,</span> +<span class="cp">#else</span> +<span class="cp">#ifdef CONFIG_X86_VSYSCALL_EMULATION</span> + <span class="n">VSYSCALL_PAGE</span> <span class="o">=</span> <span class="p">(</span><span class="n">FIXADDR_TOP</span> <span class="o">-</span> <span class="n">VSYSCALL_ADDR</span><span class="p">)</span> <span class="o">>></span> <span class="n">PAGE_SHIFT</span><span class="p">,</span> +<span class="cp">#endif</span> +<span class="cp">#endif</span> + <span class="n">FIX_DBGP_BASE</span><span class="p">,</span> + <span class="n">FIX_EARLYCON_MEM_BASE</span><span class="p">,</span> +<span class="cp">#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT</span> + <span class="n">FIX_OHCI1394_BASE</span><span class="p">,</span> +<span class="cp">#endif</span> +<span class="cp">#ifdef CONFIG_X86_LOCAL_APIC</span> + <span class="n">FIX_APIC_BASE</span><span class="p">,</span> <span class="cm">/* local (CPU) APIC) -- required for SMP or not */</span> +<span class="cp">#endif</span> +<span class="cp">#ifdef CONFIG_X86_IO_APIC</span> + <span class="n">FIX_IO_APIC_BASE_0</span><span class="p">,</span> + <span class="n">FIX_IO_APIC_BASE_END</span> <span class="o">=</span> <span class="n">FIX_IO_APIC_BASE_0</span> <span class="o">+</span> <span class="n">MAX_IO_APICS</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> +<span class="cp">#endif</span> +<span class="cp">#ifdef CONFIG_X86_32</span> + <span class="n">FIX_KMAP_BEGIN</span><span class="p">,</span> <span class="cm">/* reserved pte's for temporary kernel mappings */</span> + <span class="n">FIX_KMAP_END</span> <span class="o">=</span> <span class="n">FIX_KMAP_BEGIN</span><span class="o">+</span><span class="p">(</span><span class="n">KM_TYPE_NR</span><span class="o">*</span><span class="n">NR_CPUS</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> +<span class="cp">#ifdef CONFIG_PCI_MMCONFIG</span> + <span class="n">FIX_PCIE_MCFG</span><span class="p">,</span> +<span class="cp">#endif</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-conversion-between-virtual-address-fixed-address-indexes slide level-2"> + +<h2>Conversion between virtual address fixed address indexes</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))</span> +<span class="cp">#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)</span> + +<span class="cp">#ifndef __ASSEMBLY__</span> +<span class="cm">/*</span> +<span class="cm"> * 'index to address' translation. If anyone tries to use the idx</span> +<span class="cm"> * directly without translation, we catch the bug with a NULL-deference</span> +<span class="cm"> * kernel oops. Illegal ranges of incoming indices are caught too.</span> +<span class="cm"> */</span> + <span class="k">static</span> <span class="n">__always_inline</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="nf">fix_to_virt</span><span class="p">(</span><span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">idx</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">BUILD_BUG_ON</span><span class="p">(</span><span class="n">idx</span> <span class="o">>=</span> <span class="n">__end_of_fixed_addresses</span><span class="p">);</span> + <span class="k">return</span> <span class="n">__fix_to_virt</span><span class="p">(</span><span class="n">idx</span><span class="p">);</span> + <span class="p">}</span> + + <span class="k">static</span> <span class="kr">inline</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="nf">virt_to_fix</span><span class="p">(</span><span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">vaddr</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">BUG_ON</span><span class="p">(</span><span class="n">vaddr</span> <span class="o">>=</span> <span class="n">FIXADDR_TOP</span> <span class="o">||</span> <span class="n">vaddr</span> <span class="o"><</span> <span class="n">FIXADDR_START</span><span class="p">);</span> + <span class="k">return</span> <span class="n">__virt_to_fix</span><span class="p">(</span><span class="n">vaddr</span><span class="p">);</span> + <span class="p">}</span> + + + <span class="kr">inline</span> <span class="kt">long</span> <span class="nf">fix_to_virt</span><span class="p">(</span><span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">idx</span><span class="p">)</span> + <span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">idx</span> <span class="o">>=</span> <span class="n">__end_of_fixed_addresses</span><span class="p">)</span> + <span class="n">__this_fixmap_does_not_exist</span><span class="p">();</span> + <span class="k">return</span> <span class="p">(</span><span class="mh">0xffffe000UL</span> <span class="o">-</span> <span class="p">(</span><span class="n">idx</span> <span class="o"><<</span> <span class="n">PAGE_SHIFT</span><span class="p">));</span> + <span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-temporary-mappings slide level-2"> + +<h2>Temporary mappings</h2> + +<ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">kmap_atomic()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">kunmap_atomic()</span></code></li> +<li>No context switch is permitted in atomic kmap section</li> +<li>Can be used in interrupt context</li> +<li>No locking required</li> +<li>Only invalidates on TLB entry</li> +</ul> + + + + +</article> +<article class="admonition-temporary-mappings-implementation slide level-2"> + +<h2>Temporary mappings implementation</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define kmap_atomic(page) kmap_atomic_prot(page, kmap_prot)</span> + +<span class="kt">void</span> <span class="o">*</span><span class="nf">kmap_atomic_high_prot</span><span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">,</span> <span class="n">pgprot_t</span> <span class="n">prot</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">vaddr</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">idx</span><span class="p">,</span> <span class="n">type</span><span class="p">;</span> + + <span class="n">type</span> <span class="o">=</span> <span class="n">kmap_atomic_idx_push</span><span class="p">();</span> + <span class="n">idx</span> <span class="o">=</span> <span class="n">type</span> <span class="o">+</span> <span class="n">KM_TYPE_NR</span><span class="o">*</span><span class="n">smp_processor_id</span><span class="p">();</span> + <span class="n">vaddr</span> <span class="o">=</span> <span class="n">__fix_to_virt</span><span class="p">(</span><span class="n">FIX_KMAP_BEGIN</span> <span class="o">+</span> <span class="n">idx</span><span class="p">);</span> + <span class="n">BUG_ON</span><span class="p">(</span><span class="o">!</span><span class="n">pte_none</span><span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="n">kmap_pte</span><span class="o">-</span><span class="n">idx</span><span class="p">)));</span> + <span class="n">set_pte</span><span class="p">(</span><span class="n">kmap_pte</span><span class="o">-</span><span class="n">idx</span><span class="p">,</span> <span class="n">mk_pte</span><span class="p">(</span><span class="n">page</span><span class="p">,</span> <span class="n">prot</span><span class="p">));</span> + <span class="n">arch_flush_lazy_mmu_mode</span><span class="p">();</span> + + <span class="k">return</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">vaddr</span><span class="p">;</span> +<span class="p">}</span> +<span class="n">EXPORT_SYMBOL</span><span class="p">(</span><span class="n">kmap_atomic_high_prot</span><span class="p">);</span> + +<span class="k">static</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="nf">kmap_atomic_idx_push</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">idx</span> <span class="o">=</span> <span class="n">__this_cpu_inc_return</span><span class="p">(</span><span class="n">__kmap_atomic_idx</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> + +<span class="cp">#ifdef CONFIG_DEBUG_HIGHMEM</span> + <span class="n">WARN_ON_ONCE</span><span class="p">(</span><span class="n">in_irq</span><span class="p">()</span> <span class="o">&&</span> <span class="o">!</span><span class="n">irqs_disabled</span><span class="p">());</span> + <span class="n">BUG_ON</span><span class="p">(</span><span class="n">idx</span> <span class="o">>=</span> <span class="n">KM_TYPE_NR</span><span class="p">);</span> +<span class="cp">#endif</span> + <span class="k">return</span> <span class="n">idx</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-implementation-of-temporary-mappings slide level-2"> + +<h2>Implementation of temporary mappings</h2> + +<ul class="simple"> +<li>Use the fixed-mapped linear addresses</li> +<li>Every CPU has KM_TYPE_NR reserved entries to be used for +temporary mappings</li> +<li>Stack like selection: every user picks the current entry and +increments the "stack" counter</li> +</ul> + + + + +</article> +<article class="admonition-permanent-mappings slide level-2"> + +<h2>Permanent mappings</h2> + +<ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">kmap()</span></code>, <code class="xref c c-func docutils literal"><span class="pre">kunmap()</span></code></li> +<li>Context switches are allowed</li> +<li>Only available in process context</li> +<li>One page table is reserved for permanent mappings</li> +<li>Page counter<ul> +<li>0 - page is not mapped, free and ready to use</li> +<li>1 - page is not mapped, may be present in TLB needs flushing before using</li> +<li>N - page is mapped N-1 times</li> +</ul> +</li> +</ul> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec6-address-space.html b/refs/pull/405/merge/so2/lec6-address-space.html new file mode 100644 index 00000000..74e8e2f7 --- /dev/null +++ b/refs/pull/405/merge/so2/lec6-address-space.html @@ -0,0 +1,802 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lecture 06 - Address Space — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lecture 07 - Memory Management" href="lec7-memory-management.html" /> + <link rel="prev" title="SO2 Lecture 05 - Symmetric Multi-Processing" href="lec5-smp.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lecture 06 - Address Space</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="#x86-mmu">x86 MMU</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#selectors">Selectors</a></li> +<li class="toctree-l4"><a class="reference internal" href="#segment-descriptor">Segment descriptor</a></li> +<li class="toctree-l4"><a class="reference internal" href="#segmentation-in-linux">Segmentation in Linux</a></li> +<li class="toctree-l4"><a class="reference internal" href="#inspecting-selectors-and-segments">Inspecting selectors and segments</a></li> +<li class="toctree-l4"><a class="reference internal" href="#x86-paging">x86 Paging</a></li> +<li class="toctree-l4"><a class="reference internal" href="#page-tables">Page tables</a></li> +<li class="toctree-l4"><a class="reference internal" href="#linux-paging">Linux paging</a></li> +<li class="toctree-l4"><a class="reference internal" href="#translation-look-aside-buffer">Translation Look-aside Buffer</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#linux-address-space">Linux address space</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#address-space-options-for-32bit-systems">Address space options for 32bit systems</a></li> +<li class="toctree-l4"><a class="reference internal" href="#linear-mappings">Linear mappings</a></li> +<li class="toctree-l4"><a class="reference internal" href="#highmem">Highmem</a></li> +<li class="toctree-l4"><a class="reference internal" href="#fixed-mapped-linear-addresses">Fixed-mapped linear addresses</a></li> +<li class="toctree-l4"><a class="reference internal" href="#temporary-mappings">Temporary mappings</a></li> +<li class="toctree-l4"><a class="reference internal" href="#permanent-mappings">Permanent mappings</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lecture 06 - Address Space</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lec6-address-space.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lecture-06-address-space"> +<h1>SO2 Lecture 06 - Address Space<a class="headerlink" href="#so2-lecture-06-address-space" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="lec6-address-space-slides.html">View slides</a></p> +<span class="admonition-so2-lecture-06-address-space"></span><div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-address-space simple"> +<li>x86 MMU<ul> +<li>Segmentation</li> +<li>Paging</li> +<li>TLB</li> +</ul> +</li> +<li>Linux Address Space<ul> +<li>User</li> +<li>Kernel</li> +<li>High memory</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="x86-mmu"> +<h2>x86 MMU<a class="headerlink" href="#x86-mmu" title="Permalink to this headline">¶</a></h2> +<p>The x86 MMU has a segmentation and a pagination unit. The segmentation +unit can be used to define logical memory segments defined by a +logical (virtual) start address, a base linear (mapped) address and a +size. A segment can also restrict access based on the access type +(read, execute, write) or the privilege level (we can define some +segments to be accessible only by kernel for example).</p> +<p>When the CPU makes a memory access, it will use the segmentation unit +to translate the logical address to a linear address, based on the +information in the segment descriptor.</p> +<p>If pagination is enabled the linear address will be further +transformed into a physical address, using the information from the +page tables.</p> +<p>Note that the segmentation unit can not be disabled, so if the MMU has +been enabled, segmentation will always be used.</p> +<p class="admonition-x86-mmu"> </p> +<img alt="../_images/ditaa-f3703e3f627a948c59f6f960518d5f68eb7becec.png" src="../_images/ditaa-f3703e3f627a948c59f6f960518d5f68eb7becec.png" /> +<div class="section" id="selectors"> +<h3>Selectors<a class="headerlink" href="#selectors" title="Permalink to this headline">¶</a></h3> +<p>A program can use multiple segments and in order to determine which +segment to use, special registers (named selectors) are used. The +basic selectors that are typically used are CS - "Code Selector", DS - +"Data Selector" and SS - "Stack Selector".</p> +<p>Instruction fetches will by default use CS, while data access will by +default use DS unless the stack is used (e.g. data access through the +pop and push instructions) in which case SS will be used by default.</p> +<p>Selectors have three main fields: the index, the table index and the +running privilege level:</p> +<p class="admonition-selectors"> </p> +<img alt="../_images/ditaa-d6845a04f0ec792beec598d2a9f4c5b92c65529e.png" src="../_images/ditaa-d6845a04f0ec792beec598d2a9f4c5b92c65529e.png" /> +<p>The index will be used to determine which entry of the descriptor +table should be used. <cite>TI</cite> is used to select either the Global +Descriptor Table (GDT) or the Local Descriptor Table (LDT). The tables +are effectively arrays that start at the location specified in the +special registers <cite>GDTR</cite> (for GDT) and <cite>LDTR</cite> (for LDT).</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">LDT was designed so that applications can define their own +particular segments. Although not many applications use this +feature, Linux (and Windows) provide system calls that +allows an application to create their own segments.</p> +</div> +<p><cite>RPL</cite> is only used for CS and it represents the current privilege +level. There are 4 privilege levels, the highest level being 0 (and +typically used by the kernel) and the lowest is 3 (and typically used +by user applications).</p> +</div> +<div class="section" id="segment-descriptor"> +<h3>Segment descriptor<a class="headerlink" href="#segment-descriptor" title="Permalink to this headline">¶</a></h3> +<p>The CPU will use the <cite>index</cite> field of the selector to access an 8 byte +descriptor:</p> +<p class="admonition-segment-descriptor"> </p> +<img alt="../_images/ditaa-5cd4a8fa1ad97cff4bb1f64da13ce9ebfcfc4562.png" src="../_images/ditaa-5cd4a8fa1ad97cff4bb1f64da13ce9ebfcfc4562.png" /> +<ul class="simple"> +<li>Base: linear address for the start of the segment</li> +<li>Limit: size of the segment</li> +<li>G: granularity bit: if set the size is in bytes otherwise in 4K pages</li> +<li>B/D: data/code</li> +<li>Type: code segment, data/stack, TSS, LDT, GDT</li> +<li>Protection: the minimum priviledge level required to access the +segment (RPL is checked against DPL)</li> +</ul> +<p>Some of the descriptor fields should be familiar. And that is because +there is some resemblance with Interrupt Descriptors we looked at +previously.</p> +</div> +<div class="section" id="segmentation-in-linux"> +<h3>Segmentation in Linux<a class="headerlink" href="#segmentation-in-linux" title="Permalink to this headline">¶</a></h3> +<p>In Linux, segments are not used to define the stack, code or +data. These will be setup using the paging unit as it allows better +granularity and more importantly it allows Linux to use a generic +approach that works on other architectures (that don't have +segmentation support).</p> +<p>However, because the segmentation unit can not be disabled Linux must +create 4 generic 0 - 4GB segments for: kernel code, kernel data, user +code and user data.</p> +<p>Besides these, Linux uses segments for implementing Thread Local +Storage (TLS) together with the <cite>set_thread_area</cite> system call.</p> +<p>It also uses the TSS segment in order to define the kernel stack to +use when a change of privilege (e.g. system call, interrupt while +running in user-space) occurs.</p> +<div class="admonition-segmentation-in-linux highlight-c"><div class="highlight"><pre><span></span><span class="cm">/*</span> +<span class="cm"> * The layout of the per-CPU GDT under Linux:</span> +<span class="cm"> *</span> +<span class="cm"> * 0 - null <=== cacheline #1</span> +<span class="cm"> * 1 - reserved</span> +<span class="cm"> * 2 - reserved</span> +<span class="cm"> * 3 - reserved</span> +<span class="cm"> *</span> +<span class="cm"> * 4 - unused <=== cacheline #2</span> +<span class="cm"> * 5 - unused</span> +<span class="cm"> *</span> +<span class="cm"> * ------- start of TLS (Thread-Local Storage) segments:</span> +<span class="cm"> *</span> +<span class="cm"> * 6 - TLS segment #1 [ glibc's TLS segment ]</span> +<span class="cm"> * 7 - TLS segment #2 [ Wine's %fs Win32 segment ]</span> +<span class="cm"> * 8 - TLS segment #3 <=== cacheline #3</span> +<span class="cm"> * 9 - reserved</span> +<span class="cm"> * 10 - reserved</span> +<span class="cm"> * 11 - reserved</span> +<span class="cm"> *</span> +<span class="cm"> * ------- start of kernel segments:</span> +<span class="cm"> *</span> +<span class="cm"> * 12 - kernel code segment <=== cacheline #4</span> +<span class="cm"> * 13 - kernel data segment</span> +<span class="cm"> * 14 - default user CS</span> +<span class="cm"> * 15 - default user DS</span> +<span class="cm"> * 16 - TSS <=== cacheline #5</span> +<span class="cm"> * 17 - LDT</span> +<span class="cm"> * 18 - PNPBIOS support (16->32 gate)</span> +<span class="cm"> * 19 - PNPBIOS support</span> +<span class="cm"> * 20 - PNPBIOS support <=== cacheline #6</span> +<span class="cm"> * 21 - PNPBIOS support</span> +<span class="cm"> * 22 - PNPBIOS support</span> +<span class="cm"> * 23 - APM BIOS support</span> +<span class="cm"> * 24 - APM BIOS support <=== cacheline #7</span> +<span class="cm"> * 25 - APM BIOS support</span> +<span class="cm"> *</span> +<span class="cm"> * 26 - ESPFIX small SS</span> +<span class="cm"> * 27 - per-cpu [ offset to per-cpu data area ]</span> +<span class="cm"> * 28 - stack_canary-20 [ for stack protector ] <=== cacheline #8</span> +<span class="cm"> * 29 - unused</span> +<span class="cm"> * 30 - unused</span> +<span class="cm"> * 31 - TSS for double fault handler</span> +<span class="cm"> */</span> + + <span class="n">DEFINE_PER_CPU_PAGE_ALIGNED</span><span class="p">(</span><span class="k">struct</span> <span class="n">gdt_page</span><span class="p">,</span> <span class="n">gdt_page</span><span class="p">)</span> <span class="o">=</span> <span class="p">{</span> <span class="p">.</span><span class="n">gdt</span> <span class="o">=</span> <span class="p">{</span> + <span class="cp">#ifdef CONFIG_X86_64</span> + <span class="cm">/*</span> +<span class="cm"> * We need valid kernel segments for data and code in long mode too</span> +<span class="cm"> * IRET will check the segment types kkeil 2000/10/28</span> +<span class="cm"> * Also sysret mandates a special GDT layout</span> +<span class="cm"> *</span> +<span class="cm"> * TLS descriptors are currently at a different place compared to i386.</span> +<span class="cm"> * Hopefully nobody expects them at a fixed place (Wine?)</span> +<span class="cm"> */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL32_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc09b</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xa09b</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc093</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER32_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0fb</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0f3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xa0fb</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="cp">#else</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc09a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_CS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0fa</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0f2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="cm">/*</span> +<span class="cm"> * Segments used for calling PnP BIOS have byte granularity.</span> +<span class="cm"> * They code segments and data segments have fixed 64k limits,</span> +<span class="cm"> * the transfer segment sizes are set at run time.</span> +<span class="cm"> */</span> + <span class="cm">/* 32-bit code */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_CS32</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x409a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* 16-bit code */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_CS16</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x009a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* 16-bit data */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_DS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x0092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* 16-bit data */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_TS1</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x0092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> + <span class="cm">/* 16-bit data */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PNPBIOS_TS2</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x0092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> + <span class="cm">/*</span> +<span class="cm"> * The APM segments have byte granularity and their bases</span> +<span class="cm"> * are set at run time. All have 64k limits.</span> +<span class="cm"> */</span> + <span class="cm">/* 32-bit code */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_APMBIOS_BASE</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x409a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* 16-bit code */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_APMBIOS_BASE</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x009a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + <span class="cm">/* data */</span> + <span class="p">[</span><span class="n">GDT_ENTRY_APMBIOS_BASE</span><span class="o">+</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0x4092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xffff</span><span class="p">),</span> + + <span class="p">[</span><span class="n">GDT_ENTRY_ESPFIX_SS</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="p">[</span><span class="n">GDT_ENTRY_PERCPU</span><span class="p">]</span> <span class="o">=</span> <span class="n">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span> + <span class="n">GDT_STACK_CANARY_INIT</span> + <span class="cp">#endif</span> + <span class="p">}</span> <span class="p">};</span> + <span class="n">EXPORT_PER_CPU_SYMBOL_GPL</span><span class="p">(</span><span class="n">gdt_page</span><span class="p">);</span> +</pre></div> +</div> +</div> +<div class="section" id="inspecting-selectors-and-segments"> +<h3>Inspecting selectors and segments<a class="headerlink" href="#inspecting-selectors-and-segments" title="Permalink to this headline">¶</a></h3> +<p class="admonition-inspecting-selectors-and-segments"> </p> +<asciinema-player src="../_images/selectors-and-segments.cast"></asciinema-player></div> +<div class="section" id="x86-paging"> +<h3>x86 Paging<a class="headerlink" href="#x86-paging" title="Permalink to this headline">¶</a></h3> +<p>The x86 paging unit support two types of paging: regular and extended paging.</p> +<p>Regular paging has 2 levels and a fixed page size of 4KB. The linear +address is split in three fields:</p> +<ul class="simple"> +<li>Directory (the 10 most significant bits)</li> +<li>Table (the next 10 most bits)</li> +<li>Offset (the least significant 12 bits)</li> +</ul> +<p class="admonition-regular-paging"> </p> +<img alt="../_images/ditaa-def299abebe530d760a6c8f16c791bbb016f9238.png" src="../_images/ditaa-def299abebe530d760a6c8f16c791bbb016f9238.png" /> +<p>When extended paging is enabled, a single level is used and pages are +4MB. The linear address is split in two fields:</p> +<ul class="simple"> +<li>Directory (10 most significant bits)</li> +<li>Offset (least significant 22 bits)</li> +</ul> +<img alt="../_images/ditaa-709c2e7a68bfcdcfe9c1938d6ef2a0c9b5627931.png" class="admonition-extended-paging" src="../_images/ditaa-709c2e7a68bfcdcfe9c1938d6ef2a0c9b5627931.png" /> +</div> +<div class="section" id="page-tables"> +<h3>Page tables<a class="headerlink" href="#page-tables" title="Permalink to this headline">¶</a></h3> +<p>We can mix regular and extended paging, the directory page has a bit +that specifies if extended or regular paging should be used. The +special CR3 register points to the base of the page directory and page +directory entries point to the base of the page table.</p> +<p>Both page directory and page table have 1024 entries and each entry +has 4 bytes.</p> +<p>All tables are stored in memory and the page table addresses are +physical addresses.</p> +<span class="admonition-page-tables"></span><p>Page table entry fields:</p> +<ul class="admonition-page-table-entry-fields simple"> +<li>Present/Absent</li> +<li>PFN (Page Frame Number): the most 20 significant bits of the physical address</li> +<li>Accessed - not updated by hardware (can be used by OS for housekeeping)</li> +<li>Dirty - not updated by hardware (can be used by OS for housekeeping)</li> +<li>Access rights: Read/Write</li> +<li>Privilege: User/Supervisor</li> +<li>Page size - only for page directory; if set extended paging is used</li> +<li>PCD (page cache disable), PWT (page write through)</li> +</ul> +</div> +<div class="section" id="linux-paging"> +<h3>Linux paging<a class="headerlink" href="#linux-paging" title="Permalink to this headline">¶</a></h3> +<p>Linux paging uses 4 levels in order to support 64bit +architectures. The diagram below shows how the various virtual address +chunks are used to index the page tables and compute the physical +address.</p> +<img alt="../_images/ditaa-5e4d73e3fcb24db9d1f8c16daddf98694c063fe6.png" class="admonition-linux-paging" src="../_images/ditaa-5e4d73e3fcb24db9d1f8c16daddf98694c063fe6.png" /> +<p>Linux has a common API for creating and walking page tables. Creating +and modifying address spaces for kernel and processes is done using +the same generic code which relies on macros and functions to +translate these generic operations in code that runs on different +architectures.</p> +<p>Here is an example of how we can translate a virtual address to a +physical address, using the Linux page table APIs:</p> +<div class="admonition-linux-apis-for-page-table-handling highlight-c"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="o">*</span> <span class="n">page</span><span class="p">;</span> +<span class="n">pgd_t</span> <span class="n">pgd</span><span class="p">;</span> +<span class="n">pmd_t</span> <span class="n">pmd</span><span class="p">;</span> +<span class="n">pud_t</span> <span class="n">pud</span><span class="p">;</span> +<span class="n">pte_t</span> <span class="n">pte</span><span class="p">;</span> +<span class="kt">void</span> <span class="o">*</span><span class="n">laddr</span><span class="p">,</span> <span class="o">*</span><span class="n">paddr</span><span class="p">;</span> + +<span class="n">pgd</span> <span class="o">=</span> <span class="n">pgd_offset</span><span class="p">(</span><span class="n">mm</span><span class="p">,</span> <span class="n">vaddr</span><span class="p">);</span> +<span class="n">pud</span> <span class="o">=</span> <span class="n">pud_offet</span><span class="p">(</span><span class="n">pgd</span><span class="p">,</span> <span class="n">vaddr</span><span class="p">);</span> +<span class="n">pmd</span> <span class="o">=</span> <span class="n">pmd_offset</span><span class="p">(</span><span class="n">pud</span><span class="p">,</span> <span class="n">vaddr</span><span class="p">);</span> +<span class="n">pte</span> <span class="o">=</span> <span class="n">pte_offset</span><span class="p">(</span><span class="n">pmd</span><span class="p">,</span> <span class="n">vaddr</span><span class="p">);</span> +<span class="n">page</span> <span class="o">=</span> <span class="n">pte_page</span><span class="p">(</span><span class="n">pte</span><span class="p">);</span> +<span class="n">laddr</span> <span class="o">=</span> <span class="n">page_address</span><span class="p">(</span><span class="n">page</span><span class="p">);</span> +<span class="n">paddr</span> <span class="o">=</span> <span class="n">virt_to_phys</span><span class="p">(</span><span class="n">laddr</span><span class="p">);</span> +</pre></div> +</div> +<p>In order to support architectures with less than 4 levels of +pagination (such as for x86 32bits) some macros and / or functions are +0 / empty:</p> +<div class="admonition-what-about-platforms-with-less-then-4-levels-of-pagination highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kr">inline</span> <span class="n">pud_t</span> <span class="o">*</span> <span class="nf">pud_offset</span><span class="p">(</span><span class="n">pgd_t</span> <span class="o">*</span> <span class="n">pgd</span><span class="p">,</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">address</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="p">(</span><span class="n">pud_t</span> <span class="o">*</span><span class="p">)</span><span class="n">pgd</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kr">inline</span> <span class="n">pmd_t</span> <span class="o">*</span> <span class="nf">pmd_offset</span><span class="p">(</span><span class="n">pud_t</span> <span class="o">*</span> <span class="n">pud</span><span class="p">,</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">address</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">return</span> <span class="p">(</span><span class="n">pmd_t</span> <span class="o">*</span><span class="p">)</span><span class="n">pud</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="translation-look-aside-buffer"> +<h3>Translation Look-aside Buffer<a class="headerlink" href="#translation-look-aside-buffer" title="Permalink to this headline">¶</a></h3> +<p>When using virtual memory, due to the table page organization, we may +need an extra 1 (x86 extended paging), 2 (x86 regular paging) or 3 +(x86 64bit) memory access(es).</p> +<p>A special cache, called Translation Look-aside Buffer (TLB) is used to +speed up translations from virtual address to physical addresses.</p> +<p>The TLB has the following properties:</p> +<ul class="admonition-translation-look-aside-buffer simple"> +<li>Caches paging information (PFN, rights, privilege)</li> +<li>Content Addressable Memory / Associative Memory<ul> +<li>Very small (64-128)</li> +<li>Very fast (single cycle due to parallel search implementation)</li> +</ul> +</li> +<li>CPUs usually have two TLBs: i-TLB (code) and d-TLB (data)</li> +<li>TLB miss penalty: up hundreds of cycles</li> +</ul> +<p>As with other caches, we must be careful to not create consistency +issues.</p> +<p>For example, when changing the mapping of one page to point to a +different physical memory location in the page tables, we must +invalidate the associated TLB entry. Otherwise, the MMU will do the +translation to the old physical address instead of the new physical +address.</p> +<p>The x86 platform supports TLB invalidation through two types of +operations.</p> +<p class="admonition-tlb-invalidation">Single address invalidation:</p> +<div class="highlight-asm"><div class="highlight"><pre><span></span>mov $addr, %eax +invlpg %(eax) +</pre></div> +</div> +<p>Full invalidation:</p> +<div class="highlight-asm"><div class="highlight"><pre><span></span><span class="nf">mov</span> <span class="nv">%cr3</span><span class="p">,</span> <span class="nv">%eax</span> +<span class="nf">mov</span> <span class="nv">%eax</span><span class="p">,</span> <span class="nv">%cr3</span> +</pre></div> +</div> +</div> +</div> +<div class="section" id="linux-address-space"> +<h2>Linux address space<a class="headerlink" href="#linux-address-space" title="Permalink to this headline">¶</a></h2> +<div class="section" id="address-space-options-for-32bit-systems"> +<h3>Address space options for 32bit systems<a class="headerlink" href="#address-space-options-for-32bit-systems" title="Permalink to this headline">¶</a></h3> +<p>There are two main options for implementing kernel and user space: +either dedicated address spaces for each, or split a shared address +space.</p> +<p class="admonition-address-space-options-for-32bit-systems"> </p> +<img alt="../_images/ditaa-d5d1129b0298a2ea5f116c9d4b246eb1b888db6b.png" src="../_images/ditaa-d5d1129b0298a2ea5f116c9d4b246eb1b888db6b.png" /> +<p>Each has advantages and disadvantages:</p> +<ul class="admonition-advantages-and-disadvantages simple"> +<li>Disadvantages for dedicated kernel space:<ul> +<li>Fully invalidating the TLB for every system call</li> +</ul> +</li> +<li>Disadvantages for shared address space<ul> +<li>Less address space for both kernel and user processes</li> +</ul> +</li> +</ul> +<p>Linux is using a split address space for 32 bit systems, although in +the past there were options for supporting 4/4s split or dedicated +kernel address space (on those architecture that supports it, +e.g. x86). Linux always uses split address space for 64 bit systems.</p> +<p>On overview of the Linux address space is presented below:</p> +<p class="admonition-linux-address-space-for-32bit-systems"> </p> +<img alt="../_images/ditaa-3985c420def8f30934a72ea8c738a00ed629c298.png" src="../_images/ditaa-3985c420def8f30934a72ea8c738a00ed629c298.png" /> +</div> +<div class="section" id="linear-mappings"> +<h3>Linear mappings<a class="headerlink" href="#linear-mappings" title="Permalink to this headline">¶</a></h3> +<p>Linear mappings refer to particular way of mapping virtual pages to +physical pages, where virtual page V, V + 1, ... V + n is mapped to +physical pages P, P + 1, ..., P + n.</p> +<p>To understand the necessity of linear mappings, we should look at +common kernel operations that involves using both the virtual and +physical address of a page such as an I/O transfer:</p> +<ul class="admonition-virtual-to-physical-address-translations-for-i-o-transfers simple"> +<li>Use the virtual address of a kernel buffer in order to copy to +data from from user space</li> +<li>Walk the page tables to transform the kernel buffer virtual +address to a physical address</li> +<li>Use the physical address of the kernel buffer to start a DMA +transfer</li> +</ul> +<p>However, if we use linear mappings and the kernel buffers are in the +linear mapping area, then:</p> +<ul class="admonition-linear-mappings simple"> +<li>Virtual to physical address space translation is reduced to one +operation (instead of walking the page tables)</li> +<li>Less memory is used to create the page tables</li> +<li>Less TLB entries are used for the kernel memory</li> +</ul> +</div> +<div class="section" id="highmem"> +<h3>Highmem<a class="headerlink" href="#highmem" title="Permalink to this headline">¶</a></h3> +<p>The "highmem" part of the virtual address space is used to create +arbitrary mappings (as opposed to linear mappings in lowmem). On 32bit +systems the highmem area is absolutely required in order to access +physical memory outside of lowmem. However, highmem is also used on +64bit systems but the use-case there is mainly to allow arbitrary +mappings in kernel space.</p> +<p class="admonition-highmem"> </p> +<img alt="../_images/ditaa-bb8455a43088bf800eece11869f6ff857574605d.png" src="../_images/ditaa-bb8455a43088bf800eece11869f6ff857574605d.png" /> +<p>There are multiple types of mappings in the highmem area:</p> +<ul class="simple"> +<li>Multi-page permanent mappings (vmalloc, ioremap)</li> +<li>Temporary 1 page mappings (atomic_kmap)</li> +<li>Permanent 1 page mappings (kmap, fix-mapped linear addresses)</li> +</ul> +<p>Multiple page mappings allows mapping of ranges of physical memory +into the highmem area. Each such mapping is guarded by a +non-accessible page to catch buffer overflow and underflow errors.</p> +<p>The APIs that maps multiple pages into highmem are:</p> +<div class="admonition-multi-page-permanent-mappings highlight-c"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="o">*</span> <span class="nf">vmalloc</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">size</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">vfree</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span> <span class="n">addr</span><span class="p">);</span> + +<span class="kt">void</span> <span class="o">*</span><span class="nf">ioremap</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">offset</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">size</span><span class="p">);</span> +<span class="kt">void</span> <span class="nf">iounmap</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span> <span class="n">addr</span><span class="p">);</span> +</pre></div> +</div> +<p><code class="xref c c-func docutils literal"><span class="pre">vmalloc()</span></code> is used to allocate non-contiguous system memory +pages as a contiguous segment in the kernel virtual address space. It +is usefully when allocating large buffers because due to fragmentation +it is unlikely to find free large chunks of physical contiguous memory.</p> +<p><code class="xref c c-func docutils literal"><span class="pre">ioremap()</span></code> is used to map device memory or device registers +into the kernel address space. It maps a contiguous physical memory +range into highmem with page caching disabled.</p> +</div> +<div class="section" id="fixed-mapped-linear-addresses"> +<h3>Fixed-mapped linear addresses<a class="headerlink" href="#fixed-mapped-linear-addresses" title="Permalink to this headline">¶</a></h3> +<p>Fixed-mapped linear addresses are a special class of singular page +mappings that are used for accessing registers of commonly used +peripherals such as the APIC or IO APIC.</p> +<p>Typical I/O access for peripherals is to use a base (the kernel +virtual address space where the peripheral registers are mapped) + +offsets for various registers.</p> +<p>In order to optimize access, the base is reserved at compile time +(e.g. 0xFFFFF000). Since the base is constant, the various register +accesses of the form <cite>base + register offset</cite> will also be constant +and thus the compiler will avoid generating an extra instruction.</p> +<p>In summary, fixed-mapped linear addresses are:</p> +<ul class="admonition-fixed-mapped-linear-addresses simple"> +<li>Reserved virtual addresses (constants)</li> +<li>Mapped to physical addresses during boot</li> +</ul> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">set_fixmap</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="n">phys_addr</span><span class="p">)</span> +<span class="n">set_fixmap_nocache</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="n">phys_addr</span><span class="p">)</span> +</pre></div> +</div> +<p>These addresses are architecture defined and, as an example, this is +the map for x86:</p> +<div class="admonition-fixed-mapped-linear-addresses highlight-c"><div class="highlight"><pre><span></span><span class="cm">/*</span> +<span class="cm"> * Here we define all the compile-time 'special' virtual</span> +<span class="cm"> * addresses. The point is to have a constant address at</span> +<span class="cm"> * compile time, but to set the physical address only</span> +<span class="cm"> * in the boot process.</span> +<span class="cm"> * for x86_32: We allocate these special addresses</span> +<span class="cm"> * from the end of virtual memory (0xfffff000) backwards.</span> +<span class="cm"> * Also this lets us do fail-safe vmalloc(), we</span> +<span class="cm"> * can guarantee that these special addresses and</span> +<span class="cm"> * vmalloc()-ed addresses never overlap.</span> +<span class="cm"> *</span> +<span class="cm"> * These 'compile-time allocated' memory buffers are</span> +<span class="cm"> * fixed-size 4k pages (or larger if used with an increment</span> +<span class="cm"> * higher than 1). Use set_fixmap(idx,phys) to associate</span> +<span class="cm"> * physical memory with fixmap indices.</span> +<span class="cm"> *</span> +<span class="cm"> * TLB entries of such buffers will not be flushed across</span> +<span class="cm"> * task switches.</span> +<span class="cm"> */</span> + +<span class="k">enum</span> <span class="n">fixed_addresses</span> <span class="p">{</span> +<span class="cp">#ifdef CONFIG_X86_32</span> + <span class="n">FIX_HOLE</span><span class="p">,</span> +<span class="cp">#else</span> +<span class="cp">#ifdef CONFIG_X86_VSYSCALL_EMULATION</span> + <span class="n">VSYSCALL_PAGE</span> <span class="o">=</span> <span class="p">(</span><span class="n">FIXADDR_TOP</span> <span class="o">-</span> <span class="n">VSYSCALL_ADDR</span><span class="p">)</span> <span class="o">>></span> <span class="n">PAGE_SHIFT</span><span class="p">,</span> +<span class="cp">#endif</span> +<span class="cp">#endif</span> + <span class="n">FIX_DBGP_BASE</span><span class="p">,</span> + <span class="n">FIX_EARLYCON_MEM_BASE</span><span class="p">,</span> +<span class="cp">#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT</span> + <span class="n">FIX_OHCI1394_BASE</span><span class="p">,</span> +<span class="cp">#endif</span> +<span class="cp">#ifdef CONFIG_X86_LOCAL_APIC</span> + <span class="n">FIX_APIC_BASE</span><span class="p">,</span> <span class="cm">/* local (CPU) APIC) -- required for SMP or not */</span> +<span class="cp">#endif</span> +<span class="cp">#ifdef CONFIG_X86_IO_APIC</span> + <span class="n">FIX_IO_APIC_BASE_0</span><span class="p">,</span> + <span class="n">FIX_IO_APIC_BASE_END</span> <span class="o">=</span> <span class="n">FIX_IO_APIC_BASE_0</span> <span class="o">+</span> <span class="n">MAX_IO_APICS</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> +<span class="cp">#endif</span> +<span class="cp">#ifdef CONFIG_X86_32</span> + <span class="n">FIX_KMAP_BEGIN</span><span class="p">,</span> <span class="cm">/* reserved pte's for temporary kernel mappings */</span> + <span class="n">FIX_KMAP_END</span> <span class="o">=</span> <span class="n">FIX_KMAP_BEGIN</span><span class="o">+</span><span class="p">(</span><span class="n">KM_TYPE_NR</span><span class="o">*</span><span class="n">NR_CPUS</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> +<span class="cp">#ifdef CONFIG_PCI_MMCONFIG</span> + <span class="n">FIX_PCIE_MCFG</span><span class="p">,</span> +<span class="cp">#endif</span> +</pre></div> +</div> +<p>Notice how easy is to do the conversion between the virtual address +and the fixed address indexes:</p> +<div class="admonition-conversion-between-virtual-address-fixed-address-indexes highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))</span> +<span class="cp">#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)</span> + +<span class="cp">#ifndef __ASSEMBLY__</span> +<span class="cm">/*</span> +<span class="cm"> * 'index to address' translation. If anyone tries to use the idx</span> +<span class="cm"> * directly without translation, we catch the bug with a NULL-deference</span> +<span class="cm"> * kernel oops. Illegal ranges of incoming indices are caught too.</span> +<span class="cm"> */</span> + <span class="k">static</span> <span class="n">__always_inline</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="nf">fix_to_virt</span><span class="p">(</span><span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">idx</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">BUILD_BUG_ON</span><span class="p">(</span><span class="n">idx</span> <span class="o">>=</span> <span class="n">__end_of_fixed_addresses</span><span class="p">);</span> + <span class="k">return</span> <span class="n">__fix_to_virt</span><span class="p">(</span><span class="n">idx</span><span class="p">);</span> + <span class="p">}</span> + + <span class="k">static</span> <span class="kr">inline</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="nf">virt_to_fix</span><span class="p">(</span><span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">vaddr</span><span class="p">)</span> + <span class="p">{</span> + <span class="n">BUG_ON</span><span class="p">(</span><span class="n">vaddr</span> <span class="o">>=</span> <span class="n">FIXADDR_TOP</span> <span class="o">||</span> <span class="n">vaddr</span> <span class="o"><</span> <span class="n">FIXADDR_START</span><span class="p">);</span> + <span class="k">return</span> <span class="n">__virt_to_fix</span><span class="p">(</span><span class="n">vaddr</span><span class="p">);</span> + <span class="p">}</span> + + + <span class="kr">inline</span> <span class="kt">long</span> <span class="nf">fix_to_virt</span><span class="p">(</span><span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">idx</span><span class="p">)</span> + <span class="p">{</span> + <span class="k">if</span> <span class="p">(</span><span class="n">idx</span> <span class="o">>=</span> <span class="n">__end_of_fixed_addresses</span><span class="p">)</span> + <span class="n">__this_fixmap_does_not_exist</span><span class="p">();</span> + <span class="k">return</span> <span class="p">(</span><span class="mh">0xffffe000UL</span> <span class="o">-</span> <span class="p">(</span><span class="n">idx</span> <span class="o"><<</span> <span class="n">PAGE_SHIFT</span><span class="p">));</span> + <span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="temporary-mappings"> +<h3>Temporary mappings<a class="headerlink" href="#temporary-mappings" title="Permalink to this headline">¶</a></h3> +<p>Temporary mappings can be used to map a single physical page, very +fast, in kernel space. It can be used in interrupt context but the +atomic kmap section, defined in between the <code class="xref c c-func docutils literal"><span class="pre">kmap_atomic()</span></code> and +<code class="xref c c-func docutils literal"><span class="pre">kunmap_atomic()</span></code> can not be preempted. That is why these are +called temporary mappings, as they can only be used momentarily.</p> +<span class="admonition-temporary-mappings"></span><p>Temporary mappings are very fast because there is no locking or +searching required and also there is no full TLB invalidation, just +the particular virtual page will be TLB invalidated.</p> +<p>Here are some code snippets that show that temporary mappings are +implemented:</p> +<div class="admonition-temporary-mappings-implementation highlight-c"><div class="highlight"><pre><span></span><span class="cp">#define kmap_atomic(page) kmap_atomic_prot(page, kmap_prot)</span> + +<span class="kt">void</span> <span class="o">*</span><span class="nf">kmap_atomic_high_prot</span><span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">,</span> <span class="n">pgprot_t</span> <span class="n">prot</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">vaddr</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">idx</span><span class="p">,</span> <span class="n">type</span><span class="p">;</span> + + <span class="n">type</span> <span class="o">=</span> <span class="n">kmap_atomic_idx_push</span><span class="p">();</span> + <span class="n">idx</span> <span class="o">=</span> <span class="n">type</span> <span class="o">+</span> <span class="n">KM_TYPE_NR</span><span class="o">*</span><span class="n">smp_processor_id</span><span class="p">();</span> + <span class="n">vaddr</span> <span class="o">=</span> <span class="n">__fix_to_virt</span><span class="p">(</span><span class="n">FIX_KMAP_BEGIN</span> <span class="o">+</span> <span class="n">idx</span><span class="p">);</span> + <span class="n">BUG_ON</span><span class="p">(</span><span class="o">!</span><span class="n">pte_none</span><span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="n">kmap_pte</span><span class="o">-</span><span class="n">idx</span><span class="p">)));</span> + <span class="n">set_pte</span><span class="p">(</span><span class="n">kmap_pte</span><span class="o">-</span><span class="n">idx</span><span class="p">,</span> <span class="n">mk_pte</span><span class="p">(</span><span class="n">page</span><span class="p">,</span> <span class="n">prot</span><span class="p">));</span> + <span class="n">arch_flush_lazy_mmu_mode</span><span class="p">();</span> + + <span class="k">return</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">vaddr</span><span class="p">;</span> +<span class="p">}</span> +<span class="n">EXPORT_SYMBOL</span><span class="p">(</span><span class="n">kmap_atomic_high_prot</span><span class="p">);</span> + +<span class="k">static</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="nf">kmap_atomic_idx_push</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">int</span> <span class="n">idx</span> <span class="o">=</span> <span class="n">__this_cpu_inc_return</span><span class="p">(</span><span class="n">__kmap_atomic_idx</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> + +<span class="cp">#ifdef CONFIG_DEBUG_HIGHMEM</span> + <span class="n">WARN_ON_ONCE</span><span class="p">(</span><span class="n">in_irq</span><span class="p">()</span> <span class="o">&&</span> <span class="o">!</span><span class="n">irqs_disabled</span><span class="p">());</span> + <span class="n">BUG_ON</span><span class="p">(</span><span class="n">idx</span> <span class="o">>=</span> <span class="n">KM_TYPE_NR</span><span class="p">);</span> +<span class="cp">#endif</span> + <span class="k">return</span> <span class="n">idx</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Notice that fix-mapped linear addresses and a stack like approach is +used: each CPU has KM_TYPE_NR reserved entries which are used in a +first code first serve option. This allows using multiple temporary +mappings at once, for example one in process context, one in an +interrupt handler, and a few more in tasklets or softirqs.</p> +<span class="admonition-implementation-of-temporary-mappings"></span></div> +<div class="section" id="permanent-mappings"> +<h3>Permanent mappings<a class="headerlink" href="#permanent-mappings" title="Permalink to this headline">¶</a></h3> +<p>Permanent mappings allows users to hold on to a mapping for long +(undefined) periods of time which means that context switch are +allowed after a mapping and before releasing it.</p> +<p>This flexibility comes with a price though. A search operation is +performed to find a free entry and they can not be used in interrupt +context - the operation that tries to find a free virtual address page +may block. There is a limited number of permanent mappings available +(topically one page is reserved for permanent mappings)</p> +<span class="admonition-permanent-mappings"></span></div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lec5-smp.html" class="btn btn-neutral float-left" title="SO2 Lecture 05 - Symmetric Multi-Processing" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lec7-memory-management.html" class="btn btn-neutral float-right" title="SO2 Lecture 07 - Memory Management" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec7-memory-management-slides.html b/refs/pull/405/merge/so2/lec7-memory-management-slides.html new file mode 100644 index 00000000..b3adc06f --- /dev/null +++ b/refs/pull/405/merge/so2/lec7-memory-management-slides.html @@ -0,0 +1,560 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>SO2 Lecture 07 - Memory Management — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="up" title="Operating Systems 2" href="index.html" /> + <link rel="next" title="SO2 Lecture 08 - Filesystem Management" href="lec8-filesystems.html" /> + <link rel="prev" title="SO2 Lecture 06 - Address Space" href="lec6-address-space.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-so2-lecture-07-memory-management slide level-1"> + +<h1>SO2 Lecture 07 - Memory Management</h1> + + + + + +</article> +<article class="admonition-memory-management slide level-2"> + +<h2>Memory Management</h2> + +<ul class="simple"> +<li>Physical Memory Management<ul> +<li>Page allocations</li> +<li>Small allocations</li> +</ul> +</li> +<li>Virtual Memory Management</li> +<li>Page Fault Handling Overview</li> +</ul> + + + + +</article> +<article class="admonition-physical-memory-management slide level-2"> + +<h2>Physical Memory Management</h2> + +<ul class="simple"> +<li>Algorithms and data structure that keep track of physical memory +pages</li> +<li>Independent of virtual memory management</li> +<li>Both virtual and physical memory management is required for complete +memory management</li> +<li>Physical pages are being tracked using a special data structure: +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code></li> +<li>All physical pages have an entry reserved in the <code class="xref c c-data docutils literal"><span class="pre">mem_map</span></code> +vector</li> +<li>The physical page status may include: a counter for how many +times is a page used, position in swap or file, buffers for this +page, position int the page cache, etc.</li> +</ul> + + + + +</article> +<article class="admonition-memory-zones slide level-2"> + +<h2>Memory zones</h2> + +<ul class="simple"> +<li>DMA zone</li> +<li>DMA32 zone</li> +<li>Normal zone (LowMem)</li> +<li>HighMem Zone</li> +<li>Movable Zone</li> +</ul> + + + + +</article> +<article class="admonition-non-uniform-memory-access slide level-2"> + +<h2>Non-Uniform Memory Access</h2> + +<ul class="simple"> +<li>Physical memory is split in between multiple nodes, one for each CPU</li> +<li>There is single physical address space accessible from every node</li> +<li>Access to the local memory is faster</li> +<li>Each node maintains is own memory zones (.e. DMA, NORMAL, HIGHMEM, etc.)</li> +</ul> + + + + +</article> +<article class="admonition-page-allocation slide level-2"> + +<h2>Page allocation</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* Allocates 2^order contiguous pages and returns a pointer to the</span> +<span class="cm"> * descriptor for the first page</span> +<span class="cm"> */</span> +<span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="nf">alloc_pages</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">,</span> <span class="n">order</span><span class="p">);</span> + +<span class="cm">/* allocates a single page */</span> +<span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="nf">alloc_page</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">);</span> + + +<span class="cm">/* helper functions that return the kernel virtual address */</span> +<span class="kt">void</span> <span class="o">*</span><span class="nf">__get_free_pages</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">,</span> <span class="n">order</span><span class="p">);</span> +<span class="kt">void</span> <span class="o">*</span><span class="nf">__get_free_page</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">);</span> +<span class="kt">void</span> <span class="o">*</span><span class="nf">__get_zero_page</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">);</span> +<span class="kt">void</span> <span class="o">*</span><span class="nf">__get_dma_pages</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">,</span> <span class="n">order</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-why-only-allocate-pages-in-chunks-of-power-of-2 slide level-2"> + +<h2>Why only allocate pages in chunks of power of 2?</h2> + +<ul class="simple"> +<li>Typical memory allocation algorithms have linear complexity</li> +<li>Why not use paging?<ul> +<li>Sometime we do need contiguous memory allocations (for DMA)</li> +<li>Allocation would require page table changes and TLB flushes</li> +<li>Not able to use extended pages</li> +<li>Some architecture directly (in hardware) linearly maps a part +of the address space (e.g. MIPS)</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-the-buddy-algorithm slide level-2"> + +<h2>The buddy algorithm</h2> + +<ul class="simple"> +<li>Free blocks are distributed in multiple lists</li> +<li>Each list contains blocks of the same size</li> +<li>The block size is a power of two</li> +</ul> + + + + +</article> +<article class="admonition-allocating-a-block-of-size-n slide level-2"> + +<h2>Allocating a block of size N</h2> + +<ul class="simple"> +<li>If there is a free block in the N-size list, pick the first</li> +<li>If not, look for a free block in the 2N-size list</li> +<li>Split the 2N-size block in two N-size blocks and add them to the +N-size list</li> +<li>Now that we have the N-size list populated, pick the first free +block from that list</li> +</ul> + + + + +</article> +<article class="admonition-freeing-a-block-of-size-n slide level-2"> + +<h2>Freeing a block of size N</h2> + +<ul class="simple"> +<li>If the "buddy" is free coalesce into a 2N-size block</li> +<li>Try until no more free buddy block is found and place the +resulting block in the respective list</li> +</ul> + + + + +</article> +<article class="admonition-the-linux-implementation slide level-2"> + +<h2>The Linux implementation</h2> + +<ul class="simple"> +<li>11 lists for blocks of 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, +1024 pages</li> +<li>Each memory zone has its own buddy allocator</li> +<li>Each zone has a vector of descriptors for free blocks, one entry +for each size</li> +<li>The descriptor contains the number of free blocks and the head of +the list</li> +<li>Blocks are linked in the list using the <cite>lru</cite> field of +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code></li> +<li>Free pages have the PG_buddy flag set</li> +<li>The page descriptor keeps a copy of the block size in the private +field to easily check if the "buddy" is free</li> +</ul> + + + + +</article> +<article class="admonition-small-allocations slide level-2"> + +<h2>Small allocations</h2> + +<ul class="simple"> +<li>Buddy is used to allocate pages</li> +<li>Many of the kernel subsystems need to allocate buffers smaller +than a page</li> +<li>Typical solution: variable size buffer allocation<ul> +<li>Leads to external fragmentation</li> +</ul> +</li> +<li>Alternative solution: fixed size buffer allocation<ul> +<li>Leads to internal fragmentation</li> +</ul> +</li> +<li>Compromise: fixed size block allocation with multiple sizes, geometrically distributed<ul> +<li>e.g.: 32, 64, ..., 131056</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-the-slab-allocator slide level-2"> + +<h2>The SLAB allocator</h2> + +<ul class="simple"> +<li>Buffers = objects</li> +<li>Uses buddy to allocate a pool of pages for object allocations</li> +<li>Each object (optionally) has a constructor and destructor</li> +<li>Deallocated objects are cached - avoids subsequent calls for +constructors and buddy allocation / deallocation</li> +</ul> + + + + +</article> +<article class="admonition-why-slab slide level-2"> + +<h2>Why SLAB?</h2> + +<ul class="simple"> +<li>The kernel will typically allocate and deallocate multiple types +the same data structures over time (e.g. <code class="xref c c-type docutils literal"><span class="pre">struct</span> +<span class="pre">task_struct</span></code>) effectively using fixed size allocations. Using the +SLAB reduces the frequency of the more heavy +allocation/deallocation operations.</li> +<li>For variable size buffers (which occurs less frequently) a +geometric distribution of caches with fixed-size can be used</li> +<li>Reduces the memory allocation foot-print since we are searching a +much smaller memory area, compared to buddy which can span over a +larger area</li> +<li>Employs cache optimization techniques (slab coloring)</li> +</ul> + + + + +</article> +<article class="admonition-slab-architecture slide level-2"> + +<h2>Slab architecture</h2> + +<img alt="../_images/slab-overview1.png" src="../_images/slab-overview1.png" /> + + + + +</article> +<article class="admonition-cache-descriptors slide level-2"> + +<h2>Cache descriptors</h2> + +<ul class="simple"> +<li>A name to identify the cache for stats</li> +<li>object constructor and destructor functions</li> +<li>size of the objects</li> +<li>Flags</li> +<li>Size of the slab in power of 2 pages</li> +<li>GFP masks</li> +<li>One or mores slabs, grouped by state: full, partially full, empty</li> +</ul> + + + + +</article> +<article class="admonition-slab-descriptors slide level-2"> + +<h2>SLAB descriptors</h2> + +<ul class="simple"> +<li>Number of objects</li> +<li>Memory region where the objects are stored</li> +<li>Pointer to the first free object</li> +<li>Descriptor are stored either in<ul> +<li>the SLAB itself (if the object size is lower the 512 or if +internal fragmentation leaves enough space for the SLAB +descriptor)</li> +<li>in generic caches internally used by the SLAB allocator</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-slab-detailed-architecture slide level-2"> + +<h2>Slab detailed architecture</h2> + +<img alt="../_images/slab-detailed-arch1.png" src="../_images/slab-detailed-arch1.png" /> + + + + +</article> +<article class="admonition-generic-vs-specific-caches slide level-2"> + +<h2>Generic vs specific caches</h2> + +<ul class="simple"> +<li>Generic caches are used internally by the slab allocator<ul> +<li>allocating memory for cache and slab descriptors</li> +</ul> +</li> +<li>They are also used to implement <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> by implementing +20 caches with object sizes geometrically distributed between +32bytes and 4MB</li> +<li>Specific cache are created on demand by kernel subsystems</li> +</ul> + + + + +</article> +<article class="admonition-object-descriptors slide level-2"> + +<h2>Object descriptors</h2> + +<img alt="../_images/slab-object-descriptors1.png" src="../_images/slab-object-descriptors1.png" /> + + + + +</article> +<article class="admonition-object-descriptors slide level-2"> + +<h2>Object descriptors</h2> + +<ul class="simple"> +<li>Only used for free objects</li> +<li>An integer that points to the next free object</li> +<li>The last free object uses a terminator value</li> +<li>Internal descriptors - stored in the slab</li> +<li>External descriptors - stored in generic caches</li> +</ul> + + + + +</article> +<article class="admonition-slab-coloring slide level-2"> + +<h2>SLAB coloring</h2> + +<img alt="../_images/slab-coloring1.png" src="../_images/slab-coloring1.png" /> + + + + +</article> +<article class="admonition-virtual-memory-management slide level-2"> + +<h2>Virtual memory management</h2> + +<ul class="simple"> +<li>Used in both kernel and user space</li> +<li>Using virtual memory requires:<ul> +<li>reserving (allocating) a segment in the <em>virtual</em> address space +(be it kernel or user)</li> +<li>allocating one or more physical pages for the buffer</li> +<li>allocating one or more physical pages for page tables and +internal structures</li> +<li>mapping the virtual memory segment to the physical allocated +pages</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-address-space-descriptors slide level-2"> + +<h2>Address space descriptors</h2> + +<p> </p> +<img alt="../_images/ditaa-0eda95a3f39dfac448fd07589656b123d3548328.png" src="../_images/ditaa-0eda95a3f39dfac448fd07589656b123d3548328.png" /> + + + + +</article> +<article class="admonition-address-space-descriptors slide level-2"> + +<h2>Address space descriptors</h2> + +<ul class="simple"> +<li>Page table is used either by:<ul> +<li>The CPU's MMU</li> +<li>The kernel to handle TLB exception (some RISC processors)</li> +</ul> +</li> +<li>The address space descriptor is used by the kernel to maintain +high level information such as file and file offset (for mmap +with files), read-only segment, copy-on-write segment, etc.</li> +</ul> + + + + +</article> +<article class="admonition-allocating-virtual-memory slide level-2"> + +<h2>Allocating virtual memory</h2> + +<ul class="simple"> +<li>Search a free area in the address space descriptor</li> +<li>Allocate memory for a new area descriptor</li> +<li>Insert the new area descriptor in the address space descriptor</li> +<li>Allocate physical memory for one or more page tables</li> +<li>Setup the page tables for the newly allocated area in the virtual +address space</li> +<li>Allocating (on demand) physical pages and map them in the virtual +address space by updating the page tables</li> +</ul> + + + + +</article> +<article class="admonition-freeing-virtual-memory slide level-2"> + +<h2>Freeing virtual memory</h2> + +<ul class="simple"> +<li>Removing the area descriptor</li> +<li>Freeing the area descriptor memory</li> +<li>Updating the page tables to remove the area from the virtual +address space</li> +<li>Flushing the TLB for the freed virtual memory area</li> +<li>Freeing physical memory of the page tables associated with the +freed area</li> +<li>Freeing physical memory of the freed virtual memory area</li> +</ul> + + + + +</article> +<article class="admonition-linux-virtual-memory-management slide level-2"> + +<h2>Linux virtual memory management</h2> + +<ul class="simple"> +<li>Kernel<ul> +<li>vmalloc<ul> +<li>area descriptor: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_struct</span></code></li> +<li>address space descriptor: simple linked list of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_struct</span></code></li> +</ul> +</li> +</ul> +</li> +<li>Userspace<ul> +<li>area descriptor: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code></li> +<li>address space descriptor: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code>, red-black tree</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-linux-virtual-memory-management slide level-2"> + +<h2>Linux virtual memory management</h2> + +<img alt="../_images/page-fault-handling1.png" src="../_images/page-fault-handling1.png" /> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec7-memory-management.html b/refs/pull/405/merge/so2/lec7-memory-management.html new file mode 100644 index 00000000..cf36a285 --- /dev/null +++ b/refs/pull/405/merge/so2/lec7-memory-management.html @@ -0,0 +1,468 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lecture 07 - Memory Management — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lecture 08 - Filesystem Management" href="lec8-filesystems.html" /> + <link rel="prev" title="SO2 Lecture 06 - Address Space" href="lec6-address-space.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lecture 07 - Memory Management</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="#physical-memory-management">Physical Memory Management</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#memory-zones">Memory zones</a></li> +<li class="toctree-l4"><a class="reference internal" href="#non-uniform-memory-access">Non-Uniform Memory Access</a></li> +<li class="toctree-l4"><a class="reference internal" href="#page-allocation">Page allocation</a></li> +<li class="toctree-l4"><a class="reference internal" href="#small-allocations">Small allocations</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#virtual-memory-management">Virtual memory management</a></li> +<li class="toctree-l3"><a class="reference internal" href="#fault-page-handling">Fault page handling</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lecture 07 - Memory Management</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lec7-memory-management.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lecture-07-memory-management"> +<h1>SO2 Lecture 07 - Memory Management<a class="headerlink" href="#so2-lecture-07-memory-management" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="lec7-memory-management-slides.html">View slides</a></p> +<span class="admonition-so2-lecture-07-memory-management"></span><div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-memory-management simple"> +<li>Physical Memory Management<ul> +<li>Page allocations</li> +<li>Small allocations</li> +</ul> +</li> +<li>Virtual Memory Management</li> +<li>Page Fault Handling Overview</li> +</ul> +</div> +<div class="section" id="physical-memory-management"> +<h2>Physical Memory Management<a class="headerlink" href="#physical-memory-management" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-physical-memory-management simple"> +<li>Algorithms and data structure that keep track of physical memory +pages</li> +<li>Independent of virtual memory management</li> +<li>Both virtual and physical memory management is required for complete +memory management</li> +<li>Physical pages are being tracked using a special data structure: +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code></li> +<li>All physical pages have an entry reserved in the <code class="xref c c-data docutils literal"><span class="pre">mem_map</span></code> +vector</li> +<li>The physical page status may include: a counter for how many +times is a page used, position in swap or file, buffers for this +page, position int the page cache, etc.</li> +</ul> +<div class="section" id="memory-zones"> +<h3>Memory zones<a class="headerlink" href="#memory-zones" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-memory-zones simple"> +<li>DMA zone</li> +<li>DMA32 zone</li> +<li>Normal zone (LowMem)</li> +<li>HighMem Zone</li> +<li>Movable Zone</li> +</ul> +</div> +<div class="section" id="non-uniform-memory-access"> +<h3>Non-Uniform Memory Access<a class="headerlink" href="#non-uniform-memory-access" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-non-uniform-memory-access simple"> +<li>Physical memory is split in between multiple nodes, one for each CPU</li> +<li>There is single physical address space accessible from every node</li> +<li>Access to the local memory is faster</li> +<li>Each node maintains is own memory zones (.e. DMA, NORMAL, HIGHMEM, etc.)</li> +</ul> +</div> +<div class="section" id="page-allocation"> +<h3>Page allocation<a class="headerlink" href="#page-allocation" title="Permalink to this headline">¶</a></h3> +<div class="admonition-page-allocation highlight-c"><div class="highlight"><pre><span></span><span class="cm">/* Allocates 2^order contiguous pages and returns a pointer to the</span> +<span class="cm"> * descriptor for the first page</span> +<span class="cm"> */</span> +<span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="nf">alloc_pages</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">,</span> <span class="n">order</span><span class="p">);</span> + +<span class="cm">/* allocates a single page */</span> +<span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="nf">alloc_page</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">);</span> + + +<span class="cm">/* helper functions that return the kernel virtual address */</span> +<span class="kt">void</span> <span class="o">*</span><span class="nf">__get_free_pages</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">,</span> <span class="n">order</span><span class="p">);</span> +<span class="kt">void</span> <span class="o">*</span><span class="nf">__get_free_page</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">);</span> +<span class="kt">void</span> <span class="o">*</span><span class="nf">__get_zero_page</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">);</span> +<span class="kt">void</span> <span class="o">*</span><span class="nf">__get_dma_pages</span><span class="p">(</span><span class="n">gfp_mask</span><span class="p">,</span> <span class="n">order</span><span class="p">);</span> +</pre></div> +</div> +<ul class="admonition-why-only-allocate-pages-in-chunks-of-power-of-2 simple"> +<li>Typical memory allocation algorithms have linear complexity</li> +<li>Why not use paging?<ul> +<li>Sometime we do need contiguous memory allocations (for DMA)</li> +<li>Allocation would require page table changes and TLB flushes</li> +<li>Not able to use extended pages</li> +<li>Some architecture directly (in hardware) linearly maps a part +of the address space (e.g. MIPS)</li> +</ul> +</li> +</ul> +<ul class="admonition-the-buddy-algorithm simple"> +<li>Free blocks are distributed in multiple lists</li> +<li>Each list contains blocks of the same size</li> +<li>The block size is a power of two</li> +</ul> +<ul class="admonition-allocating-a-block-of-size-n simple"> +<li>If there is a free block in the N-size list, pick the first</li> +<li>If not, look for a free block in the 2N-size list</li> +<li>Split the 2N-size block in two N-size blocks and add them to the +N-size list</li> +<li>Now that we have the N-size list populated, pick the first free +block from that list</li> +</ul> +<ul class="admonition-freeing-a-block-of-size-n simple"> +<li>If the "buddy" is free coalesce into a 2N-size block</li> +<li>Try until no more free buddy block is found and place the +resulting block in the respective list</li> +</ul> +<ul class="admonition-the-linux-implementation simple"> +<li>11 lists for blocks of 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, +1024 pages</li> +<li>Each memory zone has its own buddy allocator</li> +<li>Each zone has a vector of descriptors for free blocks, one entry +for each size</li> +<li>The descriptor contains the number of free blocks and the head of +the list</li> +<li>Blocks are linked in the list using the <cite>lru</cite> field of +<code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">page</span></code></li> +<li>Free pages have the PG_buddy flag set</li> +<li>The page descriptor keeps a copy of the block size in the private +field to easily check if the "buddy" is free</li> +</ul> +</div> +<div class="section" id="small-allocations"> +<h3>Small allocations<a class="headerlink" href="#small-allocations" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-small-allocations simple"> +<li>Buddy is used to allocate pages</li> +<li>Many of the kernel subsystems need to allocate buffers smaller +than a page</li> +<li>Typical solution: variable size buffer allocation<ul> +<li>Leads to external fragmentation</li> +</ul> +</li> +<li>Alternative solution: fixed size buffer allocation<ul> +<li>Leads to internal fragmentation</li> +</ul> +</li> +<li>Compromise: fixed size block allocation with multiple sizes, geometrically distributed<ul> +<li>e.g.: 32, 64, ..., 131056</li> +</ul> +</li> +</ul> +<ul class="admonition-the-slab-allocator simple"> +<li>Buffers = objects</li> +<li>Uses buddy to allocate a pool of pages for object allocations</li> +<li>Each object (optionally) has a constructor and destructor</li> +<li>Deallocated objects are cached - avoids subsequent calls for +constructors and buddy allocation / deallocation</li> +</ul> +<ul class="admonition-why-slab simple"> +<li>The kernel will typically allocate and deallocate multiple types +the same data structures over time (e.g. <code class="xref c c-type docutils literal"><span class="pre">struct</span> +<span class="pre">task_struct</span></code>) effectively using fixed size allocations. Using the +SLAB reduces the frequency of the more heavy +allocation/deallocation operations.</li> +<li>For variable size buffers (which occurs less frequently) a +geometric distribution of caches with fixed-size can be used</li> +<li>Reduces the memory allocation foot-print since we are searching a +much smaller memory area, compared to buddy which can span over a +larger area</li> +<li>Employs cache optimization techniques (slab coloring)</li> +</ul> +<img alt="../_images/slab-overview1.png" class="admonition-slab-architecture" src="../_images/slab-overview1.png" /> +<ul class="admonition-cache-descriptors simple"> +<li>A name to identify the cache for stats</li> +<li>object constructor and destructor functions</li> +<li>size of the objects</li> +<li>Flags</li> +<li>Size of the slab in power of 2 pages</li> +<li>GFP masks</li> +<li>One or mores slabs, grouped by state: full, partially full, empty</li> +</ul> +<ul class="admonition-slab-descriptors simple"> +<li>Number of objects</li> +<li>Memory region where the objects are stored</li> +<li>Pointer to the first free object</li> +<li>Descriptor are stored either in<ul> +<li>the SLAB itself (if the object size is lower the 512 or if +internal fragmentation leaves enough space for the SLAB +descriptor)</li> +<li>in generic caches internally used by the SLAB allocator</li> +</ul> +</li> +</ul> +<img alt="../_images/slab-detailed-arch1.png" class="admonition-slab-detailed-architecture" src="../_images/slab-detailed-arch1.png" /> +<ul class="admonition-generic-vs-specific-caches simple"> +<li>Generic caches are used internally by the slab allocator<ul> +<li>allocating memory for cache and slab descriptors</li> +</ul> +</li> +<li>They are also used to implement <code class="xref c c-func docutils literal"><span class="pre">kmalloc()</span></code> by implementing +20 caches with object sizes geometrically distributed between +32bytes and 4MB</li> +<li>Specific cache are created on demand by kernel subsystems</li> +</ul> +<img alt="../_images/slab-object-descriptors1.png" class="admonition-object-descriptors" src="../_images/slab-object-descriptors1.png" /> +<ul class="admonition-object-descriptors simple"> +<li>Only used for free objects</li> +<li>An integer that points to the next free object</li> +<li>The last free object uses a terminator value</li> +<li>Internal descriptors - stored in the slab</li> +<li>External descriptors - stored in generic caches</li> +</ul> +<img alt="../_images/slab-coloring1.png" class="admonition-slab-coloring" src="../_images/slab-coloring1.png" /> +</div> +</div> +<div class="section" id="virtual-memory-management"> +<h2>Virtual memory management<a class="headerlink" href="#virtual-memory-management" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-virtual-memory-management simple"> +<li>Used in both kernel and user space</li> +<li>Using virtual memory requires:<ul> +<li>reserving (allocating) a segment in the <em>virtual</em> address space +(be it kernel or user)</li> +<li>allocating one or more physical pages for the buffer</li> +<li>allocating one or more physical pages for page tables and +internal structures</li> +<li>mapping the virtual memory segment to the physical allocated +pages</li> +</ul> +</li> +</ul> +<p class="admonition-address-space-descriptors"> </p> +<img alt="../_images/ditaa-0eda95a3f39dfac448fd07589656b123d3548328.png" src="../_images/ditaa-0eda95a3f39dfac448fd07589656b123d3548328.png" /> +<ul class="admonition-address-space-descriptors simple"> +<li>Page table is used either by:<ul> +<li>The CPU's MMU</li> +<li>The kernel to handle TLB exception (some RISC processors)</li> +</ul> +</li> +<li>The address space descriptor is used by the kernel to maintain +high level information such as file and file offset (for mmap +with files), read-only segment, copy-on-write segment, etc.</li> +</ul> +<ul class="admonition-allocating-virtual-memory simple"> +<li>Search a free area in the address space descriptor</li> +<li>Allocate memory for a new area descriptor</li> +<li>Insert the new area descriptor in the address space descriptor</li> +<li>Allocate physical memory for one or more page tables</li> +<li>Setup the page tables for the newly allocated area in the virtual +address space</li> +<li>Allocating (on demand) physical pages and map them in the virtual +address space by updating the page tables</li> +</ul> +<ul class="admonition-freeing-virtual-memory simple"> +<li>Removing the area descriptor</li> +<li>Freeing the area descriptor memory</li> +<li>Updating the page tables to remove the area from the virtual +address space</li> +<li>Flushing the TLB for the freed virtual memory area</li> +<li>Freeing physical memory of the page tables associated with the +freed area</li> +<li>Freeing physical memory of the freed virtual memory area</li> +</ul> +<ul class="admonition-linux-virtual-memory-management simple"> +<li>Kernel<ul> +<li>vmalloc<ul> +<li>area descriptor: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_struct</span></code></li> +<li>address space descriptor: simple linked list of <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_struct</span></code></li> +</ul> +</li> +</ul> +</li> +<li>Userspace<ul> +<li>area descriptor: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">vm_area_struct</span></code></li> +<li>address space descriptor: <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">mm_struct</span></code>, red-black tree</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="fault-page-handling"> +<h2>Fault page handling<a class="headerlink" href="#fault-page-handling" title="Permalink to this headline">¶</a></h2> +<img alt="../_images/page-fault-handling1.png" class="admonition-linux-virtual-memory-management" src="../_images/page-fault-handling1.png" /> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lec6-address-space.html" class="btn btn-neutral float-left" title="SO2 Lecture 06 - Address Space" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lec8-filesystems.html" class="btn btn-neutral float-right" title="SO2 Lecture 08 - Filesystem Management" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec8-filesystems-slides.html b/refs/pull/405/merge/so2/lec8-filesystems-slides.html new file mode 100644 index 00000000..f757454b --- /dev/null +++ b/refs/pull/405/merge/so2/lec8-filesystems-slides.html @@ -0,0 +1,582 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>SO2 Lecture 08 - Filesystem Management — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="up" title="Operating Systems 2" href="index.html" /> + <link rel="next" title="SO2 Lecture 09 - Kernel debugging" href="lec9-debugging.html" /> + <link rel="prev" title="SO2 Lecture 07 - Memory Management" href="lec7-memory-management.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-so2-lecture-08-filesystem-management slide level-1"> + +<h1>SO2 Lecture 08 - Filesystem Management</h1> + + + + + +</article> +<article class="admonition-filesystem-management slide level-2"> + +<h2>Filesystem Management</h2> + +<ul class="simple"> +<li>Filesystem abstractions</li> +<li>Filesystem operations</li> +<li>Linux VFS</li> +<li>Overview of Linux I/O Management</li> +</ul> + + + + +</article> +<article class="admonition-filesystem-abstractions slide level-2"> + +<h2>Filesystem Abstractions</h2> + +<ul class="simple"> +<li>superblock</li> +<li>file</li> +<li>inode</li> +<li>dentry</li> +</ul> + + + + +</article> +<article class="admonition-filesystem-abstractions-in-memory slide level-2"> + +<h2>Filesystem Abstractions - in memory</h2> + +<img alt="../_images/ditaa-29f54aaa1a85b819ff29cb7d101a4d646b3b0b06.png" src="../_images/ditaa-29f54aaa1a85b819ff29cb7d101a4d646b3b0b06.png" /> + + + + +</article> +<article class="admonition-filesystem-abstractions-on-storage slide level-2"> + +<h2>Filesystem Abstractions - on storage</h2> + +<img alt="../_images/ditaa-bc662dab7bb3d9ba3a37efbf69b82c513dcaadd4.png" src="../_images/ditaa-bc662dab7bb3d9ba3a37efbf69b82c513dcaadd4.png" /> + + + + +</article> +<article class="admonition-simple-filesystem-example slide level-2"> + +<h2>Simple filesystem example</h2> + +<p> </p> +<img alt="../_images/ditaa-8b59fc3f5245ffb5d7089dc80cf2e306c39a62d8.png" src="../_images/ditaa-8b59fc3f5245ffb5d7089dc80cf2e306c39a62d8.png" /> + + + + +</article> +<article class="admonition-overview slide level-2"> + +<h2>Overview</h2> + +<img alt="../_images/ditaa-6d39f541805ae8197b413ec9c79116382abc4dbc.png" src="../_images/ditaa-6d39f541805ae8197b413ec9c79116382abc4dbc.png" /> + + + + +</article> +<article class="admonition-filesystem-operations slide level-2"> + +<h2>Filesystem Operations</h2> + +<ul class="simple"> +<li>Mount</li> +<li>Open a file</li> +<li>Querying file attributes</li> +<li>Reading data from a file</li> +<li>Writing file to a file</li> +<li>Creating a file</li> +<li>Deleting a file</li> +</ul> + + + + +</article> +<article class="admonition-mounting-a-filesystem slide level-2"> + +<h2>Mounting a filesystem</h2> + +<ul class="simple"> +<li>Input: a storage device (partition)</li> +<li>Output: dentry pointing to the root directory</li> +<li>Steps: check device, determine filesystem parameters, locate the root inode</li> +<li>Example: check magic, determine block size, read the root inode and create dentry</li> +</ul> + + + + +</article> +<article class="admonition-opening-a-file slide level-2"> + +<h2>Opening a file</h2> + +<ul class="simple"> +<li>Input: path</li> +<li>Output: file descriptor</li> +<li>Steps:<ul> +<li>Determine the filesystem type</li> +<li>For each name in the path: lookup parent dentry, load inode, +load data, find dentry</li> +<li>Create a new <em>file</em> that points to the last <em>dentry</em></li> +<li>Find a free entry in the file descriptor table and set it to <em>file</em></li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-querying-file-attributes slide level-2"> + +<h2>Querying file attributes</h2> + +<ul class="simple"> +<li>Input: path</li> +<li>Output: file attributes</li> +<li>Steps:<ul> +<li>Access <cite>file->dentry->inode</cite></li> +<li>Read file attributes from the <em>inode</em></li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-reading-data-from-a-file slide level-2"> + +<h2>Reading data from a file</h2> + +<ul class="simple"> +<li>Input: file descriptor, offset, length</li> +<li>Output: data</li> +<li>Steps:<ul> +<li>Access <cite>file->dentry->inode</cite></li> +<li>Determine data blocks</li> +<li>Copy data blocks to memory</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-writing-data-to-a-file slide level-2"> + +<h2>Writing data to a file</h2> + +<ul class="simple"> +<li>Input: file descriptor, offset, length, data</li> +<li>Output:</li> +<li>Steps:<ul> +<li>Allocate one or more data blocks</li> +<li>Add the allocated blocks to the inode and update file size</li> +<li>Copy data from userspace to internal buffers and write them to +storage</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-closing-a-file slide level-2"> + +<h2>Closing a file</h2> + +<ul class="simple"> +<li>Input: file descriptor</li> +<li>Output:</li> +<li>Steps:<ul> +<li>set the file descriptor entry to NULL</li> +<li>Decrement file reference counter</li> +<li>When the counter reaches 0 free <em>file</em></li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-directories slide level-2"> + +<h2>Directories</h2> + +<p>Directories are special files which contain one or more dentries.</p> + + + + +</article> +<article class="admonition-creating-a-file slide level-2"> + +<h2>Creating a file</h2> + +<ul class="simple"> +<li>Input: path</li> +<li>Output:</li> +<li>Steps:<ul> +<li>Determine the inode directory</li> +<li>Read data blocks and find space for a new dentry</li> +<li>Write back the modified inode directory data blocks</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-deleting-a-file slide level-2"> + +<h2>Deleting a file</h2> + +<ul class="simple"> +<li>Input: path</li> +<li>Output:</li> +<li>Steps:<ul> +<li>determine the parent inode</li> +<li>read parent inode data blocks</li> +<li>find and erase the dentry (check for links)</li> +<li>when last file is closed: deallocate data and inode blocks</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-virtual-file-system slide level-2"> + +<h2>Virtual File System</h2> + +<a class="reference internal image-reference" href="../_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.png"><img alt="../_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.png" src="../_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.png" style="height: 100%;" /></a> + + + + +</article> +<article class="admonition-superblock-operations slide level-2"> + +<h2>Superblock Operations</h2> + +<table class="hlist"><tr><td><ul class="simple"> +<li>fill_super</li> +<li>put_super</li> +<li>write_super</li> +<li>read_inode</li> +</ul> +</td><td><ul class="simple"> +<li>write_inode</li> +<li>evict_inode</li> +<li>statfs</li> +<li>remount_fs</li> +</ul> +</td></tr></table> + + + + +</article> +<article class="admonition-inode-operations slide level-2"> + +<h2>Inode Operations</h2> + +<table class="hlist"><tr><td><ul class="simple"> +<li>create</li> +<li>lookup</li> +<li>link</li> +<li>unlink</li> +<li>symlink</li> +<li>mkdir</li> +</ul> +</td><td><ul class="simple"> +<li>rmdir</li> +<li>rename</li> +<li>readlink</li> +<li>follow_link</li> +<li>put_link</li> +<li>...</li> +</ul> +</td></tr></table> + + + + +</article> +<article class="admonition-the-inode-cache slide level-2"> + +<h2>The Inode Cache</h2> + +<ul class="simple"> +<li>Caches inodes into memory to avoid costly storage operations</li> +<li>An inode is cached until low memory conditions are triggered</li> +<li>inodes are indexed with a hash table</li> +<li>The inode hash function takes the superblock and inode number as +inputs</li> +</ul> + + + + +</article> +<article class="admonition-the-dentry-cache slide level-2"> + +<h2>The Dentry Cache</h2> + +<ul class="simple"> +<li>State:<ul> +<li>Used – <em>d_inode</em> is valid and the <em>dentry</em> object is in use</li> +<li>Unused – <em>d_inode</em> is valid but the dentry object is not in use</li> +<li>Negative – <em>d_inode</em> is not valid; the inode was not yet loaded +or the file was erased</li> +</ul> +</li> +<li>Dentry cache<ul> +<li>List of used dentries (dentry->d_state == used)</li> +<li>List of the most recent used dentries (sorted by access time)</li> +<li>Hash table to avoid searching the tree</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-the-page-cache slide level-2"> + +<h2>The Page Cache</h2> + +<ul class="simple"> +<li>Caches file data and not block device data</li> +<li>Uses the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">address_space</span></code> to translate file offsets +to block offsets</li> +<li>Used for both <cite>read</cite> / <cite>write</cite> and <cite>mmap</cite></li> +<li>Uses a radix tree</li> +</ul> + + + + +</article> +<article class="admonition-struct-address-space slide level-2"> + +<h2>struct address_space</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/**</span> +<span class="cm"> * struct address_space - Contents of a cacheable, mappable object.</span> +<span class="cm"> * @host: Owner, either the inode or the block_device.</span> +<span class="cm"> * @i_pages: Cached pages.</span> +<span class="cm"> * @gfp_mask: Memory allocation flags to use for allocating pages.</span> +<span class="cm"> * @i_mmap_writable: Number of VM_SHARED mappings.</span> +<span class="cm"> * @nr_thps: Number of THPs in the pagecache (non-shmem only).</span> +<span class="cm"> * @i_mmap: Tree of private and shared mappings.</span> +<span class="cm"> * @i_mmap_rwsem: Protects @i_mmap and @i_mmap_writable.</span> +<span class="cm"> * @nrpages: Number of page entries, protected by the i_pages lock.</span> +<span class="cm"> * @nrexceptional: Shadow or DAX entries, protected by the i_pages lock.</span> +<span class="cm"> * @writeback_index: Writeback starts here.</span> +<span class="cm"> * @a_ops: Methods.</span> +<span class="cm"> * @flags: Error bits and flags (AS_*).</span> +<span class="cm"> * @wb_err: The most recent error which has occurred.</span> +<span class="cm"> * @private_lock: For use by the owner of the address_space.</span> +<span class="cm"> * @private_list: For use by the owner of the address_space.</span> +<span class="cm"> * @private_data: For use by the owner of the address_space.</span> +<span class="cm"> */</span> +<span class="k">struct</span> <span class="n">address_space</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">host</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">xarray</span> <span class="n">i_pages</span><span class="p">;</span> + <span class="n">gfp_t</span> <span class="n">gfp_mask</span><span class="p">;</span> + <span class="n">atomic_t</span> <span class="n">i_mmap_writable</span><span class="p">;</span> +<span class="cp">#ifdef CONFIG_READ_ONLY_THP_FOR_FS</span> + <span class="cm">/* number of thp, only for non-shmem files */</span> + <span class="n">atomic_t</span> <span class="n">nr_thps</span><span class="p">;</span> +<span class="cp">#endif</span> + <span class="k">struct</span> <span class="n">rb_root_cached</span> <span class="n">i_mmap</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">rw_semaphore</span> <span class="n">i_mmap_rwsem</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">nrpages</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">nrexceptional</span><span class="p">;</span> + <span class="n">pgoff_t</span> <span class="n">writeback_index</span><span class="p">;</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">address_space_operations</span> <span class="o">*</span><span class="n">a_ops</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + <span class="n">errseq_t</span> <span class="n">wb_err</span><span class="p">;</span> + <span class="n">spinlock_t</span> <span class="n">private_lock</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="n">private_list</span><span class="p">;</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">private_data</span><span class="p">;</span> +<span class="p">}</span> <span class="n">__attribute__</span><span class="p">((</span><span class="n">aligned</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">long</span><span class="p">))))</span> <span class="n">__randomize_layout</span><span class="p">;</span> + +<span class="k">struct</span> <span class="n">address_space_operations</span> <span class="p">{</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">writepage</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">,</span> <span class="k">struct</span> <span class="n">writeback_control</span> <span class="o">*</span><span class="n">wbc</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">readpage</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + + <span class="cm">/* Write back some dirty pages from this mapping. */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">writepages</span><span class="p">)(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">writeback_control</span> <span class="o">*</span><span class="p">);</span> + + <span class="cm">/* Set a page dirty. Return true if this dirtied it */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">set_page_dirty</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">);</span> + + <span class="cm">/*</span> +<span class="cm"> * Reads in the requested pages. Unlike ->readpage(), this is</span> +<span class="cm"> * PURELY used for read-ahead!.</span> +<span class="cm"> */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">readpages</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">filp</span><span class="p">,</span> <span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="n">mapping</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="o">*</span><span class="n">pages</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">nr_pages</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">readahead</span><span class="p">)(</span><span class="k">struct</span> <span class="n">readahead_control</span> <span class="o">*</span><span class="p">);</span> + + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">write_begin</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="n">mapping</span><span class="p">,</span> + <span class="n">loff_t</span> <span class="n">pos</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">len</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">flags</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">page</span> <span class="o">**</span><span class="n">pagep</span><span class="p">,</span> <span class="kt">void</span> <span class="o">**</span><span class="n">fsdata</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">write_end</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="n">mapping</span><span class="p">,</span> + <span class="n">loff_t</span> <span class="n">pos</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">len</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">copied</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">fsdata</span><span class="p">);</span> + + <span class="cm">/* Unfortunately this kludge is needed for FIBMAP. Don't use it */</span> + <span class="n">sector_t</span> <span class="p">(</span><span class="o">*</span><span class="n">bmap</span><span class="p">)(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="p">,</span> <span class="n">sector_t</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">invalidatepage</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">releasepage</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="n">gfp_t</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">freepage</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">ssize_t</span> <span class="p">(</span><span class="o">*</span><span class="n">direct_IO</span><span class="p">)(</span><span class="k">struct</span> <span class="n">kiocb</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">iov_iter</span> <span class="o">*</span><span class="n">iter</span><span class="p">);</span> + <span class="cm">/*</span> +<span class="cm"> * migrate the contents of a page to the specified target. If</span> +<span class="cm"> * migrate_mode is MIGRATE_ASYNC, it must not block.</span> +<span class="cm"> */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">migratepage</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="k">enum</span> <span class="n">migrate_mode</span><span class="p">);</span> + <span class="kt">bool</span> <span class="p">(</span><span class="o">*</span><span class="n">isolate_page</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="n">isolate_mode_t</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">putback_page</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">launder_page</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">is_partially_uptodate</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">is_dirty_writeback</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="kt">bool</span> <span class="o">*</span><span class="p">,</span> <span class="kt">bool</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">error_remove_page</span><span class="p">)(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + + <span class="cm">/* swapfile support */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">swap_activate</span><span class="p">)(</span><span class="k">struct</span> <span class="n">swap_info_struct</span> <span class="o">*</span><span class="n">sis</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> + <span class="n">sector_t</span> <span class="o">*</span><span class="n">span</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">swap_deactivate</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">);</span> +<span class="p">};</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-reading-data slide level-2"> + +<h2>Reading data</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="cm">/**</span> +<span class="cm"> * generic_file_read_iter - generic filesystem read routine</span> +<span class="cm"> * @iocb: kernel I/O control block</span> +<span class="cm"> * @iter: destination for the data read</span> +<span class="cm"> *</span> +<span class="cm"> * This is the "read_iter()" routine for all filesystems</span> +<span class="cm"> * that can use the page cache directly.</span> +<span class="cm"> *</span> +<span class="cm"> * The IOCB_NOWAIT flag in iocb->ki_flags indicates that -EAGAIN shall</span> +<span class="cm"> * be returned when no data can be read without waiting for I/O requests</span> +<span class="cm"> * to complete; it doesn't prevent readahead.</span> +<span class="cm"> *</span> +<span class="cm"> * The IOCB_NOIO flag in iocb->ki_flags indicates that no new I/O</span> +<span class="cm"> * requests shall be made for the read or for readahead. When no data</span> +<span class="cm"> * can be read, -EAGAIN shall be returned. When readahead would be</span> +<span class="cm"> * triggered, a partial, possibly empty read shall be returned.</span> +<span class="cm"> *</span> +<span class="cm"> * Return:</span> +<span class="cm"> * * number of bytes copied, even for partial reads</span> +<span class="cm"> * * negative error code (or 0 if IOCB_NOIO) if nothing was read</span> +<span class="cm"> */</span> +<span class="kt">ssize_t</span> +<span class="n">generic_file_read_iter</span><span class="p">(</span><span class="k">struct</span> <span class="n">kiocb</span> <span class="o">*</span><span class="n">iocb</span><span class="p">,</span> <span class="k">struct</span> <span class="n">iov_iter</span> <span class="o">*</span><span class="n">iter</span><span class="p">)</span> + +<span class="cm">/*</span> +<span class="cm"> * Generic "read page" function for block devices that have the normal</span> +<span class="cm"> * get_block functionality. This is most of the block device filesystems.</span> +<span class="cm"> * Reads the page asynchronously --- the unlock_buffer() and</span> +<span class="cm"> * set/clear_buffer_uptodate() functions propagate buffer state into the</span> +<span class="cm"> * page struct once IO has completed.</span> +<span class="cm"> */</span> +<span class="kt">int</span> <span class="n">block_read_full_page</span><span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">,</span> <span class="n">get_block_t</span> <span class="o">*</span><span class="n">get_block</span><span class="p">)</span> +</pre></div> +</div> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec8-filesystems.html b/refs/pull/405/merge/so2/lec8-filesystems.html new file mode 100644 index 00000000..55b95608 --- /dev/null +++ b/refs/pull/405/merge/so2/lec8-filesystems.html @@ -0,0 +1,689 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lecture 08 - Filesystem Management — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lecture 09 - Kernel debugging" href="lec9-debugging.html" /> + <link rel="prev" title="SO2 Lecture 07 - Memory Management" href="lec7-memory-management.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lecture 08 - Filesystem Management</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="#filesystem-abstractions">Filesystem Abstractions</a></li> +<li class="toctree-l3"><a class="reference internal" href="#filesystem-operations">Filesystem Operations</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#mounting-a-filesystem">Mounting a filesystem</a></li> +<li class="toctree-l4"><a class="reference internal" href="#opening-a-file">Opening a file</a></li> +<li class="toctree-l4"><a class="reference internal" href="#querying-file-attributes">Querying file attributes</a></li> +<li class="toctree-l4"><a class="reference internal" href="#reading-data-from-a-file">Reading data from a file</a></li> +<li class="toctree-l4"><a class="reference internal" href="#writing-data-to-a-file">Writing data to a file</a></li> +<li class="toctree-l4"><a class="reference internal" href="#closing-a-file">Closing a file</a></li> +<li class="toctree-l4"><a class="reference internal" href="#directories">Directories</a></li> +<li class="toctree-l4"><a class="reference internal" href="#creating-a-file">Creating a file</a></li> +<li class="toctree-l4"><a class="reference internal" href="#deleting-a-file">Deleting a file</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#linux-virtual-file-system">Linux Virtual File System</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#superblock-operations">Superblock Operations</a></li> +<li class="toctree-l4"><a class="reference internal" href="#inode-operations">Inode Operations</a></li> +<li class="toctree-l4"><a class="reference internal" href="#the-inode-cache">The Inode Cache</a></li> +<li class="toctree-l4"><a class="reference internal" href="#the-dentry-cache">The Dentry Cache</a></li> +<li class="toctree-l4"><a class="reference internal" href="#the-page-cache">The Page Cache</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lec9-debugging.html">SO2 Lecture 09 - Kernel debugging</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lecture 08 - Filesystem Management</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lec8-filesystems.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lecture-08-filesystem-management"> +<h1>SO2 Lecture 08 - Filesystem Management<a class="headerlink" href="#so2-lecture-08-filesystem-management" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="lec8-filesystems-slides.html">View slides</a></p> +<span class="admonition-so2-lecture-08-filesystem-management"></span><div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-filesystem-management simple"> +<li>Filesystem abstractions</li> +<li>Filesystem operations</li> +<li>Linux VFS</li> +<li>Overview of Linux I/O Management</li> +</ul> +</div> +<div class="section" id="filesystem-abstractions"> +<h2>Filesystem Abstractions<a class="headerlink" href="#filesystem-abstractions" title="Permalink to this headline">¶</a></h2> +<p>A fileystem is a way to organize files and directories on storage +devices such as hard disks, SSDs or flash memory. There are many types +of filesystems (e.g. FAT, ext4, btrfs, ntfs) and on one running system +we can have multiple instances of the same filesystem type in use.</p> +<p>While filesystems use different data structures to organizing the +files, directories, user data and meta (internal) data on storage +devices there are a few common abstractions that are used in almost +all filesystems:</p> +<ul class="admonition-filesystem-abstractions simple"> +<li>superblock</li> +<li>file</li> +<li>inode</li> +<li>dentry</li> +</ul> +<p>Some of these abstractions are present both on disk and in memory +while some are only present in memory.</p> +<p>The <em>superblock</em> abstraction contains information about the filesystem +instance such as the block size, the root inode, filesystem size. It +is present both on storage and in memory (for caching purposes).</p> +<p>The <em>file</em> abstraction contains information about an opened file such +as the current file pointer. It only exists in memory.</p> +<p>The <em>inode</em> is identifying a file on disk. It exists both on storage +and in memory (for caching purposes). An inode identifies a file in a +unique way and has various properties such as the file size, access +rights, file type, etc.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">The file name is not a property of the file.</p> +</div> +<p>The <em>dentry</em> associates a name with an inode. It exists both on +storage and in memory (for caching purposes).</p> +<p>The following diagram shows the relationship between the various filesystem +abstractions as they used in memory:</p> +<img alt="../_images/ditaa-29f54aaa1a85b819ff29cb7d101a4d646b3b0b06.png" class="admonition-filesystem-abstractions-in-memory" src="../_images/ditaa-29f54aaa1a85b819ff29cb7d101a4d646b3b0b06.png" /> +<p>Note that not all of the one to many relationships between the various +abstractions are depicted.</p> +<p>Multiple file descriptors can point to the same <em>file</em> because we can +use the <code class="xref c c-func docutils literal"><span class="pre">dup()</span></code> system call to duplicate a file descriptor.</p> +<p>Multiple <em>file</em> abstractions can point to the same <em>dentry</em> if we open +the same path multiple times.</p> +<p>Multiple <em>dentries</em> can point to the same <em>inode</em> when hard links are +used.</p> +<p>The following diagram shows the relationship of the filesystem +abstraction on storage:</p> +<img alt="../_images/ditaa-bc662dab7bb3d9ba3a37efbf69b82c513dcaadd4.png" class="admonition-filesystem-abstractions-on-storage" src="../_images/ditaa-bc662dab7bb3d9ba3a37efbf69b82c513dcaadd4.png" /> +<p>The diagram shows that the <em>superblock</em> is typically stored at the +beginning of the fileystem and that various blocks are used with +different purposes: some to store dentries, some to store inodes and +some to store user data blocks. There are also blocks used to manage +the available free blocks (e.g. bitmaps for the simple filesystems).</p> +<p>The next diagram show a very simple filesystem where blocks are +grouped together by function:</p> +<ul class="simple"> +<li>the superblock contains information about the block size as well as +the IMAP, DMAP, IZONE and DZONE areas.</li> +<li>the IMAP area is comprised of multiple blocks which contains a +bitmap for inode allocation; it maintains the allocated/free state +for all inodes in the IZONE area</li> +<li>the DMAP area is comprised of multiple blocks which contains a +bitmap for data blocks; it maintains the allocated/free state for +all blocks the DZONE area</li> +</ul> +<p class="admonition-simple-filesystem-example"> </p> +<img alt="../_images/ditaa-8b59fc3f5245ffb5d7089dc80cf2e306c39a62d8.png" src="../_images/ditaa-8b59fc3f5245ffb5d7089dc80cf2e306c39a62d8.png" /> +</div> +<div class="section" id="filesystem-operations"> +<h2>Filesystem Operations<a class="headerlink" href="#filesystem-operations" title="Permalink to this headline">¶</a></h2> +<p>The following diagram shows a high level overview of how the file +system drivers interact with the rest of the file system "stack". In +order to support multiple filesystem types and instances Linux +implements a large and complex subsystem that deals with filesystem +management. This is called Virtual File System (or sometimes Virtual +File Switch) and it is abbreviated with VFS.</p> +<img alt="../_images/ditaa-6d39f541805ae8197b413ec9c79116382abc4dbc.png" class="admonition-overview" src="../_images/ditaa-6d39f541805ae8197b413ec9c79116382abc4dbc.png" /> +<p>VFS translates the complex file management related system calls to +simpler operations that are implemented by the device drivers. These +are some of the operations that a file system must implement:</p> +<ul class="admonition-filesystem-operations simple"> +<li>Mount</li> +<li>Open a file</li> +<li>Querying file attributes</li> +<li>Reading data from a file</li> +<li>Writing file to a file</li> +<li>Creating a file</li> +<li>Deleting a file</li> +</ul> +<p>The next sections will look in-depth at some of these operations.</p> +<div class="section" id="mounting-a-filesystem"> +<h3>Mounting a filesystem<a class="headerlink" href="#mounting-a-filesystem" title="Permalink to this headline">¶</a></h3> +<p>A summary of a typical implementation is presented below:</p> +<ul class="admonition-mounting-a-filesystem simple"> +<li>Input: a storage device (partition)</li> +<li>Output: dentry pointing to the root directory</li> +<li>Steps: check device, determine filesystem parameters, locate the root inode</li> +<li>Example: check magic, determine block size, read the root inode and create dentry</li> +</ul> +</div> +<div class="section" id="opening-a-file"> +<h3>Opening a file<a class="headerlink" href="#opening-a-file" title="Permalink to this headline">¶</a></h3> +<p>A summary of a typical implementation is presented below:</p> +<ul class="admonition-opening-a-file simple"> +<li>Input: path</li> +<li>Output: file descriptor</li> +<li>Steps:<ul> +<li>Determine the filesystem type</li> +<li>For each name in the path: lookup parent dentry, load inode, +load data, find dentry</li> +<li>Create a new <em>file</em> that points to the last <em>dentry</em></li> +<li>Find a free entry in the file descriptor table and set it to <em>file</em></li> +</ul> +</li> +</ul> +</div> +<div class="section" id="querying-file-attributes"> +<h3>Querying file attributes<a class="headerlink" href="#querying-file-attributes" title="Permalink to this headline">¶</a></h3> +<p>A summary of a typical implementation is presented below:</p> +<ul class="admonition-querying-file-attributes simple"> +<li>Input: path</li> +<li>Output: file attributes</li> +<li>Steps:<ul> +<li>Access <cite>file->dentry->inode</cite></li> +<li>Read file attributes from the <em>inode</em></li> +</ul> +</li> +</ul> +</div> +<div class="section" id="reading-data-from-a-file"> +<h3>Reading data from a file<a class="headerlink" href="#reading-data-from-a-file" title="Permalink to this headline">¶</a></h3> +<p>A summary of a typical implementation is presented below:</p> +<ul class="admonition-reading-data-from-a-file simple"> +<li>Input: file descriptor, offset, length</li> +<li>Output: data</li> +<li>Steps:<ul> +<li>Access <cite>file->dentry->inode</cite></li> +<li>Determine data blocks</li> +<li>Copy data blocks to memory</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="writing-data-to-a-file"> +<h3>Writing data to a file<a class="headerlink" href="#writing-data-to-a-file" title="Permalink to this headline">¶</a></h3> +<p>A summary of a typical implementation is presented below:</p> +<ul class="admonition-writing-data-to-a-file simple"> +<li>Input: file descriptor, offset, length, data</li> +<li>Output:</li> +<li>Steps:<ul> +<li>Allocate one or more data blocks</li> +<li>Add the allocated blocks to the inode and update file size</li> +<li>Copy data from userspace to internal buffers and write them to +storage</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="closing-a-file"> +<h3>Closing a file<a class="headerlink" href="#closing-a-file" title="Permalink to this headline">¶</a></h3> +<p>A summary of a typical implementation is presented below:</p> +<ul class="admonition-closing-a-file simple"> +<li>Input: file descriptor</li> +<li>Output:</li> +<li>Steps:<ul> +<li>set the file descriptor entry to NULL</li> +<li>Decrement file reference counter</li> +<li>When the counter reaches 0 free <em>file</em></li> +</ul> +</li> +</ul> +</div> +<div class="section" id="directories"> +<h3>Directories<a class="headerlink" href="#directories" title="Permalink to this headline">¶</a></h3> +<p class="admonition-directories">Directories are special files which contain one or more dentries.</p> +</div> +<div class="section" id="creating-a-file"> +<h3>Creating a file<a class="headerlink" href="#creating-a-file" title="Permalink to this headline">¶</a></h3> +<p>A summary of a typical implementation is presented below:</p> +<ul class="admonition-creating-a-file simple"> +<li>Input: path</li> +<li>Output:</li> +<li>Steps:<ul> +<li>Determine the inode directory</li> +<li>Read data blocks and find space for a new dentry</li> +<li>Write back the modified inode directory data blocks</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="deleting-a-file"> +<h3>Deleting a file<a class="headerlink" href="#deleting-a-file" title="Permalink to this headline">¶</a></h3> +<p>A summary of a typical implementation is presented below:</p> +<ul class="admonition-deleting-a-file simple"> +<li>Input: path</li> +<li>Output:</li> +<li>Steps:<ul> +<li>determine the parent inode</li> +<li>read parent inode data blocks</li> +<li>find and erase the dentry (check for links)</li> +<li>when last file is closed: deallocate data and inode blocks</li> +</ul> +</li> +</ul> +</div> +</div> +<div class="section" id="linux-virtual-file-system"> +<h2>Linux Virtual File System<a class="headerlink" href="#linux-virtual-file-system" title="Permalink to this headline">¶</a></h2> +<p>Although the main purpose for the original introduction of VFS in UNIX +kernels was to support multiple filesystem types and instances, a side +effect was that it simplified fileystem device driver development +since command parts are now implement in the VFS. Almost all of the +caching and buffer management is dealt with VFS, leaving just +efficient data storage management to the filesystem device driver.</p> +<p>In order to deal with multiple filesystem types, VFS introduced the +common filesystem abstractions previously presented. Note that the +filesystem driver can also use its own particular fileystem +abstractions in memory (e.g. ext4 inode or dentry) and that there +might be a different abstraction on storage as well. Thus we may end +up with three slightly different filesystem abstractions: one for +VFS - always in memory, and two for a particular filesystem - one in +memory used by the filesystem driver, and one on storage.</p> +<a class="admonition-virtual-file-system reference internal image-reference" href="../_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.png"><img alt="../_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.png" class="admonition-virtual-file-system" src="../_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.png" style="height: 100%;" /></a> +<div class="section" id="superblock-operations"> +<h3>Superblock Operations<a class="headerlink" href="#superblock-operations" title="Permalink to this headline">¶</a></h3> +<p>VFS requires that all filesystem implement a set of "superblock +operations".</p> +<p>They deal with initializing, updating and freeing the VFS superblock:</p> +<blockquote> +<div><ul class="simple"> +<li><code class="xref c c-func docutils literal"><span class="pre">fill_super()</span></code> - reads the filesystem statistics (e.g. total +number of inode, free number of inodes, total number of blocks, free +number of blocks)</li> +<li><code class="xref c c-func docutils literal"><span class="pre">write_super()</span></code> - updates the superblock information on storage +(e.g. updating the number of free inode or data blocks)</li> +<li><code class="xref c c-func docutils literal"><span class="pre">put_super()</span></code> - free any data associated with the filsystem +instance, called when unmounting a filesystem</li> +</ul> +</div></blockquote> +<p>The next class of operations are dealing with manipulating fileystem +inodes. These operations will receive VFS inodes as parameters but the +filesystem driver may use its own inode structures internally and, if +so, they will convert in between them as necessary.</p> +<p>A summary of the superblock operations are presented below:</p> +<table class="hlist"><tr><td><ul class="simple"> +<li>fill_super</li> +<li>put_super</li> +<li>write_super</li> +<li>read_inode</li> +</ul> +</td><td><ul class="simple"> +<li>write_inode</li> +<li>evict_inode</li> +<li>statfs</li> +<li>remount_fs</li> +</ul> +</td></tr></table> +</div> +<div class="section" id="inode-operations"> +<h3>Inode Operations<a class="headerlink" href="#inode-operations" title="Permalink to this headline">¶</a></h3> +<p>The next set of operations that VFS calls when interacting with +filesystem device drivers are the "inode operations". Non-intuitively +these mostly deal with manipulating dentries - looking up a file name, +creating, linking and removing files, dealing with symbolic links, +creating and removing directories.</p> +<p>This is the list of the most important inode operations:</p> +<table class="hlist"><tr><td><ul class="simple"> +<li>create</li> +<li>lookup</li> +<li>link</li> +<li>unlink</li> +<li>symlink</li> +<li>mkdir</li> +</ul> +</td><td><ul class="simple"> +<li>rmdir</li> +<li>rename</li> +<li>readlink</li> +<li>follow_link</li> +<li>put_link</li> +<li>...</li> +</ul> +</td></tr></table> +</div> +<div class="section" id="the-inode-cache"> +<h3>The Inode Cache<a class="headerlink" href="#the-inode-cache" title="Permalink to this headline">¶</a></h3> +<p>The inode cache is used to avoid reading and writing inodes to and +from storage every time we need to read or update them. The cache uses +a hash table and inodes are indexed with a hash function which takes +as parameters the superblock (of a particular filesystem instance) and +the inode number associated with an inode.</p> +<p>inodes are cached until either the filesystem is unmounted, the inode +deleted or the system enters a memory pressure state. When this +happens the Linux memory management system will (among other things) +free inodes from the inode cache based on how often they were +accessed.</p> +<ul class="admonition-the-inode-cache simple"> +<li>Caches inodes into memory to avoid costly storage operations</li> +<li>An inode is cached until low memory conditions are triggered</li> +<li>inodes are indexed with a hash table</li> +<li>The inode hash function takes the superblock and inode number as +inputs</li> +</ul> +</div> +<div class="section" id="the-dentry-cache"> +<h3>The Dentry Cache<a class="headerlink" href="#the-dentry-cache" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-the-dentry-cache simple"> +<li>State:<ul> +<li>Used – <em>d_inode</em> is valid and the <em>dentry</em> object is in use</li> +<li>Unused – <em>d_inode</em> is valid but the dentry object is not in use</li> +<li>Negative – <em>d_inode</em> is not valid; the inode was not yet loaded +or the file was erased</li> +</ul> +</li> +<li>Dentry cache<ul> +<li>List of used dentries (dentry->d_state == used)</li> +<li>List of the most recent used dentries (sorted by access time)</li> +<li>Hash table to avoid searching the tree</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="the-page-cache"> +<h3>The Page Cache<a class="headerlink" href="#the-page-cache" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-the-page-cache simple"> +<li>Caches file data and not block device data</li> +<li>Uses the <code class="xref c c-type docutils literal"><span class="pre">struct</span> <span class="pre">address_space</span></code> to translate file offsets +to block offsets</li> +<li>Used for both <cite>read</cite> / <cite>write</cite> and <cite>mmap</cite></li> +<li>Uses a radix tree</li> +</ul> +<div class="admonition-struct-address-space highlight-c"><div class="highlight"><pre><span></span><span class="cm">/**</span> +<span class="cm"> * struct address_space - Contents of a cacheable, mappable object.</span> +<span class="cm"> * @host: Owner, either the inode or the block_device.</span> +<span class="cm"> * @i_pages: Cached pages.</span> +<span class="cm"> * @gfp_mask: Memory allocation flags to use for allocating pages.</span> +<span class="cm"> * @i_mmap_writable: Number of VM_SHARED mappings.</span> +<span class="cm"> * @nr_thps: Number of THPs in the pagecache (non-shmem only).</span> +<span class="cm"> * @i_mmap: Tree of private and shared mappings.</span> +<span class="cm"> * @i_mmap_rwsem: Protects @i_mmap and @i_mmap_writable.</span> +<span class="cm"> * @nrpages: Number of page entries, protected by the i_pages lock.</span> +<span class="cm"> * @nrexceptional: Shadow or DAX entries, protected by the i_pages lock.</span> +<span class="cm"> * @writeback_index: Writeback starts here.</span> +<span class="cm"> * @a_ops: Methods.</span> +<span class="cm"> * @flags: Error bits and flags (AS_*).</span> +<span class="cm"> * @wb_err: The most recent error which has occurred.</span> +<span class="cm"> * @private_lock: For use by the owner of the address_space.</span> +<span class="cm"> * @private_list: For use by the owner of the address_space.</span> +<span class="cm"> * @private_data: For use by the owner of the address_space.</span> +<span class="cm"> */</span> +<span class="k">struct</span> <span class="n">address_space</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">inode</span> <span class="o">*</span><span class="n">host</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">xarray</span> <span class="n">i_pages</span><span class="p">;</span> + <span class="n">gfp_t</span> <span class="n">gfp_mask</span><span class="p">;</span> + <span class="n">atomic_t</span> <span class="n">i_mmap_writable</span><span class="p">;</span> +<span class="cp">#ifdef CONFIG_READ_ONLY_THP_FOR_FS</span> + <span class="cm">/* number of thp, only for non-shmem files */</span> + <span class="n">atomic_t</span> <span class="n">nr_thps</span><span class="p">;</span> +<span class="cp">#endif</span> + <span class="k">struct</span> <span class="n">rb_root_cached</span> <span class="n">i_mmap</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">rw_semaphore</span> <span class="n">i_mmap_rwsem</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">nrpages</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">nrexceptional</span><span class="p">;</span> + <span class="n">pgoff_t</span> <span class="n">writeback_index</span><span class="p">;</span> + <span class="k">const</span> <span class="k">struct</span> <span class="n">address_space_operations</span> <span class="o">*</span><span class="n">a_ops</span><span class="p">;</span> + <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span> + <span class="n">errseq_t</span> <span class="n">wb_err</span><span class="p">;</span> + <span class="n">spinlock_t</span> <span class="n">private_lock</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="n">private_list</span><span class="p">;</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">private_data</span><span class="p">;</span> +<span class="p">}</span> <span class="n">__attribute__</span><span class="p">((</span><span class="n">aligned</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">long</span><span class="p">))))</span> <span class="n">__randomize_layout</span><span class="p">;</span> + +<span class="k">struct</span> <span class="n">address_space_operations</span> <span class="p">{</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">writepage</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">,</span> <span class="k">struct</span> <span class="n">writeback_control</span> <span class="o">*</span><span class="n">wbc</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">readpage</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + + <span class="cm">/* Write back some dirty pages from this mapping. */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">writepages</span><span class="p">)(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">writeback_control</span> <span class="o">*</span><span class="p">);</span> + + <span class="cm">/* Set a page dirty. Return true if this dirtied it */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">set_page_dirty</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">);</span> + + <span class="cm">/*</span> +<span class="cm"> * Reads in the requested pages. Unlike ->readpage(), this is</span> +<span class="cm"> * PURELY used for read-ahead!.</span> +<span class="cm"> */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">readpages</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">filp</span><span class="p">,</span> <span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="n">mapping</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">list_head</span> <span class="o">*</span><span class="n">pages</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">nr_pages</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">readahead</span><span class="p">)(</span><span class="k">struct</span> <span class="n">readahead_control</span> <span class="o">*</span><span class="p">);</span> + + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">write_begin</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="n">mapping</span><span class="p">,</span> + <span class="n">loff_t</span> <span class="n">pos</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">len</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">flags</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">page</span> <span class="o">**</span><span class="n">pagep</span><span class="p">,</span> <span class="kt">void</span> <span class="o">**</span><span class="n">fsdata</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">write_end</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="n">mapping</span><span class="p">,</span> + <span class="n">loff_t</span> <span class="n">pos</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">len</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">copied</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">fsdata</span><span class="p">);</span> + + <span class="cm">/* Unfortunately this kludge is needed for FIBMAP. Don't use it */</span> + <span class="n">sector_t</span> <span class="p">(</span><span class="o">*</span><span class="n">bmap</span><span class="p">)(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="p">,</span> <span class="n">sector_t</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">invalidatepage</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">releasepage</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="n">gfp_t</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">freepage</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">ssize_t</span> <span class="p">(</span><span class="o">*</span><span class="n">direct_IO</span><span class="p">)(</span><span class="k">struct</span> <span class="n">kiocb</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">iov_iter</span> <span class="o">*</span><span class="n">iter</span><span class="p">);</span> + <span class="cm">/*</span> +<span class="cm"> * migrate the contents of a page to the specified target. If</span> +<span class="cm"> * migrate_mode is MIGRATE_ASYNC, it must not block.</span> +<span class="cm"> */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">migratepage</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="k">enum</span> <span class="n">migrate_mode</span><span class="p">);</span> + <span class="kt">bool</span> <span class="p">(</span><span class="o">*</span><span class="n">isolate_page</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="n">isolate_mode_t</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">putback_page</span><span class="p">)(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">launder_page</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">is_partially_uptodate</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">,</span> + <span class="kt">unsigned</span> <span class="kt">long</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">is_dirty_writeback</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">,</span> <span class="kt">bool</span> <span class="o">*</span><span class="p">,</span> <span class="kt">bool</span> <span class="o">*</span><span class="p">);</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">error_remove_page</span><span class="p">)(</span><span class="k">struct</span> <span class="n">address_space</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="p">);</span> + + <span class="cm">/* swapfile support */</span> + <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">swap_activate</span><span class="p">)(</span><span class="k">struct</span> <span class="n">swap_info_struct</span> <span class="o">*</span><span class="n">sis</span><span class="p">,</span> <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> + <span class="n">sector_t</span> <span class="o">*</span><span class="n">span</span><span class="p">);</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">swap_deactivate</span><span class="p">)(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">);</span> +<span class="p">};</span> +</pre></div> +</div> +<div class="admonition-reading-data highlight-c"><div class="highlight"><pre><span></span><span class="cm">/**</span> +<span class="cm"> * generic_file_read_iter - generic filesystem read routine</span> +<span class="cm"> * @iocb: kernel I/O control block</span> +<span class="cm"> * @iter: destination for the data read</span> +<span class="cm"> *</span> +<span class="cm"> * This is the "read_iter()" routine for all filesystems</span> +<span class="cm"> * that can use the page cache directly.</span> +<span class="cm"> *</span> +<span class="cm"> * The IOCB_NOWAIT flag in iocb->ki_flags indicates that -EAGAIN shall</span> +<span class="cm"> * be returned when no data can be read without waiting for I/O requests</span> +<span class="cm"> * to complete; it doesn't prevent readahead.</span> +<span class="cm"> *</span> +<span class="cm"> * The IOCB_NOIO flag in iocb->ki_flags indicates that no new I/O</span> +<span class="cm"> * requests shall be made for the read or for readahead. When no data</span> +<span class="cm"> * can be read, -EAGAIN shall be returned. When readahead would be</span> +<span class="cm"> * triggered, a partial, possibly empty read shall be returned.</span> +<span class="cm"> *</span> +<span class="cm"> * Return:</span> +<span class="cm"> * * number of bytes copied, even for partial reads</span> +<span class="cm"> * * negative error code (or 0 if IOCB_NOIO) if nothing was read</span> +<span class="cm"> */</span> +<span class="kt">ssize_t</span> +<span class="n">generic_file_read_iter</span><span class="p">(</span><span class="k">struct</span> <span class="n">kiocb</span> <span class="o">*</span><span class="n">iocb</span><span class="p">,</span> <span class="k">struct</span> <span class="n">iov_iter</span> <span class="o">*</span><span class="n">iter</span><span class="p">)</span> + +<span class="cm">/*</span> +<span class="cm"> * Generic "read page" function for block devices that have the normal</span> +<span class="cm"> * get_block functionality. This is most of the block device filesystems.</span> +<span class="cm"> * Reads the page asynchronously --- the unlock_buffer() and</span> +<span class="cm"> * set/clear_buffer_uptodate() functions propagate buffer state into the</span> +<span class="cm"> * page struct once IO has completed.</span> +<span class="cm"> */</span> +<span class="kt">int</span> <span class="n">block_read_full_page</span><span class="p">(</span><span class="k">struct</span> <span class="n">page</span> <span class="o">*</span><span class="n">page</span><span class="p">,</span> <span class="n">get_block_t</span> <span class="o">*</span><span class="n">get_block</span><span class="p">)</span> +</pre></div> +</div> +</div> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lec7-memory-management.html" class="btn btn-neutral float-left" title="SO2 Lecture 07 - Memory Management" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lec9-debugging.html" class="btn btn-neutral float-right" title="SO2 Lecture 09 - Kernel debugging" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec9-debugging-slides.html b/refs/pull/405/merge/so2/lec9-debugging-slides.html new file mode 100644 index 00000000..e668003a --- /dev/null +++ b/refs/pull/405/merge/so2/lec9-debugging-slides.html @@ -0,0 +1,840 @@ +<!DOCTYPE html> + + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>SO2 Lecture 09 - Kernel debugging — The Linux Kernel documentation</title> + + <link rel="stylesheet" href="../_static/basic.css" type="text/css" /> + <link rel="stylesheet" href="../_static/styles.css" type="text/css" /> + <link rel="stylesheet" href="../_static/single.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + + + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <script type="text/javascript" src="../_static/asciinema-player.js"></script> + <script type="text/javascript" src="../_static/common.js"></script> + + <script type="text/javascript" src="../_static/slides.js"></script> + <script type="text/javascript" src="../_static/sync.js"></script> + <script type="text/javascript" src="../_static/controller.js"></script> + <script type="text/javascript" src="../_static/init.js"></script> + + + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="top" title="The Linux Kernel documentation" href="../index.html" /> + <link rel="up" title="Operating Systems 2" href="index.html" /> + <link rel="next" title="SO2 Lecture 10 - Networking" href="lec10-networking.html" /> + <link rel="prev" title="SO2 Lecture 08 - Filesystem Management" href="lec8-filesystems.html" /> + </head> + <body> + +<section + id="slide_container" + class='slides layout-regular'> + + + +<article class="admonition-so2-lecture-09-kernel-debugging slide level-1"> + +<h1>SO2 Lecture 09 - Kernel debugging</h1> + + + + + +</article> +<article class="admonition-debugging slide level-2"> + +<h2>Debugging</h2> + +<ul class="simple"> +<li>decoding an oops/panic</li> +<li>list debugging</li> +<li>memory debugging</li> +<li>locking debugging</li> +<li>profiling</li> +</ul> + + + + +</article> +<article class="admonition-oops-module slide level-2"> + +<h2>Oops module</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">noinline</span> <span class="kt">void</span> <span class="nf">do_oops</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="o">*</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="p">)</span><span class="mh">0x42</span> <span class="o">=</span> <span class="sc">'a'</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">so2_oops_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"oops_init</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="n">do_oops</span><span class="p">();</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">so2_oops_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"oops exit</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> +<span class="p">}</span> + +<span class="n">module_init</span><span class="p">(</span><span class="n">so2_oops_init</span><span class="p">);</span> +<span class="n">module_exit</span><span class="p">(</span><span class="n">so2_oops_exit</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-oops-information slide level-2"> + +<h2>Oops information</h2> + +<div class="highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~/skels/debugging/oops# insmod oops.ko +BUG: unable to handle kernel NULL pointer dereference at <span class="m">00000042</span> +IP: do_oops+0x8/0x10 <span class="o">[</span>oops<span class="o">]</span> +*pde <span class="o">=</span> <span class="m">00000000</span> +Oops: <span class="m">0002</span> <span class="o">[</span><span class="c1">#1] SMP</span> +Modules linked in: oops<span class="o">(</span>O+<span class="o">)</span> +CPU: <span class="m">0</span> PID: <span class="m">234</span> Comm: insmod Tainted: G O <span class="m">4</span>.15.0+ <span class="c1">#3</span> +Hardware name: QEMU Standard PC <span class="o">(</span>i440FX + PIIX, <span class="m">1996</span><span class="o">)</span>, BIOS Ubuntu-1.8.2-1ubuntu1 <span class="m">04</span>/01/2014 +EIP: do_oops+0x8/0x10 <span class="o">[</span>oops<span class="o">]</span> +CR0: <span class="m">80050033</span> CR2: <span class="m">00000042</span> CR3: 0785f000 CR4: <span class="m">00000690</span> +EIP: 0x44902cc2 +EFLAGS: <span class="m">00000206</span> CPU: <span class="m">0</span> +EAX: ffffffda EBX: 08afb050 ECX: 0000eef4 EDX: 08afb008 +ESI: <span class="m">00000000</span> EDI: bf914dbc EBP: <span class="m">00000000</span> ESP: bf914c1c +DS: 007b ES: 007b FS: <span class="m">0000</span> GS: <span class="m">0033</span> SS: 007b +Code: <a3> <span class="m">42</span> <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> 5d c3 <span class="m">90</span> <span class="m">55</span> <span class="m">89</span> e5 <span class="m">83</span> ec <span class="m">04</span> c7 <span class="m">04</span> <span class="m">24</span> <span class="m">24</span> <span class="m">70</span> <span class="m">81</span> c8 e8 +Killed +</pre></div> +</div> + + + + +</article> +<article class="admonition-oops-stacktrace slide level-2"> + +<h2>Oops stacktrace</h2> + +<div class="highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~/skels/debugging/oops# insmod oops.ko +BUG: unable to handle kernel NULL pointer dereference at <span class="m">00000042</span> +Call Trace: +so2_oops_init+0x17/0x20 <span class="o">[</span>oops<span class="o">]</span> +do_one_initcall+0x37/0x170 +? cache_alloc_debugcheck_after.isra.19+0x15f/0x2f0 +? __might_sleep+0x32/0x90 +? trace_hardirqs_on_caller+0x11c/0x1a0 +? do_init_module+0x17/0x1c2 +? kmem_cache_alloc+0xa4/0x1e0 +? do_init_module+0x17/0x1c2 +do_init_module+0x46/0x1c2 +load_module+0x1f45/0x2380 +SyS_init_module+0xe5/0x100 +do_int80_syscall_32+0x61/0x190 +entry_INT80_32+0x2f/0x2f +Killed +</pre></div> +</div> + + + + +</article> +<article class="admonition-debugging slide level-2"> + +<h2>Debugging</h2> + +<ul class="simple"> +<li>CONFIG_DEBUG_INFO</li> +<li>addr2line</li> +<li>gdb</li> +<li>objdump -dSr</li> +</ul> + + + + +</article> +<article class="admonition-addr2line slide level-2"> + +<h2>addr2line</h2> + +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ addr2line -e oops.o 0x08 +$ skels/debugging/oops/oops.c:5 +$ <span class="c1"># 0x08 is the offset of the offending instruction inside the oops.ko module</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-objdump slide level-2"> + +<h2>objdump</h2> + +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ cat /proc/modules +oops <span class="m">20480</span> <span class="m">1</span> - Loading 0xc8816000 <span class="o">(</span>O+<span class="o">)</span> + +$ objdump -dS --adjust-vma<span class="o">=</span>0xc8816000 oops.ko +c8816000: b8 <span class="m">61</span> <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> mov <span class="nv">$0</span>x61,%eax + +static noinline void do_oops<span class="o">(</span>void<span class="o">)</span> +<span class="o">{</span> +c8816005: <span class="m">55</span> push %ebp +c8816006: <span class="m">89</span> e5 mov %esp,%ebp +*<span class="o">(</span>int*<span class="o">)</span><span class="nv">0x42</span> <span class="o">=</span> <span class="s1">'a'</span><span class="p">;</span> +c8816008: a3 <span class="m">42</span> <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> mov %eax,0x42 +</pre></div> +</div> + + + + +</article> +<article class="admonition-gdb slide level-2"> + +<h2>gdb</h2> + +<div class="highlight-bash"><div class="highlight"><pre><span></span>$ gdb ./vmlinux + +<span class="o">(</span>gdb<span class="o">)</span> list *<span class="o">(</span>do_panic+0x8<span class="o">)</span> +0xc1244138 is in do_panic <span class="o">(</span>lib/test_panic.c:8<span class="o">)</span>. +<span class="m">3</span> +<span class="m">4</span> static struct timer_list panic_timer<span class="p">;</span> +<span class="m">5</span> +<span class="m">6</span> static void do_panic<span class="o">(</span>struct timer_list *unused<span class="o">)</span> +<span class="m">7</span> <span class="o">{</span> +<span class="m">8</span> *<span class="o">(</span>int*<span class="o">)</span><span class="nv">0x42</span> <span class="o">=</span> <span class="s1">'a'</span><span class="p">;</span> +<span class="m">9</span> <span class="o">}</span> +<span class="m">10</span> +<span class="m">11</span> static int so2_panic_init<span class="o">(</span>void<span class="o">)</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-kernel-panic slide level-2"> + +<h2>Kernel panic</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="k">struct</span> <span class="n">timer_list</span> <span class="n">panic_timer</span><span class="p">;</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">do_panic</span><span class="p">(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span><span class="n">unused</span><span class="p">)</span> +<span class="p">{</span> + <span class="o">*</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="p">)</span><span class="mh">0x42</span> <span class="o">=</span> <span class="sc">'a'</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">so2_panic_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"panic_init</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + + <span class="n">timer_setup</span><span class="p">(</span><span class="o">&</span><span class="n">panic_timer</span><span class="p">,</span> <span class="n">do_panic</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> + <span class="n">mod_timer</span><span class="p">(</span><span class="o">&</span><span class="n">panic_timer</span><span class="p">,</span> <span class="n">jiffies</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">HZ</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-list-debugging slide level-2"> + +<h2>List debugging</h2> + +<div class="highlight-bash"><div class="highlight"><pre><span></span>static inline void list_del<span class="o">(</span>struct list_head *entry<span class="o">)</span> +<span class="o">{</span> + __list_del<span class="o">(</span>entry->prev, entry->next<span class="o">)</span><span class="p">;</span> + entry->next <span class="o">=</span> <span class="o">(</span>struct list_head*<span class="o">)</span>LIST_POISON1<span class="p">;</span> + entry->prev <span class="o">=</span> <span class="o">(</span>struct list_head*<span class="o">)</span>LIST_POISON2<span class="p">;</span> +<span class="o">}</span> + +BUG: unable to handle kernel NULL pointer dereference at <span class="m">00000100</span> +IP: crush+0x80/0xb0 <span class="o">[</span>list<span class="o">]</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-memory-debugging slide level-2"> + +<h2>Memory debugging</h2> + +<ul class="simple"> +<li>SLAB/SLUB debugging</li> +<li>KASAN</li> +<li>kmemcheck</li> +<li>DEBUG_PAGEALLOC</li> +</ul> + + + + +</article> +<article class="admonition-slab-debugging slide level-2"> + +<h2>Slab debugging</h2> + +<ul class="simple"> +<li>CONFIG_DEBUG_SLAB</li> +<li>poisoned based memory debuggers</li> +</ul> +<img alt="../_images/ditaa-5e6f93e563d6e94c14fe3d483f988e0579b05b38.png" src="../_images/ditaa-5e6f93e563d6e94c14fe3d483f988e0579b05b38.png" /> + + + + +</article> +<article class="admonition-use-before-initialize-bugs slide level-2"> + +<h2>Use before initialize bugs</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>BUG: unable to handle kernel paging request at 5a5a5a5a +IP: [<c1225063>] __list_del_entry+0x37/0x71 +… +Call Trace: +[<c12250a8>] list_del+0xb/0x1b +[<f1de81a2>] use_before_init+0x31/0x38 [crusher] +[<f1de8265>] crush_it+0x38/0xa9 [crusher] +[<f1de82de>] init_module+0x8/0xa [crusher] +[<c1001072>] do_one_initcall+0x72/0x119 +[<f1de82d6>] ? crush_it+0xa9/0xa9 [crusher] +[<c106b8ae>] sys_init_module+0xc8d/0xe77 +[<c14d7d18>] syscall_call+0x7/0xb +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">noinline</span> <span class="kt">void</span> <span class="nf">use_before_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">list_m</span> <span class="o">*</span><span class="n">m</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">m</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + + <span class="n">printk</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">list_del</span><span class="p">(</span><span class="o">&</span><span class="n">m</span><span class="o">-></span><span class="n">lh</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-use-after-free-bug slide level-2"> + +<h2>Use after free bug</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>BUG: unable to handle kernel paging request at 6b6b6b6b +IP: [<c1225063>] __list_del_entry+0x37/0x71 +… +Call Trace: +[<c12250a8>] list_del+0xb/0x1b +[<f4c6816a>] use_after_free+0x38/0x3f [crusher] +[<f4c6827f>] crush_it+0x52/0xa9 [crusher] +[<f4c682de>] init_module+0x8/0xa [crusher] +[<c1001072>] do_one_initcall+0x72/0x119 +[<f4c682d6>] ? crush_it+0xa9/0xa9 [crusher] +[<c106b8ae>] sys_init_module+0xc8d/0xe77 +[<c14d7d18>] syscall_call+0x7/0xb +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">noinline</span> <span class="kt">void</span> <span class="nf">use_after_free</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">list_m</span> <span class="o">*</span><span class="n">m</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">m</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + + <span class="n">printk</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">kfree</span><span class="p">(</span><span class="n">m</span><span class="p">);</span> + <span class="n">list_del</span><span class="p">(</span><span class="o">&</span><span class="n">m</span><span class="o">-></span><span class="n">lh</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-use-after-free-bug slide level-2"> + +<h2>Use after free bug</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span># insmod /system/lib/modules/crusher.ko test=use_before_init +Slab corruption: size-4096 start=ed612000, len=4096 +000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6b 6b +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">noinline</span> <span class="kt">void</span> <span class="nf">use_after_free2</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">char</span> <span class="o">*</span><span class="n">b</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="mi">3000</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + <span class="n">kfree</span><span class="p">(</span><span class="n">b</span><span class="p">);</span> + <span class="n">memset</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">30</span><span class="p">);</span> + <span class="n">b</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="mi">3000</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + <span class="n">kfree</span><span class="p">(</span><span class="n">b</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-buffer-overflow-bugs slide level-2"> + +<h2>Buffer overflow bugs</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>slab error in verify_redzone_free(): cache `dummy': memory outside object was overwritten +Pid: 1282, comm: insmod Not tainted 3.0.16-mid10-00007-ga4a6b62-dirty #70 +Call Trace: +[<c10cc1de>] __slab_error+0x17/0x1c +[<c10cc7ca>] __cache_free+0x12c/0x317 +[<c10ccaba>] kmem_cache_free+0x2b/0xaf +[<f27f1138>] buffer_overflow+0x4c/0x57 [crusher] +[<f27f12aa>] crush_it+0x6c/0xa9 [crusher] +[<f27f12ef>] init_module+0x8/0xd [crusher] +[<c1001072>] do_one_initcall+0x72/0x119 +[<c106b8ae>] sys_init_module+0xc8d/0xe77 +[<c14d7d18>] syscall_call+0x7/0xb +eb002bf8: redzone 1:0xd84156c5635688c0, redzone 2:0x0 +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">noinline</span> <span class="kt">void</span> <span class="nf">buffer_overflow</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">kmem_cache</span> <span class="o">*</span><span class="n">km</span> <span class="o">=</span> <span class="n">kmem_cache_create</span><span class="p">(</span><span class="s">"dummy"</span><span class="p">,</span> <span class="mi">3000</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span> + <span class="kt">char</span> <span class="o">*</span><span class="n">b</span> <span class="o">=</span> <span class="n">kmem_cache_alloc</span><span class="p">(</span><span class="n">km</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + + <span class="n">printk</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">memset</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">3016</span><span class="p">);</span> + <span class="n">kmem_cache_free</span><span class="p">(</span><span class="n">km</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-debug-pagealloc slide level-2"> + +<h2>DEBUG_PAGEALLOC</h2> + +<ul class="simple"> +<li>Memory debugger that works at a page level</li> +<li>Detects invalid accesses either by:<ul> +<li>Filling pages with poison byte patterns and checking the pattern at +reallocation</li> +<li>Unmapping the dellocated pages from kernel space (just a few +architectures)</li> +</ul> +</li> +</ul> + + + + +</article> +<article class="admonition-kasan slide level-2"> + +<h2>KASan</h2> + +<ul class="simple"> +<li>dynamic memory error detector</li> +<li>finds user-after-free or out-of-bound bugs</li> +<li>uses shadow memory to track memory operations</li> +<li>lib/test_kasan.c</li> +</ul> + + + + +</article> +<article class="admonition-kasan-vs-debug-pagealloc slide level-2"> + +<h2>KASan vs DEBUG_PAGEALLOC</h2> + +<p>KASan is slower than DEBUG_PAGEALLOC, but KASan works on sub-page granularity +level, so it able to find more bugs.</p> + + + + +</article> +<article class="admonition-kasan-vs-slub-debug slide level-2"> + +<h2>KASan vs SLUB_DEBUG</h2> + +<ul class="simple"> +<li>SLUB_DEBUG has lower overhead than KASan.</li> +<li>SLUB_DEBUG in most cases are not able to detect bad reads, KASan able to +detect both reads and writes.</li> +<li>In some cases (e.g. redzone overwritten) SLUB_DEBUG detect bugs only on +allocation/freeing of object. KASan catch bugs right before it will happen, +so we always know exact place of first bad read/write.</li> +</ul> + + + + +</article> +<article class="admonition-kmemleak slide level-2"> + +<h2>Kmemleak</h2> + +<ul class="simple"> +<li>enable kernel config: <cite>CONFIG_DEBUG_KMEMLEAK</cite></li> +<li>setup: <cite>mount -t debugfs nodev /sys/kernel/debug</cite></li> +<li>trigger a memory scan: <cite>echo scan > /sys/kernel/debug/kmemleak</cite></li> +<li>show memory leaks: <cite>cat /sys/kernel/debug/kmemleak</cite></li> +<li>clear all possible leaks: <cite>echo clear > /sys/kernel/debug/kmemleak</cite></li> +</ul> + + + + +</article> +<article class="admonition-kmemleak-example slide level-2"> + +<h2>Kmemleak example</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">leak_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + + <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">kmalloc</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="n">MODULE_LICENSE</span><span class="p">(</span><span class="s">"GPL v2"</span><span class="p">);</span> +<span class="n">module_init</span><span class="p">(</span><span class="n">leak_init</span><span class="p">);</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-kmemleak-report slide level-2"> + +<h2>Kmemleak report</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>root@qemux86:~# insmod skels/debugging/leak/leak.ko +leak: loading out-of-tree module taints kernel. +leak_init +root@qemux86:~# echo scan > /sys/kernel/debug/kmemleak +root@qemux86:~# echo scan > /sys/kernel/debug/kmemleak +kmemleak: 1 new suspected memory leaks (see /sys/kernel/debug/kmemleak) +root@qemux86:~# cat /sys/kernel/debug/kmemleak +unreferenced object 0xd7871500 (size 32): +comm "insmod", pid 237, jiffies 4294902108 (age 24.628s) +hex dump (first 32 bytes): +5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ +5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a a5 ZZZZZZZZZZZZZZZ. +backtrace: +[<(ptrval)>] kmem_cache_alloc_trace+0x163/0x310 +[<(ptrval)>] leak_init+0x2f/0x1000 [leak] +[<(ptrval)>] do_one_initcall+0x57/0x2e0 +[<(ptrval)>] do_init_module+0x4b/0x1be +[<(ptrval)>] load_module+0x201a/0x2590 +[<(ptrval)>] sys_init_module+0xfd/0x120 +[<(ptrval)>] do_int80_syscall_32+0x6a/0x1a0 +</pre></div> +</div> + + + + +</article> +<article class="admonition-lockdep-checker slide level-2"> + +<h2>Lockdep checker</h2> + +<ul class="simple"> +<li>CONFIG_DEBUG_LOCKDEP</li> +<li>Detects lock inversio, circular dependencies, incorrect usage of locks +(including interrupt context)</li> +<li>Maintains dependency between classes of locks not individual locks</li> +<li>Each scenario is only checked once and hashed</li> +</ul> + + + + +</article> +<article class="admonition-ab-ba-deadlock-example slide level-2"> + +<h2>AB BA Deadlock Example</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">noinline</span> <span class="kt">int</span> <span class="nf">thread_a</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">unused</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">mutex_lock</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired A</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">mutex_lock</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired B</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + + <span class="n">mutex_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">);</span> + <span class="n">mutex_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">noinline</span> <span class="kt">int</span> <span class="nf">thread_b</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">unused</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">mutex_lock</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired B</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">mutex_lock</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired A</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + + <span class="n">mutex_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">);</span> + <span class="n">mutex_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-ab-ba-deadlock-report slide level-2"> + +<h2>AB BA Deadlock Report</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>thread_a acquired A +thread_a acquired B +thread_b acquired B + +====================================================== +WARNING: possible circular locking dependency detected +4.19.0+ #4 Tainted: G O +------------------------------------------------------ +thread_b/238 is trying to acquire lock: +(ptrval) (a){+.+.}, at: thread_b+0x48/0x90 [locking] + +but task is already holding lock: +(ptrval) (b){+.+.}, at: thread_b+0x27/0x90 [locking] + +which lock already depends on the new lock. +</pre></div> +</div> + + + + +</article> +<article class="admonition-ab-ba-deadlock-report-dependency-chain slide level-2"> + +<h2>AB BA Deadlock Report (dependency chain)</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>the existing dependency chain (in reverse order) is: + +-> #1 (b){+.+.}: + __mutex_lock+0x60/0x830 + mutex_lock_nested+0x20/0x30 + thread_a+0x48/0x90 [locking] + kthread+0xeb/0x100 + ret_from_fork+0x2e/0x38 + +-> #0 (a){+.+.}: + lock_acquire+0x93/0x190 + __mutex_lock+0x60/0x830 + mutex_lock_nested+0x20/0x30 + thread_b+0x48/0x90 [locking] + kthread+0xeb/0x100 + ret_from_fork+0x2e/0x38 +</pre></div> +</div> + + + + +</article> +<article class="admonition-ab-ba-deadlock-report-unsafe-locking-scenario slide level-2"> + +<h2>AB BA Deadlock Report (unsafe locking scenario)</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>other info that might help us debug this: + +Possible unsafe locking scenario: + +CPU0 CPU1 +---- ---- +lock(b); + lock(a); + lock(b); +lock(a); + +*** DEADLOCK *** +</pre></div> +</div> + + + + +</article> +<article class="admonition-irq-deadlock-example slide level-2"> + +<h2>IRQ Deadlock Example</h2> + +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="nf">DEFINE_SPINLOCK</span><span class="p">(</span><span class="n">lock</span><span class="p">);</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">timerfn</span><span class="p">(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span><span class="n">unused</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquiring lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s released lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="nf">DEFINE_TIMER</span><span class="p">(</span><span class="n">timer</span><span class="p">,</span> <span class="n">timerfn</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">init_module</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">mod_timer</span><span class="p">(</span><span class="o">&</span><span class="n">timer</span><span class="p">,</span> <span class="n">jiffies</span><span class="p">);</span> + + <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquiring lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s released lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> + + + + +</article> +<article class="admonition-irq-deadlock-report slide level-2"> + +<h2>IRQ Deadlock Report</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>init_module acquiring lock +init_module acquired lock +init_module released lock +timerfn acquiring lock + +================================ +WARNING: inconsistent lock state +4.19.0+ #4 Tainted: G O +-------------------------------- +inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage. +ksoftirqd/0/9 [HC0[0]:SC1[1]:HE1:SE0] takes: +(ptrval) (lock#4){+.?.}, at: timerfn+0x25/0x60 [locking2] +{SOFTIRQ-ON-W} state was registered at: +lock_acquire+0x93/0x190 +_raw_spin_lock+0x39/0x50 +init_module+0x35/0x70 [locking2] +do_one_initcall+0x57/0x2e0 +do_init_module+0x4b/0x1be +load_module+0x201a/0x2590 +sys_init_module+0xfd/0x120 +do_int80_syscall_32+0x6a/0x1a0 +restore_all+0x0/0x8d +</pre></div> +</div> + + + + +</article> +<article class="admonition-irq-deadlock-report slide level-2"> + +<h2>IRQ Deadlock Report</h2> + +<div class="highlight-none"><div class="highlight"><pre><span></span>Possible unsafe locking scenario: + + CPU0 + ---- + lock(lock#4); + <Interrupt> + lock(lock#4); + + *** DEADLOCK *** + +1 lock held by ksoftirqd/0/9: +#0: (ptrval) (/home/tavi/src/linux/tools/labs/skels/./debugging/locking2/locking2.c:13){+.-.}, at: call_timer_f0 +stack backtrace: +CPU: 0 PID: 9 Comm: ksoftirqd/0 Tainted: G O 4.19.0+ #4 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014 +Call Trace: +dump_stack+0x66/0x96 +print_usage_bug.part.26+0x1ee/0x200 +mark_lock+0x5ea/0x640 +__lock_acquire+0x4b4/0x17a0 +lock_acquire+0x93/0x190 +_raw_spin_lock+0x39/0x50 +timerfn+0x25/0x60 [locking2] +</pre></div> +</div> + + + + +</article> +<article class="admonition-perf slide level-2"> + +<h2>perf</h2> + +<ul class="simple"> +<li>performance counters, tracepoints, kprobes, uprobes</li> +<li>hardware events: CPU cycles, TLB misses, cache misses</li> +<li>software events: page faults , context switches</li> +<li>collects backtraces (user + kernel)</li> +</ul> + + + + +</article> +<article class="admonition-other-tools slide level-2"> + +<h2>Other tools</h2> + +<ul class="simple"> +<li>ftrace</li> +<li>kprobes</li> +<li>sparse</li> +<li>coccinelle</li> +<li>checkpatch.pl</li> +<li>printk</li> +<li>dump_stack()</li> +</ul> + + + + +</article> + +</section> + +<section id="slide_notes"> + +</section> + + </body> +</html> \ No newline at end of file diff --git a/refs/pull/405/merge/so2/lec9-debugging.html b/refs/pull/405/merge/so2/lec9-debugging.html new file mode 100644 index 00000000..35c9774a --- /dev/null +++ b/refs/pull/405/merge/so2/lec9-debugging.html @@ -0,0 +1,933 @@ +<!DOCTYPE html> +<html class="writer-html4" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SO2 Lecture 09 - Kernel debugging — The Linux Kernel documentation</title><link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/asciinema-player.css" type="text/css" /> + <link rel="stylesheet" href="../_static/theme_overrides.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script> + var DOCUMENTATION_OPTIONS = { + URL_ROOT:'../', + VERSION:'', + LANGUAGE:'None', + COLLAPSE_INDEX:false, + FILE_SUFFIX:'.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt' + }; + </script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/asciinema-player.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="SO2 Lecture 10 - Networking" href="lec10-networking.html" /> + <link rel="prev" title="SO2 Lecture 08 - Filesystem Management" href="lec8-filesystems.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + + + <a href="../index.html" class="icon icon-home"> + The Linux Kernel + </a> + <div class="version"> + 5.10.14 + </div> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <ul class="current"> +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Operating Systems 2</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="grading.html">SO2 - General Rules and Grading</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec1-intro.html">SO2 Lecture 01 - Course overview and Linux kernel introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec2-syscalls.html">SO2 Lecture 02 - System calls</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec3-processes.html">SO2 Lecture 03 - Processes</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec4-interrupts.html">SO2 Lecture 04 - Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec5-smp.html">SO2 Lecture 05 - Symmetric Multi-Processing</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec6-address-space.html">SO2 Lecture 06 - Address Space</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec7-memory-management.html">SO2 Lecture 07 - Memory Management</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec8-filesystems.html">SO2 Lecture 08 - Filesystem Management</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">SO2 Lecture 09 - Kernel debugging</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#lecture-objectives">Lecture objectives:</a></li> +<li class="toctree-l3"><a class="reference internal" href="#decoding-an-oops-panic">Decoding an oops/panic</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#decoding-an-oops">Decoding an oops</a></li> +<li class="toctree-l4"><a class="reference internal" href="#addr2line">addr2line</a></li> +<li class="toctree-l4"><a class="reference internal" href="#objdump">objdump</a></li> +<li class="toctree-l4"><a class="reference internal" href="#gdb">gdb</a></li> +<li class="toctree-l4"><a class="reference internal" href="#kernel-panic">Kernel panic</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#list-debugging">List debugging</a></li> +<li class="toctree-l3"><a class="reference internal" href="#memory-debugging">Memory debugging</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#slab-debugging">Slab debugging</a></li> +<li class="toctree-l4"><a class="reference internal" href="#debug-pagealloc">DEBUG_PAGEALLOC</a></li> +<li class="toctree-l4"><a class="reference internal" href="#kasan">KASan</a></li> +<li class="toctree-l4"><a class="reference internal" href="#kmemleak">Kmemleak</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#lockdep-checker">Lockdep checker</a></li> +<li class="toctree-l3"><a class="reference internal" href="#perf">perf</a></li> +<li class="toctree-l3"><a class="reference internal" href="#other-tools">Other tools</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="lec10-networking.html">SO2 Lecture 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec11-arch.html">SO2 Lecture 11 - Architecture Layer</a></li> +<li class="toctree-l2"><a class="reference internal" href="lec12-virtualization.html">SO2 Lecture 12 - Virtualization</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab1-intro.html">SO2 Lab 01 - Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab2-kernel-api.html">SO2 Lab 02 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab3-device-drivers.html">SO2 Lab 03 - Character device drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab4-interrupts.html">SO2 Lab 04 - I/O access and Interrupts</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab5-deferred-work.html">SO2 Lab 05 - Deferred work</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab6-memory-mapping.html">SO2 Lab 06 - Memory Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab7-block-device-drivers.html">SO2 Lab 07 - Block Device Drivers</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab8-filesystems-part1.html">SO2 Lab 08 - File system drivers (Part 1)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab9-filesystems-part2.html">SO2 Lab 09 - File system drivers (Part 2)</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab10-networking.html">SO2 Lab 10 - Networking</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab11-arm-kernel-development.html">SO2 Lab 11 - Kernel Development on ARM</a></li> +<li class="toctree-l2"><a class="reference internal" href="lab12-kernel-profiling.html">SO2 Lab 12 - Kernel Profiling</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign-collaboration.html">Collaboration</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign0-kernel-api.html">Assignment 0 - Kernel API</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign1-kprobe-based-tracer.html">Assignment 1 - Kprobe based tracer</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign2-driver-uart.html">Assignment 2 - Driver UART</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign3-software-raid.html">Assignment 3 - Software RAID</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign4-transport-protocol.html">Assignment 4 - SO2 Transport Protocol</a></li> +<li class="toctree-l2"><a class="reference internal" href="assign7-kvm-vmm.html">Assignment 7 - SO2 Virtual Machine Manager with KVM</a></li> +</ul> +</li> +</ul> +<p class="caption"><span class="caption-text">Lectures</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../lectures/intro.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/syscalls.html">System Calls</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/processes.html">Processes</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/interrupts.html">Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/smp.html">Symmetric Multi-Processing</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/address-space.html">Address Space</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/memory-management.html">Memory Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/fs.html">Filesystem Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/debugging.html">Debugging</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/networking.html">Network Management</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/arch.html">Architecture Layer</a></li> +<li class="toctree-l1"><a class="reference internal" href="../lectures/virt.html">Virtualization</a></li> +</ul> +<p class="caption"><span class="caption-text">Labs</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../labs/infrastructure.html">Infrastructure</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_modules.html">Kernel modules</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_api.html">Kernel API</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_drivers.html">Character device drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/interrupts.html">I/O access and Interrupts</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/deferred_work.html">Deferred work</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/block_device_drivers.html">Block Device Drivers</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part1.html">File system drivers (Part 1)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/filesystems_part2.html">File system drivers (Part 2)</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/networking.html">Networking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/arm_kernel_development.html">Kernel Development on ARM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/memory_mapping.html">Memory mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/device_model.html">Linux Device Model</a></li> +<li class="toctree-l1"><a class="reference internal" href="../labs/kernel_profiling.html">Kernel Profiling</a></li> +</ul> +<p class="caption"><span class="caption-text">Useful info</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html">Recommended Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/vm.html#virtual-machine-setup">Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/extra-vm.html">Customizing the Virtual Machine Setup</a></li> +<li class="toctree-l1"><a class="reference internal" href="../info/contributing.html">Contributing to linux-kernel-labs</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">The Linux Kernel</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li> + <li class="breadcrumb-item"><a href="index.html">Operating Systems 2</a></li> + <li class="breadcrumb-item active">SO2 Lecture 09 - Kernel debugging</li> + <li class="wy-breadcrumbs-aside"> + <a href="../_sources/so2/lec9-debugging.rst.txt" rel="nofollow"> View page source</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <div class="section" id="so2-lecture-09-kernel-debugging"> +<h1>SO2 Lecture 09 - Kernel debugging<a class="headerlink" href="#so2-lecture-09-kernel-debugging" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="lec9-debugging-slides.html">View slides</a></p> +<span class="admonition-so2-lecture-09-kernel-debugging"></span><div class="section" id="lecture-objectives"> +<h2>Lecture objectives:<a class="headerlink" href="#lecture-objectives" title="Permalink to this headline">¶</a></h2> +<p>One essential part of Linux kernel development is debugging. In user space we had +the support of the kernel so we could easily stop processes and use gdb to inspect +their behavior. In the kernel, in order to use gdb we need to use hypervisor like +QEMU or JTAG based hardware interfaces which are not always available. The Linux +kernel provides a set of tools and debug options useful for investigating abnormal +behavior.</p> +<p>In this lecture we will learn about:</p> +<ul class="admonition-debugging simple"> +<li>decoding an oops/panic</li> +<li>list debugging</li> +<li>memory debugging</li> +<li>locking debugging</li> +<li>profiling</li> +</ul> +</div> +<div class="section" id="decoding-an-oops-panic"> +<h2>Decoding an oops/panic<a class="headerlink" href="#decoding-an-oops-panic" title="Permalink to this headline">¶</a></h2> +<p>An oops is an inconsistent state that the kernel detects inside itself. +Upon detecting an oops the Linux kernel kills the offending process, +prints information that can help debug the problem and continues execution +but with limited reliability.</p> +<p>Lets consider the following Linux kernel module:</p> +<div class="admonition-oops-module highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">noinline</span> <span class="kt">void</span> <span class="nf">do_oops</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="o">*</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="p">)</span><span class="mh">0x42</span> <span class="o">=</span> <span class="sc">'a'</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">so2_oops_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"oops_init</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + <span class="n">do_oops</span><span class="p">();</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">so2_oops_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"oops exit</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> +<span class="p">}</span> + +<span class="n">module_init</span><span class="p">(</span><span class="n">so2_oops_init</span><span class="p">);</span> +<span class="n">module_exit</span><span class="p">(</span><span class="n">so2_oops_exit</span><span class="p">);</span> +</pre></div> +</div> +<p>Notice that ''do_oops'' function tries to write at an invalid memory address. Because the kernel +cannot find a suitable physical page were to write, it kills the insmod task in the context of +which ''do_oops'' runs. Then it prints the following oops message:</p> +<blockquote> +<div><div class="highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~/skels/debugging/oops# insmod oops.ko +BUG: unable to handle kernel NULL pointer dereference at <span class="m">00000042</span> +IP: do_oops+0x8/0x10 <span class="o">[</span>oops<span class="o">]</span> +*pde <span class="o">=</span> <span class="m">00000000</span> +Oops: <span class="m">0002</span> <span class="o">[</span><span class="c1">#1] SMP</span> +Modules linked in: oops<span class="o">(</span>O+<span class="o">)</span> +CPU: <span class="m">0</span> PID: <span class="m">234</span> Comm: insmod Tainted: G O <span class="m">4</span>.15.0+ <span class="c1">#3</span> +Hardware name: QEMU Standard PC <span class="o">(</span>i440FX + PIIX, <span class="m">1996</span><span class="o">)</span>, BIOS Ubuntu-1.8.2-1ubuntu1 <span class="m">04</span>/01/2014 +EIP: do_oops+0x8/0x10 <span class="o">[</span>oops<span class="o">]</span> +EFLAGS: <span class="m">00000292</span> CPU: <span class="m">0</span> +EAX: <span class="m">00000061</span> EBX: <span class="m">00000000</span> ECX: c7ed3584 EDX: c7ece8dc +ESI: c716c908 EDI: c8816010 EBP: c7257df0 ESP: c7257df0 +DS: 007b ES: 007b FS: 00d8 GS: <span class="m">0033</span> SS: <span class="m">0068</span> +CR0: <span class="m">80050033</span> CR2: <span class="m">00000042</span> CR3: 0785f000 CR4: <span class="m">00000690</span> +Call Trace: +so2_oops_init+0x17/0x20 <span class="o">[</span>oops<span class="o">]</span> +do_one_initcall+0x37/0x170 +? cache_alloc_debugcheck_after.isra.19+0x15f/0x2f0 +? __might_sleep+0x32/0x90 +? trace_hardirqs_on_caller+0x11c/0x1a0 +? do_init_module+0x17/0x1c2 +? kmem_cache_alloc+0xa4/0x1e0 +? do_init_module+0x17/0x1c2 +do_init_module+0x46/0x1c2 +load_module+0x1f45/0x2380 +SyS_init_module+0xe5/0x100 +do_int80_syscall_32+0x61/0x190 +entry_INT80_32+0x2f/0x2f +EIP: 0x44902cc2 +EFLAGS: <span class="m">00000206</span> CPU: <span class="m">0</span> +EAX: ffffffda EBX: 08afb050 ECX: 0000eef4 EDX: 08afb008 +ESI: <span class="m">00000000</span> EDI: bf914dbc EBP: <span class="m">00000000</span> ESP: bf914c1c +DS: 007b ES: 007b FS: <span class="m">0000</span> GS: <span class="m">0033</span> SS: 007b +Code: <a3> <span class="m">42</span> <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> 5d c3 <span class="m">90</span> <span class="m">55</span> <span class="m">89</span> e5 <span class="m">83</span> ec <span class="m">04</span> c7 <span class="m">04</span> <span class="m">24</span> <span class="m">24</span> <span class="m">70</span> <span class="m">81</span> c8 e8 +EIP: do_oops+0x8/0x10 <span class="o">[</span>oops<span class="o">]</span> SS:ESP: <span class="m">0068</span>:c7257df0 +CR2: <span class="m">0000000000000042</span> +---<span class="o">[</span> end trace 011848be72f8bb42 <span class="o">]</span>--- +Killed +</pre></div> +</div> +</div></blockquote> +<p>An oops contains information about the IP which caused the fault, register status, process, +CPU on which the fault happend like below:</p> +<div class="admonition-oops-information highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~/skels/debugging/oops# insmod oops.ko +BUG: unable to handle kernel NULL pointer dereference at <span class="m">00000042</span> +IP: do_oops+0x8/0x10 <span class="o">[</span>oops<span class="o">]</span> +*pde <span class="o">=</span> <span class="m">00000000</span> +Oops: <span class="m">0002</span> <span class="o">[</span><span class="c1">#1] SMP</span> +Modules linked in: oops<span class="o">(</span>O+<span class="o">)</span> +CPU: <span class="m">0</span> PID: <span class="m">234</span> Comm: insmod Tainted: G O <span class="m">4</span>.15.0+ <span class="c1">#3</span> +Hardware name: QEMU Standard PC <span class="o">(</span>i440FX + PIIX, <span class="m">1996</span><span class="o">)</span>, BIOS Ubuntu-1.8.2-1ubuntu1 <span class="m">04</span>/01/2014 +EIP: do_oops+0x8/0x10 <span class="o">[</span>oops<span class="o">]</span> +CR0: <span class="m">80050033</span> CR2: <span class="m">00000042</span> CR3: 0785f000 CR4: <span class="m">00000690</span> +EIP: 0x44902cc2 +EFLAGS: <span class="m">00000206</span> CPU: <span class="m">0</span> +EAX: ffffffda EBX: 08afb050 ECX: 0000eef4 EDX: 08afb008 +ESI: <span class="m">00000000</span> EDI: bf914dbc EBP: <span class="m">00000000</span> ESP: bf914c1c +DS: 007b ES: 007b FS: <span class="m">0000</span> GS: <span class="m">0033</span> SS: 007b +Code: <a3> <span class="m">42</span> <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> 5d c3 <span class="m">90</span> <span class="m">55</span> <span class="m">89</span> e5 <span class="m">83</span> ec <span class="m">04</span> c7 <span class="m">04</span> <span class="m">24</span> <span class="m">24</span> <span class="m">70</span> <span class="m">81</span> c8 e8 +Killed +</pre></div> +</div> +<p>Another important thing that an oops can provide is the stack trace of functions called before +the fault happend:</p> +<div class="admonition-oops-stacktrace highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~/skels/debugging/oops# insmod oops.ko +BUG: unable to handle kernel NULL pointer dereference at <span class="m">00000042</span> +Call Trace: +so2_oops_init+0x17/0x20 <span class="o">[</span>oops<span class="o">]</span> +do_one_initcall+0x37/0x170 +? cache_alloc_debugcheck_after.isra.19+0x15f/0x2f0 +? __might_sleep+0x32/0x90 +? trace_hardirqs_on_caller+0x11c/0x1a0 +? do_init_module+0x17/0x1c2 +? kmem_cache_alloc+0xa4/0x1e0 +? do_init_module+0x17/0x1c2 +do_init_module+0x46/0x1c2 +load_module+0x1f45/0x2380 +SyS_init_module+0xe5/0x100 +do_int80_syscall_32+0x61/0x190 +entry_INT80_32+0x2f/0x2f +Killed +</pre></div> +</div> +<div class="section" id="decoding-an-oops"> +<h3>Decoding an oops<a class="headerlink" href="#decoding-an-oops" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-debugging simple"> +<li>CONFIG_DEBUG_INFO</li> +<li>addr2line</li> +<li>gdb</li> +<li>objdump -dSr</li> +</ul> +</div> +<div class="section" id="addr2line"> +<h3>addr2line<a class="headerlink" href="#addr2line" title="Permalink to this headline">¶</a></h3> +<p><em>addr2line</em> translates addresses into file names and line numbers. Given +an address in an executable it uses the debugging information to figure out +which file name and line number are associated with it.</p> +<p>Modules are loaded at dynamic addresses but are compiled starting with 0 as +a base address. So, in order to find the line number for a given dynamic address +we need to know module's load address.</p> +<div class="admonition-addr2line highlight-bash"><div class="highlight"><pre><span></span>$ addr2line -e oops.o 0x08 +$ skels/debugging/oops/oops.c:5 +$ <span class="c1"># 0x08 is the offset of the offending instruction inside the oops.ko module</span> +</pre></div> +</div> +</div> +<div class="section" id="objdump"> +<h3>objdump<a class="headerlink" href="#objdump" title="Permalink to this headline">¶</a></h3> +<p>Similar we can determine the offending line using objdump:</p> +<div class="admonition-objdump highlight-bash"><div class="highlight"><pre><span></span>$ cat /proc/modules +oops <span class="m">20480</span> <span class="m">1</span> - Loading 0xc8816000 <span class="o">(</span>O+<span class="o">)</span> + +$ objdump -dS --adjust-vma<span class="o">=</span>0xc8816000 oops.ko +c8816000: b8 <span class="m">61</span> <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> mov <span class="nv">$0</span>x61,%eax + +static noinline void do_oops<span class="o">(</span>void<span class="o">)</span> +<span class="o">{</span> +c8816005: <span class="m">55</span> push %ebp +c8816006: <span class="m">89</span> e5 mov %esp,%ebp +*<span class="o">(</span>int*<span class="o">)</span><span class="nv">0x42</span> <span class="o">=</span> <span class="s1">'a'</span><span class="p">;</span> +c8816008: a3 <span class="m">42</span> <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> mov %eax,0x42 +</pre></div> +</div> +</div> +<div class="section" id="gdb"> +<h3>gdb<a class="headerlink" href="#gdb" title="Permalink to this headline">¶</a></h3> +<div class="admonition-gdb highlight-bash"><div class="highlight"><pre><span></span>$ gdb ./vmlinux + +<span class="o">(</span>gdb<span class="o">)</span> list *<span class="o">(</span>do_panic+0x8<span class="o">)</span> +0xc1244138 is in do_panic <span class="o">(</span>lib/test_panic.c:8<span class="o">)</span>. +<span class="m">3</span> +<span class="m">4</span> static struct timer_list panic_timer<span class="p">;</span> +<span class="m">5</span> +<span class="m">6</span> static void do_panic<span class="o">(</span>struct timer_list *unused<span class="o">)</span> +<span class="m">7</span> <span class="o">{</span> +<span class="m">8</span> *<span class="o">(</span>int*<span class="o">)</span><span class="nv">0x42</span> <span class="o">=</span> <span class="s1">'a'</span><span class="p">;</span> +<span class="m">9</span> <span class="o">}</span> +<span class="m">10</span> +<span class="m">11</span> static int so2_panic_init<span class="o">(</span>void<span class="o">)</span> +</pre></div> +</div> +</div> +<div class="section" id="kernel-panic"> +<h3>Kernel panic<a class="headerlink" href="#kernel-panic" title="Permalink to this headline">¶</a></h3> +<p>A kernel panic is a special type of oops where the kernel cannot continue execution. For example +if the function do_oops from above was called in the interrupt context, the kernel wouldn't know how to kill +and it will decide that it is better to crash the kernel and stop execution.</p> +<p>Here is a sample code that will generate a kernel panic:</p> +<div class="admonition-kernel-panic highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="k">struct</span> <span class="n">timer_list</span> <span class="n">panic_timer</span><span class="p">;</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">do_panic</span><span class="p">(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span><span class="n">unused</span><span class="p">)</span> +<span class="p">{</span> + <span class="o">*</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="p">)</span><span class="mh">0x42</span> <span class="o">=</span> <span class="sc">'a'</span><span class="p">;</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="kt">int</span> <span class="nf">so2_panic_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"panic_init</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> + + <span class="n">timer_setup</span><span class="p">(</span><span class="o">&</span><span class="n">panic_timer</span><span class="p">,</span> <span class="n">do_panic</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> + <span class="n">mod_timer</span><span class="p">(</span><span class="o">&</span><span class="n">panic_timer</span><span class="p">,</span> <span class="n">jiffies</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">HZ</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Loading the module will generate the following kernel panic message:</p> +<div class="highlight-bash"><div class="highlight"><pre><span></span>root@qemux86:~/skels/debugging/panic# insmod panic.ko +panic: loading out-of-tree module taints kernel. +panic_init +root@qemux86:~/skels/debugging/panic# BUG: unable to handle kernel NULL pointer dereference at <span class="m">00000042</span> +IP: do_panic+0x8/0x10 <span class="o">[</span>panic<span class="o">]</span> +*pde <span class="o">=</span> <span class="m">00000000</span> +Oops: <span class="m">0002</span> <span class="o">[</span><span class="c1">#1] SMP</span> +Modules linked in: panic<span class="o">(</span>O<span class="o">)</span> +CPU: <span class="m">0</span> PID: <span class="m">0</span> Comm: swapper/0 Tainted: G O <span class="m">4</span>.15.0+ <span class="c1">#19</span> +Hardware name: QEMU Standard PC <span class="o">(</span>i440FX + PIIX, <span class="m">1996</span><span class="o">)</span>, BIOS Ubuntu-1.8.2-1ubuntu1 <span class="m">04</span>/01/2014 +EIP: do_panic+0x8/0x10 <span class="o">[</span>panic<span class="o">]</span> +EFLAGS: <span class="m">00010246</span> CPU: <span class="m">0</span> +EAX: <span class="m">00000061</span> EBX: <span class="m">00000101</span> ECX: 000002d8 EDX: <span class="m">00000000</span> +ESI: c8817000 EDI: c8819200 EBP: c780ff34 ESP: c780ff34 +DS: 007b ES: 007b FS: 00d8 GS: <span class="m">0000</span> SS: <span class="m">0068</span> +CR0: <span class="m">80050033</span> CR2: <span class="m">00000042</span> CR3: 0716b000 CR4: <span class="m">00000690</span> +Call Trace: +<SOFTIRQ> +call_timer_fn+0x63/0xf0 +? process_timeout+0x10/0x10 +run_timer_softirq+0x14f/0x170 +? 0xc8817000 +? trace_hardirqs_on_caller+0x9b/0x1a0 +__do_softirq+0xde/0x1f2 +? __irqentry_text_end+0x6/0x6 +do_softirq_own_stack+0x57/0x70 +</SOFTIRQ> +irq_exit+0x7d/0x90 +smp_apic_timer_interrupt+0x4f/0x90 +? trace_hardirqs_off_thunk+0xc/0x1d +apic_timer_interrupt+0x3a/0x40 +EIP: default_idle+0xa/0x10 +EFLAGS: <span class="m">00000246</span> CPU: <span class="m">0</span> +EAX: c15c97c0 EBX: <span class="m">00000000</span> ECX: <span class="m">00000000</span> EDX: <span class="m">00000001</span> +ESI: <span class="m">00000000</span> EDI: <span class="m">00000000</span> EBP: c15c3f48 ESP: c15c3f48 +DS: 007b ES: 007b FS: 00d8 GS: <span class="m">0000</span> SS: <span class="m">0068</span> +arch_cpu_idle+0x9/0x10 +default_idle_call+0x19/0x30 +do_idle+0x105/0x180 +cpu_startup_entry+0x25/0x30 +rest_init+0x1e3/0x1f0 +start_kernel+0x305/0x30a +i386_start_kernel+0x95/0x99 +startup_32_smp+0x15f/0x164 +Code: <a3> <span class="m">42</span> <span class="m">00</span> <span class="m">00</span> <span class="m">00</span> 5d c3 <span class="m">90</span> <span class="m">55</span> <span class="m">89</span> e5 <span class="m">83</span> ec <span class="m">08</span> c7 <span class="m">04</span> <span class="m">24</span> <span class="m">24</span> <span class="m">80</span> <span class="m">81</span> c8 e8 +EIP: do_panic+0x8/0x10 <span class="o">[</span>panic<span class="o">]</span> SS:ESP: <span class="m">0068</span>:c780ff34 +CR2: <span class="m">0000000000000042</span> +---<span class="o">[</span> end trace 77f49f83f2e42f91 <span class="o">]</span>--- +Kernel panic - not syncing: Fatal exception in interrupt +Kernel Offset: disabled +---<span class="o">[</span> end Kernel panic - not syncing: Fatal exception in interrupt +</pre></div> +</div> +</div> +</div> +<div class="section" id="list-debugging"> +<h2>List debugging<a class="headerlink" href="#list-debugging" title="Permalink to this headline">¶</a></h2> +<p>In order to catch access to uninitialized elements the kernel uses poison +magic values.</p> +<div class="admonition-list-debugging highlight-bash"><div class="highlight"><pre><span></span>static inline void list_del<span class="o">(</span>struct list_head *entry<span class="o">)</span> +<span class="o">{</span> + __list_del<span class="o">(</span>entry->prev, entry->next<span class="o">)</span><span class="p">;</span> + entry->next <span class="o">=</span> <span class="o">(</span>struct list_head*<span class="o">)</span>LIST_POISON1<span class="p">;</span> + entry->prev <span class="o">=</span> <span class="o">(</span>struct list_head*<span class="o">)</span>LIST_POISON2<span class="p">;</span> +<span class="o">}</span> + +BUG: unable to handle kernel NULL pointer dereference at <span class="m">00000100</span> +IP: crush+0x80/0xb0 <span class="o">[</span>list<span class="o">]</span> +</pre></div> +</div> +</div> +<div class="section" id="memory-debugging"> +<h2>Memory debugging<a class="headerlink" href="#memory-debugging" title="Permalink to this headline">¶</a></h2> +<p>There are several tools for memory debugging:</p> +<ul class="admonition-memory-debugging simple"> +<li>SLAB/SLUB debugging</li> +<li>KASAN</li> +<li>kmemcheck</li> +<li>DEBUG_PAGEALLOC</li> +</ul> +<div class="section" id="slab-debugging"> +<h3>Slab debugging<a class="headerlink" href="#slab-debugging" title="Permalink to this headline">¶</a></h3> +<p>Slab debugging uses a memory poison technique to detect several types of memory +bugs in the SLAB/SUB allocators.</p> +<p>The allocated buffers are guarded with memory that has been filled in with +special markers. Any adjacent writes to the buffer will be detected at a later +time when other memory management operations on that buffer are performed +(e.g. when the buffer is freed).</p> +<p>Upon allocation of the buffer, the buffer it is also filled in with a special +value to potentially detect buffer access before initialization (e.g. if the +buffer holds pointers). The value is selected in such a way that it is unlikely +to be a valid address and as such to trigger kernel bugs at the access time.</p> +<p>A similar technique is used when freeing the buffer: the buffer is filled with +another special value that will cause kernel bugs if pointers are accessed after +the memory is freed. In this case, the allocator also checks the next time the +buffer is allocated that the buffer was not modified.</p> +<p>The diagram bellow shows a summary of the way SLAB/SLUB poisoning works:</p> +<ul class="admonition-slab-debugging simple"> +<li>CONFIG_DEBUG_SLAB</li> +<li>poisoned based memory debuggers</li> +</ul> +<img alt="../_images/ditaa-5e6f93e563d6e94c14fe3d483f988e0579b05b38.png" src="../_images/ditaa-5e6f93e563d6e94c14fe3d483f988e0579b05b38.png" /> +<p>Example of an use before initialize bug:</p> +<div class="admonition-use-before-initialize-bugs highlight-none"><div class="highlight"><pre><span></span>BUG: unable to handle kernel paging request at 5a5a5a5a +IP: [<c1225063>] __list_del_entry+0x37/0x71 +… +Call Trace: +[<c12250a8>] list_del+0xb/0x1b +[<f1de81a2>] use_before_init+0x31/0x38 [crusher] +[<f1de8265>] crush_it+0x38/0xa9 [crusher] +[<f1de82de>] init_module+0x8/0xa [crusher] +[<c1001072>] do_one_initcall+0x72/0x119 +[<f1de82d6>] ? crush_it+0xa9/0xa9 [crusher] +[<c106b8ae>] sys_init_module+0xc8d/0xe77 +[<c14d7d18>] syscall_call+0x7/0xb +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">noinline</span> <span class="kt">void</span> <span class="nf">use_before_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">list_m</span> <span class="o">*</span><span class="n">m</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">m</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + + <span class="n">printk</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">list_del</span><span class="p">(</span><span class="o">&</span><span class="n">m</span><span class="o">-></span><span class="n">lh</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Example of an use after free bug:</p> +<div class="admonition-use-after-free-bug highlight-none"><div class="highlight"><pre><span></span>BUG: unable to handle kernel paging request at 6b6b6b6b +IP: [<c1225063>] __list_del_entry+0x37/0x71 +… +Call Trace: +[<c12250a8>] list_del+0xb/0x1b +[<f4c6816a>] use_after_free+0x38/0x3f [crusher] +[<f4c6827f>] crush_it+0x52/0xa9 [crusher] +[<f4c682de>] init_module+0x8/0xa [crusher] +[<c1001072>] do_one_initcall+0x72/0x119 +[<f4c682d6>] ? crush_it+0xa9/0xa9 [crusher] +[<c106b8ae>] sys_init_module+0xc8d/0xe77 +[<c14d7d18>] syscall_call+0x7/0xb +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">noinline</span> <span class="kt">void</span> <span class="nf">use_after_free</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">list_m</span> <span class="o">*</span><span class="n">m</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">m</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + + <span class="n">printk</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">kfree</span><span class="p">(</span><span class="n">m</span><span class="p">);</span> + <span class="n">list_del</span><span class="p">(</span><span class="o">&</span><span class="n">m</span><span class="o">-></span><span class="n">lh</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Another example of an use after free bug is shown below. Note that this time the +bug is detected at the next allocation.</p> +<div class="admonition-use-after-free-bug highlight-none"><div class="highlight"><pre><span></span># insmod /system/lib/modules/crusher.ko test=use_before_init +Slab corruption: size-4096 start=ed612000, len=4096 +000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6b 6b +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">noinline</span> <span class="kt">void</span> <span class="nf">use_after_free2</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="kt">char</span> <span class="o">*</span><span class="n">b</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="mi">3000</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + <span class="n">kfree</span><span class="p">(</span><span class="n">b</span><span class="p">);</span> + <span class="n">memset</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">30</span><span class="p">);</span> + <span class="n">b</span> <span class="o">=</span> <span class="n">kmalloc</span><span class="p">(</span><span class="mi">3000</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + <span class="n">kfree</span><span class="p">(</span><span class="n">b</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Finally this is an example of a buffer overflow bug:</p> +<div class="admonition-buffer-overflow-bugs highlight-none"><div class="highlight"><pre><span></span>slab error in verify_redzone_free(): cache `dummy': memory outside object was overwritten +Pid: 1282, comm: insmod Not tainted 3.0.16-mid10-00007-ga4a6b62-dirty #70 +Call Trace: +[<c10cc1de>] __slab_error+0x17/0x1c +[<c10cc7ca>] __cache_free+0x12c/0x317 +[<c10ccaba>] kmem_cache_free+0x2b/0xaf +[<f27f1138>] buffer_overflow+0x4c/0x57 [crusher] +[<f27f12aa>] crush_it+0x6c/0xa9 [crusher] +[<f27f12ef>] init_module+0x8/0xd [crusher] +[<c1001072>] do_one_initcall+0x72/0x119 +[<c106b8ae>] sys_init_module+0xc8d/0xe77 +[<c14d7d18>] syscall_call+0x7/0xb +eb002bf8: redzone 1:0xd84156c5635688c0, redzone 2:0x0 +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="n">noinline</span> <span class="kt">void</span> <span class="nf">buffer_overflow</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">kmem_cache</span> <span class="o">*</span><span class="n">km</span> <span class="o">=</span> <span class="n">kmem_cache_create</span><span class="p">(</span><span class="s">"dummy"</span><span class="p">,</span> <span class="mi">3000</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span> + <span class="kt">char</span> <span class="o">*</span><span class="n">b</span> <span class="o">=</span> <span class="n">kmem_cache_alloc</span><span class="p">(</span><span class="n">km</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + + <span class="n">printk</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">memset</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">3016</span><span class="p">);</span> + <span class="n">kmem_cache_free</span><span class="p">(</span><span class="n">km</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span> +<span class="p">}</span> +</pre></div> +</div> +</div> +<div class="section" id="debug-pagealloc"> +<h3>DEBUG_PAGEALLOC<a class="headerlink" href="#debug-pagealloc" title="Permalink to this headline">¶</a></h3> +<ul class="admonition-debug-pagealloc simple"> +<li>Memory debugger that works at a page level</li> +<li>Detects invalid accesses either by:<ul> +<li>Filling pages with poison byte patterns and checking the pattern at +reallocation</li> +<li>Unmapping the dellocated pages from kernel space (just a few +architectures)</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="kasan"> +<h3>KASan<a class="headerlink" href="#kasan" title="Permalink to this headline">¶</a></h3> +<p>KASan is a dynamic memory error detector designed to find use-after-free +and out-of-bounds bugs.</p> +<p>The main idea of KASAN is to use shadow memory to record whether each byte +of memory is safe to access or not, and use compiler's instrumentation to +check the shadow memory on each memory access.</p> +<p>Address sanitizer uses 1 byte of shadow memory to track 8 bytes of kernel +address space. It uses 0-7 to encode the number of consecutive bytes at +the beginning of the eigh-byte region that are valid.</p> +<p>See <cite>The Kernel Address Sanitizer (KASAN)</cite> for more information and have a look +at lib/test_kasan.c for an example of problems that KASan can detect.</p> +<ul class="admonition-kasan simple"> +<li>dynamic memory error detector</li> +<li>finds user-after-free or out-of-bound bugs</li> +<li>uses shadow memory to track memory operations</li> +<li>lib/test_kasan.c</li> +</ul> +<div class="section" id="kasan-vs-debug-pagealloc"> +<h4>KASan vs DEBUG_PAGEALLOC<a class="headerlink" href="#kasan-vs-debug-pagealloc" title="Permalink to this headline">¶</a></h4> +<p class="admonition-kasan-vs-debug-pagealloc">KASan is slower than DEBUG_PAGEALLOC, but KASan works on sub-page granularity +level, so it able to find more bugs.</p> +</div> +<div class="section" id="kasan-vs-slub-debug"> +<h4>KASan vs SLUB_DEBUG<a class="headerlink" href="#kasan-vs-slub-debug" title="Permalink to this headline">¶</a></h4> +<ul class="admonition-kasan-vs-slub-debug simple"> +<li>SLUB_DEBUG has lower overhead than KASan.</li> +<li>SLUB_DEBUG in most cases are not able to detect bad reads, KASan able to +detect both reads and writes.</li> +<li>In some cases (e.g. redzone overwritten) SLUB_DEBUG detect bugs only on +allocation/freeing of object. KASan catch bugs right before it will happen, +so we always know exact place of first bad read/write.</li> +</ul> +</div> +</div> +<div class="section" id="kmemleak"> +<h3>Kmemleak<a class="headerlink" href="#kmemleak" title="Permalink to this headline">¶</a></h3> +<p>Kmemleak provides a way of detecting kernel memory leaks in a way similar to a +tracing garbage collector. Since tracing pointers is not possible in C, kmemleak +scans the kernel stacks as well as dynamically and statically kernel memory for +pointers to allocated buffers. A buffer for which there is no pointer is +considered as leaked. The basic steps to use kmemleak are presented bellow, for +more information see <cite>Kernel Memory Leak Detector</cite></p> +<ul class="admonition-kmemleak simple"> +<li>enable kernel config: <cite>CONFIG_DEBUG_KMEMLEAK</cite></li> +<li>setup: <cite>mount -t debugfs nodev /sys/kernel/debug</cite></li> +<li>trigger a memory scan: <cite>echo scan > /sys/kernel/debug/kmemleak</cite></li> +<li>show memory leaks: <cite>cat /sys/kernel/debug/kmemleak</cite></li> +<li>clear all possible leaks: <cite>echo clear > /sys/kernel/debug/kmemleak</cite></li> +</ul> +<p>As an example, lets look at the following simple module:</p> +<div class="admonition-kmemleak-example highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">leak_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + + <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">kmalloc</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> + +<span class="n">MODULE_LICENSE</span><span class="p">(</span><span class="s">"GPL v2"</span><span class="p">);</span> +<span class="n">module_init</span><span class="p">(</span><span class="n">leak_init</span><span class="p">);</span> +</pre></div> +</div> +<p>Loading the module and triggering a kmemleak scan will issue the +following report:</p> +<div class="admonition-kmemleak-report highlight-none"><div class="highlight"><pre><span></span>root@qemux86:~# insmod skels/debugging/leak/leak.ko +leak: loading out-of-tree module taints kernel. +leak_init +root@qemux86:~# echo scan > /sys/kernel/debug/kmemleak +root@qemux86:~# echo scan > /sys/kernel/debug/kmemleak +kmemleak: 1 new suspected memory leaks (see /sys/kernel/debug/kmemleak) +root@qemux86:~# cat /sys/kernel/debug/kmemleak +unreferenced object 0xd7871500 (size 32): +comm "insmod", pid 237, jiffies 4294902108 (age 24.628s) +hex dump (first 32 bytes): +5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ +5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a a5 ZZZZZZZZZZZZZZZ. +backtrace: +[<(ptrval)>] kmem_cache_alloc_trace+0x163/0x310 +[<(ptrval)>] leak_init+0x2f/0x1000 [leak] +[<(ptrval)>] do_one_initcall+0x57/0x2e0 +[<(ptrval)>] do_init_module+0x4b/0x1be +[<(ptrval)>] load_module+0x201a/0x2590 +[<(ptrval)>] sys_init_module+0xfd/0x120 +[<(ptrval)>] do_int80_syscall_32+0x6a/0x1a0 +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Notice that we did not had to unload the module to detect the memory +leak since kmemleak detects that the allocated buffer is not +reachable anymore.</p> +</div> +</div> +</div> +<div class="section" id="lockdep-checker"> +<h2>Lockdep checker<a class="headerlink" href="#lockdep-checker" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-lockdep-checker simple"> +<li>CONFIG_DEBUG_LOCKDEP</li> +<li>Detects lock inversio, circular dependencies, incorrect usage of locks +(including interrupt context)</li> +<li>Maintains dependency between classes of locks not individual locks</li> +<li>Each scenario is only checked once and hashed</li> +</ul> +<p>Lets take for example the following kernel module that runs two kernel threads:</p> +<div class="admonition-ab-ba-deadlock-example highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">noinline</span> <span class="kt">int</span> <span class="nf">thread_a</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">unused</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">mutex_lock</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired A</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">mutex_lock</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired B</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + + <span class="n">mutex_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">);</span> + <span class="n">mutex_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<div class="highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">noinline</span> <span class="kt">int</span> <span class="nf">thread_b</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">unused</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">mutex_lock</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired B</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">mutex_lock</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired A</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + + <span class="n">mutex_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">);</span> + <span class="n">mutex_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">);</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>Loading this module with lockdep checker active will produce the following +kernel log:</p> +<div class="admonition-ab-ba-deadlock-report highlight-none"><div class="highlight"><pre><span></span>thread_a acquired A +thread_a acquired B +thread_b acquired B + +====================================================== +WARNING: possible circular locking dependency detected +4.19.0+ #4 Tainted: G O +------------------------------------------------------ +thread_b/238 is trying to acquire lock: +(ptrval) (a){+.+.}, at: thread_b+0x48/0x90 [locking] + +but task is already holding lock: +(ptrval) (b){+.+.}, at: thread_b+0x27/0x90 [locking] + +which lock already depends on the new lock. +</pre></div> +</div> +<p>As you can see, although the deadlock condition did not trigger (because thread +A did not complete execution before thread B started execution) the lockdep +checker identified a potential deadlock scenario.</p> +<p>Lockdep checker will provide even more information to help determine what caused +the deadlock, like the dependency chain:</p> +<div class="admonition-ab-ba-deadlock-report-dependency-chain highlight-none"><div class="highlight"><pre><span></span>the existing dependency chain (in reverse order) is: + +-> #1 (b){+.+.}: + __mutex_lock+0x60/0x830 + mutex_lock_nested+0x20/0x30 + thread_a+0x48/0x90 [locking] + kthread+0xeb/0x100 + ret_from_fork+0x2e/0x38 + +-> #0 (a){+.+.}: + lock_acquire+0x93/0x190 + __mutex_lock+0x60/0x830 + mutex_lock_nested+0x20/0x30 + thread_b+0x48/0x90 [locking] + kthread+0xeb/0x100 + ret_from_fork+0x2e/0x38 +</pre></div> +</div> +<p>and even an unsafe locking scenario:</p> +<div class="admonition-ab-ba-deadlock-report-unsafe-locking-scenario highlight-none"><div class="highlight"><pre><span></span>other info that might help us debug this: + +Possible unsafe locking scenario: + +CPU0 CPU1 +---- ---- +lock(b); + lock(a); + lock(b); +lock(a); + +*** DEADLOCK *** +</pre></div> +</div> +<p>Another example of unsafe locking issues that lockdep checker detects +is unsafe locking from interrupt context. Lets consider the following +kernel module:</p> +<div class="admonition-irq-deadlock-example highlight-c"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="nf">DEFINE_SPINLOCK</span><span class="p">(</span><span class="n">lock</span><span class="p">);</span> + +<span class="k">static</span> <span class="kt">void</span> <span class="nf">timerfn</span><span class="p">(</span><span class="k">struct</span> <span class="n">timer_list</span> <span class="o">*</span><span class="n">unused</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquiring lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s released lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> +<span class="p">}</span> + +<span class="k">static</span> <span class="nf">DEFINE_TIMER</span><span class="p">(</span><span class="n">timer</span><span class="p">,</span> <span class="n">timerfn</span><span class="p">);</span> + +<span class="kt">int</span> <span class="nf">init_module</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> +<span class="p">{</span> + <span class="n">mod_timer</span><span class="p">(</span><span class="o">&</span><span class="n">timer</span><span class="p">,</span> <span class="n">jiffies</span><span class="p">);</span> + + <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquiring lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">spin_lock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s acquired lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="n">spin_unlock</span><span class="p">(</span><span class="o">&</span><span class="n">lock</span><span class="p">);</span> <span class="n">pr_info</span><span class="p">(</span><span class="s">"%s released lock</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">__func__</span><span class="p">);</span> + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>As in the previous case, loading the module will trigger a lockdep +warning:</p> +<div class="admonition-irq-deadlock-report highlight-none"><div class="highlight"><pre><span></span>init_module acquiring lock +init_module acquired lock +init_module released lock +timerfn acquiring lock + +================================ +WARNING: inconsistent lock state +4.19.0+ #4 Tainted: G O +-------------------------------- +inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage. +ksoftirqd/0/9 [HC0[0]:SC1[1]:HE1:SE0] takes: +(ptrval) (lock#4){+.?.}, at: timerfn+0x25/0x60 [locking2] +{SOFTIRQ-ON-W} state was registered at: +lock_acquire+0x93/0x190 +_raw_spin_lock+0x39/0x50 +init_module+0x35/0x70 [locking2] +do_one_initcall+0x57/0x2e0 +do_init_module+0x4b/0x1be +load_module+0x201a/0x2590 +sys_init_module+0xfd/0x120 +do_int80_syscall_32+0x6a/0x1a0 +restore_all+0x0/0x8d +</pre></div> +</div> +<p>The warning will also provide additional information and a potential unsafe +locking scenario:</p> +<div class="admonition-irq-deadlock-report highlight-none"><div class="highlight"><pre><span></span>Possible unsafe locking scenario: + + CPU0 + ---- + lock(lock#4); + <Interrupt> + lock(lock#4); + + *** DEADLOCK *** + +1 lock held by ksoftirqd/0/9: +#0: (ptrval) (/home/tavi/src/linux/tools/labs/skels/./debugging/locking2/locking2.c:13){+.-.}, at: call_timer_f0 +stack backtrace: +CPU: 0 PID: 9 Comm: ksoftirqd/0 Tainted: G O 4.19.0+ #4 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014 +Call Trace: +dump_stack+0x66/0x96 +print_usage_bug.part.26+0x1ee/0x200 +mark_lock+0x5ea/0x640 +__lock_acquire+0x4b4/0x17a0 +lock_acquire+0x93/0x190 +_raw_spin_lock+0x39/0x50 +timerfn+0x25/0x60 [locking2] +</pre></div> +</div> +</div> +<div class="section" id="perf"> +<h2>perf<a class="headerlink" href="#perf" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-perf simple"> +<li>performance counters, tracepoints, kprobes, uprobes</li> +<li>hardware events: CPU cycles, TLB misses, cache misses</li> +<li>software events: page faults , context switches</li> +<li>collects backtraces (user + kernel)</li> +</ul> +</div> +<div class="section" id="other-tools"> +<h2>Other tools<a class="headerlink" href="#other-tools" title="Permalink to this headline">¶</a></h2> +<ul class="admonition-other-tools simple"> +<li>ftrace</li> +<li>kprobes</li> +<li>sparse</li> +<li>coccinelle</li> +<li>checkpatch.pl</li> +<li>printk</li> +<li>dump_stack()</li> +</ul> +</div> +</div> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="lec8-filesystems.html" class="btn btn-neutral float-left" title="SO2 Lecture 08 - Filesystem Management" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="lec10-networking.html" class="btn btn-neutral float-right" title="SO2 Lecture 10 - Networking" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright The kernel development community.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file